2022-08-09 07:54:32 +02:00
|
|
|
/*
|
|
|
|
* RmgMap.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 "RmgMap.h"
|
|
|
|
#include "TileInfo.h"
|
|
|
|
#include "CMapGenOptions.h"
|
|
|
|
#include "Zone.h"
|
|
|
|
#include "../mapping/CMapEditManager.h"
|
2023-02-24 22:38:12 +02:00
|
|
|
#include "../mapping/CMap.h"
|
2022-08-09 07:54:32 +02:00
|
|
|
#include "../CTownHandler.h"
|
|
|
|
#include "ObjectManager.h"
|
|
|
|
#include "RoadPlacer.h"
|
|
|
|
#include "TreasurePlacer.h"
|
|
|
|
#include "ConnectionsPlacer.h"
|
|
|
|
#include "TownPlacer.h"
|
2023-03-27 09:09:58 +02:00
|
|
|
#include "ObjectDistributor.h"
|
2022-08-09 07:54:32 +02:00
|
|
|
#include "WaterAdopter.h"
|
|
|
|
#include "WaterProxy.h"
|
|
|
|
#include "WaterRoutes.h"
|
|
|
|
#include "RockPlacer.h"
|
|
|
|
#include "ObstaclePlacer.h"
|
|
|
|
#include "RiverPlacer.h"
|
|
|
|
#include "TerrainPainter.h"
|
|
|
|
#include "Functions.h"
|
|
|
|
#include "CMapGenerator.h"
|
|
|
|
|
2022-07-26 15:07:42 +02:00
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
2022-08-09 07:54:32 +02:00
|
|
|
RmgMap::RmgMap(const CMapGenOptions& mapGenOptions) :
|
|
|
|
mapGenOptions(mapGenOptions), zonesTotal(0)
|
|
|
|
{
|
|
|
|
mapInstance = std::make_unique<CMap>();
|
|
|
|
getEditManager()->getUndoManager().setUndoRedoLimit(0);
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:05:02 +02:00
|
|
|
void RmgMap::foreach_neighbour(const int3 & pos, const std::function<void(int3 & pos)> & foo) const
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
|
|
|
for(const int3 &dir : int3::getDirs())
|
|
|
|
{
|
|
|
|
int3 n = pos + dir;
|
|
|
|
/*important notice: perform any translation before this function is called,
|
|
|
|
so the actual mapInstance->position is checked*/
|
|
|
|
if(mapInstance->isInTheMap(n))
|
|
|
|
foo(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:05:02 +02:00
|
|
|
void RmgMap::foreachDirectNeighbour(const int3 & pos, const std::function<void(int3 & pos)> & foo) const
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
2022-08-28 10:54:06 +02:00
|
|
|
for(const int3 &dir : rmg::dirs4)
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
|
|
|
int3 n = pos + dir;
|
|
|
|
if(mapInstance->isInTheMap(n))
|
|
|
|
foo(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:05:02 +02:00
|
|
|
void RmgMap::foreachDiagonalNeighbour(const int3 & pos, const std::function<void(int3 & pos)> & foo) const
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
2022-08-28 10:54:06 +02:00
|
|
|
for (const int3 &dir : rmg::dirsDiagonal)
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
|
|
|
int3 n = pos + dir;
|
|
|
|
if (mapInstance->isInTheMap(n))
|
|
|
|
foo(n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::initTiles(CMapGenerator & generator)
|
|
|
|
{
|
|
|
|
mapInstance->initTerrain();
|
|
|
|
|
2022-09-18 16:39:10 +02:00
|
|
|
tiles.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->levels()]);
|
|
|
|
zoneColouring.resize(boost::extents[mapInstance->width][mapInstance->height][mapInstance->levels()]);
|
2022-08-09 07:54:32 +02:00
|
|
|
|
|
|
|
//init native town count with 0
|
|
|
|
for (auto faction : VLC->townh->getAllowedFactions())
|
|
|
|
zonesPerFaction[faction] = 0;
|
|
|
|
|
|
|
|
getEditManager()->clearTerrain(&generator.rand);
|
|
|
|
getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
|
2022-12-20 18:35:40 +02:00
|
|
|
getEditManager()->drawTerrain(ETerrainId::GRASS, &generator.rand);
|
2023-02-11 18:05:02 +02:00
|
|
|
|
|
|
|
const auto * tmpl = mapGenOptions.getMapTemplate();
|
2022-08-09 07:54:32 +02:00
|
|
|
zones.clear();
|
|
|
|
for(const auto & option : tmpl->getZones())
|
|
|
|
{
|
|
|
|
auto zone = std::make_shared<Zone>(*this, generator);
|
2023-02-11 18:05:02 +02:00
|
|
|
zone->setOptions(*option.second);
|
2022-08-09 07:54:32 +02:00
|
|
|
zones[zone->getId()] = zone;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(mapGenOptions.getWaterContent())
|
|
|
|
{
|
|
|
|
case EWaterContent::NORMAL:
|
|
|
|
case EWaterContent::ISLANDS:
|
|
|
|
TRmgTemplateZoneId waterId = zones.size() + 1;
|
|
|
|
rmg::ZoneOptions options;
|
|
|
|
options.setId(waterId);
|
|
|
|
options.setType(ETemplateZoneType::WATER);
|
|
|
|
auto zone = std::make_shared<Zone>(*this, generator);
|
|
|
|
zone->setOptions(options);
|
|
|
|
zones[zone->getId()] = zone;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::addModificators()
|
|
|
|
{
|
|
|
|
for(auto & z : getZones())
|
|
|
|
{
|
|
|
|
auto zone = z.second;
|
|
|
|
|
|
|
|
zone->addModificator<ObjectManager>();
|
2023-03-27 09:09:58 +02:00
|
|
|
zone->addModificator<ObjectDistributor>();
|
2022-08-09 07:54:32 +02:00
|
|
|
zone->addModificator<TreasurePlacer>();
|
|
|
|
zone->addModificator<ObstaclePlacer>();
|
|
|
|
zone->addModificator<TerrainPainter>();
|
|
|
|
|
|
|
|
if(zone->getType() == ETemplateZoneType::WATER)
|
|
|
|
{
|
|
|
|
for(auto & z1 : getZones())
|
|
|
|
{
|
|
|
|
z1.second->addModificator<WaterAdopter>();
|
|
|
|
z1.second->getModificator<WaterAdopter>()->setWaterZone(zone->getId());
|
|
|
|
}
|
|
|
|
zone->addModificator<WaterProxy>();
|
|
|
|
zone->addModificator<WaterRoutes>();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
zone->addModificator<TownPlacer>();
|
|
|
|
zone->addModificator<ConnectionsPlacer>();
|
|
|
|
zone->addModificator<RoadPlacer>();
|
|
|
|
zone->addModificator<RiverPlacer>();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(zone->isUnderground())
|
|
|
|
{
|
|
|
|
zone->addModificator<RockPlacer>();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CMap & RmgMap::map() const
|
|
|
|
{
|
|
|
|
return *mapInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
CMapEditManager* RmgMap::getEditManager() const
|
|
|
|
{
|
|
|
|
return mapInstance->getEditManager();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isOnMap(const int3 & tile) const
|
|
|
|
{
|
|
|
|
return mapInstance->isInTheMap(tile);
|
|
|
|
}
|
|
|
|
|
|
|
|
const CMapGenOptions& RmgMap::getMapGenOptions() const
|
|
|
|
{
|
|
|
|
return mapGenOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::assertOnMap(const int3& tile) const
|
|
|
|
{
|
|
|
|
if (!mapInstance->isInTheMap(tile))
|
|
|
|
throw rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile.toString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
RmgMap::Zones & RmgMap::getZones()
|
|
|
|
{
|
|
|
|
return zones;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isBlocked(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].isBlocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::shouldBeBlocked(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].shouldBeBlocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isPossible(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].isPossible();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isFree(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].isFree();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isUsed(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].isUsed();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RmgMap::isRoad(const int3& tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].isRoad();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::setOccupied(const int3 &tile, ETileType::ETileType state)
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
tiles[tile.x][tile.y][tile.z].setOccupied(state);
|
|
|
|
}
|
|
|
|
|
2022-09-29 11:44:46 +02:00
|
|
|
void RmgMap::setRoad(const int3& tile, RoadId roadType)
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
tiles[tile.x][tile.y][tile.z].setRoadType(roadType);
|
|
|
|
}
|
|
|
|
|
|
|
|
TileInfo RmgMap::getTile(const int3& tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z];
|
|
|
|
}
|
|
|
|
|
|
|
|
TRmgTemplateZoneId RmgMap::getZoneID(const int3& tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return zoneColouring[tile.x][tile.y][tile.z];
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::setZoneID(const int3& tile, TRmgTemplateZoneId zid)
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
zoneColouring[tile.x][tile.y][tile.z] = zid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::setNearestObjectDistance(int3 &tile, float value)
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
tiles[tile.x][tile.y][tile.z].setNearestObjectDistance(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
float RmgMap::getNearestObjectDistance(const int3 &tile) const
|
|
|
|
{
|
|
|
|
assertOnMap(tile);
|
|
|
|
|
|
|
|
return tiles[tile.x][tile.y][tile.z].getNearestObjectDistance();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::registerZone(TFaction faction)
|
|
|
|
{
|
|
|
|
zonesPerFaction[faction]++;
|
|
|
|
zonesTotal++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ui32 RmgMap::getZoneCount(TFaction faction)
|
|
|
|
{
|
|
|
|
return zonesPerFaction[faction];
|
|
|
|
}
|
|
|
|
|
|
|
|
ui32 RmgMap::getTotalZoneCount() const
|
|
|
|
{
|
|
|
|
return zonesTotal;
|
|
|
|
}
|
|
|
|
|
2023-02-11 18:05:02 +02:00
|
|
|
bool RmgMap::isAllowedSpell(const SpellID & sid) const
|
2022-08-09 07:54:32 +02:00
|
|
|
{
|
|
|
|
assert(sid >= 0);
|
|
|
|
if (sid < mapInstance->allowedSpell.size())
|
|
|
|
{
|
|
|
|
return mapInstance->allowedSpell[sid];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RmgMap::dump(bool zoneId) const
|
|
|
|
{
|
|
|
|
static int id = 0;
|
|
|
|
std::ofstream out(boost::to_string(boost::format("zone_%d.txt") % id++));
|
2022-09-18 16:39:10 +02:00
|
|
|
int levels = mapInstance->levels();
|
2022-08-09 07:54:32 +02:00
|
|
|
int width = mapInstance->width;
|
|
|
|
int height = mapInstance->height;
|
|
|
|
for (int k = 0; k < levels; k++)
|
|
|
|
{
|
|
|
|
for(int j = 0; j < height; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < width; i++)
|
|
|
|
{
|
|
|
|
if(zoneId)
|
|
|
|
{
|
|
|
|
out << getZoneID(int3(i, j, k));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char t = '?';
|
|
|
|
switch (getTile(int3(i, j, k)).getTileType())
|
|
|
|
{
|
|
|
|
case ETileType::FREE:
|
|
|
|
t = ' '; break;
|
|
|
|
case ETileType::BLOCKED:
|
|
|
|
t = '#'; break;
|
|
|
|
case ETileType::POSSIBLE:
|
|
|
|
t = '-'; break;
|
|
|
|
case ETileType::USED:
|
|
|
|
t = 'O'; break;
|
|
|
|
}
|
|
|
|
out << t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out << std::endl;
|
|
|
|
}
|
|
|
|
out << std::endl;
|
|
|
|
}
|
|
|
|
out << std::endl;
|
|
|
|
}
|
2022-07-26 15:07:42 +02:00
|
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|