mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Allow filtering obstacles by faction aligmnment
This commit is contained in:
parent
6c9d18a85c
commit
a356fdaf2a
@ -27,6 +27,20 @@
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
"alignment" : {
|
||||
"anyOf": [
|
||||
{
|
||||
"type" : "string",
|
||||
"enum" : ["good", "evil", "neutral"],
|
||||
"description" : "Alignment of faction of the zone"
|
||||
},
|
||||
{
|
||||
"type" : "array",
|
||||
"items" : { "type" : "string" },
|
||||
"description" : "Alignment of faction of the zone"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -13,7 +13,8 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
enum class EAlignment : int8_t
|
||||
{
|
||||
GOOD,
|
||||
ANY = -1,
|
||||
GOOD = 0,
|
||||
EVIL,
|
||||
NEUTRAL
|
||||
};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "ObstacleSetHandler.h"
|
||||
|
||||
#include "../modding/IdentifierStorage.h"
|
||||
#include "../constants/stringConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -32,21 +33,41 @@ void ObstacleSet::addObstacle(std::shared_ptr<const ObjectTemplate> obstacle)
|
||||
obstacles.push_back(obstacle);
|
||||
}
|
||||
|
||||
ObstacleSetFilter::ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain = TerrainId::ANY_TERRAIN):
|
||||
ObstacleSetFilter::ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain = TerrainId::ANY_TERRAIN, EAlignment alignment = EAlignment::ANY):
|
||||
allowedTypes(allowedTypes),
|
||||
terrain(terrain)
|
||||
terrain(terrain),
|
||||
alignment(alignment)
|
||||
{
|
||||
}
|
||||
|
||||
ObstacleSetFilter::ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain = TerrainId::ANY_TERRAIN):
|
||||
ObstacleSetFilter::ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain = TerrainId::ANY_TERRAIN, EAlignment alignment = EAlignment::ANY):
|
||||
allowedTypes({allowedType}),
|
||||
terrain(terrain)
|
||||
terrain(terrain),
|
||||
alignment(alignment)
|
||||
{
|
||||
}
|
||||
|
||||
bool ObstacleSetFilter::filter(const ObstacleSet &set) const
|
||||
{
|
||||
return (vstd::contains(set.getTerrains(), terrain) || terrain == TerrainId::ANY_TERRAIN);
|
||||
if (terrain != TerrainId::ANY_TERRAIN && !vstd::contains(set.getTerrains(), terrain))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Also check specific factions
|
||||
auto alignments = set.getAlignments();
|
||||
|
||||
if (alignment != EAlignment::ANY && !alignments.empty() && !vstd::contains(alignments, alignment))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TerrainId ObstacleSetFilter::getTerrain() const
|
||||
{
|
||||
return terrain;
|
||||
}
|
||||
|
||||
std::set<TerrainId> ObstacleSet::getTerrains() const
|
||||
@ -69,6 +90,16 @@ void ObstacleSet::addTerrain(TerrainId terrain)
|
||||
this->allowedTerrains.insert(terrain);
|
||||
}
|
||||
|
||||
void ObstacleSet::addAlignment(EAlignment alignment)
|
||||
{
|
||||
this->allowedAlignments.insert(alignment);
|
||||
}
|
||||
|
||||
std::set<EAlignment> ObstacleSet::getAlignments() const
|
||||
{
|
||||
return allowedAlignments;
|
||||
}
|
||||
|
||||
ObstacleSet::EObstacleType ObstacleSet::getType() const
|
||||
{
|
||||
return type;
|
||||
@ -185,6 +216,16 @@ std::vector<ObstacleSet::EObstacleType> ObstacleSetFilter::getAllowedTypes() con
|
||||
return allowedTypes;
|
||||
}
|
||||
|
||||
void ObstacleSetFilter::setType(ObstacleSet::EObstacleType type)
|
||||
{
|
||||
allowedTypes = {type};
|
||||
}
|
||||
|
||||
void ObstacleSetFilter::setTypes(std::vector<ObstacleSet::EObstacleType> types)
|
||||
{
|
||||
this->allowedTypes = types;
|
||||
}
|
||||
|
||||
std::vector<JsonNode> ObstacleSetHandler::loadLegacyData()
|
||||
{
|
||||
return {};
|
||||
@ -248,6 +289,29 @@ std::shared_ptr<ObstacleSet> ObstacleSetHandler::loadFromJson(const std::string
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move this parser to some utils
|
||||
auto parseAlignment = [](const std::string & str) ->EAlignment
|
||||
{
|
||||
int alignment = vstd::find_pos(GameConstants::ALIGNMENT_NAMES, str);
|
||||
if (alignment == -1)
|
||||
logGlobal->error("Incorrect alignment: ", str);
|
||||
else
|
||||
return static_cast<EAlignment>(alignment);
|
||||
};
|
||||
|
||||
if (json["alignment"].isString())
|
||||
{
|
||||
os->addAlignment(parseAlignment(json["alignment"].String()));
|
||||
}
|
||||
else if (json["alignment"].isVector())
|
||||
{
|
||||
auto alignments = json["alignment"].Vector();
|
||||
for (const auto & node : alignments)
|
||||
{
|
||||
os->addAlignment(parseAlignment(node.String()));
|
||||
}
|
||||
}
|
||||
|
||||
auto templates = json["templates"].Vector();
|
||||
for (const auto & node : templates)
|
||||
{
|
||||
|
@ -50,6 +50,8 @@ public:
|
||||
void setTerrain(TerrainId terrain);
|
||||
void setTerrains(const std::set<TerrainId> & terrains);
|
||||
void addTerrain(TerrainId terrain);
|
||||
std::set<EAlignment> getAlignments() const;
|
||||
void addAlignment(EAlignment alignment);
|
||||
|
||||
static EObstacleType typeFromString(const std::string &str);
|
||||
std::string toString() const;
|
||||
@ -59,6 +61,7 @@ public:
|
||||
private:
|
||||
EObstacleType type;
|
||||
std::set<TerrainId> allowedTerrains;
|
||||
std::set<EAlignment> allowedAlignments; // Empty means all
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> obstacles;
|
||||
};
|
||||
|
||||
@ -67,17 +70,22 @@ typedef std::vector<std::shared_ptr<ObstacleSet>> TObstacleTypes;
|
||||
class DLL_LINKAGE ObstacleSetFilter
|
||||
{
|
||||
public:
|
||||
ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain);
|
||||
ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain);
|
||||
ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain , EAlignment alignment);
|
||||
ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain, EAlignment alignment);
|
||||
|
||||
bool filter(const ObstacleSet &set) const;
|
||||
|
||||
void setType(ObstacleSet::EObstacleType type);
|
||||
void setTypes(std::vector<ObstacleSet::EObstacleType> types);
|
||||
std::vector<ObstacleSet::EObstacleType> getAllowedTypes() const;
|
||||
TerrainId getTerrain() const;
|
||||
|
||||
void setAlignment(EAlignment alignment);
|
||||
|
||||
private:
|
||||
std::vector<ObstacleSet::EObstacleType> allowedTypes;
|
||||
// TODO: Filter by faction, alignment, surface/underground, etc.
|
||||
EAlignment alignment;
|
||||
// TODO: Filter by faction, surface/underground, etc.
|
||||
const TerrainId terrain;
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ void ObstacleProxy::sortObstacles()
|
||||
});
|
||||
}
|
||||
|
||||
bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
bool ObstacleProxy::prepareBiome(const ObstacleSetFilter & filter, CRandomGenerator & rand)
|
||||
{
|
||||
// FIXME: All the mountains have same ID and mostly same subID, how to differentiate them?
|
||||
|
||||
@ -68,7 +68,11 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
const size_t MIN_SMALL_SETS = 3;
|
||||
const size_t MAX_SMALL_SETS = 5;
|
||||
|
||||
TObstacleTypes mountainSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::MOUNTAINS, terrain));
|
||||
auto terrain = filter.getTerrain();
|
||||
auto localFilter = filter;
|
||||
localFilter.setType(ObstacleSet::EObstacleType::MOUNTAINS);
|
||||
|
||||
TObstacleTypes mountainSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
|
||||
if (!mountainSets.empty())
|
||||
{
|
||||
@ -78,11 +82,12 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warn("No mountain sets found for terrain %s", terrain.encode(terrain.getNum()));
|
||||
logGlobal->warn("No mountain sets found for terrain %s", TerrainId::encode(terrain.getNum()));
|
||||
// FIXME: Do we ever want to generate obstacles without any mountains?
|
||||
}
|
||||
|
||||
TObstacleTypes treeSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::TREES, terrain));
|
||||
localFilter.setType(ObstacleSet::EObstacleType::TREES);
|
||||
TObstacleTypes treeSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
|
||||
// 1 or 2 tree sets
|
||||
size_t treeSetsCount = std::min<size_t>(treeSets.size(), rand.nextInt(1, 2));
|
||||
@ -94,8 +99,8 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
logGlobal->info("Added %d tree sets", treeSetsCount);
|
||||
|
||||
// Some obstacle types may be completely missing from water, but it's not a problem
|
||||
TObstacleTypes largeSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter({ObstacleSet::EObstacleType::LAKES, ObstacleSet::EObstacleType::CRATERS},
|
||||
terrain));
|
||||
localFilter.setTypes({ObstacleSet::EObstacleType::LAKES, ObstacleSet::EObstacleType::CRATERS});
|
||||
TObstacleTypes largeSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
|
||||
// We probably don't want to have lakes and craters at the same time, choose one of them
|
||||
|
||||
@ -108,7 +113,8 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
logGlobal->info("Added large set of type %s", obstacleSets.back()->getType());
|
||||
}
|
||||
|
||||
TObstacleTypes rockSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::ROCKS, terrain));
|
||||
localFilter.setType(ObstacleSet::EObstacleType::ROCKS);
|
||||
TObstacleTypes rockSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
|
||||
size_t rockSetsCount = std::min<size_t>(rockSets.size(), rand.nextInt(1, 2));
|
||||
for (size_t i = 0; i < rockSetsCount; i++)
|
||||
@ -118,7 +124,8 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
}
|
||||
logGlobal->info("Added %d rock sets", rockSetsCount);
|
||||
|
||||
TObstacleTypes plantSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::PLANTS, terrain));
|
||||
localFilter.setType(ObstacleSet::EObstacleType::PLANTS);
|
||||
TObstacleTypes plantSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
|
||||
// 1 or 2 sets (3 - rock sets)
|
||||
size_t plantSetsCount = std::min<size_t>(plantSets.size(), rand.nextInt(1, std::max<size_t>(3 - rockSetsCount, 2)));
|
||||
@ -138,12 +145,12 @@ bool ObstacleProxy::prepareBiome(TerrainId terrain, CRandomGenerator & rand)
|
||||
|
||||
size_t smallSets = rand.nextInt(MIN_SMALL_SETS, maxSmallSets);
|
||||
|
||||
TObstacleTypes smallObstacleSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter({ObstacleSet::EObstacleType::STRUCTURES, ObstacleSet::EObstacleType::ANIMALS},
|
||||
terrain));
|
||||
localFilter.setTypes({ObstacleSet::EObstacleType::STRUCTURES, ObstacleSet::EObstacleType::ANIMALS});
|
||||
TObstacleTypes smallObstacleSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
RandomGeneratorUtil::randomShuffle(smallObstacleSets, rand);
|
||||
|
||||
TObstacleTypes otherSets = VLC->biomeHandler->getObstacles(ObstacleSetFilter(ObstacleSet::EObstacleType::OTHER,
|
||||
terrain));
|
||||
localFilter.setType(ObstacleSet::EObstacleType::OTHER);
|
||||
TObstacleTypes otherSets = VLC->biomeHandler->getObstacles(localFilter);
|
||||
RandomGeneratorUtil::randomShuffle(otherSets, rand);
|
||||
|
||||
while (smallSets > 0)
|
||||
|
@ -20,6 +20,7 @@ class CGObjectInstance;
|
||||
class ObjectTemplate;
|
||||
class CRandomGenerator;
|
||||
class IGameCallback;
|
||||
class ObstacleSetFilter;
|
||||
|
||||
class DLL_LINKAGE ObstacleProxy
|
||||
{
|
||||
@ -29,7 +30,7 @@ public:
|
||||
virtual ~ObstacleProxy() = default;
|
||||
|
||||
void collectPossibleObstacles(TerrainId terrain);
|
||||
bool prepareBiome(TerrainId terrain, CRandomGenerator & rand);
|
||||
bool prepareBiome(const ObstacleSetFilter & filter, CRandomGenerator & rand);
|
||||
|
||||
void addBlockedTile(const int3 & tile);
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../mapping/ObstacleProxy.h"
|
||||
#include "../../mapObjects/CGObjectInstance.h"
|
||||
#include "../../mapObjects/ObstacleSetHandler.h"
|
||||
#include "../../CTownHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -34,7 +36,9 @@ void ObstaclePlacer::process()
|
||||
if(!manager)
|
||||
return;
|
||||
|
||||
if (!prepareBiome(zone.getTerrainType(), zone.getRand()))
|
||||
ObstacleSetFilter filter(ObstacleSet::EObstacleType::INVALID, zone.getTerrainType(), zone.getTownType().toFaction()->alignment);
|
||||
|
||||
if (!prepareBiome(filter, zone.getRand()))
|
||||
{
|
||||
logGlobal->warn("Failed to prepare biome, using all possible obstacles");
|
||||
// Use all if we fail to create proper biome
|
||||
|
Loading…
Reference in New Issue
Block a user