mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Merge pull request #2053 from vcmi/parellel_rmg
Okay, let's merge this.
This commit is contained in:
commit
c99aa74434
@ -94,6 +94,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatH3M.cpp
|
||||
${MAIN_LIB_DIR}/mapping/MapReaderH3M.cpp
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatJson.cpp
|
||||
${MAIN_LIB_DIR}/mapping/ObstacleProxy.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/registerTypes/RegisterTypes.cpp
|
||||
${MAIN_LIB_DIR}/registerTypes/TypesClientPacks1.cpp
|
||||
@ -121,21 +122,25 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/rmg/TileInfo.cpp
|
||||
${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
|
||||
${MAIN_LIB_DIR}/rmg/RockPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/ObstaclePlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/RiverPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/TerrainPainter.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/Modificator.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RoadPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TreasurePlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/QuestArtifactPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ConnectionsPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterAdopter.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/MinePlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TownPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterProxy.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterRoutes.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RockPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RockFiller.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObstaclePlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RiverPlacer.cpp
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TerrainPainter.cpp
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/MapProxy.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/serializer/BinaryDeserializer.cpp
|
||||
${MAIN_LIB_DIR}/serializer/BinarySerializer.cpp
|
||||
@ -385,6 +390,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatH3M.h
|
||||
${MAIN_LIB_DIR}/mapping/MapReaderH3M.h
|
||||
${MAIN_LIB_DIR}/mapping/MapFormatJson.h
|
||||
${MAIN_LIB_DIR}/mapping/ObstacleProxy.h
|
||||
|
||||
${MAIN_LIB_DIR}/registerTypes/RegisterTypes.h
|
||||
|
||||
@ -404,23 +410,29 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/rmg/CZonePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/TileInfo.h
|
||||
${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
|
||||
${MAIN_LIB_DIR}/rmg/RockPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/ObstaclePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/RiverPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/TerrainPainter.h
|
||||
${MAIN_LIB_DIR}/rmg/float3.h
|
||||
${MAIN_LIB_DIR}/rmg/Functions.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/Modificator.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RoadPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TreasurePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/QuestArtifactPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ConnectionsPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterAdopter.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/MinePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TownPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterProxy.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/WaterRoutes.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RockPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RockFiller.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/ObstaclePlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/RiverPlacer.h
|
||||
${MAIN_LIB_DIR}/rmg/modificators/TerrainPainter.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/BlockingQueue.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/ThreadPool.h
|
||||
${MAIN_LIB_DIR}/rmg/threadpool/MapProxy.h
|
||||
|
||||
${MAIN_LIB_DIR}/serializer/BinaryDeserializer.h
|
||||
${MAIN_LIB_DIR}/serializer/BinarySerializer.h
|
||||
|
@ -41,5 +41,6 @@
|
||||
{
|
||||
"value" : [2000, 5333, 8666, 12000],
|
||||
"rewardValue" : [5000, 10000, 15000, 20000]
|
||||
}
|
||||
},
|
||||
"singleThread" : false
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ObstaclePlacer.cpp, part of VCMI engine
|
||||
* ObstacleProxy.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@ -9,20 +9,9 @@
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ObstacleProxy.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "RmgMap.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "Functions.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
@ -55,7 +44,27 @@ void ObstacleProxy::collectPossibleObstacles(TerrainId terrain)
|
||||
});
|
||||
}
|
||||
|
||||
int ObstacleProxy::getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects)
|
||||
void ObstacleProxy::addBlockedTile(const int3& tile)
|
||||
{
|
||||
blockedArea.add(tile);
|
||||
}
|
||||
|
||||
void ObstacleProxy::setBlockedArea(const rmg::Area& area)
|
||||
{
|
||||
blockedArea = area;
|
||||
}
|
||||
|
||||
void ObstacleProxy::clearBlockedArea()
|
||||
{
|
||||
blockedArea.clear();
|
||||
}
|
||||
|
||||
bool ObstacleProxy::isProhibited(const rmg::Area& objArea) const
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
int ObstacleProxy::getWeightedObjects(const int3 & tile, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects)
|
||||
{
|
||||
int maxWeight = std::numeric_limits<int>::min();
|
||||
for(auto & possibleObstacle : possibleObstacles)
|
||||
@ -75,12 +84,13 @@ int ObstacleProxy::getWeightedObjects(const int3 & tile, const CMap * map, CRand
|
||||
for(const auto & offset : obj->getBlockedOffsets())
|
||||
{
|
||||
rmgObject->setPosition(tile - offset);
|
||||
if(!map->isInTheMap(rmgObject->getPosition()))
|
||||
|
||||
if(!isInTheMap(rmgObject->getPosition()))
|
||||
continue;
|
||||
|
||||
if(!rmgObject->getArea().getSubarea([map](const int3 & t)
|
||||
if(!rmgObject->getArea().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return !map->isInTheMap(t);
|
||||
return !isInTheMap(t);
|
||||
}).empty())
|
||||
continue;
|
||||
|
||||
@ -124,7 +134,7 @@ int ObstacleProxy::getWeightedObjects(const int3 & tile, const CMap * map, CRand
|
||||
return maxWeight;
|
||||
}
|
||||
|
||||
void ObstacleProxy::placeObstacles(CMap * map, CRandomGenerator & rand)
|
||||
std::set<CGObjectInstance*> ObstacleProxy::createObstacles(CRandomGenerator & rand)
|
||||
{
|
||||
//reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left
|
||||
auto blockedTiles = blockedArea.getTilesVector();
|
||||
@ -137,7 +147,7 @@ void ObstacleProxy::placeObstacles(CMap * map, CRandomGenerator & rand)
|
||||
|
||||
std::list<rmg::Object> allObjects;
|
||||
std::vector<std::pair<rmg::Object*, int3>> weightedObjects;
|
||||
int maxWeight = getWeightedObjects(tile, map, rand, allObjects, weightedObjects);
|
||||
int maxWeight = getWeightedObjects(tile, rand, allObjects, weightedObjects);
|
||||
|
||||
if(weightedObjects.empty())
|
||||
{
|
||||
@ -164,9 +174,11 @@ void ObstacleProxy::placeObstacles(CMap * map, CRandomGenerator & rand)
|
||||
}
|
||||
}
|
||||
|
||||
finalInsertion(map->getEditManager(), objs);
|
||||
return objs;
|
||||
}
|
||||
|
||||
//FIXME: Only editor placer obstacles directly
|
||||
|
||||
void ObstacleProxy::finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances)
|
||||
{
|
||||
manager->insertObjects(instances); //insert as one operation - for undo purposes
|
||||
@ -185,85 +197,20 @@ void ObstacleProxy::placeObject(rmg::Object & object, std::set<CGObjectInstance*
|
||||
}
|
||||
}
|
||||
|
||||
void ObstacleProxy::postProcess(const rmg::Object & object)
|
||||
EditorObstaclePlacer::EditorObstaclePlacer(CMap* map):
|
||||
map(map)
|
||||
{
|
||||
}
|
||||
|
||||
bool ObstacleProxy::isProhibited(const rmg::Area & objArea) const
|
||||
bool EditorObstaclePlacer::isInTheMap(const int3& tile)
|
||||
{
|
||||
return false;
|
||||
return map->isInTheMap(tile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObstaclePlacer::process()
|
||||
void EditorObstaclePlacer::placeObstacles(CRandomGenerator & rand)
|
||||
{
|
||||
manager = zone.getModificator<ObjectManager>();
|
||||
if(!manager)
|
||||
return;
|
||||
|
||||
riverManager = zone.getModificator<RiverPlacer>();
|
||||
|
||||
collectPossibleObstacles(zone.getTerrainType());
|
||||
|
||||
blockedArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return map.shouldBeBlocked(t);
|
||||
});
|
||||
blockedArea.subtract(zone.areaUsed());
|
||||
zone.areaPossible().subtract(blockedArea);
|
||||
|
||||
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
||||
|
||||
placeObstacles(&map.map(), generator.rand);
|
||||
auto obstacles = createObstacles(rand);
|
||||
finalInsertion(map->getEditManager(), obstacles);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::init()
|
||||
{
|
||||
DEPENDENCY(ObjectManager);
|
||||
DEPENDENCY(TreasurePlacer);
|
||||
DEPENDENCY(WaterRoutes);
|
||||
DEPENDENCY(WaterProxy);
|
||||
DEPENDENCY(RoadPlacer);
|
||||
DEPENDENCY_ALL(RockPlacer);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> ObstaclePlacer::verifyCoverage(const int3 & t) const
|
||||
{
|
||||
return {map.shouldBeBlocked(t), zone.areaPossible().contains(t)};
|
||||
}
|
||||
|
||||
void ObstaclePlacer::placeObject(rmg::Object & object, std::set<CGObjectInstance*> &)
|
||||
{
|
||||
manager->placeObject(object, false, false);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::postProcess(const rmg::Object & object)
|
||||
{
|
||||
//river processing
|
||||
if(riverManager)
|
||||
{
|
||||
const auto objTypeName = object.instances().front()->object().typeName;
|
||||
if(objTypeName == "mountain")
|
||||
riverManager->riverSource().unite(object.getArea());
|
||||
else if(objTypeName == "lake")
|
||||
riverManager->riverSink().unite(object.getArea());
|
||||
}
|
||||
}
|
||||
|
||||
bool ObstaclePlacer::isProhibited(const rmg::Area & objArea) const
|
||||
{
|
||||
if(prohibitedArea.overlap(objArea))
|
||||
return true;
|
||||
|
||||
if(!zone.area().contains(objArea))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObstaclePlacer::finalInsertion(CMapEditManager *, std::set<CGObjectInstance*> &)
|
||||
{
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
VCMI_LIB_NAMESPACE_END
|
76
lib/mapping/ObstacleProxy.h
Normal file
76
lib/mapping/ObstacleProxy.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* ObstacleProxy.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 "../rmg/RmgObject.h"
|
||||
#include "CMapEditManager.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CMapEditManager;
|
||||
class CGObjectInstance;
|
||||
class ObjectTemplate;
|
||||
class CRandomGenerator;
|
||||
|
||||
class DLL_LINKAGE ObstacleProxy
|
||||
{
|
||||
//Base class generating random obstacles for RMG and map editor
|
||||
public:
|
||||
ObstacleProxy() = default;
|
||||
virtual ~ObstacleProxy() = default;
|
||||
|
||||
void collectPossibleObstacles(TerrainId terrain);
|
||||
|
||||
void addBlockedTile(const int3 & tile);
|
||||
|
||||
void setBlockedArea(const rmg::Area & area);
|
||||
|
||||
void clearBlockedArea();
|
||||
|
||||
virtual bool isProhibited(const rmg::Area& objArea) const;
|
||||
|
||||
virtual std::pair<bool, bool> verifyCoverage(const int3 & t) const;
|
||||
|
||||
virtual void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
virtual std::set<CGObjectInstance*> createObstacles(CRandomGenerator & rand);
|
||||
|
||||
virtual bool isInTheMap(const int3& tile) = 0;
|
||||
|
||||
void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
virtual void postProcess(const rmg::Object& object) {};
|
||||
|
||||
protected:
|
||||
int getWeightedObjects(const int3& tile, CRandomGenerator& rand, std::list<rmg::Object>& allObjects, std::vector<std::pair<rmg::Object*, int3>>& weightedObjects);
|
||||
|
||||
rmg::Area blockedArea;
|
||||
|
||||
using ObstacleVector = std::vector<std::shared_ptr<const ObjectTemplate>>;
|
||||
std::map<int, ObstacleVector> obstaclesBySize;
|
||||
using ObstaclePair = std::pair<int, ObstacleVector>;
|
||||
std::vector<ObstaclePair> possibleObstacles;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE EditorObstaclePlacer : public ObstacleProxy
|
||||
{
|
||||
public:
|
||||
EditorObstaclePlacer(CMap* map);
|
||||
|
||||
bool isInTheMap(const int3& tile) override;
|
||||
|
||||
void placeObstacles(CRandomGenerator& rand);
|
||||
|
||||
private:
|
||||
CMap* map;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -23,20 +23,22 @@
|
||||
#include "Zone.h"
|
||||
#include "Functions.h"
|
||||
#include "RmgMap.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "threadpool/ThreadPool.h"
|
||||
#include "modificators/ObjectManager.h"
|
||||
#include "modificators/TreasurePlacer.h"
|
||||
#include "modificators/RoadPlacer.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed) :
|
||||
mapGenOptions(mapGenOptions), randomSeed(RandomSeed),
|
||||
prisonsRemaining(0), monolithIndex(0)
|
||||
allowedPrisons(0), monolithIndex(0)
|
||||
{
|
||||
loadConfig();
|
||||
rand.setSeed(this->randomSeed);
|
||||
mapGenOptions.finalize(rand);
|
||||
map = std::make_unique<RmgMap>(mapGenOptions);
|
||||
placer = std::make_shared<CZonePlacer>(*map);
|
||||
}
|
||||
|
||||
int CMapGenerator::getRandomSeed() const
|
||||
@ -81,6 +83,7 @@ void CMapGenerator::loadConfig()
|
||||
config.secondaryRoadType = "";
|
||||
if(!mapGenOptions.isRoadEnabled(config.defaultRoadType))
|
||||
config.defaultRoadType = config.secondaryRoadType;
|
||||
config.singleThread = randomMapJson["singleThread"].Bool();
|
||||
}
|
||||
|
||||
const CMapGenerator::Config & CMapGenerator::getConfig() const
|
||||
@ -98,20 +101,22 @@ const CMapGenOptions& CMapGenerator::getMapGenOptions() const
|
||||
|
||||
void CMapGenerator::initPrisonsRemaining()
|
||||
{
|
||||
prisonsRemaining = 0;
|
||||
for (auto isAllowed : map->map().allowedHeroes)
|
||||
allowedPrisons = 0;
|
||||
for (auto isAllowed : map->getMap(this).allowedHeroes)
|
||||
{
|
||||
if (isAllowed)
|
||||
prisonsRemaining++;
|
||||
allowedPrisons++;
|
||||
}
|
||||
prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * mapGenOptions.getPlayerCount()); //so at least 16 heroes will be available for every player
|
||||
allowedPrisons = std::max<int> (0, allowedPrisons - 16 * mapGenOptions.getPlayerCount()); //so at least 16 heroes will be available for every player
|
||||
}
|
||||
|
||||
void CMapGenerator::initQuestArtsRemaining()
|
||||
{
|
||||
//TODO: Move to QuestArtifactPlacer?
|
||||
for (auto art : VLC->arth->objects)
|
||||
{
|
||||
if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty()) //don't use parts of combined artifacts
|
||||
//Don't use parts of combined artifacts
|
||||
if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty())
|
||||
questArtifacts.push_back(art->getId());
|
||||
}
|
||||
}
|
||||
@ -123,13 +128,13 @@ std::unique_ptr<CMap> CMapGenerator::generate()
|
||||
try
|
||||
{
|
||||
addHeaderInfo();
|
||||
map->initTiles(*this);
|
||||
map->initTiles(*this, rand);
|
||||
Load::Progress::step();
|
||||
initPrisonsRemaining();
|
||||
initQuestArtsRemaining();
|
||||
genZones();
|
||||
Load::Progress::step();
|
||||
map->map().calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
|
||||
map->getMap(this).calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded
|
||||
map->addModificators();
|
||||
Load::Progress::step(3);
|
||||
fillZones();
|
||||
@ -160,7 +165,7 @@ std::string CMapGenerator::getMapDescription() const
|
||||
std::stringstream ss;
|
||||
ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
|
||||
", levels %d, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() %
|
||||
randomSeed % map->map().width % map->map().height % static_cast<int>(map->map().levels()) % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
randomSeed % map->width() % map->height() % static_cast<int>(map->levels()) % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
|
||||
monsterStrengthStr[monsterStrengthIndex]);
|
||||
|
||||
@ -259,22 +264,21 @@ void CMapGenerator::addPlayerInfo()
|
||||
teamNumbers[j].erase(itTeam);
|
||||
}
|
||||
teamsTotal.insert(player.team.getNum());
|
||||
map->map().players[pSettings.getColor().getNum()] = player;
|
||||
map->getMap(this).players[pSettings.getColor().getNum()] = player;
|
||||
}
|
||||
|
||||
map->map().howManyTeams = teamsTotal.size();
|
||||
map->getMap(this).howManyTeams = teamsTotal.size();
|
||||
}
|
||||
|
||||
void CMapGenerator::genZones()
|
||||
{
|
||||
CZonePlacer placer(*map);
|
||||
placer.placeZones(&rand);
|
||||
placer.assignZones(&rand);
|
||||
placer->placeZones(&rand);
|
||||
placer->assignZones(&rand);
|
||||
|
||||
logGlobal->info("Zones generated successfully");
|
||||
}
|
||||
|
||||
void CMapGenerator::createWaterTreasures()
|
||||
void CMapGenerator::addWaterTreasuresInfo()
|
||||
{
|
||||
if (!getZoneWater())
|
||||
return;
|
||||
@ -288,14 +292,16 @@ void CMapGenerator::createWaterTreasures()
|
||||
|
||||
void CMapGenerator::fillZones()
|
||||
{
|
||||
findZonesForQuestArts();
|
||||
createWaterTreasures();
|
||||
addWaterTreasuresInfo();
|
||||
|
||||
logGlobal->info("Started filling zones");
|
||||
|
||||
size_t numZones = map->getZones().size();
|
||||
|
||||
//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);
|
||||
|
||||
Load::Progress::setupStepsTill(numZones, 50);
|
||||
for (const auto& it : map->getZones())
|
||||
{
|
||||
it.second->initFreeTiles();
|
||||
@ -303,16 +309,82 @@ void CMapGenerator::fillZones()
|
||||
Progress::Progress::step();
|
||||
}
|
||||
|
||||
Load::Progress::setupStepsTill(map->getZones().size(), 240);
|
||||
std::vector<std::shared_ptr<Zone>> treasureZones;
|
||||
|
||||
TModificators allJobs;
|
||||
for (auto& it : map->getZones())
|
||||
{
|
||||
allJobs.splice(allJobs.end(), it.second->getModificators());
|
||||
}
|
||||
|
||||
Load::Progress::setupStepsTill(allJobs.size(), 240);
|
||||
|
||||
if (config.singleThread) //No thread pool, just queue with deterministic order
|
||||
{
|
||||
while (!allJobs.empty())
|
||||
{
|
||||
for (auto it = allJobs.begin(); it != allJobs.end();)
|
||||
{
|
||||
if ((*it)->isReady())
|
||||
{
|
||||
auto jobCopy = *it;
|
||||
jobCopy->run();
|
||||
Progress::Progress::step(); //Update progress bar
|
||||
allJobs.erase(it);
|
||||
break; //Restart from the first job
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool pool;
|
||||
std::vector<boost::future<void>> futures;
|
||||
//At most one Modificator can run for every zone
|
||||
pool.init(std::min<int>(boost::thread::hardware_concurrency(), numZones));
|
||||
|
||||
while (!allJobs.empty())
|
||||
{
|
||||
for (auto it = allJobs.begin(); it != allJobs.end();)
|
||||
{
|
||||
if ((*it)->isFinished())
|
||||
{
|
||||
it = allJobs.erase(it);
|
||||
Progress::Progress::step();
|
||||
}
|
||||
else if ((*it)->isReady())
|
||||
{
|
||||
auto jobCopy = *it;
|
||||
futures.emplace_back(pool.async([this, jobCopy]() -> void
|
||||
{
|
||||
jobCopy->run();
|
||||
Progress::Progress::step(); //Update progress bar
|
||||
}
|
||||
));
|
||||
it = allJobs.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Wait for all the tasks
|
||||
for (auto& fut : futures)
|
||||
{
|
||||
fut.get();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& it : map->getZones())
|
||||
{
|
||||
it.second->processModificators();
|
||||
|
||||
if (it.second->getType() == ETemplateZoneType::TREASURE)
|
||||
treasureZones.push_back(it.second);
|
||||
|
||||
Progress::Progress::step();
|
||||
}
|
||||
|
||||
//find place for Grail
|
||||
@ -324,44 +396,23 @@ void CMapGenerator::fillZones()
|
||||
}
|
||||
auto grailZone = *RandomGeneratorUtil::nextItem(treasureZones, rand);
|
||||
|
||||
map->map().grailPos = *RandomGeneratorUtil::nextItem(grailZone->freePaths().getTiles(), rand);
|
||||
map->getMap(this).grailPos = *RandomGeneratorUtil::nextItem(grailZone->freePaths().getTiles(), rand);
|
||||
|
||||
logGlobal->info("Zones filled successfully");
|
||||
|
||||
Load::Progress::set(250);
|
||||
}
|
||||
|
||||
void CMapGenerator::findZonesForQuestArts()
|
||||
{
|
||||
//we want to place arties in zones that were not yet filled (higher index)
|
||||
|
||||
for (auto connection : mapGenOptions.getMapTemplate()->getConnections())
|
||||
{
|
||||
auto zoneA = map->getZones()[connection.getZoneA()];
|
||||
auto zoneB = map->getZones()[connection.getZoneB()];
|
||||
|
||||
if (zoneA->getId() > zoneB->getId())
|
||||
{
|
||||
if(auto * m = zoneB->getModificator<TreasurePlacer>())
|
||||
m->setQuestArtZone(zoneA.get());
|
||||
}
|
||||
else if (zoneA->getId() < zoneB->getId())
|
||||
{
|
||||
if(auto * m = zoneA->getModificator<TreasurePlacer>())
|
||||
m->setQuestArtZone(zoneB.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMapGenerator::addHeaderInfo()
|
||||
{
|
||||
map->map().version = EMapFormat::VCMI;
|
||||
map->map().width = mapGenOptions.getWidth();
|
||||
map->map().height = mapGenOptions.getHeight();
|
||||
map->map().twoLevel = mapGenOptions.getHasTwoLevels();
|
||||
map->map().name = VLC->generaltexth->allTexts[740];
|
||||
map->map().description = getMapDescription();
|
||||
map->map().difficulty = 1;
|
||||
auto& m = map->getMap(this);
|
||||
m.version = EMapFormat::VCMI;
|
||||
m.width = mapGenOptions.getWidth();
|
||||
m.height = mapGenOptions.getHeight();
|
||||
m.twoLevel = mapGenOptions.getHasTwoLevels();
|
||||
m.name = VLC->generaltexth->allTexts[740];
|
||||
m.description = getMapDescription();
|
||||
m.difficulty = 1;
|
||||
addPlayerInfo();
|
||||
}
|
||||
|
||||
@ -389,23 +440,41 @@ int CMapGenerator::getNextMonlithIndex()
|
||||
|
||||
int CMapGenerator::getPrisonsRemaning() const
|
||||
{
|
||||
return prisonsRemaining;
|
||||
return allowedPrisons;
|
||||
}
|
||||
|
||||
void CMapGenerator::decreasePrisonsRemaining()
|
||||
std::shared_ptr<CZonePlacer> CMapGenerator::getZonePlacer() const
|
||||
{
|
||||
prisonsRemaining = std::max (0, prisonsRemaining - 1);
|
||||
return placer;
|
||||
}
|
||||
|
||||
const std::vector<ArtifactID> & CMapGenerator::getQuestArtsRemaning() const
|
||||
const std::vector<ArtifactID> & CMapGenerator::getAllPossibleQuestArtifacts() const
|
||||
{
|
||||
return questArtifacts;
|
||||
}
|
||||
|
||||
const std::vector<HeroTypeID> CMapGenerator::getAllPossibleHeroes() const
|
||||
{
|
||||
//Skip heroes that were banned, including the ones placed in prisons
|
||||
std::vector<HeroTypeID> ret;
|
||||
for (int j = 0; j < map->getMap(this).allowedHeroes.size(); j++)
|
||||
{
|
||||
if (map->getMap(this).allowedHeroes[j])
|
||||
ret.push_back(HeroTypeID(j));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CMapGenerator::banQuestArt(const ArtifactID & id)
|
||||
{
|
||||
map->map().allowedArtifact[id] = false;
|
||||
vstd::erase_if_present(questArtifacts, id);
|
||||
//TODO: Protect with mutex
|
||||
map->getMap(this).allowedArtifact[id] = false;
|
||||
}
|
||||
|
||||
void CMapGenerator::banHero(const HeroTypeID & id)
|
||||
{
|
||||
//TODO: Protect with mutex
|
||||
map->getMap(this).allowedHeroes[id] = false;
|
||||
}
|
||||
|
||||
Zone * CMapGenerator::getZoneWater() const
|
||||
|
@ -25,6 +25,7 @@ class JsonNode;
|
||||
class RmgMap;
|
||||
class CMap;
|
||||
class Zone;
|
||||
class CZonePlacer;
|
||||
|
||||
using JsonVector = std::vector<JsonNode>;
|
||||
|
||||
@ -46,6 +47,7 @@ public:
|
||||
int pandoraMultiplierGold, pandoraMultiplierExperience, pandoraMultiplierSpells, pandoraSpellSchool, pandoraSpell60;
|
||||
std::vector<int> pandoraCreatureValues;
|
||||
std::vector<int> questValues, questRewardValues;
|
||||
bool singleThread;
|
||||
};
|
||||
|
||||
explicit CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed = std::time(nullptr));
|
||||
@ -53,37 +55,34 @@ public:
|
||||
|
||||
const Config & getConfig() const;
|
||||
|
||||
CRandomGenerator rand;
|
||||
|
||||
const CMapGenOptions& getMapGenOptions() const;
|
||||
|
||||
std::unique_ptr<CMap> generate();
|
||||
|
||||
void findZonesForQuestArts();
|
||||
|
||||
int getNextMonlithIndex();
|
||||
int getPrisonsRemaning() const;
|
||||
void decreasePrisonsRemaining();
|
||||
const std::vector<ArtifactID> & getQuestArtsRemaning() const;
|
||||
std::shared_ptr<CZonePlacer> getZonePlacer() const;
|
||||
const std::vector<ArtifactID> & getAllPossibleQuestArtifacts() const;
|
||||
const std::vector<HeroTypeID> getAllPossibleHeroes() const;
|
||||
void banQuestArt(const ArtifactID & id);
|
||||
void banHero(const HeroTypeID& id);
|
||||
|
||||
Zone * getZoneWater() const;
|
||||
void createWaterTreasures();
|
||||
void addWaterTreasuresInfo();
|
||||
|
||||
int getRandomSeed() const;
|
||||
|
||||
private:
|
||||
CRandomGenerator rand;
|
||||
int randomSeed;
|
||||
CMapGenOptions& mapGenOptions;
|
||||
Config config;
|
||||
std::unique_ptr<RmgMap> map;
|
||||
std::shared_ptr<CZonePlacer> placer;
|
||||
|
||||
std::vector<rmg::ZoneConnection> connectionsLeft;
|
||||
|
||||
//std::pair<Zones::key_type, Zones::mapped_type> zoneWater;
|
||||
|
||||
int prisonsRemaining;
|
||||
//int questArtsRemaining;
|
||||
int allowedPrisons;
|
||||
int monolithIndex;
|
||||
std::vector<ArtifactID> questArtifacts;
|
||||
|
||||
@ -98,7 +97,6 @@ private:
|
||||
void addHeaderInfo();
|
||||
void genZones();
|
||||
void fillZones();
|
||||
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -38,7 +38,7 @@ CZonePlacer::CZonePlacer(RmgMap & map)
|
||||
|
||||
int3 CZonePlacer::cords(const float3 & f) const
|
||||
{
|
||||
return int3(static_cast<si32>(std::max(0.f, (f.x * map.map().width) - 1)), static_cast<si32>(std::max(0.f, (f.y * map.map().height - 1))), f.z);
|
||||
return int3(static_cast<si32>(std::max(0.f, (f.x * map.width()) - 1)), static_cast<si32>(std::max(0.f, (f.y * map.height() - 1))), f.z);
|
||||
}
|
||||
|
||||
float CZonePlacer::getDistance (float distance) const
|
||||
@ -221,11 +221,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
|
||||
}
|
||||
|
||||
//Spread apart player starting zones
|
||||
|
||||
auto zoneType = zone->getType();
|
||||
auto existingZoneType = existingZone->getType();
|
||||
if ((zoneType == ETemplateZoneType::PLAYER_START || zoneType == ETemplateZoneType::CPU_START) &&
|
||||
(existingZoneType == ETemplateZoneType::PLAYER_START || existingZoneType == ETemplateZoneType::CPU_START))
|
||||
if (zone->getOwner() && existingZone->getOwner()) //Players participate in game
|
||||
{
|
||||
int firstPlayer = zone->getOwner().value();
|
||||
int secondPlayer = existingZone->getOwner().value();
|
||||
@ -785,7 +781,7 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
||||
zone->setPos(int3(total.x / size, total.y / size, total.z / size));
|
||||
};
|
||||
|
||||
int levels = map.map().levels();
|
||||
int levels = map.levels();
|
||||
|
||||
/*
|
||||
1. Create Voronoi diagram
|
||||
@ -862,11 +858,17 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
|
||||
}
|
||||
|
||||
//make sure that terrain inside zone is not a rock
|
||||
//FIXME: reorder actions?
|
||||
paintZoneTerrain(*zone.second, *rand, map, ETerrainId::SUBTERRANEAN);
|
||||
|
||||
auto v = zone.second->getArea().getTilesVector();
|
||||
map.getMapProxy()->drawTerrain(*rand, v, ETerrainId::SUBTERRANEAN);
|
||||
}
|
||||
}
|
||||
logGlobal->info("Finished zone colouring");
|
||||
}
|
||||
|
||||
const TDistanceMap& CZonePlacer::getDistanceMap()
|
||||
{
|
||||
return distancesBetweenZones;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -22,10 +22,11 @@ class CRandomGenerator;
|
||||
class RmgMap;
|
||||
class Zone;
|
||||
|
||||
using TZoneVector = std::vector<std::pair<TRmgTemplateZoneId, std::shared_ptr<Zone>>>;
|
||||
using TZoneMap = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
||||
using TForceVector = std::map<std::shared_ptr<Zone>, float3>;
|
||||
using TDistanceVector = std::map<std::shared_ptr<Zone>, float>;
|
||||
typedef std::vector<std::pair<TRmgTemplateZoneId, std::shared_ptr<Zone>>> TZoneVector;
|
||||
typedef std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>> TZoneMap;
|
||||
typedef std::map<std::shared_ptr<Zone>, float3> TForceVector;
|
||||
typedef std::map<std::shared_ptr<Zone>, float> TDistanceVector;
|
||||
typedef std::map<int, std::map<int, size_t>> TDistanceMap;
|
||||
|
||||
class CZonePlacer
|
||||
{
|
||||
@ -40,6 +41,8 @@ public:
|
||||
void findPathsBetweenZones();
|
||||
void placeOnGrid(CRandomGenerator* rand);
|
||||
void assignZones(CRandomGenerator * rand);
|
||||
|
||||
const TDistanceMap & getDistanceMap();
|
||||
|
||||
private:
|
||||
void prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const bool underground, CRandomGenerator * rand);
|
||||
@ -65,7 +68,7 @@ private:
|
||||
float bestTotalOverlap;
|
||||
|
||||
//distance [a][b] = number of zone connections required to travel between the zones
|
||||
std::map<int, std::map<int, size_t>> distancesBetweenZones;
|
||||
TDistanceMap distancesBetweenZones;
|
||||
std::set<TRmgTemplateZoneId> lastSwappedZones;
|
||||
RmgMap & map;
|
||||
};
|
||||
|
@ -11,19 +11,11 @@
|
||||
#include "StdInc.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "RmgMap.h"
|
||||
#include "TileInfo.h"
|
||||
#include "RmgPath.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapObjects/CommonConstructors.h"
|
||||
#include "../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
|
||||
@ -31,32 +23,6 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void createModificators(RmgMap & map)
|
||||
{
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
auto & zone = *z.second;
|
||||
switch(zone.getType())
|
||||
{
|
||||
case ETemplateZoneType::WATER:
|
||||
zone.addModificator<ObjectManager>();
|
||||
zone.addModificator<TreasurePlacer>();
|
||||
zone.addModificator<WaterProxy>();
|
||||
zone.addModificator<WaterRoutes>();
|
||||
break;
|
||||
|
||||
default:
|
||||
zone.addModificator<TownPlacer>();
|
||||
zone.addModificator<ObjectManager>();
|
||||
zone.addModificator<ConnectionsPlacer>();
|
||||
zone.addModificator<TreasurePlacer>();
|
||||
zone.addModificator<RoadPlacer>();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rmg::Tileset collectDistantTiles(const Zone& zone, int distance)
|
||||
{
|
||||
uint32_t distanceSq = distance * distance;
|
||||
@ -67,132 +33,16 @@ rmg::Tileset collectDistantTiles(const Zone& zone, int distance)
|
||||
return subarea.getTiles();
|
||||
}
|
||||
|
||||
void createBorder(RmgMap & gen, Zone & zone)
|
||||
{
|
||||
rmg::Area borderArea(zone.getArea().getBorder());
|
||||
rmg::Area borderOutsideArea(zone.getArea().getBorderOutside());
|
||||
auto blockBorder = borderArea.getSubarea([&gen, &borderOutsideArea](const int3 & t)
|
||||
{
|
||||
auto tile = borderOutsideArea.nearest(t);
|
||||
return gen.isOnMap(tile) && gen.getZones()[gen.getZoneID(tile)]->getType() != ETemplateZoneType::WATER;
|
||||
});
|
||||
|
||||
for(const auto & tile : blockBorder.getTilesVector())
|
||||
{
|
||||
if(gen.isPossible(tile))
|
||||
{
|
||||
gen.setOccupied(tile, ETileType::BLOCKED);
|
||||
zone.areaPossible().erase(tile);
|
||||
}
|
||||
|
||||
gen.foreachDirectNeighbour(tile, [&gen, &zone](int3 &nearbyPos)
|
||||
{
|
||||
if(gen.isPossible(nearbyPos) && gen.getZoneID(nearbyPos) == zone.getId())
|
||||
{
|
||||
gen.setOccupied(nearbyPos, ETileType::BLOCKED);
|
||||
zone.areaPossible().erase(nearbyPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrain)
|
||||
{
|
||||
auto v = zone.getArea().getTilesVector();
|
||||
map.getEditManager()->getTerrainSelection().setSelection(v);
|
||||
map.getEditManager()->drawTerrain(terrain, &generator);
|
||||
}
|
||||
|
||||
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId terrain)
|
||||
{
|
||||
auto factories = VLC->objtypeh->knownSubObjects(ObjID);
|
||||
vstd::erase_if(factories, [ObjID, &terrain](si32 f)
|
||||
{
|
||||
//TODO: Use templates with lowest number of terrains (most specific)
|
||||
return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrain).empty();
|
||||
});
|
||||
|
||||
return *RandomGeneratorUtil::nextItem(factories, generator);
|
||||
}
|
||||
|
||||
void initTerrainType(Zone & zone, CMapGenerator & gen)
|
||||
{
|
||||
if(zone.getType()==ETemplateZoneType::WATER)
|
||||
{
|
||||
//collect all water terrain types
|
||||
std::vector<TerrainId> waterTerrains;
|
||||
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
||||
if(terrain->isWater())
|
||||
waterTerrains.push_back(terrain->getId());
|
||||
|
||||
zone.setTerrainType(*RandomGeneratorUtil::nextItem(waterTerrains, gen.rand));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(zone.isMatchTerrainToTown() && zone.getTownType() != ETownType::NEUTRAL)
|
||||
{
|
||||
auto terrainType = (*VLC->townh)[zone.getTownType()]->nativeTerrain;
|
||||
|
||||
if (terrainType <= ETerrainId::NONE)
|
||||
{
|
||||
logGlobal->warn("Town %s has invalid terrain type: %d", zone.getTownType(), terrainType);
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
zone.setTerrainType(terrainType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto terrainTypes = zone.getTerrainTypes();
|
||||
if (terrainTypes.empty())
|
||||
{
|
||||
logGlobal->warn("No terrain types found, falling back to DIRT");
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
zone.setTerrainType(*RandomGeneratorUtil::nextItem(terrainTypes, gen.rand));
|
||||
}
|
||||
}
|
||||
|
||||
//Now, replace disallowed terrains on surface and in the underground
|
||||
const auto & terrainType = VLC->terrainTypeHandler->getById(zone.getTerrainType());
|
||||
|
||||
if(zone.isUnderground())
|
||||
{
|
||||
if(!terrainType->isUnderground())
|
||||
{
|
||||
zone.setTerrainType(ETerrainId::SUBTERRANEAN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!terrainType->isSurface())
|
||||
{
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createObstaclesCommon2(RmgMap & map, CRandomGenerator & generator)
|
||||
{
|
||||
if(map.map().twoLevel)
|
||||
{
|
||||
//finally mark rock tiles as occupied, spawn no obstacles there
|
||||
for(int x = 0; x < map.map().width; x++)
|
||||
{
|
||||
for(int y = 0; y < map.map().height; y++)
|
||||
{
|
||||
int3 tile(x, y, 1);
|
||||
if(!map.map().getTile(tile).terType->isPassable())
|
||||
{
|
||||
map.setOccupied(tile, ETileType::USED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -41,12 +41,6 @@ public:
|
||||
|
||||
rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
|
||||
|
||||
void createBorder(RmgMap & gen, Zone & zone);
|
||||
|
||||
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrainType);
|
||||
|
||||
void initTerrainType(Zone & zone, CMapGenerator & gen);
|
||||
|
||||
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId terrain);
|
||||
|
||||
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* ObstaclePlacer.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 CMap;
|
||||
class CMapEditManager;
|
||||
class RiverPlacer;
|
||||
class ObjectManager;
|
||||
|
||||
class DLL_LINKAGE ObstacleProxy
|
||||
{
|
||||
public:
|
||||
ObstacleProxy() = default;
|
||||
virtual ~ObstacleProxy() = default;
|
||||
|
||||
rmg::Area blockedArea;
|
||||
|
||||
void collectPossibleObstacles(TerrainId terrain);
|
||||
|
||||
void placeObstacles(CMap * map, CRandomGenerator & rand);
|
||||
|
||||
virtual std::pair<bool, bool> verifyCoverage(const int3 & t) const;
|
||||
|
||||
virtual void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
virtual void postProcess(const rmg::Object & object);
|
||||
|
||||
virtual bool isProhibited(const rmg::Area & objArea) const;
|
||||
|
||||
virtual void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances);
|
||||
|
||||
protected:
|
||||
int getWeightedObjects(const int3 & tile, const CMap * map, CRandomGenerator & rand, std::list<rmg::Object> & allObjects, std::vector<std::pair<rmg::Object*, int3>> & weightedObjects);
|
||||
|
||||
using ObstacleVector = std::vector<std::shared_ptr<const ObjectTemplate>>;
|
||||
std::map<int, ObstacleVector> obstaclesBySize;
|
||||
using ObstaclePair = std::pair<int, ObstacleVector>;
|
||||
std::vector<ObstaclePair> possibleObstacles;
|
||||
};
|
||||
|
||||
class ObstaclePlacer: public Modificator, public ObstacleProxy
|
||||
{
|
||||
public:
|
||||
MODIFICATOR(ObstaclePlacer);
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
|
||||
std::pair<bool, bool> verifyCoverage(const int3 & t) const override;
|
||||
|
||||
void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances) override;
|
||||
|
||||
void postProcess(const rmg::Object & object) override;
|
||||
|
||||
bool isProhibited(const rmg::Area & objArea) const override;
|
||||
|
||||
void finalInsertion(CMapEditManager * manager, std::set<CGObjectInstance*> & instances) override;
|
||||
|
||||
private:
|
||||
rmg::Area prohibitedArea;
|
||||
RiverPlacer * riverManager;
|
||||
ObjectManager * manager;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -16,20 +16,22 @@
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "MinePlacer.h"
|
||||
#include "ObjectDistributor.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "TerrainPainter.h"
|
||||
#include "modificators/ObjectManager.h"
|
||||
#include "modificators/RoadPlacer.h"
|
||||
#include "modificators/TreasurePlacer.h"
|
||||
#include "modificators/QuestArtifactPlacer.h"
|
||||
#include "modificators/ConnectionsPlacer.h"
|
||||
#include "modificators/TownPlacer.h"
|
||||
#include "modificators/MinePlacer.h"
|
||||
#include "modificators/ObjectDistributor.h"
|
||||
#include "modificators/WaterAdopter.h"
|
||||
#include "modificators/WaterProxy.h"
|
||||
#include "modificators/WaterRoutes.h"
|
||||
#include "modificators/RockPlacer.h"
|
||||
#include "modificators/RockFiller.h"
|
||||
#include "modificators/ObstaclePlacer.h"
|
||||
#include "modificators/RiverPlacer.h"
|
||||
#include "modificators/TerrainPainter.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
|
||||
@ -39,6 +41,7 @@ RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) :
|
||||
mapGenOptions(mapGenOptions), zonesTotal(0)
|
||||
{
|
||||
mapInstance = std::make_unique<CMap>();
|
||||
mapProxy = std::make_shared<MapProxy>(*this);
|
||||
getEditManager()->getUndoManager().setUndoRedoLimit(0);
|
||||
}
|
||||
|
||||
@ -74,7 +77,7 @@ void RmgMap::foreachDiagonalNeighbour(const int3 & pos, const std::function<void
|
||||
}
|
||||
}
|
||||
|
||||
void RmgMap::initTiles(CMapGenerator & generator)
|
||||
void RmgMap::initTiles(CMapGenerator & generator, CRandomGenerator & rand)
|
||||
{
|
||||
mapInstance->initTerrain();
|
||||
|
||||
@ -85,15 +88,15 @@ void RmgMap::initTiles(CMapGenerator & generator)
|
||||
for (auto faction : VLC->townh->getAllowedFactions())
|
||||
zonesPerFaction[faction] = 0;
|
||||
|
||||
getEditManager()->clearTerrain(&generator.rand);
|
||||
getEditManager()->clearTerrain(&rand);
|
||||
getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
|
||||
getEditManager()->drawTerrain(ETerrainId::GRASS, &generator.rand);
|
||||
getEditManager()->drawTerrain(ETerrainId::GRASS, &rand);
|
||||
|
||||
const auto * tmpl = mapGenOptions.getMapTemplate();
|
||||
zones.clear();
|
||||
for(const auto & option : tmpl->getZones())
|
||||
{
|
||||
auto zone = std::make_shared<Zone>(*this, generator);
|
||||
auto zone = std::make_shared<Zone>(*this, generator, rand);
|
||||
zone->setOptions(*option.second);
|
||||
zones[zone->getId()] = zone;
|
||||
}
|
||||
@ -106,7 +109,7 @@ void RmgMap::initTiles(CMapGenerator & generator)
|
||||
rmg::ZoneOptions options;
|
||||
options.setId(waterId);
|
||||
options.setType(ETemplateZoneType::WATER);
|
||||
auto zone = std::make_shared<Zone>(*this, generator);
|
||||
auto zone = std::make_shared<Zone>(*this, generator, rand);
|
||||
zone->setOptions(options);
|
||||
zones[zone->getId()] = zone;
|
||||
break;
|
||||
@ -115,12 +118,19 @@ void RmgMap::initTiles(CMapGenerator & generator)
|
||||
|
||||
void RmgMap::addModificators()
|
||||
{
|
||||
bool hasObjectDistributor = false;
|
||||
bool hasRockFiller = false;
|
||||
|
||||
for(auto & z : getZones())
|
||||
{
|
||||
auto zone = z.second;
|
||||
|
||||
zone->addModificator<ObjectManager>();
|
||||
zone->addModificator<ObjectDistributor>();
|
||||
if (!hasObjectDistributor)
|
||||
{
|
||||
zone->addModificator<ObjectDistributor>();
|
||||
hasObjectDistributor = true;
|
||||
}
|
||||
zone->addModificator<TreasurePlacer>();
|
||||
zone->addModificator<ObstaclePlacer>();
|
||||
zone->addModificator<TerrainPainter>();
|
||||
@ -139,6 +149,7 @@ void RmgMap::addModificators()
|
||||
{
|
||||
zone->addModificator<TownPlacer>();
|
||||
zone->addModificator<MinePlacer>();
|
||||
zone->addModificator<QuestArtifactPlacer>();
|
||||
zone->addModificator<ConnectionsPlacer>();
|
||||
zone->addModificator<RoadPlacer>();
|
||||
zone->addModificator<RiverPlacer>();
|
||||
@ -147,12 +158,42 @@ void RmgMap::addModificators()
|
||||
if(zone->isUnderground())
|
||||
{
|
||||
zone->addModificator<RockPlacer>();
|
||||
if (!hasRockFiller)
|
||||
{
|
||||
zone->addModificator<RockFiller>();
|
||||
hasRockFiller = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CMap & RmgMap::map() const
|
||||
int RmgMap::levels() const
|
||||
{
|
||||
return mapInstance->levels();
|
||||
}
|
||||
|
||||
int RmgMap::width() const
|
||||
{
|
||||
return mapInstance->width;
|
||||
}
|
||||
|
||||
int RmgMap::height() const
|
||||
{
|
||||
return mapInstance->height;
|
||||
}
|
||||
|
||||
PlayerInfo & RmgMap::getPlayer(int playerId)
|
||||
{
|
||||
return mapInstance->players.at(playerId);
|
||||
}
|
||||
|
||||
std::shared_ptr<MapProxy> RmgMap::getMapProxy() const
|
||||
{
|
||||
return mapProxy;
|
||||
}
|
||||
|
||||
CMap& RmgMap::getMap(const CMapGenerator*) const
|
||||
{
|
||||
return *mapInstance;
|
||||
}
|
||||
@ -239,13 +280,18 @@ void RmgMap::setRoad(const int3& tile, RoadId roadType)
|
||||
tiles[tile.x][tile.y][tile.z].setRoadType(roadType);
|
||||
}
|
||||
|
||||
TileInfo RmgMap::getTile(const int3& tile) const
|
||||
TileInfo RmgMap::getTileInfo(const int3& tile) const
|
||||
{
|
||||
assertOnMap(tile);
|
||||
|
||||
return tiles[tile.x][tile.y][tile.z];
|
||||
}
|
||||
|
||||
TerrainTile & RmgMap::getTile(const int3& tile) const
|
||||
{
|
||||
return mapInstance->getTile(tile);
|
||||
}
|
||||
|
||||
TRmgTemplateZoneId RmgMap::getZoneID(const int3& tile) const
|
||||
{
|
||||
assertOnMap(tile);
|
||||
@ -276,6 +322,7 @@ float RmgMap::getNearestObjectDistance(const int3 &tile) const
|
||||
|
||||
void RmgMap::registerZone(FactionID faction)
|
||||
{
|
||||
//FIXME: Protect with lock guard?
|
||||
zonesPerFaction[faction]++;
|
||||
zonesTotal++;
|
||||
}
|
||||
@ -321,7 +368,7 @@ void RmgMap::dump(bool zoneId) const
|
||||
else
|
||||
{
|
||||
char t = '?';
|
||||
switch (getTile(int3(i, j, k)).getTileType())
|
||||
switch (getTileInfo(int3(i, j, k)).getTileType())
|
||||
{
|
||||
case ETileType::FREE:
|
||||
t = ' '; break;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#pragma once
|
||||
#include "../int3.h"
|
||||
#include "../GameConstants.h"
|
||||
#include "threadpool/MapProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -20,12 +21,15 @@ class TileInfo;
|
||||
class CMapGenOptions;
|
||||
class Zone;
|
||||
class CMapGenerator;
|
||||
class MapProxy;
|
||||
class playerInfo;
|
||||
|
||||
class RmgMap
|
||||
{
|
||||
public:
|
||||
mutable std::unique_ptr<CMap> mapInstance;
|
||||
CMap & map() const;
|
||||
std::shared_ptr<MapProxy> getMapProxy() const;
|
||||
CMap & getMap(const CMapGenerator *) const; //limited access
|
||||
|
||||
RmgMap(const CMapGenOptions& mapGenOptions);
|
||||
~RmgMap() = default;
|
||||
@ -44,11 +48,17 @@ public:
|
||||
bool isUsed(const int3 &tile) const;
|
||||
bool isRoad(const int3 &tile) const;
|
||||
bool isOnMap(const int3 & tile) const;
|
||||
|
||||
int levels() const;
|
||||
int width() const;
|
||||
int height() const;
|
||||
PlayerInfo & getPlayer(int playerId);
|
||||
|
||||
void setOccupied(const int3 &tile, ETileType::ETileType state);
|
||||
void setRoad(const int3 &tile, RoadId roadType);
|
||||
|
||||
TileInfo getTile(const int3 & tile) const;
|
||||
TileInfo getTileInfo(const int3 & tile) const;
|
||||
TerrainTile & getTile(const int3 & tile) const;
|
||||
|
||||
float getNearestObjectDistance(const int3 &tile) const;
|
||||
void setNearestObjectDistance(int3 &tile, float value);
|
||||
@ -57,13 +67,15 @@ public:
|
||||
void setZoneID(const int3& tile, TRmgTemplateZoneId zid);
|
||||
|
||||
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
||||
using ZonePair = std::pair<TRmgTemplateZoneId, std::shared_ptr<Zone>>;
|
||||
using ZoneVector = std::vector<ZonePair>;
|
||||
|
||||
Zones & getZones();
|
||||
|
||||
void registerZone(FactionID faction);
|
||||
ui32 getZoneCount(FactionID faction);
|
||||
ui32 getTotalZoneCount() const;
|
||||
void initTiles(CMapGenerator & generator);
|
||||
void initTiles(CMapGenerator & generator, CRandomGenerator & rand);
|
||||
void addModificators();
|
||||
|
||||
bool isAllowedSpell(const SpellID & sid) const;
|
||||
@ -74,6 +86,9 @@ private:
|
||||
void assertOnMap(const int3 &tile) const; //throws
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<MapProxy> mapProxy;
|
||||
|
||||
Zones zones;
|
||||
std::map<FactionID, ui32> zonesPerFaction;
|
||||
ui32 zonesTotal; //zones that have their main town only
|
||||
|
@ -310,7 +310,7 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
//If no specific template was defined for this object, select any matching
|
||||
if (!dObject.appearance)
|
||||
{
|
||||
const auto * terrainType = map.map().getTile(getPosition(true)).terType;
|
||||
const auto * terrainType = map.getTile(getPosition(true)).terType;
|
||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->getId());
|
||||
if (templates.empty())
|
||||
{
|
||||
@ -336,7 +336,7 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
map.setOccupied(tile, ETileType::ETileType::USED);
|
||||
}
|
||||
|
||||
map.getEditManager()->insertObject(&dObject);
|
||||
map.getMapProxy()->insertObject(&dObject);
|
||||
}
|
||||
|
||||
void Object::finalize(RmgMap & map)
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* TerrainPainter.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 "TerrainPainter.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void TerrainPainter::process()
|
||||
{
|
||||
initTerrainType(zone, generator);
|
||||
paintZoneTerrain(zone, generator.rand, map, zone.getTerrainType());
|
||||
}
|
||||
|
||||
void TerrainPainter::init()
|
||||
{
|
||||
DEPENDENCY(TownPlacer);
|
||||
DEPENDENCY_ALL(WaterAdopter);
|
||||
POSTFUNCTION_ALL(WaterProxy);
|
||||
POSTFUNCTION_ALL(ConnectionsPlacer);
|
||||
POSTFUNCTION(ObjectManager);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
156
lib/rmg/Zone.cpp
156
lib/rmg/Zone.cpp
@ -13,8 +13,6 @@
|
||||
#include "RmgMap.h"
|
||||
#include "Functions.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../CStopWatch.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgPath.h"
|
||||
|
||||
@ -25,13 +23,14 @@ std::function<bool(const int3 &)> AREA_NO_FILTER = [](const int3 & t)
|
||||
return true;
|
||||
};
|
||||
|
||||
Zone::Zone(RmgMap & map, CMapGenerator & generator)
|
||||
: townType(ETownType::NEUTRAL)
|
||||
Zone::Zone(RmgMap & map, CMapGenerator & generator, CRandomGenerator & r)
|
||||
: finished(false)
|
||||
, townType(ETownType::NEUTRAL)
|
||||
, terrainType(ETerrainId::GRASS)
|
||||
, map(map)
|
||||
, generator(generator)
|
||||
{
|
||||
|
||||
rand.setSeed(r.nextInt());
|
||||
}
|
||||
|
||||
bool Zone::isUnderground() const
|
||||
@ -87,6 +86,7 @@ rmg::Area & Zone::area()
|
||||
|
||||
rmg::Area & Zone::areaPossible()
|
||||
{
|
||||
//FIXME: make const, only modify via mutex-protected interface
|
||||
return dAreaPossible;
|
||||
}
|
||||
|
||||
@ -97,6 +97,7 @@ rmg::Area & Zone::areaUsed()
|
||||
|
||||
void Zone::clearTiles()
|
||||
{
|
||||
//Lock lock(mx);
|
||||
dArea.clear();
|
||||
dAreaPossible.clear();
|
||||
dAreaFree.clear();
|
||||
@ -105,6 +106,7 @@ void Zone::clearTiles()
|
||||
void Zone::initFreeTiles()
|
||||
{
|
||||
rmg::Tileset possibleTiles;
|
||||
//Lock lock(mx);
|
||||
vstd::copy_if(dArea.getTiles(), vstd::set_inserter(possibleTiles), [this](const int3 &tile) -> bool
|
||||
{
|
||||
return map.isPossible(tile);
|
||||
@ -154,12 +156,12 @@ rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, const std::
|
||||
return 2;
|
||||
return 3;
|
||||
};
|
||||
|
||||
|
||||
auto area = (dAreaPossible + dAreaFree).getSubarea(areafilter);
|
||||
rmg::Path freePath(area);
|
||||
rmg::Path resultPath(area);
|
||||
freePath.connect(dAreaFree);
|
||||
|
||||
|
||||
//connect to all pieces
|
||||
auto goals = connectedAreas(src, onlyStraight);
|
||||
for(auto & goal : goals)
|
||||
@ -167,18 +169,23 @@ rmg::Path Zone::searchPath(const rmg::Area & src, bool onlyStraight, const std::
|
||||
auto path = freePath.search(goal, onlyStraight, movementCost);
|
||||
if(path.getPathArea().empty())
|
||||
return rmg::Path::invalid();
|
||||
|
||||
|
||||
freePath.connect(path.getPathArea());
|
||||
resultPath.connect(path.getPathArea());
|
||||
}
|
||||
|
||||
|
||||
return resultPath;
|
||||
}
|
||||
|
||||
rmg::Path Zone::searchPath(const int3 & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter) const
|
||||
///connect current tile to any other free tile within zone
|
||||
{
|
||||
return searchPath(rmg::Area({src}), onlyStraight, areafilter);
|
||||
return searchPath(rmg::Area({ src }), onlyStraight, areafilter);
|
||||
}
|
||||
|
||||
TModificators Zone::getModificators()
|
||||
{
|
||||
return modificators;
|
||||
}
|
||||
|
||||
void Zone::connectPath(const rmg::Path & path)
|
||||
@ -197,6 +204,7 @@ void Zone::fractalize()
|
||||
rmg::Area tilesToIgnore; //will be erased in this iteration
|
||||
|
||||
const float minDistance = 10 * 10; //squared
|
||||
float blockDistance = minDistance * 0.25f;
|
||||
|
||||
if(type != ETemplateZoneType::JUNCTION)
|
||||
{
|
||||
@ -206,7 +214,7 @@ void Zone::fractalize()
|
||||
{
|
||||
//link tiles in random order
|
||||
std::vector<int3> tilesToMakePath = possibleTiles.getTilesVector();
|
||||
RandomGeneratorUtil::randomShuffle(tilesToMakePath, generator.rand);
|
||||
RandomGeneratorUtil::randomShuffle(tilesToMakePath, getRand());
|
||||
|
||||
int3 nodeFound(-1, -1, -1);
|
||||
|
||||
@ -231,7 +239,7 @@ void Zone::fractalize()
|
||||
tilesToIgnore.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Lock lock(areaMutex);
|
||||
//cut straight paths towards the center. A* is too slow for that.
|
||||
auto areas = connectedAreas(clearedTiles, false);
|
||||
for(auto & area : areas)
|
||||
@ -260,7 +268,6 @@ void Zone::fractalize()
|
||||
}
|
||||
|
||||
//now block most distant tiles away from passages
|
||||
float blockDistance = minDistance * 0.25f;
|
||||
auto areaToBlock = dArea.getSubarea([this, blockDistance](const int3 & t)
|
||||
{
|
||||
auto distance = static_cast<float>(dAreaFree.distanceSqr(t));
|
||||
@ -268,6 +275,8 @@ void Zone::fractalize()
|
||||
});
|
||||
dAreaPossible.subtract(areaToBlock);
|
||||
dAreaFree.subtract(areaToBlock);
|
||||
|
||||
lock.unlock();
|
||||
for(const auto & t : areaToBlock.getTiles())
|
||||
map.setOccupied(t, ETileType::BLOCKED);
|
||||
}
|
||||
@ -281,126 +290,9 @@ void Zone::initModificators()
|
||||
logGlobal->info("Zone %d modificators initialized", getId());
|
||||
}
|
||||
|
||||
void Zone::processModificators()
|
||||
CRandomGenerator& Zone::getRand()
|
||||
{
|
||||
for(auto & modificator : modificators)
|
||||
{
|
||||
try
|
||||
{
|
||||
modificator->run();
|
||||
}
|
||||
catch (const rmgException & e)
|
||||
{
|
||||
logGlobal->info("Zone %d, modificator %s - FAILED: %s", getId(), e.what());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
logGlobal->info("Zone %d filled successfully", getId());
|
||||
}
|
||||
|
||||
Modificator::Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator) : zone(zone), map(map), generator(generator)
|
||||
{
|
||||
}
|
||||
|
||||
void Modificator::setName(const std::string & n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
|
||||
const std::string & Modificator::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Modificator::isFinished() const
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
void Modificator::run()
|
||||
{
|
||||
started = true;
|
||||
if(!finished)
|
||||
{
|
||||
for(auto * modificator : preceeders)
|
||||
{
|
||||
if(!modificator->started)
|
||||
modificator->run();
|
||||
}
|
||||
logGlobal->info("Modificator zone %d - %s - started", zone.getId(), getName());
|
||||
CStopWatch processTime;
|
||||
try
|
||||
{
|
||||
process();
|
||||
}
|
||||
catch(rmgException &e)
|
||||
{
|
||||
logGlobal->error("Modificator %s, exception: %s", getName(), e.what());
|
||||
}
|
||||
#ifdef RMG_DUMP
|
||||
dump();
|
||||
#endif
|
||||
finished = true;
|
||||
logGlobal->info("Modificator zone %d - %s - done (%d ms)", zone.getId(), getName(), processTime.getDiff());
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::dependency(Modificator * modificator)
|
||||
{
|
||||
if(modificator && modificator != this)
|
||||
{
|
||||
if(std::find(preceeders.begin(), preceeders.end(), modificator) == preceeders.end())
|
||||
preceeders.push_back(modificator);
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::postfunction(Modificator * modificator)
|
||||
{
|
||||
if(modificator && modificator != this)
|
||||
{
|
||||
if(std::find(modificator->preceeders.begin(), modificator->preceeders.end(), this) == modificator->preceeders.end())
|
||||
modificator->preceeders.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::dump()
|
||||
{
|
||||
std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName()));
|
||||
auto & mapInstance = map.map();
|
||||
int levels = mapInstance.levels();
|
||||
int width = mapInstance.width;
|
||||
int height = mapInstance.height;
|
||||
for(int z = 0; z < levels; z++)
|
||||
{
|
||||
for(int j=0; j<height; j++)
|
||||
{
|
||||
for(int i=0; i<width; i++)
|
||||
{
|
||||
out << dump(int3(i, j, z));
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
char Modificator::dump(const int3 & t)
|
||||
{
|
||||
if(zone.freePaths().contains(t))
|
||||
return '.'; //free path
|
||||
if(zone.areaPossible().contains(t))
|
||||
return ' '; //possible
|
||||
if(zone.areaUsed().contains(t))
|
||||
return 'U'; //used
|
||||
if(zone.area().contains(t))
|
||||
{
|
||||
if(map.shouldBeBlocked(t))
|
||||
return '#'; //obstacle
|
||||
else
|
||||
return '^'; //visitable points?
|
||||
}
|
||||
return '?';
|
||||
return rand;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -13,71 +13,31 @@
|
||||
#include "../GameConstants.h"
|
||||
#include "float3.h"
|
||||
#include "../int3.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "CRmgTemplate.h"
|
||||
#include "RmgArea.h"
|
||||
#include "RmgPath.h"
|
||||
#include "RmgObject.h"
|
||||
#include "modificators/Modificator.h"
|
||||
|
||||
//uncomment to generate dumps afger every step of map generation
|
||||
//#define RMG_DUMP
|
||||
|
||||
#define MODIFICATOR(x) x(Zone & z, RmgMap & m, CMapGenerator & g): Modificator(z, m, g) {setName(#x);}
|
||||
#define DEPENDENCY(x) dependency(zone.getModificator<x>());
|
||||
#define POSTFUNCTION(x) postfunction(zone.getModificator<x>());
|
||||
#define DEPENDENCY_ALL(x) for(auto & z : map.getZones()) \
|
||||
{ \
|
||||
dependency(z.second->getModificator<x>()); \
|
||||
}
|
||||
#define POSTFUNCTION_ALL(x) for(auto & z : map.getZones()) \
|
||||
{ \
|
||||
postfunction(z.second->getModificator<x>()); \
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RmgMap;
|
||||
class CMapGenerator;
|
||||
class Zone;
|
||||
|
||||
class Modificator
|
||||
{
|
||||
public:
|
||||
Modificator() = delete;
|
||||
Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator);
|
||||
|
||||
virtual void process() = 0;
|
||||
virtual void init() {/*override to add dependencies*/}
|
||||
virtual char dump(const int3 &);
|
||||
virtual ~Modificator() = default;
|
||||
|
||||
void setName(const std::string & n);
|
||||
const std::string & getName() const;
|
||||
|
||||
void run();
|
||||
void dependency(Modificator * modificator);
|
||||
void postfunction(Modificator * modificator);
|
||||
|
||||
protected:
|
||||
RmgMap & map;
|
||||
CMapGenerator & generator;
|
||||
Zone & zone;
|
||||
|
||||
bool isFinished() const;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
bool started = false;
|
||||
bool finished = false;
|
||||
std::list<Modificator*> preceeders; //must be ordered container
|
||||
void dump();
|
||||
};
|
||||
class Modificator;
|
||||
class CRandomGenerator;
|
||||
|
||||
extern std::function<bool(const int3 &)> AREA_NO_FILTER;
|
||||
|
||||
typedef std::list<std::shared_ptr<Modificator>> TModificators;
|
||||
|
||||
class Zone : public rmg::ZoneOptions
|
||||
{
|
||||
public:
|
||||
Zone(RmgMap & map, CMapGenerator & generator);
|
||||
Zone(RmgMap & map, CMapGenerator & generator, CRandomGenerator & rand);
|
||||
Zone(const Zone &) = delete;
|
||||
|
||||
void setOptions(const rmg::ZoneOptions & options);
|
||||
@ -93,7 +53,7 @@ public:
|
||||
rmg::Area & areaPossible();
|
||||
rmg::Area & freePaths();
|
||||
rmg::Area & areaUsed();
|
||||
|
||||
|
||||
void initFreeTiles();
|
||||
void clearTiles();
|
||||
void fractalize();
|
||||
@ -107,6 +67,8 @@ public:
|
||||
rmg::Path searchPath(const rmg::Area & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter = AREA_NO_FILTER) const;
|
||||
rmg::Path searchPath(const int3 & src, bool onlyStraight, const std::function<bool(const int3 &)> & areafilter = AREA_NO_FILTER) const;
|
||||
|
||||
TModificators getModificators();
|
||||
|
||||
template<class T>
|
||||
T* getModificator()
|
||||
{
|
||||
@ -123,12 +85,18 @@ public:
|
||||
}
|
||||
|
||||
void initModificators();
|
||||
void processModificators();
|
||||
|
||||
CRandomGenerator & getRand();
|
||||
public:
|
||||
boost::recursive_mutex areaMutex;
|
||||
using Lock = boost::unique_lock<boost::recursive_mutex>;
|
||||
|
||||
protected:
|
||||
CMapGenerator & generator;
|
||||
CRandomGenerator rand;
|
||||
RmgMap & map;
|
||||
std::list<std::unique_ptr<Modificator>> modificators;
|
||||
TModificators modificators;
|
||||
bool finished;
|
||||
|
||||
//placement info
|
||||
int3 pos;
|
||||
@ -137,11 +105,11 @@ protected:
|
||||
rmg::Area dAreaPossible;
|
||||
rmg::Area dAreaFree; //core paths of free tiles that all other objects will be linked to
|
||||
rmg::Area dAreaUsed;
|
||||
std::vector<int3> possibleQuestArtifactPos;
|
||||
|
||||
//template info
|
||||
si32 townType;
|
||||
TerrainId terrainType;
|
||||
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -10,50 +10,66 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
#include "../RmgObject.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "TownPlacer.h"
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ConnectionsPlacer::process()
|
||||
{
|
||||
collectNeighbourZones();
|
||||
for(auto & c : dConnections)
|
||||
|
||||
auto diningPhilosophers = [this](std::function<void(const rmg::ZoneConnection&)> f)
|
||||
{
|
||||
for (auto& c : dConnections)
|
||||
{
|
||||
if (c.getZoneA() != zone.getId() && c.getZoneB() != zone.getId())
|
||||
continue;
|
||||
|
||||
auto otherZone = map.getZones().at(c.getZoneB());
|
||||
auto* cp = otherZone->getModificator<ConnectionsPlacer>();
|
||||
|
||||
while (cp)
|
||||
{
|
||||
RecursiveLock lock1(externalAccessMutex, boost::try_to_lock_t{});
|
||||
RecursiveLock lock2(cp->externalAccessMutex, boost::try_to_lock_t{});
|
||||
if (lock1.owns_lock() && lock2.owns_lock())
|
||||
{
|
||||
if (!vstd::contains(dCompleted, c))
|
||||
{
|
||||
f(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
diningPhilosophers([this](const rmg::ZoneConnection& c)
|
||||
{
|
||||
if(c.getZoneA() != zone.getId() && c.getZoneB() != zone.getId())
|
||||
continue;
|
||||
|
||||
if(vstd::contains(dCompleted, c))
|
||||
continue;
|
||||
|
||||
selfSideDirectConnection(c);
|
||||
}
|
||||
|
||||
createBorder(map, zone);
|
||||
|
||||
for(auto & c : dConnections)
|
||||
});
|
||||
|
||||
createBorder();
|
||||
|
||||
diningPhilosophers([this](const rmg::ZoneConnection& c)
|
||||
{
|
||||
if(c.getZoneA() != zone.getId() && c.getZoneB() != zone.getId())
|
||||
continue;
|
||||
|
||||
if(vstd::contains(dCompleted, c))
|
||||
continue;
|
||||
|
||||
selfSideIndirectConnection(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ConnectionsPlacer::init()
|
||||
@ -97,11 +113,11 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
|
||||
int3 borderPos;
|
||||
while(!directConnectionIterator->second.empty())
|
||||
{
|
||||
borderPos = *RandomGeneratorUtil::nextItem(directConnectionIterator->second, generator.rand);
|
||||
borderPos = *RandomGeneratorUtil::nextItem(directConnectionIterator->second, zone.getRand());
|
||||
guardPos = zone.areaPossible().nearest(borderPos);
|
||||
assert(borderPos != guardPos);
|
||||
|
||||
float dist = map.getTile(guardPos).getNearestObjectDistance();
|
||||
float dist = map.getTileInfo(guardPos).getNearestObjectDistance();
|
||||
if (dist >= 3) //Don't place guards at adjacent tiles
|
||||
{
|
||||
|
||||
@ -228,11 +244,12 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
||||
bool guarded2 = managerOther.addGuard(rmgGate2, connection.getGuardStrength(), true);
|
||||
int minDist = 3;
|
||||
|
||||
std::scoped_lock doubleLock(zone.areaMutex, otherZone->areaMutex);
|
||||
rmg::Path path2(otherZone->area());
|
||||
rmg::Path path1 = manager.placeAndConnectObject(commonArea, rmgGate1, [this, minDist, &path2, &rmgGate1, &zShift, guarded2, &managerOther, &rmgGate2 ](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto otherTi = map.getTile(tile - zShift);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
auto otherTi = map.getTileInfo(tile - zShift);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
float otherDist = otherTi.getNearestObjectDistance();
|
||||
if(dist < minDist || otherDist < minDist)
|
||||
@ -296,4 +313,34 @@ void ConnectionsPlacer::collectNeighbourZones()
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionsPlacer::createBorder()
|
||||
{
|
||||
rmg::Area borderArea(zone.getArea().getBorder());
|
||||
rmg::Area borderOutsideArea(zone.getArea().getBorderOutside());
|
||||
auto blockBorder = borderArea.getSubarea([this, &borderOutsideArea](const int3 & t)
|
||||
{
|
||||
auto tile = borderOutsideArea.nearest(t);
|
||||
return map.isOnMap(tile) && map.getZones()[map.getZoneID(tile)]->getType() != ETemplateZoneType::WATER;
|
||||
});
|
||||
|
||||
Zone::Lock lock(zone.areaMutex); //Protect from erasing same tiles again
|
||||
for(const auto & tile : blockBorder.getTilesVector())
|
||||
{
|
||||
if(map.isPossible(tile))
|
||||
{
|
||||
map.setOccupied(tile, ETileType::BLOCKED);
|
||||
zone.areaPossible().erase(tile);
|
||||
}
|
||||
|
||||
map.foreachDirectNeighbour(tile, [this](int3 &nearbyPos)
|
||||
{
|
||||
if(map.isPossible(nearbyPos) && map.getZoneID(nearbyPos) == zone.getId())
|
||||
{
|
||||
map.setOccupied(nearbyPos, ETileType::BLOCKED);
|
||||
zone.areaPossible().erase(nearbyPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -9,8 +9,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "RmgArea.h"
|
||||
#include "../Zone.h"
|
||||
#include "../RmgArea.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -27,6 +27,7 @@ public:
|
||||
void selfSideDirectConnection(const rmg::ZoneConnection & connection);
|
||||
void selfSideIndirectConnection(const rmg::ZoneConnection & connection);
|
||||
void otherSideConnection(const rmg::ZoneConnection & connection);
|
||||
void createBorder();
|
||||
|
||||
protected:
|
||||
void collectNeighbourZones();
|
@ -8,19 +8,19 @@
|
||||
#include "MinePlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "ConnectionsPlacer.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 "../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 "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -72,7 +72,7 @@ bool MinePlacer::placeMines(ObjectManager & manager)
|
||||
}
|
||||
|
||||
//Shuffle mines to avoid patterns, but don't shuffle key objects like towns
|
||||
RandomGeneratorUtil::randomShuffle(requiredObjects, generator.rand);
|
||||
RandomGeneratorUtil::randomShuffle(requiredObjects, zone.getRand());
|
||||
for (const auto& obj : requiredObjects)
|
||||
{
|
||||
manager.addRequiredObject(obj.first, obj.second);
|
||||
@ -83,7 +83,7 @@ bool MinePlacer::placeMines(ObjectManager & manager)
|
||||
{
|
||||
for(auto * mine : createdMines)
|
||||
{
|
||||
for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc)
|
||||
for(int rc = zone.getRand().nextInt(1, extraRes); rc > 0; --rc)
|
||||
{
|
||||
auto * resourse = dynamic_cast<CGResource *>(VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create());
|
||||
resourse->amount = CGResource::RANDOM_AMOUNT;
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
159
lib/rmg/modificators/Modificator.cpp
Normal file
159
lib/rmg/modificators/Modificator.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Modificator.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 "Modificator.h"
|
||||
#include "../Functions.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../CStopWatch.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
Modificator::Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator) : zone(zone), map(map), generator(generator)
|
||||
{
|
||||
mapProxy = map.getMapProxy();
|
||||
}
|
||||
|
||||
void Modificator::setName(const std::string & n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
|
||||
const std::string & Modificator::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
bool Modificator::isReady()
|
||||
{
|
||||
Lock lock(mx, boost::try_to_lock_t{});
|
||||
if (!lock.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Check prerequisites
|
||||
for (auto it = preceeders.begin(); it != preceeders.end();)
|
||||
{
|
||||
if ((*it)->isFinished()) //OK
|
||||
{
|
||||
//This preceeder won't be checked in the future
|
||||
it = preceeders.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//If a job is finished, it should be already erased from a queue
|
||||
return !finished;
|
||||
}
|
||||
}
|
||||
|
||||
bool Modificator::isFinished()
|
||||
{
|
||||
Lock lock(mx, boost::try_to_lock_t{});
|
||||
if (!lock.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::run()
|
||||
{
|
||||
Lock lock(mx);
|
||||
|
||||
if(!finished)
|
||||
{
|
||||
logGlobal->info("Modificator zone %d - %s - started", zone.getId(), getName());
|
||||
CStopWatch processTime;
|
||||
try
|
||||
{
|
||||
process();
|
||||
}
|
||||
catch(rmgException &e)
|
||||
{
|
||||
logGlobal->error("Modificator %s, exception: %s", getName(), e.what());
|
||||
}
|
||||
#ifdef RMG_DUMP
|
||||
dump();
|
||||
#endif
|
||||
finished = true;
|
||||
logGlobal->info("Modificator zone %d - %s - done (%d ms)", zone.getId(), getName(), processTime.getDiff());
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::dependency(Modificator * modificator)
|
||||
{
|
||||
if(modificator && modificator != this)
|
||||
{
|
||||
//TODO: use vstd::contains
|
||||
if(std::find(preceeders.begin(), preceeders.end(), modificator) == preceeders.end())
|
||||
preceeders.push_back(modificator);
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::postfunction(Modificator * modificator)
|
||||
{
|
||||
if(modificator && modificator != this)
|
||||
{
|
||||
if(std::find(modificator->preceeders.begin(), modificator->preceeders.end(), this) == modificator->preceeders.end())
|
||||
modificator->preceeders.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Modificator::dump()
|
||||
{
|
||||
std::ofstream out(boost::to_string(boost::format("seed_%d_modzone_%d_%s.txt") % generator.getRandomSeed() % zone.getId() % getName()));
|
||||
int levels = map.levels();
|
||||
int width = map.width();
|
||||
int height = map.height();
|
||||
for(int z = 0; z < levels; z++)
|
||||
{
|
||||
for(int j=0; j<height; j++)
|
||||
{
|
||||
for(int i=0; i<width; i++)
|
||||
{
|
||||
out << dump(int3(i, j, z));
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
char Modificator::dump(const int3 & t)
|
||||
{
|
||||
if(zone.freePaths().contains(t))
|
||||
return '.'; //free path
|
||||
if(zone.areaPossible().contains(t))
|
||||
return ' '; //possible
|
||||
if(zone.areaUsed().contains(t))
|
||||
return 'U'; //used
|
||||
if(zone.area().contains(t))
|
||||
{
|
||||
if(map.shouldBeBlocked(t))
|
||||
return '#'; //obstacle
|
||||
else
|
||||
return '^'; //visitable points?
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
81
lib/rmg/modificators/Modificator.h
Normal file
81
lib/rmg/modificators/Modificator.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Modificator.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 "../../GameConstants.h"
|
||||
#include "../../int3.h"
|
||||
#include "../Zone.h"
|
||||
#include "../threadpool/MapProxy.h"
|
||||
|
||||
class RmgMap;
|
||||
class CMapGenerator;
|
||||
class Zone;
|
||||
class MapProxy;
|
||||
|
||||
#define MODIFICATOR(x) x(Zone & z, RmgMap & m, CMapGenerator & g): Modificator(z, m, g) {setName(#x);}
|
||||
#define DEPENDENCY(x) dependency(zone.getModificator<x>());
|
||||
#define POSTFUNCTION(x) postfunction(zone.getModificator<x>());
|
||||
#define DEPENDENCY_ALL(x) for(auto & z : map.getZones()) \
|
||||
{ \
|
||||
dependency(z.second->getModificator<x>()); \
|
||||
}
|
||||
#define POSTFUNCTION_ALL(x) for(auto & z : map.getZones()) \
|
||||
{ \
|
||||
postfunction(z.second->getModificator<x>()); \
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class Modificator
|
||||
{
|
||||
public:
|
||||
Modificator() = delete;
|
||||
Modificator(Zone & zone, RmgMap & map, CMapGenerator & generator);
|
||||
|
||||
virtual void init() {/*override to add dependencies*/}
|
||||
virtual char dump(const int3 &);
|
||||
virtual ~Modificator() = default;
|
||||
|
||||
void setName(const std::string & n);
|
||||
const std::string & getName() const;
|
||||
|
||||
bool isReady();
|
||||
bool isFinished();
|
||||
|
||||
void run();
|
||||
void dependency(Modificator * modificator);
|
||||
void postfunction(Modificator * modificator);
|
||||
|
||||
protected:
|
||||
RmgMap & map;
|
||||
std::shared_ptr<MapProxy> mapProxy;
|
||||
CMapGenerator & generator;
|
||||
Zone & zone;
|
||||
|
||||
bool finished = false;
|
||||
|
||||
mutable boost::recursive_mutex externalAccessMutex; //Used to communicate between Modificators
|
||||
using RecursiveLock = boost::unique_lock<boost::recursive_mutex>;
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
|
||||
private:
|
||||
virtual void process() = 0;
|
||||
|
||||
std::string name;
|
||||
|
||||
std::list<Modificator*> preceeders; //must be ordered container
|
||||
|
||||
mutable boost::shared_mutex mx; //Used only for task scheduling
|
||||
|
||||
void dump();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -11,32 +11,30 @@
|
||||
#include "StdInc.h"
|
||||
#include "ObjectDistributor.h"
|
||||
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "RmgMap.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "../../VCMI_Lib.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "QuestArtifactPlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "TerrainPainter.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../mapObjects/MapObjects.h"
|
||||
#include "Functions.h"
|
||||
#include "RmgObject.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();
|
||||
}
|
||||
distributeLimitedObjects();
|
||||
distributeSeerHuts();
|
||||
}
|
||||
|
||||
void ObjectDistributor::init()
|
||||
{
|
||||
DEPENDENCY(TownPlacer);
|
||||
DEPENDENCY(TerrainPainter);
|
||||
//All of the terrain types need to be determined
|
||||
DEPENDENCY_ALL(TerrainPainter);
|
||||
POSTFUNCTION(TreasurePlacer);
|
||||
}
|
||||
|
||||
@ -82,6 +80,8 @@ void ObjectDistributor::distributeLimitedObjects()
|
||||
//We already know there are some templates
|
||||
auto templates = handler->getTemplates(zone->getTerrainType());
|
||||
|
||||
//FIXME: Templates empty?! Maybe zone changed terrain type over time?
|
||||
|
||||
//Assume the template with fewest terrains is the most suitable
|
||||
auto temp = *boost::min_element(templates, [](std::shared_ptr<const ObjectTemplate> lhs, std::shared_ptr<const ObjectTemplate> rhs) -> bool
|
||||
{
|
||||
@ -118,4 +118,54 @@ void ObjectDistributor::distributeLimitedObjects()
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDistributor::distributeSeerHuts()
|
||||
{
|
||||
//TODO: Move typedef outside the class?
|
||||
|
||||
//Copy by value to random shuffle
|
||||
const auto & zoneMap = map.getZones();
|
||||
RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(zones, zone.getRand());
|
||||
|
||||
const auto & possibleQuestArts = generator.getAllPossibleQuestArtifacts();
|
||||
size_t availableArts = possibleQuestArts.size();
|
||||
auto artIt = possibleQuestArts.begin();
|
||||
for (int i = zones.size() - 1; i >= 0 ; i--)
|
||||
{
|
||||
size_t localArts = std::ceil((float)availableArts / (i + 1));
|
||||
availableArts -= localArts;
|
||||
|
||||
auto * qap = zones[i].second->getModificator<QuestArtifactPlacer>();
|
||||
if (qap)
|
||||
{
|
||||
for (;localArts > 0 && artIt != possibleQuestArts.end(); artIt++, localArts--)
|
||||
{
|
||||
qap->addRandomArtifact(*artIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectDistributor::distributePrisons()
|
||||
{
|
||||
//Copy by value to random shuffle
|
||||
const auto & zoneMap = map.getZones();
|
||||
RmgMap::ZoneVector zones(zoneMap.begin(), zoneMap.end());
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(zones, zone.getRand());
|
||||
|
||||
size_t allowedPrisons = generator.getPrisonsRemaning();
|
||||
for (int i = zones.size() - 1; i >= 0; i--)
|
||||
{
|
||||
auto zone = zones[i].second;
|
||||
auto * tp = zone->getModificator<TreasurePlacer>();
|
||||
if (tp)
|
||||
{
|
||||
tp->setMaxPrisons(std::ceil(float(allowedPrisons) / (i + 1)));
|
||||
allowedPrisons -= tp->getMaxPrisons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -10,8 +10,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Zone.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../Zone.h"
|
||||
#include "../RmgObject.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -21,6 +21,8 @@ class ObjectTemplate;
|
||||
class ObjectDistributor : public Modificator
|
||||
{
|
||||
void distributeLimitedObjects();
|
||||
void distributeSeerHuts();
|
||||
void distributePrisons();
|
||||
|
||||
public:
|
||||
MODIFICATOR(ObjectDistributor);
|
@ -10,19 +10,24 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "TileInfo.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../mapObjects/CommonConstructors.h"
|
||||
#include "../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "Functions.h"
|
||||
#include "RmgObject.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "MinePlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "QuestArtifactPlacer.h"
|
||||
#include "../../CCreatureHandler.h"
|
||||
#include "../../mapObjects/CommonConstructors.h"
|
||||
#include "../../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../Functions.h"
|
||||
#include "../RmgObject.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -35,12 +40,16 @@ void ObjectManager::process()
|
||||
void ObjectManager::init()
|
||||
{
|
||||
DEPENDENCY(WaterAdopter);
|
||||
DEPENDENCY_ALL(ConnectionsPlacer); //Monoliths can be placed by other zone, too
|
||||
DEPENDENCY(TownPlacer); //Only secondary towns
|
||||
DEPENDENCY(MinePlacer);
|
||||
POSTFUNCTION(RoadPlacer);
|
||||
createDistancesPriorityQueue();
|
||||
}
|
||||
|
||||
void ObjectManager::createDistancesPriorityQueue()
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
tilesByDistance.clear();
|
||||
for(const auto & tile : zone.areaPossible().getTilesVector())
|
||||
{
|
||||
@ -50,21 +59,25 @@ void ObjectManager::createDistancesPriorityQueue()
|
||||
|
||||
void ObjectManager::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
requiredObjects.emplace_back(obj, strength);
|
||||
}
|
||||
|
||||
void ObjectManager::addCloseObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
closeObjects.emplace_back(obj, strength);
|
||||
}
|
||||
|
||||
void ObjectManager::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
nearbyObjects.emplace_back(obj, nearbyTarget);
|
||||
}
|
||||
|
||||
void ObjectManager::updateDistances(const rmg::Object & obj)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
tilesByDistance.clear();
|
||||
for (auto tile : zone.areaPossible().getTiles()) //don't need to mark distance for not possible tiles
|
||||
{
|
||||
@ -76,6 +89,7 @@ void ObjectManager::updateDistances(const rmg::Object & obj)
|
||||
|
||||
const rmg::Area & ObjectManager::getVisitableArea() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return objectsVisitableArea;
|
||||
}
|
||||
|
||||
@ -83,6 +97,7 @@ std::vector<CGObjectInstance*> ObjectManager::getMines() const
|
||||
{
|
||||
std::vector<CGObjectInstance*> mines;
|
||||
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
for(auto * object : objects)
|
||||
{
|
||||
if (object->ID == Obj::MINE)
|
||||
@ -152,6 +167,7 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
}
|
||||
}
|
||||
|
||||
//FIXME: Race condition for tiles? For Area?
|
||||
if(result.valid())
|
||||
obj.setPosition(result);
|
||||
return result;
|
||||
@ -161,14 +177,14 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
{
|
||||
return findPlaceForObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
if(dist < min_dist)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : obj.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < min_dist)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
@ -180,14 +196,14 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
||||
{
|
||||
return placeAndConnectObject(searchArea, obj, [this, min_dist, &obj](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
float dist = ti.getNearestObjectDistance();
|
||||
if(dist < min_dist)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : obj.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < min_dist)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < min_dist)
|
||||
return -1.f;
|
||||
}
|
||||
|
||||
@ -242,13 +258,17 @@ rmg::Path ObjectManager::placeAndConnectObject(const rmg::Area & searchArea, rmg
|
||||
bool ObjectManager::createRequiredObjects()
|
||||
{
|
||||
logGlobal->trace("Creating required objects");
|
||||
|
||||
|
||||
//RecursiveLock lock(externalAccessMutex); //Why could requiredObjects be modified during the loop?
|
||||
for(const auto & object : requiredObjects)
|
||||
{
|
||||
auto * obj = object.first;
|
||||
//FIXME: Invalid dObject inside object?
|
||||
rmg::Object rmgObject(*obj);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
auto path = placeAndConnectObject(zone.areaPossible(), rmgObject, 3, guarded, false, OptimizeType::DISTANCE);
|
||||
|
||||
if(!path.valid())
|
||||
@ -274,7 +294,7 @@ bool ObjectManager::createRequiredObjects()
|
||||
continue;
|
||||
}
|
||||
|
||||
rmgNearObject.setPosition(*RandomGeneratorUtil::nextItem(possibleArea.getTiles(), generator.rand));
|
||||
rmgNearObject.setPosition(*RandomGeneratorUtil::nextItem(possibleArea.getTiles(), zone.getRand()));
|
||||
placeObject(rmgNearObject, false, false);
|
||||
}
|
||||
}
|
||||
@ -282,7 +302,11 @@ bool ObjectManager::createRequiredObjects()
|
||||
for(const auto & object : closeObjects)
|
||||
{
|
||||
auto * obj = object.first;
|
||||
|
||||
//TODO: Wrap into same area proxy?
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
auto possibleArea = zone.areaPossible();
|
||||
|
||||
rmg::Object rmgObject(*obj);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
bool guarded = addGuard(rmgObject, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY));
|
||||
@ -318,7 +342,7 @@ bool ObjectManager::createRequiredObjects()
|
||||
continue;
|
||||
}
|
||||
|
||||
rmgNearObject.setPosition(*RandomGeneratorUtil::nextItem(possibleArea.getTiles(), generator.rand));
|
||||
rmgNearObject.setPosition(*RandomGeneratorUtil::nextItem(possibleArea.getTiles(), zone.getRand()));
|
||||
placeObject(rmgNearObject, false, false);
|
||||
}
|
||||
}
|
||||
@ -343,6 +367,8 @@ bool ObjectManager::createRequiredObjects()
|
||||
void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateDistance)
|
||||
{
|
||||
object.finalize(map);
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
zone.areaPossible().subtract(object.getArea());
|
||||
bool keepVisitable = zone.freePaths().contains(object.getVisitablePosition());
|
||||
zone.freePaths().subtract(object.getArea()); //just to avoid areas overlapping
|
||||
@ -379,6 +405,21 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
m->areaIsolated().add(instance->getVisitablePosition() + int3(0, -1, 0));
|
||||
}
|
||||
}
|
||||
|
||||
switch (instance->object().ID)
|
||||
{
|
||||
case Obj::RANDOM_TREASURE_ART:
|
||||
case Obj::RANDOM_MINOR_ART: //In OH3 quest artifacts have higher value than normal arts
|
||||
{
|
||||
if (auto * qap = zone.getModificator<QuestArtifactPlacer>())
|
||||
{
|
||||
qap->rememberPotentialArtifactToReplace(&instance->object());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(object.instances().front()->object().ID)
|
||||
@ -441,10 +482,10 @@ CGCreature * ObjectManager::chooseGuard(si32 strength, bool zoneGuard)
|
||||
}
|
||||
if(!possibleCreatures.empty())
|
||||
{
|
||||
creId = *RandomGeneratorUtil::nextItem(possibleCreatures, generator.rand);
|
||||
creId = *RandomGeneratorUtil::nextItem(possibleCreatures, zone.getRand());
|
||||
amount = strength / VLC->creh->objects[creId]->getAIValue();
|
||||
if (amount >= 4)
|
||||
amount = static_cast<int>(amount * generator.rand.nextDouble(0.75, 1.25));
|
||||
amount = static_cast<int>(amount * zone.getRand().nextDouble(0.75, 1.25));
|
||||
}
|
||||
else //just pick any available creature
|
||||
{
|
@ -10,8 +10,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Zone.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../Zone.h"
|
||||
#include "../RmgObject.h"
|
||||
#include <boost/heap/priority_queue.hpp> //A*
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
101
lib/rmg/modificators/ObstaclePlacer.cpp
Normal file
101
lib/rmg/modificators/ObstaclePlacer.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* ObstaclePlacer.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 "ObstaclePlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../../CRandomGenerator.h"
|
||||
#include "../Functions.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/ObstacleProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ObstaclePlacer::process()
|
||||
{
|
||||
manager = zone.getModificator<ObjectManager>();
|
||||
if(!manager)
|
||||
return;
|
||||
|
||||
collectPossibleObstacles(zone.getTerrainType());
|
||||
|
||||
blockedArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return map.shouldBeBlocked(t);
|
||||
});
|
||||
blockedArea.subtract(zone.areaUsed());
|
||||
zone.areaPossible().subtract(blockedArea);
|
||||
|
||||
prohibitedArea = zone.freePaths() + zone.areaUsed() + manager->getVisitableArea();
|
||||
|
||||
auto objs = createObstacles(zone.getRand());
|
||||
mapProxy->insertObjects(objs);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::init()
|
||||
{
|
||||
DEPENDENCY(ObjectManager);
|
||||
DEPENDENCY(TreasurePlacer);
|
||||
DEPENDENCY(WaterRoutes);
|
||||
DEPENDENCY(WaterProxy);
|
||||
DEPENDENCY(RoadPlacer);
|
||||
DEPENDENCY_ALL(RockPlacer);
|
||||
}
|
||||
|
||||
bool ObstaclePlacer::isInTheMap(const int3& tile)
|
||||
{
|
||||
return map.isOnMap(tile);
|
||||
}
|
||||
|
||||
void ObstaclePlacer::placeObject(rmg::Object & object, std::set<CGObjectInstance*> &)
|
||||
{
|
||||
manager->placeObject(object, false, false);
|
||||
}
|
||||
|
||||
std::pair<bool, bool> ObstaclePlacer::verifyCoverage(const int3 & t) const
|
||||
{
|
||||
return {map.shouldBeBlocked(t), zone.areaPossible().contains(t)};
|
||||
}
|
||||
|
||||
void ObstaclePlacer::postProcess(const rmg::Object & object)
|
||||
{
|
||||
//river processing
|
||||
riverManager = zone.getModificator<RiverPlacer>();
|
||||
if(riverManager)
|
||||
{
|
||||
const auto objTypeName = object.instances().front()->object().typeName;
|
||||
if(objTypeName == "mountain")
|
||||
riverManager->riverSource().unite(object.getArea());
|
||||
else if(objTypeName == "lake")
|
||||
riverManager->riverSink().unite(object.getArea());
|
||||
}
|
||||
}
|
||||
|
||||
bool ObstaclePlacer::isProhibited(const rmg::Area & objArea) const
|
||||
{
|
||||
if(prohibitedArea.overlap(objArea))
|
||||
return true;
|
||||
|
||||
if(!zone.area().contains(objArea))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
46
lib/rmg/modificators/ObstaclePlacer.h
Normal file
46
lib/rmg/modificators/ObstaclePlacer.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* ObstaclePlacer.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 "Modificator.h"
|
||||
#include "../../mapping/ObstacleProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CMap;
|
||||
class CMapEditManager;
|
||||
class RiverPlacer;
|
||||
class ObjectManager;
|
||||
class ObstaclePlacer: public Modificator, public ObstacleProxy
|
||||
{
|
||||
public:
|
||||
MODIFICATOR(ObstaclePlacer);
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
|
||||
bool isInTheMap(const int3& tile) override;
|
||||
|
||||
std::pair<bool, bool> verifyCoverage(const int3 & t) const override;
|
||||
|
||||
void placeObject(rmg::Object & object, std::set<CGObjectInstance*> & instances) override;
|
||||
|
||||
void postProcess(const rmg::Object & object) override;
|
||||
|
||||
bool isProhibited(const rmg::Area & objArea) const override;
|
||||
|
||||
private:
|
||||
rmg::Area prohibitedArea;
|
||||
RiverPlacer * riverManager;
|
||||
ObjectManager * manager;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
149
lib/rmg/modificators/QuestArtifactPlacer.cpp
Normal file
149
lib/rmg/modificators/QuestArtifactPlacer.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* QuestArtifact.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 "QuestArtifactPlacer.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "../CZonePlacer.h"
|
||||
#include "../../VCMI_Lib.h"
|
||||
#include "../../mapObjects/CObjectHandler.h"
|
||||
#include "../../mapObjects/CommonConstructors.h"
|
||||
#include "../../mapObjects/MapObjects.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void QuestArtifactPlacer::process()
|
||||
{
|
||||
findZonesForQuestArts();
|
||||
placeQuestArtifacts(zone.getRand());
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::init()
|
||||
{
|
||||
DEPENDENCY_ALL(TreasurePlacer);
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::addQuestArtZone(std::shared_ptr<Zone> otherZone)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
questArtZones.push_back(otherZone);
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::addQuestArtifact(const ArtifactID& id)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
logGlobal->info("Need to place quest artifact artifact %s", VLC->artifacts()->getById(id)->getNameTranslated());
|
||||
questArtifactsToPlace.emplace_back(id);
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::rememberPotentialArtifactToReplace(CGObjectInstance* obj)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
artifactsToReplace.push_back(obj);
|
||||
}
|
||||
|
||||
std::vector<CGObjectInstance*> QuestArtifactPlacer::getPossibleArtifactsToReplace() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return artifactsToReplace;
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::findZonesForQuestArts()
|
||||
{
|
||||
const auto& distances = generator.getZonePlacer()->getDistanceMap().at(zone.getId());
|
||||
for (auto const& connectedZone : distances)
|
||||
{
|
||||
// Choose zones that are 1 or 2 connections away
|
||||
if (vstd::iswithin(connectedZone.second, 1, 2))
|
||||
{
|
||||
addQuestArtZone(map.getZones().at(connectedZone.first));
|
||||
}
|
||||
}
|
||||
|
||||
logGlobal->info("Number of nearby zones suitable for quest artifacts: %d", questArtZones.size());
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::placeQuestArtifacts(CRandomGenerator & rand)
|
||||
{
|
||||
for (const auto & artifactToPlace : questArtifactsToPlace)
|
||||
{
|
||||
RandomGeneratorUtil::randomShuffle(questArtZones, rand);
|
||||
for (auto zone : questArtZones)
|
||||
{
|
||||
auto* qap = zone->getModificator<QuestArtifactPlacer>();
|
||||
std::vector<CGObjectInstance *> artifactsToReplace = qap->getPossibleArtifactsToReplace();
|
||||
if (artifactsToReplace.empty())
|
||||
continue;
|
||||
|
||||
auto artifactToReplace = *RandomGeneratorUtil::nextItem(artifactsToReplace, rand);
|
||||
logGlobal->info("Replacing %s at %s with the quest artifact %s",
|
||||
artifactToReplace->getObjectName(),
|
||||
artifactToReplace->getPosition().toString(),
|
||||
VLC->artifacts()->getById(artifactToPlace)->getNameTranslated());
|
||||
artifactToReplace->ID = Obj::ARTIFACT;
|
||||
artifactToReplace->subID = artifactToPlace;
|
||||
|
||||
//Update appearance. Terrain is irrelevant.
|
||||
auto handler = VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, artifactToPlace);
|
||||
auto templates = handler->getTemplates();
|
||||
artifactToReplace->appearance = templates.front();
|
||||
//FIXME: Instance name is still "randomArtifact"
|
||||
|
||||
for (auto z : map.getZones())
|
||||
{
|
||||
//Every qap has its OWN collection of artifacts
|
||||
auto * localQap = zone->getModificator<QuestArtifactPlacer>();
|
||||
if (localQap)
|
||||
{
|
||||
localQap->dropReplacedArtifact(artifactToReplace);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::dropReplacedArtifact(CGObjectInstance* obj)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
boost::remove(artifactsToReplace, obj);
|
||||
}
|
||||
|
||||
size_t QuestArtifactPlacer::getMaxQuestArtifactCount() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return questArtifacts.size();
|
||||
}
|
||||
|
||||
ArtifactID QuestArtifactPlacer::drawRandomArtifact()
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
if (!questArtifacts.empty())
|
||||
{
|
||||
ArtifactID ret = questArtifacts.back();
|
||||
questArtifacts.pop_back();
|
||||
RandomGeneratorUtil::randomShuffle(questArtifacts, zone.getRand());
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw rmgException("No quest artifacts left for this zone!");
|
||||
}
|
||||
}
|
||||
|
||||
void QuestArtifactPlacer::addRandomArtifact(ArtifactID artid)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
questArtifacts.push_back(artid);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
51
lib/rmg/modificators/QuestArtifactPlacer.h
Normal file
51
lib/rmg/modificators/QuestArtifactPlacer.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* QuestArtifactPlacer, 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 "../Functions.h"
|
||||
#include "../../mapObjects/ObjectTemplate.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CRandomGenerator;
|
||||
|
||||
class QuestArtifactPlacer : public Modificator
|
||||
{
|
||||
public:
|
||||
MODIFICATOR(QuestArtifactPlacer);
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
|
||||
void addQuestArtZone(std::shared_ptr<Zone> otherZone);
|
||||
void findZonesForQuestArts();
|
||||
|
||||
void addQuestArtifact(const ArtifactID& id);
|
||||
void rememberPotentialArtifactToReplace(CGObjectInstance* obj);
|
||||
std::vector<CGObjectInstance*> getPossibleArtifactsToReplace() const;
|
||||
void placeQuestArtifacts(CRandomGenerator & rand);
|
||||
void dropReplacedArtifact(CGObjectInstance* obj);
|
||||
|
||||
size_t getMaxQuestArtifactCount() const;
|
||||
ArtifactID drawRandomArtifact();
|
||||
void addRandomArtifact(ArtifactID artid);
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<std::shared_ptr<Zone>> questArtZones; //artifacts required for Seer Huts will be placed here - or not if null
|
||||
std::vector<ArtifactID> questArtifactsToPlace;
|
||||
std::vector<CGObjectInstance*> artifactsToReplace; //Common artifacts which may be replaced by quest artifacts from other zones
|
||||
|
||||
size_t maxQuestArtifacts;
|
||||
std::vector<ArtifactID> questArtifacts;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -10,15 +10,15 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../RiverHandler.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "../Functions.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../RiverHandler.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "WaterProxy.h"
|
||||
@ -87,8 +87,8 @@ void RiverPlacer::init()
|
||||
|
||||
void RiverPlacer::drawRivers()
|
||||
{
|
||||
map.getEditManager()->getTerrainSelection().setSelection(rivers.getTilesVector());
|
||||
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(zone.getTerrainType())->river, &generator.rand);
|
||||
auto tiles = rivers.getTilesVector();
|
||||
mapProxy->drawRivers(zone.getRand(), tiles, zone.getTerrainType());
|
||||
}
|
||||
|
||||
char RiverPlacer::dump(const int3 & t)
|
||||
@ -137,7 +137,7 @@ void RiverPlacer::prepareHeightmap()
|
||||
|
||||
for(const auto & t : zone.area().getTilesVector())
|
||||
{
|
||||
heightMap[t] = generator.rand.nextInt(5);
|
||||
heightMap[t] = zone.getRand().nextInt(5);
|
||||
|
||||
if(roads.contains(t))
|
||||
heightMap[t] += 30.f;
|
||||
@ -147,9 +147,9 @@ void RiverPlacer::prepareHeightmap()
|
||||
}
|
||||
|
||||
//make grid
|
||||
for(int j = 0; j < map.map().height; j += 2)
|
||||
for(int j = 0; j < map.height(); j += 2)
|
||||
{
|
||||
for(int i = 0; i < map.map().width; i += 2)
|
||||
for(int i = 0; i < map.width(); i += 2)
|
||||
{
|
||||
int3 t{i, j, zone.getPos().z};
|
||||
if(zone.area().contains(t))
|
||||
@ -183,13 +183,13 @@ void RiverPlacer::preprocess()
|
||||
//looking outside map
|
||||
if(!outOfMapInternal.empty())
|
||||
{
|
||||
auto elem = *RandomGeneratorUtil::nextItem(outOfMapInternal.getTilesVector(), generator.rand);
|
||||
auto elem = *RandomGeneratorUtil::nextItem(outOfMapInternal.getTilesVector(), zone.getRand());
|
||||
source.add(elem);
|
||||
outOfMapInternal.erase(elem);
|
||||
}
|
||||
if(!outOfMapInternal.empty())
|
||||
{
|
||||
auto elem = *RandomGeneratorUtil::nextItem(outOfMapInternal.getTilesVector(), generator.rand);
|
||||
auto elem = *RandomGeneratorUtil::nextItem(outOfMapInternal.getTilesVector(), zone.getRand());
|
||||
sink.add(elem);
|
||||
outOfMapInternal.erase(elem);
|
||||
}
|
||||
@ -294,7 +294,7 @@ void RiverPlacer::preprocess()
|
||||
//decorative river
|
||||
if(!sink.empty() && !source.empty() && riverNodes.empty() && !zone.areaPossible().empty())
|
||||
{
|
||||
addRiverNode(*RandomGeneratorUtil::nextItem(source.getTilesVector(), generator.rand));
|
||||
addRiverNode(*RandomGeneratorUtil::nextItem(source.getTilesVector(), zone.getRand()));
|
||||
}
|
||||
|
||||
if(source.empty())
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -11,13 +11,14 @@
|
||||
#include "StdInc.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "ObstaclePlacer.h"
|
||||
#include "../Functions.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../threadpool/MapProxy.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../CModHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -76,17 +77,25 @@ void RoadPlacer::drawRoads(bool secondary)
|
||||
|| (!secondary && generator.getConfig().defaultRoadType.empty()))
|
||||
return;
|
||||
|
||||
zone.areaPossible().subtract(roads);
|
||||
zone.freePaths().unite(roads);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(roads.getTilesVector());
|
||||
//RecursiveLock lock(externalAccessMutex);
|
||||
{
|
||||
//FIXME: double lock - unsafe
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
|
||||
zone.areaPossible().subtract(roads);
|
||||
zone.freePaths().unite(roads);
|
||||
}
|
||||
|
||||
auto tiles = roads.getTilesVector();
|
||||
|
||||
std::string roadName = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
|
||||
RoadId roadType(*VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "road", roadName));
|
||||
map.getEditManager()->drawRoad(roadType, &generator.rand);
|
||||
mapProxy->drawRoads(zone.getRand(), tiles, roadType);
|
||||
}
|
||||
|
||||
void RoadPlacer::addRoadNode(const int3& node)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
roadNodes.insert(node);
|
||||
}
|
||||
|
||||
@ -111,6 +120,7 @@ void RoadPlacer::connectRoads()
|
||||
return;
|
||||
|
||||
//take any tile from road nodes as destination zone for all other road nodes
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
if(roads.empty())
|
||||
roads.add(*roadNodes.begin());
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
78
lib/rmg/modificators/RockFiller.cpp
Normal file
78
lib/rmg/modificators/RockFiller.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* RockFiller.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 "RockFiller.h"
|
||||
#include "RockPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../Functions.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
#include "../../CRandomGenerator.h"
|
||||
#include "../lib/mapping/CMapEditManager.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "../threadpool/MapProxy.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class TileInfo;
|
||||
|
||||
void RockFiller::process()
|
||||
{
|
||||
processMap();
|
||||
}
|
||||
|
||||
void RockFiller::processMap()
|
||||
{
|
||||
//Merge all areas
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
auto zone = z.second;
|
||||
if(auto * m = zone->getModificator<RockPlacer>())
|
||||
{
|
||||
auto tiles = m->rockArea.getTilesVector();
|
||||
mapProxy->drawTerrain(zone->getRand(), tiles, m->rockTerrain);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
auto zone = z.second;
|
||||
if(auto * m = zone->getModificator<RockPlacer>())
|
||||
{
|
||||
//Now make sure all accessible tiles have no additional rock on them
|
||||
auto tiles = m->accessibleArea.getTilesVector();
|
||||
mapProxy->drawTerrain(zone->getRand(), tiles, zone->getTerrainType());
|
||||
|
||||
m->postProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RockFiller::init()
|
||||
{
|
||||
DEPENDENCY_ALL(RockPlacer);
|
||||
POSTFUNCTION_ALL(RoadPlacer);
|
||||
}
|
||||
|
||||
char RockFiller::dump(const int3 & t)
|
||||
{
|
||||
if(!map.getTile(t).terType->isPassable())
|
||||
{
|
||||
return zone.area().contains(t) ? 'R' : 'E';
|
||||
}
|
||||
return Modificator::dump(t);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
28
lib/rmg/modificators/RockFiller.h
Normal file
28
lib/rmg/modificators/RockFiller.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* RockFiller.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 RockFiller: public Modificator
|
||||
{
|
||||
public:
|
||||
MODIFICATOR(RockFiller);
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
char dump(const int3 &) override;
|
||||
|
||||
void processMap();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -14,77 +14,51 @@
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "RiverPlacer.h"
|
||||
#include "RmgMap.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "Functions.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../CRandomGenerator.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../Functions.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
#include "../../CRandomGenerator.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../TileInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class TileInfo;
|
||||
|
||||
void RockPlacer::process()
|
||||
{
|
||||
blockRock();
|
||||
}
|
||||
void RockPlacer::blockRock()
|
||||
{
|
||||
rockTerrain = VLC->terrainTypeHandler->getById(zone.getTerrainType())->rockTerrain;
|
||||
assert(!VLC->terrainTypeHandler->getById(rockTerrain)->isPassable());
|
||||
|
||||
|
||||
accessibleArea = zone.freePaths() + zone.areaUsed();
|
||||
if(auto * m = zone.getModificator<ObjectManager>())
|
||||
accessibleArea.unite(m->getVisitableArea());
|
||||
|
||||
|
||||
//negative approach - create rock tiles first, then make sure all accessible tiles have no rock
|
||||
rockArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return map.shouldBeBlocked(t);
|
||||
});
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
if(m != this && !m->isFinished())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processMap();
|
||||
}
|
||||
|
||||
void RockPlacer::processMap()
|
||||
{
|
||||
//merge all areas
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
map.getEditManager()->getTerrainSelection().setSelection(m->rockArea.getTilesVector());
|
||||
map.getEditManager()->drawTerrain(m->rockTerrain, &generator.rand);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & z : map.getZones())
|
||||
{
|
||||
if(auto * m = z.second->getModificator<RockPlacer>())
|
||||
{
|
||||
//now make sure all accessible tiles have no additional rock on them
|
||||
map.getEditManager()->getTerrainSelection().setSelection(m->accessibleArea.getTilesVector());
|
||||
map.getEditManager()->drawTerrain(z.second->getTerrainType(), &generator.rand);
|
||||
m->postProcess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RockPlacer::postProcess()
|
||||
{
|
||||
//finally mark rock tiles as occupied, spawn no obstacles there
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
//Finally mark rock tiles as occupied, spawn no obstacles there
|
||||
rockArea = zone.area().getSubarea([this](const int3 & t)
|
||||
{
|
||||
return !map.map().getTile(t).terType->isPassable();
|
||||
return !map.getTile(t).terType->isPassable();
|
||||
});
|
||||
|
||||
zone.areaUsed().unite(rockArea);
|
||||
zone.areaPossible().subtract(rockArea);
|
||||
|
||||
//TODO: Might need mutex here as well
|
||||
if(auto * m = zone.getModificator<RiverPlacer>())
|
||||
m->riverProhibit().unite(rockArea);
|
||||
if(auto * m = zone.getModificator<RoadPlacer>())
|
||||
@ -93,13 +67,12 @@ void RockPlacer::postProcess()
|
||||
|
||||
void RockPlacer::init()
|
||||
{
|
||||
POSTFUNCTION_ALL(RoadPlacer);
|
||||
DEPENDENCY(TreasurePlacer);
|
||||
DEPENDENCY_ALL(TreasurePlacer);
|
||||
}
|
||||
|
||||
char RockPlacer::dump(const int3 & t)
|
||||
{
|
||||
if(!map.map().getTile(t).terType->isPassable())
|
||||
if(!map.getTile(t).terType->isPassable())
|
||||
{
|
||||
return zone.area().contains(t) ? 'R' : 'E';
|
||||
}
|
@ -9,12 +9,13 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RockPlacer: public Modificator
|
||||
{
|
||||
friend class RockFiller;
|
||||
public:
|
||||
MODIFICATOR(RockPlacer);
|
||||
|
||||
@ -22,7 +23,7 @@ public:
|
||||
void init() override;
|
||||
char dump(const int3 &) override;
|
||||
|
||||
void processMap();
|
||||
void blockRock();
|
||||
void postProcess();
|
||||
|
||||
protected:
|
105
lib/rmg/modificators/TerrainPainter.cpp
Normal file
105
lib/rmg/modificators/TerrainPainter.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* TerrainPainter.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 "TerrainPainter.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "../Functions.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../VCMI_Lib.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void TerrainPainter::process()
|
||||
{
|
||||
initTerrainType();
|
||||
|
||||
auto v = zone.getArea().getTilesVector();
|
||||
mapProxy->drawTerrain(zone.getRand(), v, zone.getTerrainType());
|
||||
}
|
||||
|
||||
void TerrainPainter::init()
|
||||
{
|
||||
DEPENDENCY(TownPlacer);
|
||||
DEPENDENCY_ALL(WaterAdopter);
|
||||
POSTFUNCTION_ALL(WaterProxy);
|
||||
POSTFUNCTION_ALL(ConnectionsPlacer);
|
||||
POSTFUNCTION(ObjectManager);
|
||||
}
|
||||
|
||||
void TerrainPainter::initTerrainType()
|
||||
{
|
||||
if(zone.getType()==ETemplateZoneType::WATER)
|
||||
{
|
||||
//collect all water terrain types
|
||||
std::vector<TerrainId> waterTerrains;
|
||||
for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
||||
if(terrain->isWater())
|
||||
waterTerrains.push_back(terrain->getId());
|
||||
|
||||
zone.setTerrainType(*RandomGeneratorUtil::nextItem(waterTerrains, zone.getRand()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(zone.isMatchTerrainToTown() && zone.getTownType() != ETownType::NEUTRAL)
|
||||
{
|
||||
auto terrainType = (*VLC->townh)[zone.getTownType()]->nativeTerrain;
|
||||
|
||||
if (terrainType <= ETerrainId::NONE)
|
||||
{
|
||||
logGlobal->warn("Town %s has invalid terrain type: %d", zone.getTownType(), terrainType);
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
zone.setTerrainType(terrainType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto terrainTypes = zone.getTerrainTypes();
|
||||
if (terrainTypes.empty())
|
||||
{
|
||||
logGlobal->warn("No terrain types found, falling back to DIRT");
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
else
|
||||
{
|
||||
zone.setTerrainType(*RandomGeneratorUtil::nextItem(terrainTypes, zone.getRand()));
|
||||
}
|
||||
}
|
||||
|
||||
//Now, replace disallowed terrains on surface and in the underground
|
||||
const auto & terrainType = VLC->terrainTypeHandler->getById(zone.getTerrainType());
|
||||
|
||||
if(zone.isUnderground())
|
||||
{
|
||||
if(!terrainType->isUnderground())
|
||||
{
|
||||
zone.setTerrainType(ETerrainId::SUBTERRANEAN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!terrainType->isSurface())
|
||||
{
|
||||
zone.setTerrainType(ETerrainId::DIRT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -20,6 +20,8 @@ public:
|
||||
|
||||
void process() override;
|
||||
void init() override;
|
||||
|
||||
void initTerrainType();
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -10,20 +10,20 @@
|
||||
|
||||
#include "StdInc.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 "../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 "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "MinePlacer.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -52,7 +52,7 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
//set zone types to player faction, generate main town
|
||||
logGlobal->info("Preparing playing zone");
|
||||
int player_id = *zone.getOwner() - 1;
|
||||
auto & playerInfo = map.map().players[player_id];
|
||||
auto& playerInfo = map.getPlayer(player_id);
|
||||
PlayerColor player(player_id);
|
||||
if(playerInfo.canAnyonePlay())
|
||||
{
|
||||
@ -119,16 +119,16 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
if(!totalTowns) //if there's no town present, get random faction for dwellings and pandoras
|
||||
{
|
||||
//25% chance for neutral
|
||||
if (generator.rand.nextInt(1, 100) <= 25)
|
||||
if (zone.getRand().nextInt(1, 100) <= 25)
|
||||
{
|
||||
zone.setTownType(ETownType::NEUTRAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!zone.getTownTypes().empty())
|
||||
zone.setTownType(*RandomGeneratorUtil::nextItem(zone.getTownTypes(), generator.rand));
|
||||
zone.setTownType(*RandomGeneratorUtil::nextItem(zone.getTownTypes(), zone.getRand()));
|
||||
else if(!zone.getMonsterTypes().empty())
|
||||
zone.setTownType(*RandomGeneratorUtil::nextItem(zone.getMonsterTypes(), generator.rand)); //this happens in Clash of Dragons in treasure zones, where all towns are banned
|
||||
zone.setTownType(*RandomGeneratorUtil::nextItem(zone.getMonsterTypes(), zone.getRand())); //this happens in Clash of Dragons in treasure zones, where all towns are banned
|
||||
else //just in any case
|
||||
zone.setTownType(getRandomTownType());
|
||||
}
|
||||
@ -140,11 +140,16 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town)
|
||||
//towns are big objects and should be centered around visitable position
|
||||
rmg::Object rmgObject(town);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
auto position = manager.findPlaceForObject(zone.areaPossible(), rmgObject, [this](const int3 & t)
|
||||
|
||||
int3 position(-1, -1, -1);
|
||||
{
|
||||
float distance = zone.getPos().dist2dSQ(t);
|
||||
return 100000.f - distance; //some big number
|
||||
}, ObjectManager::OptimizeType::WEIGHT);
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
position = manager.findPlaceForObject(zone.areaPossible(), rmgObject, [this](const int3& t)
|
||||
{
|
||||
float distance = zone.getPos().dist2dSQ(t);
|
||||
return 100000.f - distance; //some big number
|
||||
}, ObjectManager::OptimizeType::WEIGHT);
|
||||
}
|
||||
rmgObject.setPosition(position + int3(2, 2, 0)); //place visitable tile in the exact center of a zone
|
||||
manager.placeObject(rmgObject, false, true);
|
||||
cleanupBoundaries(rmgObject);
|
||||
@ -154,6 +159,7 @@ int3 TownPlacer::placeMainTown(ObjectManager & manager, CGTownInstance & town)
|
||||
|
||||
void TownPlacer::cleanupBoundaries(const rmg::Object & rmgObject)
|
||||
{
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
for(const auto & t : rmgObject.getArea().getBorderOutside())
|
||||
{
|
||||
if(map.isOnMap(t))
|
||||
@ -176,9 +182,9 @@ void TownPlacer::addNewTowns(int count, bool hasFort, const PlayerColor & player
|
||||
if(!zone.areTownsSameType())
|
||||
{
|
||||
if(!zone.getTownTypes().empty())
|
||||
subType = *RandomGeneratorUtil::nextItem(zone.getTownTypes(), generator.rand);
|
||||
subType = *RandomGeneratorUtil::nextItem(zone.getTownTypes(), zone.getRand());
|
||||
else
|
||||
subType = *RandomGeneratorUtil::nextItem(zone.getDefaultTownTypes(), generator.rand); //it is possible to have zone with no towns allowed
|
||||
subType = *RandomGeneratorUtil::nextItem(zone.getDefaultTownTypes(), zone.getRand()); //it is possible to have zone with no towns allowed
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +235,7 @@ si32 TownPlacer::getRandomTownType(bool matchUndergroundType)
|
||||
townTypesAllowed = townTypesVerify;
|
||||
}
|
||||
|
||||
return *RandomGeneratorUtil::nextItem(townTypesAllowed, generator.rand);
|
||||
return *RandomGeneratorUtil::nextItem(townTypesAllowed, zone.getRand());
|
||||
}
|
||||
|
||||
int TownPlacer::getTotalTowns() const
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -10,19 +10,21 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "Functions.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../Functions.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "RmgMap.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../mapObjects/CommonConstructors.h"
|
||||
#include "../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../spells/CSpellHandler.h" //for choosing random spells
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "../CZonePlacer.h"
|
||||
#include "QuestArtifactPlacer.h"
|
||||
#include "../../mapObjects/CommonConstructors.h"
|
||||
#include "../../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
|
||||
#include "../../CCreatureHandler.h"
|
||||
#include "../../spells/CSpellHandler.h" //for choosing random spells
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -41,13 +43,9 @@ void TreasurePlacer::init()
|
||||
POSTFUNCTION(RoadPlacer);
|
||||
}
|
||||
|
||||
void TreasurePlacer::setQuestArtZone(Zone * otherZone)
|
||||
{
|
||||
questArtZone = otherZone;
|
||||
}
|
||||
|
||||
void TreasurePlacer::addObjectToRandomPool(const ObjectInfo& oi)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
possibleObjects.push_back(oi);
|
||||
}
|
||||
|
||||
@ -73,6 +71,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
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
|
||||
{
|
||||
@ -98,26 +97,28 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
//prisons
|
||||
//levels 1, 5, 10, 20, 30
|
||||
static int prisonsLevels = std::min(generator.getConfig().prisonExperience.size(), generator.getConfig().prisonValues.size());
|
||||
for(int i = 0; i < prisonsLevels; i++)
|
||||
|
||||
size_t prisonsLeft = getMaxPrisons();
|
||||
for(int i = prisonsLevels - 1; i >= 0 ;i--)
|
||||
{
|
||||
oi.value = generator.getConfig().prisonValues[i];
|
||||
if (oi.value > zone.getMaxTreasureValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance *
|
||||
{
|
||||
std::vector<ui32> possibleHeroes;
|
||||
for(int j = 0; j < map.map().allowedHeroes.size(); j++)
|
||||
{
|
||||
if(map.map().allowedHeroes[j])
|
||||
possibleHeroes.push_back(j);
|
||||
}
|
||||
|
||||
auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, generator.rand);
|
||||
auto possibleHeroes = generator.getAllPossibleHeroes();
|
||||
HeroTypeID hid = *RandomGeneratorUtil::nextItem(possibleHeroes, zone.getRand());
|
||||
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
|
||||
auto * obj = dynamic_cast<CGHeroInstance *>(factory->create());
|
||||
|
||||
obj->subID = hid; //will be initialized later
|
||||
obj->exp = generator.getConfig().prisonExperience[i];
|
||||
obj->setOwner(PlayerColor::NEUTRAL);
|
||||
map.map().allowedHeroes[hid] = false; //ban this hero
|
||||
generator.decreasePrisonsRemaining();
|
||||
generator.banHero(hid);
|
||||
obj->appearance = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0)->getTemplates(zone.getTerrainType()).front(); //can't init template with hero subID
|
||||
|
||||
return obj;
|
||||
@ -125,7 +126,10 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.setTemplate(Obj::PRISON, 0, zone.getTerrainType());
|
||||
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.
|
||||
|
||||
//Distribute all allowed prisons, starting from the most valuable
|
||||
oi.maxPerZone = (std::ceil((float)prisonsLeft / (i + 1)));
|
||||
prisonsLeft -= oi.maxPerZone;
|
||||
addObjectToRandomPool(oi);
|
||||
}
|
||||
|
||||
@ -204,7 +208,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
out.push_back(spell->id);
|
||||
}
|
||||
}
|
||||
auto * a = CArtifactInstance::createScroll(*RandomGeneratorUtil::nextItem(out, generator.rand));
|
||||
auto * a = CArtifactInstance::createScroll(*RandomGeneratorUtil::nextItem(out, zone.getRand()));
|
||||
obj->storedArtifact = a;
|
||||
return obj;
|
||||
};
|
||||
@ -318,7 +322,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
spells.push_back(spell);
|
||||
}
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(spells, generator.rand);
|
||||
RandomGeneratorUtil::randomShuffle(spells, zone.getRand());
|
||||
for(int j = 0; j < std::min(12, static_cast<int>(spells.size())); j++)
|
||||
{
|
||||
obj->spells.push_back(spells[j]->id);
|
||||
@ -347,7 +351,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
spells.push_back(spell);
|
||||
}
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(spells, generator.rand);
|
||||
RandomGeneratorUtil::randomShuffle(spells, zone.getRand());
|
||||
for(int j = 0; j < std::min(15, static_cast<int>(spells.size())); j++)
|
||||
{
|
||||
obj->spells.push_back(spells[j]->id);
|
||||
@ -375,7 +379,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
spells.push_back(spell);
|
||||
}
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(spells, generator.rand);
|
||||
RandomGeneratorUtil::randomShuffle(spells, zone.getRand());
|
||||
for(int j = 0; j < std::min(60, static_cast<int>(spells.size())); j++)
|
||||
{
|
||||
obj->spells.push_back(spells[j]->id);
|
||||
@ -388,44 +392,28 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.probability = 2;
|
||||
addObjectToRandomPool(oi);
|
||||
|
||||
//seer huts with creatures or generic rewards
|
||||
|
||||
if(questArtZone) //we won't be placing seer huts if there is no zone left to place arties
|
||||
//Seer huts with creatures or generic rewards
|
||||
|
||||
if(zone.getConnections().size()) //Unlikely, but...
|
||||
{
|
||||
static const int genericSeerHuts = 8;
|
||||
int seerHutsPerType = 0;
|
||||
const int questArtsRemaining = static_cast<int>(generator.getQuestArtsRemaning().size());
|
||||
|
||||
//general issue is that not many artifact types are available for quests
|
||||
|
||||
if(questArtsRemaining >= genericSeerHuts + static_cast<int>(creatures.size()))
|
||||
auto * qap = zone.getModificator<QuestArtifactPlacer>();
|
||||
if(!qap)
|
||||
{
|
||||
seerHutsPerType = questArtsRemaining / (genericSeerHuts + static_cast<int>(creatures.size()));
|
||||
return; //TODO: throw?
|
||||
}
|
||||
else if(questArtsRemaining >= genericSeerHuts)
|
||||
{
|
||||
seerHutsPerType = 1;
|
||||
}
|
||||
oi.maxPerZone = seerHutsPerType;
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(creatures, generator.rand);
|
||||
const int questArtsRemaining = qap->getMaxQuestArtifactCount();
|
||||
|
||||
//Generate Seer Hut one by one. Duplicated oi possible and should work fine.
|
||||
oi.maxPerZone = 1;
|
||||
|
||||
auto generateArtInfo = [this](const ArtifactID & id) -> ObjectInfo
|
||||
{
|
||||
ObjectInfo artInfo;
|
||||
artInfo.probability = std::numeric_limits<ui16>::max(); //99,9% to spawn that art in first treasure pile
|
||||
artInfo.maxPerZone = 1;
|
||||
artInfo.value = 2000; //treasure art
|
||||
artInfo.setTemplate(Obj::ARTIFACT, id, this->zone.getTerrainType());
|
||||
artInfo.generateObject = [id]() -> CGObjectInstance *
|
||||
{
|
||||
auto handler = VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, id);
|
||||
return handler->create(handler->getTemplates().front());
|
||||
};
|
||||
return artInfo;
|
||||
};
|
||||
std::vector<ObjectInfo> possibleSeerHuts;
|
||||
//14 creatures per town + 4 for each of gold / exp reward
|
||||
possibleSeerHuts.reserve(14 + 4 + 4);
|
||||
|
||||
RandomGeneratorUtil::randomShuffle(creatures, zone.getRand());
|
||||
|
||||
for(int i = 0; i < std::min(static_cast<int>(creatures.size()), questArtsRemaining - genericSeerHuts); i++)
|
||||
for(int i = 0; i < static_cast<int>(creatures.size()); i++)
|
||||
{
|
||||
auto * creature = creatures[i];
|
||||
int creaturesAmount = creatureToCount(creature);
|
||||
@ -433,9 +421,9 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
if(!creaturesAmount)
|
||||
continue;
|
||||
|
||||
int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
|
||||
int randomAppearance = chooseRandomAppearance(zone.getRand(), Obj::SEER_HUT, zone.getTerrainType());
|
||||
|
||||
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||
@ -444,34 +432,46 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
obj->rVal = creaturesAmount;
|
||||
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
||||
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
generator.banQuestArt(artid);
|
||||
|
||||
|
||||
this->questArtZone->getModificator<TreasurePlacer>()->addObjectToRandomPool(generateArtInfo(artid));
|
||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||
|
||||
return obj;
|
||||
};
|
||||
oi.probability = 3;
|
||||
oi.setTemplate(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.probability = 3;
|
||||
addObjectToRandomPool(oi);
|
||||
if (oi.value > zone.getMaxTreasureValue())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
possibleSeerHuts.push_back(oi);
|
||||
}
|
||||
}
|
||||
|
||||
static int seerLevels = std::min(generator.getConfig().questValues.size(), generator.getConfig().questRewardValues.size());
|
||||
for(int i = 0; i < seerLevels; i++) //seems that code for exp and gold reward is similiar
|
||||
{
|
||||
int randomAppearance = chooseRandomAppearance(generator.rand, Obj::SEER_HUT, zone.getTerrainType());
|
||||
int randomAppearance = chooseRandomAppearance(zone.getRand(), Obj::SEER_HUT, zone.getTerrainType());
|
||||
|
||||
oi.setTemplate(Obj::SEER_HUT, randomAppearance, zone.getTerrainType());
|
||||
oi.value = generator.getConfig().questValues[i];
|
||||
if (oi.value > zone.getMaxTreasureValue())
|
||||
{
|
||||
//Both variants have same value
|
||||
continue;
|
||||
}
|
||||
|
||||
oi.probability = 10;
|
||||
|
||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||
@ -481,21 +481,20 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
obj->rVal = generator.getConfig().questRewardValues[i];
|
||||
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
generator.banQuestArt(artid);
|
||||
|
||||
this->questArtZone->getModificator<TreasurePlacer>()->addObjectToRandomPool(generateArtInfo(artid));
|
||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
addObjectToRandomPool(oi);
|
||||
possibleSeerHuts.push_back(oi);
|
||||
|
||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
oi.generateObject = [i, randomAppearance, this, qap]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto * obj = dynamic_cast<CGSeerHut *>(factory->create());
|
||||
@ -504,28 +503,45 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
obj->rVal = generator.getConfig().questRewardValues[i];
|
||||
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
|
||||
ArtifactID artid = qap->drawRandomArtifact();
|
||||
obj->quest->addArtifactID(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
generator.banQuestArt(artid);
|
||||
|
||||
this->questArtZone->getModificator<TreasurePlacer>()->addObjectToRandomPool(generateArtInfo(artid));
|
||||
zone.getModificator<QuestArtifactPlacer>()->addQuestArtifact(artid);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
addObjectToRandomPool(oi);
|
||||
possibleSeerHuts.push_back(oi);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < questArtsRemaining; i++)
|
||||
{
|
||||
addObjectToRandomPool(*RandomGeneratorUtil::nextItem(possibleSeerHuts, zone.getRand()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t TreasurePlacer::getPossibleObjectsSize() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return possibleObjects.size();
|
||||
}
|
||||
|
||||
void TreasurePlacer::setMaxPrisons(size_t count)
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
maxPrisons = count;
|
||||
}
|
||||
|
||||
size_t TreasurePlacer::getMaxPrisons() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return maxPrisons;
|
||||
}
|
||||
|
||||
bool TreasurePlacer::isGuardNeededForTreasure(int value)
|
||||
{
|
||||
return zone.getType() != ETemplateZoneType::WATER && value > minGuardedValue;
|
||||
@ -537,7 +553,7 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
|
||||
int maxValue = treasureInfo.max;
|
||||
int minValue = treasureInfo.min;
|
||||
|
||||
const ui32 desiredValue = generator.rand.nextInt(minValue, maxValue);
|
||||
const ui32 desiredValue =zone.getRand().nextInt(minValue, maxValue);
|
||||
|
||||
int currentValue = 0;
|
||||
bool hasLargeObject = false;
|
||||
@ -615,7 +631,7 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
bestPositions = accessibleArea.getTilesVector();
|
||||
}
|
||||
|
||||
int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, generator.rand);
|
||||
int3 nextPos = *RandomGeneratorUtil::nextItem(bestPositions, zone.getRand());
|
||||
instance.setPosition(nextPos - rmgObject.getPosition());
|
||||
|
||||
auto instanceAccessibleArea = instance.getAccessibleArea();
|
||||
@ -670,7 +686,7 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = generator.rand.nextInt(1, total);
|
||||
int r = zone.getRand().nextInt(1, total);
|
||||
auto sorter = [](const std::pair<ui32, ObjectInfo *> & rhs, const ui32 lhs) -> bool
|
||||
{
|
||||
return static_cast<int>(rhs.first) < lhs;
|
||||
@ -756,6 +772,8 @@ void TreasurePlacer::createTreasures(ObjectManager & manager)
|
||||
if(guarded)
|
||||
guarded = manager.addGuard(rmgObject, value);
|
||||
|
||||
Zone::Lock lock(zone.areaMutex); //We are going to subtract this area
|
||||
//TODO: Don't place
|
||||
auto possibleArea = zone.areaPossible();
|
||||
|
||||
auto path = rmg::Path::invalid();
|
||||
@ -763,13 +781,13 @@ void TreasurePlacer::createTreasures(ObjectManager & manager)
|
||||
{
|
||||
path = manager.placeAndConnectObject(possibleArea, rmgObject, [this, &rmgObject, &minDistance, &manager](const int3 & tile)
|
||||
{
|
||||
auto ti = map.getTile(tile);
|
||||
auto ti = map.getTileInfo(tile);
|
||||
if(ti.getNearestObjectDistance() < minDistance)
|
||||
return -1.f;
|
||||
|
||||
for(const auto & t : rmgObject.getArea().getTilesVector())
|
||||
{
|
||||
if(map.getTile(t).getNearestObjectDistance() < minDistance)
|
||||
if(map.getTileInfo(t).getNearestObjectDistance() < minDistance)
|
||||
return -1.f;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* TreasurePlacer.cpp, part of VCMI engine
|
||||
* TreasurePlacer.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@ -9,8 +9,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../mapObjects/ObjectTemplate.h"
|
||||
#include "../Zone.h"
|
||||
#include "../../mapObjects/ObjectTemplate.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -18,6 +18,7 @@ class CGObjectInstance;
|
||||
class ObjectManager;
|
||||
class RmgMap;
|
||||
class CMapGenerator;
|
||||
class CRandomGenerator;
|
||||
|
||||
struct ObjectInfo
|
||||
{
|
||||
@ -43,12 +44,12 @@ public:
|
||||
char dump(const int3 &) override;
|
||||
|
||||
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;
|
||||
void setMaxPrisons(size_t count);
|
||||
size_t getMaxPrisons() const;
|
||||
|
||||
protected:
|
||||
bool isGuardNeededForTreasure(int value);
|
||||
@ -64,8 +65,8 @@ protected:
|
||||
rmg::Area treasureArea;
|
||||
rmg::Area treasureBlockArea;
|
||||
rmg::Area guards;
|
||||
|
||||
Zone * questArtZone = nullptr; //artifacts required for Seer Huts will be placed here - or not if null
|
||||
|
||||
size_t maxPrisons;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -10,20 +10,20 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
#include "../RmgObject.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -35,7 +35,6 @@ void WaterAdopter::process()
|
||||
void WaterAdopter::init()
|
||||
{
|
||||
//make dependencies
|
||||
DEPENDENCY_ALL(WaterAdopter);
|
||||
DEPENDENCY(TownPlacer);
|
||||
POSTFUNCTION(ConnectionsPlacer);
|
||||
POSTFUNCTION(TreasurePlacer);
|
||||
@ -59,8 +58,8 @@ void WaterAdopter::createWater(EWaterContent::EWaterContent waterContent)
|
||||
if(waterContent == EWaterContent::NORMAL)
|
||||
{
|
||||
waterArea.unite(collectDistantTiles(zone, zone.getSize() - 1));
|
||||
auto sliceStart = RandomGeneratorUtil::nextItem(reverseDistanceMap[0], generator.rand);
|
||||
auto sliceEnd = RandomGeneratorUtil::nextItem(reverseDistanceMap[0], generator.rand);
|
||||
auto sliceStart = RandomGeneratorUtil::nextItem(reverseDistanceMap[0], zone.getRand());
|
||||
auto sliceEnd = RandomGeneratorUtil::nextItem(reverseDistanceMap[0], zone.getRand());
|
||||
|
||||
//at least 25% without water
|
||||
bool endPassed = false;
|
||||
@ -98,7 +97,7 @@ void WaterAdopter::createWater(EWaterContent::EWaterContent waterContent)
|
||||
const int coastLength = reverseDistanceMap[coastId].size() / (coastId + 3);
|
||||
for(int coastIter = 0; coastIter < coastLength; ++coastIter)
|
||||
{
|
||||
int3 tile = *RandomGeneratorUtil::nextItem(reverseDistanceMap[coastId], generator.rand);
|
||||
int3 tile = *RandomGeneratorUtil::nextItem(reverseDistanceMap[coastId], zone.getRand());
|
||||
if(tilesChecked.find(tile) != tilesChecked.end())
|
||||
continue;
|
||||
|
||||
@ -224,7 +223,11 @@ void WaterAdopter::createWater(EWaterContent::EWaterContent waterContent)
|
||||
}
|
||||
}
|
||||
|
||||
map.getZones()[waterZoneId]->area().unite(waterArea);
|
||||
{
|
||||
Zone::Lock waterLock(map.getZones()[waterZoneId]->areaMutex);
|
||||
map.getZones()[waterZoneId]->area().unite(waterArea);
|
||||
}
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
zone.area().subtract(waterArea);
|
||||
zone.areaPossible().subtract(waterArea);
|
||||
distanceMap = zone.area().computeDistanceMap(reverseDistanceMap);
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -10,23 +10,23 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
#include "../RmgObject.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "RmgArea.h"
|
||||
#include "../RmgArea.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -38,7 +38,8 @@ void WaterProxy::process()
|
||||
map.setOccupied(t, ETileType::POSSIBLE);
|
||||
}
|
||||
|
||||
paintZoneTerrain(zone, generator.rand, map, zone.getTerrainType());
|
||||
auto v = zone.getArea().getTilesVector();
|
||||
mapProxy->drawTerrain(zone.getRand(), v, zone.getTerrainType());
|
||||
|
||||
//check terrain type
|
||||
for([[maybe_unused]] const auto & t : zone.area().getTilesVector())
|
||||
@ -52,9 +53,10 @@ void WaterProxy::process()
|
||||
if(z.second->getId() == zone.getId())
|
||||
continue;
|
||||
|
||||
Zone::Lock lock(z.second->areaMutex);
|
||||
for(const auto & t : z.second->area().getTilesVector())
|
||||
{
|
||||
if(map.map().getTile(t).terType->getId() == zone.getTerrainType())
|
||||
if(map.getTile(t).terType->getId() == zone.getTerrainType())
|
||||
{
|
||||
z.second->areaPossible().erase(t);
|
||||
z.second->area().erase(t);
|
||||
@ -90,11 +92,13 @@ void WaterProxy::init()
|
||||
|
||||
const std::vector<WaterProxy::Lake> & WaterProxy::getLakes() const
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
return lakes;
|
||||
}
|
||||
|
||||
void WaterProxy::collectLakes()
|
||||
{
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
int lakeId = 0;
|
||||
for(const auto & lake : connectedAreas(zone.getArea(), true))
|
||||
{
|
||||
@ -138,6 +142,8 @@ RouteInfo WaterProxy::waterRoute(Zone & dst)
|
||||
if(map.isPossible(ct))
|
||||
map.setOccupied(ct, ETileType::BLOCKED);
|
||||
}
|
||||
|
||||
Zone::Lock lock(dst.areaMutex);
|
||||
dst.areaPossible().subtract(lake.neighbourZones[dst.getId()]);
|
||||
continue;
|
||||
}
|
||||
@ -225,7 +231,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
|
||||
if(sailingBoatTypes.empty())
|
||||
return false;
|
||||
|
||||
auto * boat = dynamic_cast<CGBoat *>(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, generator.rand))->create());
|
||||
auto * boat = dynamic_cast<CGBoat *>(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, zone.getRand()))->create());
|
||||
|
||||
rmg::Object rmgObject(*boat);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
@ -236,7 +242,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
|
||||
auto boardingPositions = coast.getSubarea([&waterAvailable, this](const int3 & tile) //tiles where boarding is possible
|
||||
{
|
||||
//We don't want place boat right to any land object, especiallly the zone guard
|
||||
if (map.getTile(tile).getNearestObjectDistance() <= 3)
|
||||
if (map.getTileInfo(tile).getNearestObjectDistance() <= 3)
|
||||
return false;
|
||||
|
||||
rmg::Area a({tile});
|
||||
@ -288,7 +294,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route
|
||||
if(!manager)
|
||||
return false;
|
||||
|
||||
int subtype = chooseRandomAppearance(generator.rand, Obj::SHIPYARD, land.getTerrainType());
|
||||
int subtype = chooseRandomAppearance(zone.getRand(), Obj::SHIPYARD, land.getTerrainType());
|
||||
auto * shipyard = dynamic_cast<CGShipyard *>(VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create());
|
||||
shipyard->tempOwner = PlayerColor::NEUTRAL;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -11,22 +11,22 @@
|
||||
#include "StdInc.h"
|
||||
#include "WaterRoutes.h"
|
||||
#include "WaterProxy.h"
|
||||
#include "CMapGenerator.h"
|
||||
#include "RmgMap.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../mapping/CMapEditManager.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
#include "RmgPath.h"
|
||||
#include "RmgObject.h"
|
||||
#include "../CMapGenerator.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
#include "../../mapObjects/CObjectClassesHandler.h"
|
||||
#include "../RmgPath.h"
|
||||
#include "../RmgObject.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "Functions.h"
|
||||
#include "../Functions.h"
|
||||
#include "RoadPlacer.h"
|
||||
#include "TreasurePlacer.h"
|
||||
#include "TownPlacer.h"
|
||||
#include "ConnectionsPlacer.h"
|
||||
#include "TileInfo.h"
|
||||
#include "../TileInfo.h"
|
||||
#include "WaterAdopter.h"
|
||||
#include "RmgArea.h"
|
||||
#include "../RmgArea.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -44,7 +44,9 @@ void WaterRoutes::process()
|
||||
if(z.first != zone.getId())
|
||||
result.push_back(wproxy->waterRoute(*z.second));
|
||||
}
|
||||
|
||||
|
||||
Zone::Lock lock(zone.areaMutex);
|
||||
|
||||
//prohibit to place objects on sealed off lakes
|
||||
for(const auto & lake : wproxy->getLakes())
|
||||
{
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Zone.h"
|
||||
#include "../Zone.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
91
lib/rmg/threadpool/BlockingQueue.h
Normal file
91
lib/rmg/threadpool/BlockingQueue.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* BlockingQueue.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 "StdInc.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//Credit to https://github.com/Liam0205/toy-threadpool/tree/master/yuuki
|
||||
|
||||
template <typename T>
|
||||
class DLL_LINKAGE BlockingQueue : protected std::queue<T>
|
||||
{
|
||||
using WriteLock = boost::unique_lock<boost::shared_mutex>;
|
||||
using Readlock = boost::shared_lock<boost::shared_mutex>;
|
||||
|
||||
public:
|
||||
BlockingQueue() = default;
|
||||
~BlockingQueue()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
BlockingQueue(const BlockingQueue&) = delete;
|
||||
BlockingQueue(BlockingQueue&&) = delete;
|
||||
BlockingQueue& operator=(const BlockingQueue&) = delete;
|
||||
BlockingQueue& operator=(BlockingQueue&&) = delete;
|
||||
|
||||
public:
|
||||
bool empty() const
|
||||
{
|
||||
Readlock lock(mx);
|
||||
return std::queue<T>::empty();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
Readlock lock(mx);
|
||||
return std::queue<T>::size();
|
||||
}
|
||||
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
WriteLock lock(mx);
|
||||
while (!std::queue<T>::empty())
|
||||
{
|
||||
std::queue<T>::pop();
|
||||
}
|
||||
}
|
||||
|
||||
void push(const T& obj)
|
||||
{
|
||||
WriteLock lock(mx);
|
||||
std::queue<T>::push(obj);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
WriteLock lock(mx);
|
||||
std::queue<T>::emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
bool pop(T& holder)
|
||||
{
|
||||
WriteLock lock(mx);
|
||||
if (std::queue<T>::empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
holder = std::move(std::queue<T>::front());
|
||||
std::queue<T>::pop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable boost::shared_mutex mx;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
54
lib/rmg/threadpool/MapProxy.cpp
Normal file
54
lib/rmg/threadpool/MapProxy.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* MapProxy.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 "MapProxy.h"
|
||||
#include "../../TerrainHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
MapProxy::MapProxy(RmgMap & map):
|
||||
map(map)
|
||||
{
|
||||
}
|
||||
|
||||
void MapProxy::insertObject(CGObjectInstance * obj)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->insertObject(obj);
|
||||
}
|
||||
|
||||
void MapProxy::insertObjects(std::set<CGObjectInstance*>& objects)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->insertObjects(objects);
|
||||
}
|
||||
|
||||
void MapProxy::drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawTerrain(terrain, &generator);
|
||||
}
|
||||
|
||||
void MapProxy::drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(terrain)->river, &generator);
|
||||
}
|
||||
|
||||
void MapProxy::drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType)
|
||||
{
|
||||
Lock lock(mx);
|
||||
map.getEditManager()->getTerrainSelection().setSelection(tiles);
|
||||
map.getEditManager()->drawRoad(roadType, &generator);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
41
lib/rmg/threadpool/MapProxy.h
Normal file
41
lib/rmg/threadpool/MapProxy.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* MapProxy.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 "StdInc.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../RmgMap.h"
|
||||
#include "../../mapping/CMapEditManager.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class RmgMap;
|
||||
|
||||
class MapProxy
|
||||
{
|
||||
public:
|
||||
MapProxy(RmgMap & map);
|
||||
|
||||
void insertObject(CGObjectInstance * obj);
|
||||
void insertObjects(std::set<CGObjectInstance*>& objects);
|
||||
|
||||
void drawTerrain(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
|
||||
void drawRivers(CRandomGenerator & generator, std::vector<int3> & tiles, TerrainId terrain);
|
||||
void drawRoads(CRandomGenerator & generator, std::vector<int3> & tiles, RoadId roadType);
|
||||
|
||||
private:
|
||||
mutable boost::shared_mutex mx;
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
|
||||
RmgMap & map;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
192
lib/rmg/threadpool/ThreadPool.h
Normal file
192
lib/rmg/threadpool/ThreadPool.h
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* ThreadPool.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 "BlockingQueue.h"
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::function<void()> TRMGfunction ;
|
||||
typedef std::optional<TRMGfunction> TRMGJob;
|
||||
|
||||
//Credit to https://github.com/Liam0205/toy-threadpool/tree/master/yuuki
|
||||
|
||||
class DLL_LINKAGE ThreadPool
|
||||
{
|
||||
private:
|
||||
using Lock = boost::unique_lock<boost::shared_mutex>;
|
||||
mutable boost::shared_mutex mx;
|
||||
mutable boost::condition_variable_any cv;
|
||||
mutable boost::once_flag once;
|
||||
|
||||
bool isInitialized = false;
|
||||
bool stopping = false;
|
||||
bool canceling = false;
|
||||
public:
|
||||
ThreadPool();
|
||||
~ThreadPool();
|
||||
|
||||
void init(size_t numThreads);
|
||||
void spawn();
|
||||
void terminate();
|
||||
void cancel();
|
||||
|
||||
public:
|
||||
bool initialized() const;
|
||||
bool running() const;
|
||||
int size() const;
|
||||
private:
|
||||
bool isRunning() const;
|
||||
|
||||
public:
|
||||
auto async(std::function<void()>&& f) const -> boost::future<void>;
|
||||
|
||||
private:
|
||||
std::vector<boost::thread> workers;
|
||||
mutable BlockingQueue<TRMGfunction> tasks;
|
||||
};
|
||||
|
||||
ThreadPool::ThreadPool() :
|
||||
once(BOOST_ONCE_INIT)
|
||||
{};
|
||||
|
||||
ThreadPool::~ThreadPool()
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
inline void ThreadPool::init(size_t numThreads)
|
||||
{
|
||||
boost::call_once(once, [this, numThreads]()
|
||||
{
|
||||
Lock lock(mx);
|
||||
stopping = false;
|
||||
canceling = false;
|
||||
workers.reserve(numThreads);
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
workers.emplace_back(std::bind(&ThreadPool::spawn, this));
|
||||
}
|
||||
isInitialized = true;
|
||||
});
|
||||
}
|
||||
|
||||
bool ThreadPool::isRunning() const
|
||||
{
|
||||
return isInitialized && !stopping && !canceling;
|
||||
}
|
||||
|
||||
inline bool ThreadPool::initialized() const
|
||||
{
|
||||
Lock lock(mx);
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
inline bool ThreadPool::running() const
|
||||
{
|
||||
Lock lock(mx);
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
inline int ThreadPool::size() const
|
||||
{
|
||||
Lock lock(mx);
|
||||
return workers.size();
|
||||
}
|
||||
|
||||
inline void ThreadPool::spawn()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
bool pop = false;
|
||||
TRMGfunction task;
|
||||
{
|
||||
Lock lock(mx);
|
||||
cv.wait(lock, [this, &pop, &task]
|
||||
{
|
||||
pop = tasks.pop(task);
|
||||
return canceling || stopping || pop;
|
||||
});
|
||||
}
|
||||
if (canceling || (stopping && !pop))
|
||||
{
|
||||
return;
|
||||
}
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ThreadPool::terminate()
|
||||
{
|
||||
{
|
||||
Lock lock(mx);
|
||||
if (isRunning())
|
||||
{
|
||||
stopping = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
cv.notify_all();
|
||||
for (auto& worker : workers)
|
||||
{
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ThreadPool::cancel()
|
||||
{
|
||||
{
|
||||
Lock lock(mx);
|
||||
if (running())
|
||||
{
|
||||
canceling = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
tasks.clear();
|
||||
cv.notify_all();
|
||||
for (auto& worker : workers)
|
||||
{
|
||||
worker.join();
|
||||
}
|
||||
}
|
||||
|
||||
auto ThreadPool::async(std::function<void()>&& f) const -> boost::future<void>
|
||||
{
|
||||
using TaskT = boost::packaged_task<void>;
|
||||
|
||||
{
|
||||
Lock lock(mx);
|
||||
if (stopping || canceling)
|
||||
{
|
||||
throw std::runtime_error("Delegating task to a threadpool that has been terminated or canceled.");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TaskT> task = std::make_shared<TaskT>(f);
|
||||
boost::future<void> fut = task->get_future();
|
||||
tasks.emplace([task]() -> void
|
||||
{
|
||||
(*task)();
|
||||
});
|
||||
cv.notify_one();
|
||||
return fut;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -16,7 +16,6 @@
|
||||
#include "../lib/mapping/CMapEditManager.h"
|
||||
#include "../lib/TerrainHandler.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||
#include "../lib/rmg/ObstaclePlacer.h"
|
||||
#include "../lib/CSkillHandler.h"
|
||||
#include "../lib/spells/CSpellHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
@ -26,7 +25,7 @@
|
||||
#include "maphandler.h"
|
||||
#include "mainwindow.h"
|
||||
#include "inspector/inspector.h"
|
||||
|
||||
#include "VCMI_Lib.h"
|
||||
|
||||
MapController::MapController(MainWindow * m): main(m)
|
||||
{
|
||||
@ -217,6 +216,18 @@ void MapController::setMap(std::unique_ptr<CMap> cmap)
|
||||
}
|
||||
);
|
||||
_map->getEditManager()->getUndoManager().clearAll();
|
||||
|
||||
initObstaclePainters(_map.get());
|
||||
}
|
||||
|
||||
void MapController::initObstaclePainters(CMap * map)
|
||||
{
|
||||
for (auto terrain : VLC->terrainTypeHandler->objects)
|
||||
{
|
||||
auto terrainId = terrain->getId();
|
||||
_obstaclePainters[terrainId] = std::make_unique<EditorObstaclePlacer>(map);
|
||||
_obstaclePainters[terrainId]->collectPossibleObstacles(terrainId);
|
||||
}
|
||||
}
|
||||
|
||||
void MapController::sceneForceUpdate()
|
||||
@ -397,20 +408,24 @@ void MapController::commitObstacleFill(int level)
|
||||
return;
|
||||
|
||||
//split by zones
|
||||
std::map<TerrainId, ObstacleProxy> terrainSelected;
|
||||
for (auto & painter : _obstaclePainters)
|
||||
{
|
||||
painter.second->clearBlockedArea();
|
||||
}
|
||||
|
||||
for(auto & t : selection)
|
||||
{
|
||||
auto tl = _map->getTile(t);
|
||||
if(tl.blocked || tl.visitable)
|
||||
continue;
|
||||
|
||||
terrainSelected[tl.terType->getId()].blockedArea.add(t);
|
||||
auto terrain = tl.terType->getId();
|
||||
_obstaclePainters[terrain]->addBlockedTile(t);
|
||||
}
|
||||
|
||||
for(auto & sel : terrainSelected)
|
||||
for(auto & sel : _obstaclePainters)
|
||||
{
|
||||
sel.second.collectPossibleObstacles(sel.first);
|
||||
sel.second.placeObstacles(_map.get(), CRandomGenerator::getDefault());
|
||||
sel.second->placeObstacles(CRandomGenerator::getDefault());
|
||||
}
|
||||
|
||||
_mapHandler->invalidateObjects();
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "maphandler.h"
|
||||
#include "mapview.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/rmg/modificators/ObstaclePlacer.h"
|
||||
|
||||
class MainWindow;
|
||||
class MapController
|
||||
@ -24,6 +25,7 @@ public:
|
||||
~MapController();
|
||||
|
||||
void setMap(std::unique_ptr<CMap>);
|
||||
void initObstaclePainters(CMap* map);
|
||||
|
||||
void repairMap();
|
||||
|
||||
@ -72,5 +74,7 @@ private:
|
||||
std::vector<std::unique_ptr<CGObjectInstance>> _clipboard;
|
||||
int _clipboardShiftIndex = 0;
|
||||
|
||||
std::map<TerrainId, std::unique_ptr<EditorObstaclePlacer>> _obstaclePainters;
|
||||
|
||||
void connectScenes();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user