1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00
Files
vcmi/lib/mapping/CMap.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
12 KiB
C++

/*
* CMap.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 "CMapEvent.h"
#include "CMapHeader.h"
#include "TerrainTile.h"
#include "../mapObjects/CGObjectInstance.h"
#include "../callback/GameCallbackHolder.h"
#include "../networkPacks/TradeItem.h"
VCMI_LIB_NAMESPACE_BEGIN
class CArtifactInstance;
class CArtifactSet;
class CGObjectInstance;
class CGHeroInstance;
class CCommanderInstance;
class CGameState;
class CGCreature;
class CQuest;
class CGTownInstance;
class IModableArt;
class IQuestObject;
class CInputStream;
class CMapEditManager;
class JsonSerializeFormat;
class IGameSettings;
class GameSettings;
struct TeleportChannel;
enum class EGameSettings;
/// The rumor struct consists of a rumor name and text.
struct DLL_LINKAGE Rumor
{
std::string name;
MetaString text;
Rumor() = default;
~Rumor() = default;
template <typename Handler>
void serialize(Handler & h)
{
h & name;
h & text;
}
void serializeJson(JsonSerializeFormat & handler);
};
/// The map contains the map header, the tiles of the terrain, objects, heroes, towns, rumors...
class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
{
friend class CSerializer;
std::unique_ptr<GameSettings> gameSettings;
/// All artifacts that exists on map, whether on map, in hero inventory, or stored in some object
std::vector<std::shared_ptr<CArtifactInstance>> artInstances;
/// All heroes that are currently free for recruitment in taverns and are not present on map
std::vector<std::shared_ptr<CGHeroInstance> > heroesPool;
/// Precomputed indices of all towns on map
std::vector<ObjectInstanceID> towns;
/// Precomputed indices of all heroes on map. Does not includes heroes in prisons
std::vector<ObjectInstanceID> heroesOnMap;
public:
/// Central lists of items in game. Position of item in the vectors below is their (instance) id.
/// TODO: make private
std::vector<std::shared_ptr<CGObjectInstance>> objects;
explicit CMap(IGameInfoCallback *cb);
~CMap();
void initTerrain();
CMapEditManager * getEditManager();
inline TerrainTile & getTile(const int3 & tile);
inline const TerrainTile & getTile(const int3 & tile) const;
bool isCoastalTile(const int3 & pos) const;
inline bool isInTheMap(const int3 & pos) const;
bool canMoveBetween(const int3 &src, const int3 &dst) const;
bool checkForVisitableDir(const int3 & src, const TerrainTile * pom, const int3 & dst) const;
int3 guardingCreaturePosition (int3 pos) const;
void calculateGuardingGreaturePositions();
void saveCompatibilityAddMissingArtifact(std::shared_ptr<CArtifactInstance> artifact);
/// Creates instance of spell scroll artifact with provided spell
CArtifactInstance * createScroll(const SpellID & spellId);
/// Creates instance of requested artifact
/// For combined artifact this method will also create alll required components
/// For scrolls this method will also initialize its spell
CArtifactInstance * createArtifact(const ArtifactID & artId, const SpellID & spellId = SpellID::NONE);
/// Creates single instance of requested artifact
/// Does NOT creates components for combined artifacts
/// Does NOT initializes spell when spell scroll artifact is created
CArtifactInstance * createArtifactComponent(const ArtifactID & artId);
/// Returns pointer to requested Artifact Instance. Throws on invalid ID
CArtifactInstance * getArtifactInstance(const ArtifactInstanceID & artifactID);
/// Returns pointer to requested Artifact Instance. Throws on invalid ID
const CArtifactInstance * getArtifactInstance(const ArtifactInstanceID & artifactID) const;
/// Completely removes artifact instance from the game
void eraseArtifactInstance(const ArtifactInstanceID art);
void moveArtifactInstance(CArtifactSet & srcSet, const ArtifactPosition & srcSlot, CArtifactSet & dstSet, const ArtifactPosition & dstSlot);
void putArtifactInstance(CArtifactSet & set, const ArtifactInstanceID art, const ArtifactPosition & slot);
void removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot);
/// Generates unique string identifier for provided object instance
void generateUniqueInstanceName(CGObjectInstance * target);
/// Generates new, unique numeric identifier that can be used for creation of a new object
ObjectInstanceID allocateUniqueInstanceID();
/// Adds provided object to the map
/// Throws on error, for example if object is already on map
void addNewObject(std::shared_ptr<CGObjectInstance> obj);
/// Moves anchor position of requested object to specified coordinates and updates map state
/// Throws in invalid object instance ID
void moveObject(ObjectInstanceID target, const int3 & dst);
/// Hides object from map without actually removing it from object list
void hideObject(CGObjectInstance * obj);
/// Shows previously hiiden object on map
void showObject(CGObjectInstance * obj);
/// Remove objects and shifts object indicies.
/// Only for use in map editor / RMG
std::shared_ptr<CGObjectInstance> removeObject(ObjectInstanceID oldObject);
/// Replaced map object with specified ID with new object
/// Old object must exist and will be removed from map
/// Returns pointer to old object, which can be manipulated or dropped
std::shared_ptr<CGObjectInstance> replaceObject(ObjectInstanceID oldObject, const std::shared_ptr<CGObjectInstance> & newObject);
/// Erases object from map without shifting indices
/// Returns pointer to old object, which can be manipulated or dropped
std::shared_ptr<CGObjectInstance> eraseObject(ObjectInstanceID oldObject);
void heroAddedToMap(const CGHeroInstance * hero);
void heroRemovedFromMap(const CGHeroInstance * hero);
void townAddedToMap(const CGTownInstance * town);
void townRemovedFromMap(const CGTownInstance * town);
/// Adds provided hero to map pool. Hero with same identity must not exist
void addToHeroPool(std::shared_ptr<CGHeroInstance> hero);
/// Attempts to take hero of specified identity from pool. Returns nullptr on failure
/// Hero is removed from pool on success
std::shared_ptr<CGHeroInstance> tryTakeFromHeroPool(HeroTypeID hero);
/// Attempts to access hero of specified identity in pool. Returns nullptr on failure
CGHeroInstance * tryGetFromHeroPool(HeroTypeID hero);
/// Returns list of identities of heroes currently present in pool
std::vector<HeroTypeID> getHeroesInPool() const;
CGObjectInstance * getObject(ObjectInstanceID obj);
const CGObjectInstance * getObject(ObjectInstanceID obj) const;
void attachToBonusSystem(CGameState & gs);
/// Returns all valid objects of specified class present on map
template<typename ObjectType = CGObjectInstance>
std::vector<const ObjectType *> getObjects() const
{
std::vector<const ObjectType *> result;
for (const auto & object : objects)
{
auto casted = dynamic_cast<const ObjectType*>(object.get());
if (casted)
result.push_back(casted);
}
return result;
}
/// Returns all valid objects of specified class present on map
template<typename ObjectType = CGObjectInstance>
std::vector<ObjectType *> getObjects()
{
std::vector<ObjectType *> result;
for (const auto & object : objects)
{
auto casted = dynamic_cast<ObjectType*>(object.get());
if (casted)
result.push_back(casted);
}
return result;
}
/// Returns all valid artifacts present on map
std::vector<CArtifactInstance *> getArtifacts()
{
std::vector<CArtifactInstance *> result;
for (const auto & art : artInstances)
if (art)
result.push_back(art.get());
return result;
}
bool isWaterMap() const;
bool calculateWaterContent();
void banWaterArtifacts();
void banHero(const HeroTypeID& id);
void unbanHero(const HeroTypeID & id);
void banWaterSpells();
void banWaterSkills();
void banWaterContent();
/// Gets object of specified type on requested position
const CGObjectInstance * getObjectiveObjectFrom(const int3 & pos, Obj type);
/// Returns pointer to hero of specified type if hero is present on map
CGHeroInstance * getHero(HeroTypeID heroId);
const CGHeroInstance * getHero(HeroTypeID heroId) const;
/// Returns ID's of all heroes that are currently present on map
/// Includes all garrisoned and imprisoned heroes
const std::vector<ObjectInstanceID> & getHeroesOnMap() const;
/// Returns ID's of all towns present on map
const std::vector<ObjectInstanceID> & getAllTowns() const;
/// Sets the victory/loss condition objectives ??
void checkForObjectives();
void resolveQuestIdentifiers();
void reindexObjects();
std::vector<Rumor> rumors;
std::set<SpellID> allowedSpells;
std::set<ArtifactID> allowedArtifact;
std::set<SecondarySkill> allowedAbilities;
std::vector<CMapEvent> events;
int3 grailPos;
int grailRadius;
//Helper lists
std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > teleportChannels;
std::unique_ptr<CMapEditManager> editManager;
boost::multi_array<int3, 3> guardingCreaturePositions;
std::map<std::string, std::shared_ptr<CGObjectInstance> > instanceNames;
bool waterMap;
ui8 obeliskCount = 0; //how many obelisks are on map
std::map<TeamID, ui8> obelisksVisited; //map: team_id => how many obelisks has been visited
std::vector<ArtifactID> townMerchantArtifacts;
void overrideGameSettings(const JsonNode & input);
void overrideGameSetting(EGameSettings option, const JsonNode & input);
const IGameSettings & getSettings() const;
void saveCompatibilityStoreAllocatedArtifactID();
void parseUidCounter();
private:
/// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground
boost::multi_array<TerrainTile, 3> terrain;
si32 uidCounter;
public:
template <typename Handler>
void serialize(Handler &h)
{
h & static_cast<CMapHeader&>(*this);
h & triggeredEvents; //from CMapHeader
h & rumors;
h & allowedSpells;
h & allowedAbilities;
h & allowedArtifact;
h & events;
h & grailPos;
h & artInstances;
if (!h.hasFeature(Handler::Version::NO_RAW_POINTERS_IN_SERIALIZER))
{
saveCompatibilityStoreAllocatedArtifactID();
std::vector< std::shared_ptr<CQuest> > quests;
h & quests;
}
h & heroesPool;
//TODO: viccondetails
h & terrain;
h & guardingCreaturePositions;
h & objects;
if (h.hasFeature(Handler::Version::NO_RAW_POINTERS_IN_SERIALIZER))
h & heroesOnMap;
else
{
std::vector<std::shared_ptr<CGObjectInstance>> objectPtrs;
h & objectPtrs;
for (const auto & ptr : objectPtrs)
heroesOnMap.push_back(ptr->id);
for (auto & ptr : heroesPool)
if (vstd::contains(objects, ptr))
ptr = nullptr;
}
h & teleportChannels;
if (h.hasFeature(Handler::Version::NO_RAW_POINTERS_IN_SERIALIZER))
h & towns;
else
{
std::vector<std::shared_ptr<CGObjectInstance>> objectPtrs;
h & objectPtrs;
for (const auto & ptr : objectPtrs)
towns.push_back(ptr->id);
}
h & artInstances;
// static members
h & obeliskCount;
h & obelisksVisited;
h & townMerchantArtifacts;
if (!h.hasFeature(Handler::Version::UNIVERSITY_CONFIG))
{
std::vector<TradeItemBuy> townUniversitySkills;
h & townUniversitySkills;
}
h & instanceNames;
h & *gameSettings;
if (!h.hasFeature(Handler::Version::STORE_UID_COUNTER_IN_CMAP))
{
if (!h.saving)
parseUidCounter();
}
else
{
h & uidCounter;
}
}
};
inline bool CMap::isInTheMap(const int3 & pos) const
{
// Check whether coord < 0 is done implicitly. Negative signed int overflows to unsigned number larger than all signed ints.
return
static_cast<uint32_t>(pos.x) < static_cast<uint32_t>(width) &&
static_cast<uint32_t>(pos.y) < static_cast<uint32_t>(height) &&
static_cast<uint32_t>(pos.z) <= (twoLevel ? 1 : 0);
}
inline TerrainTile & CMap::getTile(const int3 & tile)
{
assert(isInTheMap(tile));
return terrain[tile.z][tile.x][tile.y];
}
inline const TerrainTile & CMap::getTile(const int3 & tile) const
{
assert(isInTheMap(tile));
return terrain[tile.z][tile.x][tile.y];
}
VCMI_LIB_NAMESPACE_END