diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 602278338..ff80ff181 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -101,11 +101,13 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/rmg/Zone.cpp ${MAIN_LIB_DIR}/rmg/Functions.cpp ${MAIN_LIB_DIR}/rmg/ObjectManager.cpp + ${MAIN_LIB_DIR}/rmg/ObjectDistributor.cpp ${MAIN_LIB_DIR}/rmg/RoadPlacer.cpp ${MAIN_LIB_DIR}/rmg/TreasurePlacer.cpp ${MAIN_LIB_DIR}/rmg/RmgMap.cpp ${MAIN_LIB_DIR}/rmg/ConnectionsPlacer.cpp ${MAIN_LIB_DIR}/rmg/WaterAdopter.cpp + ${MAIN_LIB_DIR}/rmg/MinePlacer.cpp ${MAIN_LIB_DIR}/rmg/TownPlacer.cpp ${MAIN_LIB_DIR}/rmg/WaterProxy.cpp ${MAIN_LIB_DIR}/rmg/WaterRoutes.cpp @@ -338,11 +340,13 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/rmg/Zone.h ${MAIN_LIB_DIR}/rmg/Functions.h ${MAIN_LIB_DIR}/rmg/ObjectManager.h + ${MAIN_LIB_DIR}/rmg/ObjectDistributor.h ${MAIN_LIB_DIR}/rmg/RoadPlacer.h ${MAIN_LIB_DIR}/rmg/TreasurePlacer.h ${MAIN_LIB_DIR}/rmg/RmgMap.h ${MAIN_LIB_DIR}/rmg/ConnectionsPlacer.h ${MAIN_LIB_DIR}/rmg/WaterAdopter.h + ${MAIN_LIB_DIR}/rmg/MinePlacer.h ${MAIN_LIB_DIR}/rmg/TownPlacer.h ${MAIN_LIB_DIR}/rmg/WaterProxy.h ${MAIN_LIB_DIR}/rmg/WaterRoutes.h diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index b86520095..8a9d50256 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -508,7 +508,11 @@ void AObjectTypeHandler::init(const JsonNode & input) if (!input["rmg"].isNull()) { rmgInfo.value = static_cast(input["rmg"]["value"].Float()); - rmgInfo.mapLimit = loadJsonOrMax(input["rmg"]["mapLimit"]); + + const JsonNode & mapLimit = input["rmg"]["mapLimit"]; + if (!mapLimit.isNull()) + rmgInfo.mapLimit.reset(static_cast(mapLimit.Float())); + rmgInfo.zoneLimit = loadJsonOrMax(input["rmg"]["zoneLimit"]); rmgInfo.rarity = static_cast(input["rmg"]["rarity"].Float()); } // else block is not needed - set in constructor diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index ef5035935..8fcb20678 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -43,7 +43,7 @@ struct DLL_LINKAGE RandomMapInfo ui32 value; /// How many of such objects can be placed on map, 0 = object can not be placed by RMG - ui32 mapLimit; + boost::optional mapLimit; /// How many of such objects can be placed in one zone, 0 = unplaceable ui32 zoneLimit; @@ -53,11 +53,12 @@ struct DLL_LINKAGE RandomMapInfo RandomMapInfo(): value(0), - mapLimit(0), zoneLimit(0), rarity(0) {} + void setMapLimit(ui32 val) { mapLimit.reset(val); } + template void serialize(Handler &h, const int version) { h & value; diff --git a/lib/mapObjects/ObjectTemplate.h b/lib/mapObjects/ObjectTemplate.h index 788dfbadf..64e2e46ea 100644 --- a/lib/mapObjects/ObjectTemplate.h +++ b/lib/mapObjects/ObjectTemplate.h @@ -105,7 +105,12 @@ public: inline bool canBePlacedAtAnyTerrain() const { return anyTerrain; - }; + }; + + const std::set& getAllowedTerrains() const + { + return allowedTerrains; + } // Checks if object can be placed on specific terrain bool canBePlacedAt(TerrainId terrain) const; diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 4f13b446d..2c2fd72cf 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -276,11 +276,11 @@ void CMapGenerator::genZones() void CMapGenerator::createWaterTreasures() { - if(!getZoneWater()) + if (!getZoneWater()) return; - + //add treasures on water - for(const auto & treasureInfo : getConfig().waterTreasure) + for (const auto& treasureInfo : getConfig().waterTreasure) { getZoneWater()->addTreasureInfo(treasureInfo); } @@ -296,7 +296,7 @@ void CMapGenerator::fillZones() //we need info about all town types to evaluate dwellings and pandoras with creatures properly //place main town in the middle Load::Progress::setupStepsTill(map->getZones().size(), 50); - for(const auto & it : map->getZones()) + for (const auto& it : map->getZones()) { it.second->initFreeTiles(); it.second->initModificators(); @@ -305,10 +305,10 @@ void CMapGenerator::fillZones() Load::Progress::setupStepsTill(map->getZones().size(), 240); std::vector> treasureZones; - for(const auto & it : map->getZones()) + for (const auto& it : map->getZones()) { it.second->processModificators(); - + if (it.second->getType() == ETemplateZoneType::TREASURE) treasureZones.push_back(it.second); @@ -316,10 +316,10 @@ void CMapGenerator::fillZones() } //find place for Grail - if(treasureZones.empty()) + if (treasureZones.empty()) { - for(const auto & it : map->getZones()) - if(it.second->getType() != ETemplateZoneType::WATER) + for (const auto& it : map->getZones()) + if (it.second->getType() != ETemplateZoneType::WATER) treasureZones.push_back(it.second); } auto grailZone = *RandomGeneratorUtil::nextItem(treasureZones, rand); diff --git a/lib/rmg/CRmgTemplate.cpp b/lib/rmg/CRmgTemplate.cpp index eaf4c5060..8089f71c7 100644 --- a/lib/rmg/CRmgTemplate.cpp +++ b/lib/rmg/CRmgTemplate.cpp @@ -136,6 +136,7 @@ ZoneOptions::ZoneOptions(): id(0), type(ETemplateZoneType::PLAYER_START), size(1), + maxTreasureValue(0), owner(boost::none), matchTerrainToTown(true), townsAreSameType(false), @@ -242,11 +243,22 @@ std::map ZoneOptions::getMinesInfo() const void ZoneOptions::setTreasureInfo(const std::vector & value) { treasureInfo = value; + recalculateMaxTreasureValue(); +} + +void ZoneOptions::recalculateMaxTreasureValue() +{ + maxTreasureValue = 0; + for (const auto& ti : treasureInfo) + { + vstd::amax(maxTreasureValue, ti.max); + } } void ZoneOptions::addTreasureInfo(const CTreasureInfo & value) { treasureInfo.push_back(value); + vstd::amax(maxTreasureValue, value.max); } const std::vector & ZoneOptions::getTreasureInfo() const @@ -254,6 +266,11 @@ const std::vector & ZoneOptions::getTreasureInfo() const return treasureInfo; } +ui32 ZoneOptions::getMaxTreasureValue() const +{ + return maxTreasureValue; +} + TRmgTemplateZoneId ZoneOptions::getMinesLikeZone() const { return minesLikeZone; @@ -386,6 +403,10 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler) { auto treasureData = handler.enterArray("treasure"); treasureData.serializeStruct(treasureInfo); + if (!handler.saving) + { + recalculateMaxTreasureValue(); + } } if((minesLikeZone == NO_ZONE) && (!handler.saving || !mines.empty())) diff --git a/lib/rmg/CRmgTemplate.h b/lib/rmg/CRmgTemplate.h index 1532496a6..951887844 100644 --- a/lib/rmg/CRmgTemplate.h +++ b/lib/rmg/CRmgTemplate.h @@ -144,6 +144,8 @@ public: void setTreasureInfo(const std::vector & value); void addTreasureInfo(const CTreasureInfo & value); const std::vector & getTreasureInfo() const; + ui32 getMaxTreasureValue() const; + void recalculateMaxTreasureValue(); TRmgTemplateZoneId getMinesLikeZone() const; TRmgTemplateZoneId getTerrainTypeLikeZone() const; @@ -163,6 +165,7 @@ protected: TRmgTemplateZoneId id; ETemplateZoneType::ETemplateZoneType type; int size; + ui32 maxTreasureValue; boost::optional owner; CTownInfo playerTowns; CTownInfo neutralTowns; diff --git a/lib/rmg/MinePlacer.cpp b/lib/rmg/MinePlacer.cpp new file mode 100644 index 000000000..dfe61522a --- /dev/null +++ b/lib/rmg/MinePlacer.cpp @@ -0,0 +1,97 @@ +/* +* License: GNU General Public License v2.0 or later +* Full text of license available in license.txt file, in main folder +* +*/ + +#include "StdInc.h" +#include "MinePlacer.h" +#include "TownPlacer.h" +#include "CMapGenerator.h" +#include "RmgMap.h" +#include "../mapping/CMap.h" +#include "../mapping/CMapEditManager.h" +#include "../mapObjects/CObjectClassesHandler.h" +#include "../spells/CSpellHandler.h" //for choosing random spells +#include "RmgPath.h" +#include "RmgObject.h" +#include "ObjectManager.h" +#include "Functions.h" +#include "RoadPlacer.h" +#include "WaterAdopter.h" +#include "TileInfo.h" + +VCMI_LIB_NAMESPACE_BEGIN + +void MinePlacer::process() +{ + auto * manager = zone.getModificator(); + if(!manager) + { + logGlobal->error("ObjectManager doesn't exist for zone %d, skip modificator %s", zone.getId(), getName()); + return; + } + + placeMines(*manager); +} + +void MinePlacer::init() +{ + DEPENDENCY(TownPlacer); + POSTFUNCTION(ObjectManager); + POSTFUNCTION(RoadPlacer); +} + +bool MinePlacer::placeMines(ObjectManager & manager) +{ + using namespace Res; + std::vector createdMines; + + std::vector> requiredObjects; + + for(const auto & mineInfo : zone.getMinesInfo()) + { + ERes res = static_cast(mineInfo.first); + for(int i = 0; i < mineInfo.second; ++i) + { + auto mineHandler = VLC->objtypeh->getHandlerFor(Obj::MINE, res); + const auto & rmginfo = mineHandler->getRMGInfo(); + auto * mine = dynamic_cast(mineHandler->create()); + mine->producedResource = res; + mine->tempOwner = PlayerColor::NEUTRAL; + mine->producedQuantity = mine->defaultResProduction(); + createdMines.push_back(mine); + + + if(!i && (res == ERes::WOOD || res == ERes::ORE)) + manager.addCloseObject(mine, rmginfo.value); //only first wood&ore mines are close + else + requiredObjects.push_back(std::pair(mine, rmginfo.value)); + } + } + + //Shuffle mines to avoid patterns, but don't shuffle key objects like towns + RandomGeneratorUtil::randomShuffle(requiredObjects, generator.rand); + for (const auto& obj : requiredObjects) + { + manager.addRequiredObject(obj.first, obj.second); + } + + //create extra resources + if(int extraRes = generator.getConfig().mineExtraResources) + { + for(auto * mine : createdMines) + { + for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc) + { + auto * resourse = dynamic_cast(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create()); + resourse->amount = CGResource::RANDOM_AMOUNT; + manager.addNearbyObject(resourse, mine); + } + } + } + + return true; +} + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/rmg/MinePlacer.h b/lib/rmg/MinePlacer.h new file mode 100644 index 000000000..19f9906cf --- /dev/null +++ b/lib/rmg/MinePlacer.h @@ -0,0 +1,30 @@ +/* +* MinePlacer.h, part of VCMI engine +* +* Authors: listed in file AUTHORS in main folder +* +* License: GNU General Public License v2.0 or later +* Full text of license available in license.txt file, in main folder +* +*/ +#pragma once +#include "Zone.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class ObjectManager; + +class MinePlacer: public Modificator +{ +public: + MODIFICATOR(MinePlacer); + + void process() override; + void init() override; + +protected: + bool placeMines(ObjectManager & manager); + +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/rmg/ObjectDistributor.cpp b/lib/rmg/ObjectDistributor.cpp new file mode 100644 index 000000000..c8ce97cad --- /dev/null +++ b/lib/rmg/ObjectDistributor.cpp @@ -0,0 +1,121 @@ +/* +* ObjectDistributor.cpp, part of VCMI engine +* +* Authors: listed in file AUTHORS in main folder +* +* License: GNU General Public License v2.0 or later +* Full text of license available in license.txt file, in main folder +* +*/ + +#include "StdInc.h" +#include "ObjectDistributor.h" + +#include "../VCMI_Lib.h" +#include "RmgMap.h" +#include "CMapGenerator.h" +#include "TreasurePlacer.h" +#include "TownPlacer.h" +#include "TerrainPainter.h" +#include "../mapObjects/CObjectClassesHandler.h" +#include "../mapObjects/MapObjects.h" +#include "Functions.h" +#include "RmgObject.h" + +VCMI_LIB_NAMESPACE_BEGIN + +void ObjectDistributor::process() +{ + //Firts call will add objects to ALL zones, once they were added skip it + if (zone.getModificator()->getPossibleObjectsSize() == 0) + { + ObjectDistributor::distributeLimitedObjects(); + } +} + +void ObjectDistributor::init() +{ + DEPENDENCY(TownPlacer); + DEPENDENCY(TerrainPainter); + POSTFUNCTION(TreasurePlacer); +} + +void ObjectDistributor::distributeLimitedObjects() +{ + //FIXME: Must be called after TerrainPainter::process() + + ObjectInfo oi; + auto zones = map.getZones(); + + for (auto primaryID : VLC->objtypeh->knownObjects()) + { + for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) + { + auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); + if (!handler->isStaticObject() && handler->getRMGInfo().value) + { + auto rmgInfo = handler->getRMGInfo(); + + //Skip objects which don't have global per-map limit here + if (rmgInfo.mapLimit) + { + //Count all zones where this object can be placed + std::vector> matchingZones; + + for (const auto& it : zones) + { + if (!handler->getTemplates(it.second->getTerrainType()).empty() && + rmgInfo.value <= it.second->getMaxTreasureValue()) + { + matchingZones.push_back(it.second); + } + } + + size_t numZones = matchingZones.size(); + if (!numZones) + continue; + + auto rmgInfo = handler->getRMGInfo(); + + for (auto& zone : matchingZones) + { + //We already know there are some templates + auto templates = handler->getTemplates(zone->getTerrainType()); + + //Assume the template with fewest terrains is the most suitable + auto temp = *boost::min_element(templates, [](std::shared_ptr lhs, std::shared_ptr rhs) -> bool + { + return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size(); + }); + + oi.generateObject = [temp]() -> CGObjectInstance * + { + return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp); + }; + + oi.value = rmgInfo.value; + oi.probability = rmgInfo.rarity; + oi.templ = temp; + + //Rounding up will make sure all possible objects are exhausted + uint32_t mapLimit = rmgInfo.mapLimit.get(); + uint32_t maxPerZone = std::ceil(float(mapLimit) / numZones); + + //But not more than zone limit + oi.maxPerZone = std::min(maxPerZone, rmgInfo.zoneLimit); + numZones--; + + rmgInfo.setMapLimit(mapLimit - oi.maxPerZone); + //Don't add objects with 0 count remaining + if (oi.maxPerZone) + { + zone->getModificator()->addObjectToRandomPool(oi); + } + } + } + } + } + } +} + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/rmg/ObjectDistributor.h b/lib/rmg/ObjectDistributor.h new file mode 100644 index 000000000..125d9af62 --- /dev/null +++ b/lib/rmg/ObjectDistributor.h @@ -0,0 +1,32 @@ +/* +* ObjectDistributor.h, part of VCMI engine +* +* Authors: listed in file AUTHORS in main folder +* +* License: GNU General Public License v2.0 or later +* Full text of license available in license.txt file, in main folder +* +*/ + +#pragma once + +#include "Zone.h" +#include "RmgObject.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class CGObjectInstance; +class ObjectTemplate; + +class ObjectDistributor : public Modificator +{ + void distributeLimitedObjects(); + +public: + MODIFICATOR(ObjectDistributor); + + void process() override; + void init() override; +}; + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/rmg/ObjectManager.cpp b/lib/rmg/ObjectManager.cpp index d844e94c1..5143706d4 100644 --- a/lib/rmg/ObjectManager.cpp +++ b/lib/rmg/ObjectManager.cpp @@ -236,8 +236,7 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg bool ObjectManager::createRequiredObjects() { logGlobal->trace("Creating required objects"); - - RandomGeneratorUtil::randomShuffle(requiredObjects, generator.rand); + for(const auto & object : requiredObjects) { auto * obj = object.first; diff --git a/lib/rmg/RmgMap.cpp b/lib/rmg/RmgMap.cpp index e9bcba7bc..fc1029326 100644 --- a/lib/rmg/RmgMap.cpp +++ b/lib/rmg/RmgMap.cpp @@ -21,6 +21,8 @@ #include "TreasurePlacer.h" #include "ConnectionsPlacer.h" #include "TownPlacer.h" +#include "MinePlacer.h" +#include "ObjectDistributor.h" #include "WaterAdopter.h" #include "WaterProxy.h" #include "WaterRoutes.h" @@ -118,6 +120,7 @@ void RmgMap::addModificators() auto zone = z.second; zone->addModificator(); + zone->addModificator(); zone->addModificator(); zone->addModificator(); zone->addModificator(); @@ -135,6 +138,7 @@ void RmgMap::addModificators() else { zone->addModificator(); + zone->addModificator(); zone->addModificator(); zone->addModificator(); zone->addModificator(); diff --git a/lib/rmg/TownPlacer.cpp b/lib/rmg/TownPlacer.cpp index d85226378..57e1c7736 100644 --- a/lib/rmg/TownPlacer.cpp +++ b/lib/rmg/TownPlacer.cpp @@ -21,6 +21,7 @@ #include "ObjectManager.h" #include "Functions.h" #include "RoadPlacer.h" +#include "MinePlacer.h" #include "WaterAdopter.h" #include "TileInfo.h" @@ -35,14 +36,12 @@ void TownPlacer::process() return; } - placeTowns(*manager); - placeMines(*manager); } void TownPlacer::init() { - POSTFUNCTION(ObjectManager); + POSTFUNCTION(MinePlacer); POSTFUNCTION(RoadPlacer); } @@ -146,56 +145,13 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town) float distance = zone.getPos().dist2dSQ(t); return 100000.f - distance; //some big number }, ObjectManager::OptimizeType::WEIGHT); - rmgObject.setPosition(position); + rmgObject.setPosition(position + int3(2, 2, 0)); //place visitable tile in the exact center of a zone manager.placeObject(rmgObject, false, true); cleanupBoundaries(rmgObject); zone.setPos(rmgObject.getVisitablePosition()); //roads lead to main town return position; } -bool TownPlacer::placeMines(ObjectManager & manager) -{ - using namespace Res; - std::vector createdMines; - - for(const auto & mineInfo : zone.getMinesInfo()) - { - ERes res = static_cast(mineInfo.first); - for(int i = 0; i < mineInfo.second; ++i) - { - auto mineHandler = VLC->objtypeh->getHandlerFor(Obj::MINE, res); - const auto & rmginfo = mineHandler->getRMGInfo(); - auto * mine = dynamic_cast(mineHandler->create()); - mine->producedResource = res; - mine->tempOwner = PlayerColor::NEUTRAL; - mine->producedQuantity = mine->defaultResProduction(); - createdMines.push_back(mine); - - - if(!i && (res == ERes::WOOD || res == ERes::ORE)) - manager.addCloseObject(mine, rmginfo.value); //only first wood&ore mines are close - else - manager.addRequiredObject(mine, rmginfo.value); - } - } - - //create extra resources - if(int extraRes = generator.getConfig().mineExtraResources) - { - for(auto * mine : createdMines) - { - for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc) - { - auto * resourse = dynamic_cast(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create()); - resourse->amount = CGResource::RANDOM_AMOUNT; - manager.addNearbyObject(resourse, mine); - } - } - } - - return true; -} - void TownPlacer::cleanupBoundaries(const rmg::Object & rmgObject) { for(const auto & t : rmgObject.getArea().getBorderOutside()) diff --git a/lib/rmg/TreasurePlacer.cpp b/lib/rmg/TreasurePlacer.cpp index 4706d2488..ab4efc7b7 100644 --- a/lib/rmg/TreasurePlacer.cpp +++ b/lib/rmg/TreasurePlacer.cpp @@ -46,12 +46,15 @@ void TreasurePlacer::setQuestArtZone(Zone * otherZone) questArtZone = otherZone; } +void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi) +{ + possibleObjects.push_back(oi); +} + void TreasurePlacer::addAllPossibleObjects() { ObjectInfo oi; - int numZones = static_cast(map.getZones().size()); - for(auto primaryID : VLC->objtypeh->knownObjects()) { for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) @@ -59,23 +62,32 @@ void TreasurePlacer::addAllPossibleObjects() auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); if(!handler->isStaticObject() && handler->getRMGInfo().value) { - for(const auto & temp : handler->getTemplates()) + auto rmgInfo = handler->getRMGInfo(); + if (rmgInfo.mapLimit || rmgInfo.value > zone.getMaxTreasureValue()) { - if(temp->canBePlacedAt(zone.getTerrainType())) - { - oi.generateObject = [temp]() -> CGObjectInstance * - { - return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp); - }; - auto rmgInfo = handler->getRMGInfo(); - oi.value = rmgInfo.value; - oi.probability = rmgInfo.rarity; - oi.templ = temp; - oi.maxPerZone = rmgInfo.zoneLimit; - vstd::amin(oi.maxPerZone, rmgInfo.mapLimit / numZones); //simple, but should distribute objects evenly on large maps - possibleObjects.push_back(oi); - } + //Skip objects with per-map limit here + continue; } + + auto templates = handler->getTemplates(zone.getTerrainType()); + if (templates.empty()) + continue; + + //Assume the template with fewest terrains is the most suitable + auto temp = *boost::min_element(templates, [](std::shared_ptr lhs, std::shared_ptr rhs) -> bool + { + return lhs->getAllowedTerrains().size() < rhs->getAllowedTerrains().size(); + }); + + oi.generateObject = [temp]() -> CGObjectInstance * + { + return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp); + }; + oi.value = rmgInfo.value; + oi.probability = rmgInfo.rarity; + oi.templ = temp; + oi.maxPerZone = rmgInfo.zoneLimit; + addObjectToRandomPool(oi); } } } @@ -114,7 +126,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.value = generator.getConfig().prisonValues[i]; oi.probability = 30; oi.maxPerZone = generator.getPrisonsRemaning() / 5; //probably not perfect, but we can't generate more prisons than hereos. - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //all following objects are unlimited @@ -170,7 +182,7 @@ void TreasurePlacer::addAllPossibleObjects() }; oi.templ = tmplate; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } } } @@ -199,7 +211,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::SPELL_SCROLL, 0, zone.getTerrainType()); oi.value = generator.getConfig().scrollValues[i]; oi.probability = 30; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //pandora box with gold @@ -215,7 +227,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = i * generator.getConfig().pandoraMultiplierGold; oi.probability = 5; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //pandora box with experience @@ -231,7 +243,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = i * generator.getConfig().pandoraMultiplierExperience; oi.probability = 20; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //pandora box with creatures @@ -284,7 +296,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = static_cast((2 * (creature->AIValue) * creaturesAmount * (1 + static_cast(map.getZoneCount(creature->faction)) / map.getTotalZoneCount())) / 3); oi.probability = 3; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //Pandora with 12 spells of certain level @@ -313,7 +325,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = (i + 1) * generator.getConfig().pandoraMultiplierSpells; //5000 - 15000 oi.probability = 2; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } //Pandora with 15 spells of certain school @@ -342,7 +354,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = generator.getConfig().pandoraSpellSchool; oi.probability = 2; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } // Pandora box with 60 random spells @@ -370,7 +382,7 @@ void TreasurePlacer::addAllPossibleObjects() oi.setTemplate(Obj::PANDORAS_BOX, 0, zone.getTerrainType()); oi.value = generator.getConfig().pandoraSpell60; oi.probability = 2; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); //seer huts with creatures or generic rewards @@ -436,14 +448,14 @@ void TreasurePlacer::addAllPossibleObjects() generator.banQuestArt(artid); - this->questArtZone->getModificator()->possibleObjects.push_back(generateArtInfo(artid)); + this->questArtZone->getModificator()->addObjectToRandomPool(generateArtInfo(artid)); return obj; }; oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType()); oi.value = static_cast(((2 * (creature->AIValue) * creaturesAmount * (1 + static_cast(map.getZoneCount(creature->faction)) / map.getTotalZoneCount())) - 4000) / 3); oi.probability = 3; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size()); @@ -472,12 +484,12 @@ void TreasurePlacer::addAllPossibleObjects() generator.banQuestArt(artid); - this->questArtZone->getModificator()->possibleObjects.push_back(generateArtInfo(artid)); + this->questArtZone->getModificator()->addObjectToRandomPool(generateArtInfo(artid)); return obj; }; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * { @@ -495,16 +507,21 @@ void TreasurePlacer::addAllPossibleObjects() generator.banQuestArt(artid); - this->questArtZone->getModificator()->possibleObjects.push_back(generateArtInfo(artid)); + this->questArtZone->getModificator()->addObjectToRandomPool(generateArtInfo(artid)); return obj; }; - possibleObjects.push_back(oi); + addObjectToRandomPool(oi); } } } +size_t TreasurePlacer::getPossibleObjectsSize() const +{ + return possibleObjects.size(); +} + bool TreasurePlacer::isGuardNeededForTreasure(int value) { return zone.getType() != ETemplateZoneType::WATER && value > minGuardedValue; diff --git a/lib/rmg/TreasurePlacer.h b/lib/rmg/TreasurePlacer.h index 694561376..03968e308 100644 --- a/lib/rmg/TreasurePlacer.h +++ b/lib/rmg/TreasurePlacer.h @@ -45,7 +45,10 @@ public: void createTreasures(ObjectManager & manager); void setQuestArtZone(Zone * otherZone); + void addObjectToRandomPool(const ObjectInfo& oi); void addAllPossibleObjects(); //add objects, including zone-specific, to possibleObjects + + size_t getPossibleObjectsSize() const; protected: bool isGuardNeededForTreasure(int value);