1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00
Files
vcmi/lib/rmg/CRmgTemplate.h
Ivan Savenko f58d08e563 Support for banned game entities in random map templates
The following entities can now be banned in a random map template
definition:
- Hero
- Artifact
- Spell
- Secondary skill

The ban follows the same rules as banning via the map settings in the
map editor.

It is also now possible to bypass dependencies and access identifiers
from mods that are not dependencies when defining:
- Banned entities in random map templates
- the chance of a hero class appearing in a tavern of a specific faction
- the chance of a spell appearing in a mage guild of a specific faction
- the chance of a hero class receiving a secondary skill

For this to work, the identifier must be specified in full, e.g.
`modName:objectName`. If the specified mod is not active, the game will
silently ignore this entry.

This behaviour is not affected by mod load order. It is possible to use
this format to access a mod that has not yet been loaded.
2025-07-14 00:18:11 +03:00

389 lines
10 KiB
C++

/*
* CRmgTemplate.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 "../int3.h"
#include "../GameConstants.h"
#include "../Point.h"
#include "../ResourceSet.h"
#include "ObjectInfo.h"
#include "ObjectConfig.h"
#include "../mapObjectConstructors/CObjectClassesHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
class JsonSerializeFormat;
struct CompoundMapObjectID;
class TemplateEditor;
enum class ETemplateZoneType
{
PLAYER_START,
CPU_START,
TREASURE,
JUNCTION,
WATER,
SEALED
};
namespace EWaterContent // Not enum class, because it's used in method RandomMapTab::setMapGenOptions
{ // defined in client\lobby\RandomMapTab.cpp and probably in other similar places
enum EWaterContent // as an argument of CToggleGroup::setSelected(int id) from \client\widgets\Buttons.cpp
{
RANDOM = -1,
NONE,
NORMAL,
ISLANDS
};
}
namespace EMonsterStrength // used as int in monster generation procedure and in map description for the generated random map
{
enum EMonsterStrength
{
ZONE_NONE = -3,
RANDOM = -2,
ZONE_WEAK = -1,
ZONE_NORMAL = 0,
ZONE_STRONG = 1,
GLOBAL_WEAK = 2,
GLOBAL_NORMAL = 3,
GLOBAL_STRONG = 4
};
}
class DLL_LINKAGE CTreasureInfo
{
public:
ui32 min;
ui32 max;
ui16 density;
CTreasureInfo();
CTreasureInfo(ui32 min, ui32 max, ui16 density);
bool operator ==(const CTreasureInfo & other) const;
void serializeJson(JsonSerializeFormat & handler);
};
namespace rmg
{
enum class EConnectionType
{
GUARDED = 0, //default
FICTIVE,
REPULSIVE,
WIDE,
FORCE_PORTAL
};
enum class ERoadOption
{
ROAD_TRUE,
ROAD_FALSE,
ROAD_RANDOM
};
class DLL_LINKAGE ZoneConnection
{
#ifdef ENABLE_TEMPLATE_EDITOR
friend class ::TemplateEditor;
#endif
public:
ZoneConnection();
int getId() const;
void setId(int id);
TRmgTemplateZoneId getZoneA() const;
TRmgTemplateZoneId getZoneB() const;
TRmgTemplateZoneId getOtherZoneId(TRmgTemplateZoneId id) const;
int getGuardStrength() const;
rmg::EConnectionType getConnectionType() const;
rmg::ERoadOption getRoadOption() const;
void serializeJson(JsonSerializeFormat & handler);
friend bool operator==(const ZoneConnection &, const ZoneConnection &);
private:
int id;
TRmgTemplateZoneId zoneA;
TRmgTemplateZoneId zoneB;
int guardStrength;
rmg::EConnectionType connectionType;
rmg::ERoadOption hasRoad;
};
class DLL_LINKAGE ZoneOptions
{
#ifdef ENABLE_TEMPLATE_EDITOR
friend class ::TemplateEditor;
#endif
public:
static const TRmgTemplateZoneId NO_ZONE;
class DLL_LINKAGE CTownInfo
{
#ifdef ENABLE_TEMPLATE_EDITOR
friend class ::TemplateEditor;
#endif
public:
CTownInfo();
int getTownCount() const;
int getCastleCount() const;
int getTownDensity() const;
int getCastleDensity() const;
void serializeJson(JsonSerializeFormat & handler);
private:
int townCount;
int castleCount;
int townDensity;
int castleDensity;
// TODO: Copy from another zone once its randomized
TRmgTemplateZoneId townTypesLikeZone = NO_ZONE;
TRmgTemplateZoneId townTypesNotLikeZone = NO_ZONE;
TRmgTemplateZoneId townTypesRelatedToZoneTerrain = NO_ZONE;
};
class DLL_LINKAGE CTownHints
{
public:
CTownHints();
// TODO: Make private
TRmgTemplateZoneId likeZone = NO_ZONE;
std::vector<TRmgTemplateZoneId> notLikeZone;
TRmgTemplateZoneId relatedToZoneTerrain = NO_ZONE;
void serializeJson(JsonSerializeFormat & handler);
};
ZoneOptions();
TRmgTemplateZoneId getId() const;
void setId(TRmgTemplateZoneId value);
ETemplateZoneType getType() const;
void setType(ETemplateZoneType value);
int getSize() const;
void setSize(int value);
std::optional<int> getOwner() const;
std::set<TerrainId> getTerrainTypes() const;
void setTerrainTypes(const std::set<TerrainId> & value);
std::set<TerrainId> getDefaultTerrainTypes() const;
const CTownInfo & getPlayerTowns() const;
void setPlayerTowns(const CTownInfo & value);
const CTownInfo & getNeutralTowns() const;
void setNeutralTowns(const CTownInfo & value);
bool isMatchTerrainToTown() const;
void setMatchTerrainToTown(bool value);
const std::vector<CTownHints> & getTownHints() const;
void setTownHints(const std::vector<CTownHints> & value);
std::set<FactionID> getTownTypes() const;
void setTownTypes(const std::set<FactionID> & value);
std::set<FactionID> getBannedTownTypes() const;
void setBannedTownTypes(const std::set<FactionID> & value);
std::set<FactionID> getDefaultTownTypes() const;
std::set<FactionID> getMonsterTypes() const;
void setMonsterTypes(const std::set<FactionID> & value);
void setMinesInfo(const std::map<TResource, ui16> & value);
std::map<TResource, ui16> getMinesInfo() const;
void setTreasureInfo(const std::vector<CTreasureInfo> & value);
void addTreasureInfo(const CTreasureInfo & value);
std::vector<CTreasureInfo> getTreasureInfo() const;
ui32 getMaxTreasureValue() const;
void recalculateMaxTreasureValue();
TRmgTemplateZoneId getMinesLikeZone() const;
TRmgTemplateZoneId getTerrainTypeLikeZone() const;
TRmgTemplateZoneId getTreasureLikeZone() const;
void addConnection(const ZoneConnection & connection);
std::vector<ZoneConnection> getConnections() const;
std::vector<TRmgTemplateZoneId> getConnectedZoneIds() const;
void serializeJson(JsonSerializeFormat & handler);
EMonsterStrength::EMonsterStrength monsterStrength;
bool areTownsSameType() const;
// Get a group of configured objects
const std::vector<CompoundMapObjectID> & getBannedObjects() const;
const std::vector<ObjectConfig::EObjectCategory> & getBannedObjectCategories() const;
const std::vector<ObjectInfo> & getConfiguredObjects() const;
// Copy whole custom object config from another zone
ObjectConfig getCustomObjects() const;
void setCustomObjects(const ObjectConfig & value);
TRmgTemplateZoneId getCustomObjectsLikeZone() const;
TRmgTemplateZoneId getTownsLikeZone() const;
Point getVisiblePosition() const;
void setVisiblePosition(Point value);
float getVisibleSize() const;
void setVisibleSize(float value);
protected:
TRmgTemplateZoneId id;
ETemplateZoneType type;
int size;
ui32 maxTreasureValue;
std::optional<int> owner;
Point visiblePosition;
float visibleSize;
ObjectConfig objectConfig;
CTownInfo playerTowns;
CTownInfo neutralTowns;
bool matchTerrainToTown;
std::set<TerrainId> terrainTypes;
std::set<TerrainId> bannedTerrains;
bool townsAreSameType;
std::vector<CTownHints> townHints; // For every town present on map
std::set<FactionID> townTypes;
std::set<FactionID> bannedTownTypes;
std::set<FactionID> monsterTypes;
std::set<FactionID> bannedMonsters;
std::map<TResource, ui16> mines; //obligatory mines to spawn in this zone
std::vector<CTreasureInfo> treasureInfo;
std::vector<TRmgTemplateZoneId> connectedZoneIds; //list of adjacent zone ids
std::vector<ZoneConnection> connectionDetails; //list of connections linked to that zone
TRmgTemplateZoneId townsLikeZone;
TRmgTemplateZoneId minesLikeZone;
TRmgTemplateZoneId terrainTypeLikeZone;
TRmgTemplateZoneId treasureLikeZone;
TRmgTemplateZoneId customObjectsLikeZone;
};
}
/// The CRmgTemplate describes a random map template.
class DLL_LINKAGE CRmgTemplate : boost::noncopyable
{
#ifdef ENABLE_TEMPLATE_EDITOR
friend class ::TemplateEditor;
#endif
public:
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<rmg::ZoneOptions>>;
class DLL_LINKAGE CPlayerCountRange
{
#ifdef ENABLE_TEMPLATE_EDITOR
friend class ::TemplateEditor;
#endif
public:
void addRange(int lower, int upper);
void addNumber(int value);
bool isInRange(int count) const;
std::set<int> getNumbers() const;
std::string toString() const;
void fromString(const std::string & value);
int maxValue() const;
int minValue() const;
private:
std::vector<std::pair<int, int> > range;
};
CRmgTemplate();
~CRmgTemplate();
bool matchesSize(const int3 & value) const;
bool isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const;
const std::set<EWaterContent::EWaterContent> & getWaterContentAllowed() const;
void setId(const std::string & value);
void setName(const std::string & value);
const std::string & getId() const;
const std::string & getName() const;
const std::string & getDescription() const;
const CPlayerCountRange & getPlayers() const;
const CPlayerCountRange & getHumanPlayers() const;
std::pair<int3, int3> getMapSizes() const;
const Zones & getZones() const;
const JsonNode & getMapSettings() const;
const std::vector<rmg::ZoneConnection> & getConnectedZoneIds() const;
const std::set<SpellID> & getBannedSpells() const { return bannedSpells; }
const std::set<ArtifactID> & getBannedArtifacts() const { return bannedArtifacts; }
const std::set<SecondarySkill> & getBannedSkills() const { return bannedSkills; }
const std::set<HeroTypeID> & getBannedHeroes() const { return bannedHeroes; }
void validate() const; /// Tests template on validity and throws exception on failure
void serializeJson(JsonSerializeFormat & handler);
void afterLoad();
private:
std::string id;
std::string name;
std::string description;
int3 minSize;
int3 maxSize;
CPlayerCountRange players;
CPlayerCountRange humanPlayers;
Zones zones;
std::vector<rmg::ZoneConnection> connections;
std::set<EWaterContent::EWaterContent> allowedWaterContent;
std::unique_ptr<JsonNode> mapSettings;
std::set<SpellID> bannedSpells;
std::set<ArtifactID> bannedArtifacts;
std::set<SecondarySkill> bannedSkills;
std::set<HeroTypeID> bannedHeroes;
std::set<TerrainId> inheritTerrainType(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
std::map<TResource, ui16> inheritMineTypes(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
std::vector<CTreasureInfo> inheritTreasureInfo(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
void inheritTownProperties(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
void serializeSize(JsonSerializeFormat & handler, int3 & value, const std::string & fieldName);
void serializePlayers(JsonSerializeFormat & handler, CPlayerCountRange & value, const std::string & fieldName);
template<typename T>
T inheritZoneProperty(std::shared_ptr<rmg::ZoneOptions> zone,
T (rmg::ZoneOptions::*getter)() const,
void (rmg::ZoneOptions::*setter)(const T&),
TRmgTemplateZoneId (rmg::ZoneOptions::*inheritFrom)() const,
const std::string& propertyString,
uint32_t iteration = 0);
};
VCMI_LIB_NAMESPACE_END