1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Merge pull request #1781 from vcmi/object_distribution

Improved object distribution
This commit is contained in:
DjWarmonger 2023-04-04 06:52:10 +02:00 committed by GitHub
commit 53df84459f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 391 additions and 94 deletions

View File

@ -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

View File

@ -508,7 +508,11 @@ void AObjectTypeHandler::init(const JsonNode & input)
if (!input["rmg"].isNull())
{
rmgInfo.value = static_cast<ui32>(input["rmg"]["value"].Float());
rmgInfo.mapLimit = loadJsonOrMax(input["rmg"]["mapLimit"]);
const JsonNode & mapLimit = input["rmg"]["mapLimit"];
if (!mapLimit.isNull())
rmgInfo.mapLimit.reset(static_cast<ui32>(mapLimit.Float()));
rmgInfo.zoneLimit = loadJsonOrMax(input["rmg"]["zoneLimit"]);
rmgInfo.rarity = static_cast<ui32>(input["rmg"]["rarity"].Float());
} // else block is not needed - set in constructor

View File

@ -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<ui32> 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 <typename Handler> void serialize(Handler &h, const int version)
{
h & value;

View File

@ -105,7 +105,12 @@ public:
inline bool canBePlacedAtAnyTerrain() const
{
return anyTerrain;
};
};
const std::set<TerrainId>& getAllowedTerrains() const
{
return allowedTerrains;
}
// Checks if object can be placed on specific terrain
bool canBePlacedAt(TerrainId terrain) const;

View File

@ -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<std::shared_ptr<Zone>> 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);

View File

@ -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<TResource, ui16> ZoneOptions::getMinesInfo() const
void ZoneOptions::setTreasureInfo(const std::vector<CTreasureInfo> & 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<CTreasureInfo> & ZoneOptions::getTreasureInfo() const
@ -254,6 +266,11 @@ const std::vector<CTreasureInfo> & 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()))

View File

@ -144,6 +144,8 @@ public:
void setTreasureInfo(const std::vector<CTreasureInfo> & value);
void addTreasureInfo(const CTreasureInfo & value);
const std::vector<CTreasureInfo> & 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<int> owner;
CTownInfo playerTowns;
CTownInfo neutralTowns;

97
lib/rmg/MinePlacer.cpp Normal file
View File

@ -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<ObjectManager>();
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<CGMine*> createdMines;
std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
for(const auto & mineInfo : zone.getMinesInfo())
{
ERes res = static_cast<ERes>(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<CGMine *>(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<CGObjectInstance*, ui32>(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<CGResource *>(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create());
resourse->amount = CGResource::RANDOM_AMOUNT;
manager.addNearbyObject(resourse, mine);
}
}
}
return true;
}
VCMI_LIB_NAMESPACE_END

30
lib/rmg/MinePlacer.h Normal file
View File

@ -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

View File

@ -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<TreasurePlacer>()->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<std::shared_ptr<Zone>> 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<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> 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<TreasurePlacer>()->addObjectToRandomPool(oi);
}
}
}
}
}
}
}
VCMI_LIB_NAMESPACE_END

View File

@ -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

View File

@ -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;

View File

@ -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<ObjectManager>();
zone->addModificator<ObjectDistributor>();
zone->addModificator<TreasurePlacer>();
zone->addModificator<ObstaclePlacer>();
zone->addModificator<TerrainPainter>();
@ -135,6 +138,7 @@ void RmgMap::addModificators()
else
{
zone->addModificator<TownPlacer>();
zone->addModificator<MinePlacer>();
zone->addModificator<ConnectionsPlacer>();
zone->addModificator<RoadPlacer>();
zone->addModificator<RiverPlacer>();

View File

@ -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<CGMine*> createdMines;
for(const auto & mineInfo : zone.getMinesInfo())
{
ERes res = static_cast<ERes>(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<CGMine *>(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<CGResource *>(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())

View File

@ -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<int>(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<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> 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<ui32>((2 * (creature->AIValue) * creaturesAmount * (1 + static_cast<float>(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<TreasurePlacer>()->possibleObjects.push_back(generateArtInfo(artid));
this->questArtZone->getModificator<TreasurePlacer>()->addObjectToRandomPool(generateArtInfo(artid));
return obj;
};
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
oi.value = static_cast<ui32>(((2 * (creature->AIValue) * creaturesAmount * (1 + static_cast<float>(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<TreasurePlacer>()->possibleObjects.push_back(generateArtInfo(artid));
this->questArtZone->getModificator<TreasurePlacer>()->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<TreasurePlacer>()->possibleObjects.push_back(generateArtInfo(artid));
this->questArtZone->getModificator<TreasurePlacer>()->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;

View File

@ -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);