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:
commit
53df84459f
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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()))
|
||||
|
@ -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
97
lib/rmg/MinePlacer.cpp
Normal 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
30
lib/rmg/MinePlacer.h
Normal 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
|
121
lib/rmg/ObjectDistributor.cpp
Normal file
121
lib/rmg/ObjectDistributor.cpp
Normal 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
|
32
lib/rmg/ObjectDistributor.h
Normal file
32
lib/rmg/ObjectDistributor.h
Normal 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
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user