1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00

multilevel support

This commit is contained in:
Laserlicht
2025-08-01 00:37:32 +02:00
parent 50a240a858
commit ecfe09f6b1
27 changed files with 156 additions and 107 deletions

View File

@@ -239,8 +239,7 @@ void CMap::showObject(CGObjectInstance * obj)
void CMap::calculateGuardingGreaturePositions()
{
int levels = twoLevel ? 2 : 1;
for(int z = 0; z < levels; z++)
for(int z = 0; z < levels(); z++)
{
for(int x = 0; x < width; x++)
{

View File

@@ -370,7 +370,7 @@ inline bool CMap::isInTheMap(const int3 & pos) const
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);
static_cast<uint32_t>(pos.z) <= mapLevels - 1;
}
inline TerrainTile & CMap::getTile(const int3 & tile)

View File

@@ -122,7 +122,7 @@ CMapHeader::CMapHeader()
: version(EMapFormat::VCMI)
, height(72)
, width(72)
, twoLevel(true)
, mapLevels(2)
, difficulty(EMapDifficulty::NORMAL)
, levelLimit(0)
, victoryIconIndex(0)
@@ -139,7 +139,7 @@ CMapHeader::~CMapHeader() = default;
ui8 CMapHeader::levels() const
{
return (twoLevel ? 2 : 1);
return mapLevels;
}
void CMapHeader::registerMapStrings()

View File

@@ -246,7 +246,7 @@ public:
si32 height; /// The default value is 72.
si32 width; /// The default value is 72.
bool twoLevel; /// The default value is true.
si32 mapLevels; /// The default value is 2.
MetaString name;
MetaString description;
EMapDifficulty difficulty;
@@ -295,7 +295,23 @@ public:
h & creationDateTime;
h & width;
h & height;
h & twoLevel;
if (h.version >= Handler::Version::MORE_MAP_LAYERS)
h & mapLevels;
else
{
if (h.saving)
{
bool hasTwoLevels = mapLevels == 2;
h & hasTwoLevels;
}
else
{
bool hasTwoLevels;
h & hasTwoLevels;
mapLevels = hasTwoLevels ? 2 : 1;
}
}
h & difficulty;
h & levelLimit;

View File

@@ -563,14 +563,11 @@ CDrawTerrainOperation::ValidationResult::ValidationResult(bool result, std::stri
CClearTerrainOperation::CClearTerrainOperation(CMap* map, vstd::RNG* gen) : CComposedOperation(map)
{
CTerrainSelection terrainSel(map);
terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::WATER, 0, gen));
if(map->twoLevel)
for (int i = 0; i < map->mapLevels; i++)
{
terrainSel.clearSelection();
terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::ROCK, 0, gen));
CTerrainSelection terrainSel(map);
terrainSel.selectRange(MapRect(int3(0, 0, i), map->width, map->height));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, i == 1 ? ETerrainId::ROCK : ETerrainId::WATER, 0, gen));
}
}

View File

@@ -185,7 +185,7 @@ void CMapLoaderH3M::readHeader()
// Read map name, description, dimensions,...
mapHeader->areAnyPlayers = reader->readBool();
mapHeader->height = mapHeader->width = reader->readInt32();
mapHeader->twoLevel = reader->readBool();
mapHeader->mapLevels = reader->readBool() ? 2 : 1;
mapHeader->name.appendTextID(readLocalizedString("header.name"));
mapHeader->description.appendTextID(readLocalizedString("header.description"));
mapHeader->author.appendRawString("");

View File

@@ -240,7 +240,16 @@ const int CMapFormatJson::VERSION_MINOR = 0;
const std::string CMapFormatJson::HEADER_FILE_NAME = "header.json";
const std::string CMapFormatJson::OBJECTS_FILE_NAME = "objects.json";
const std::string CMapFormatJson::TERRAIN_FILE_NAMES[2] = {"surface_terrain.json", "underground_terrain.json"};
std::string getTerrainFilename(int i)
{
if(i == 0)
return "surface_terrain.json";
else if(i == 1)
return "underground_terrain.json";
else
return "level-" + std::to_string(i + 1) + "_terrain.json";
}
CMapFormatJson::CMapFormatJson():
fileVersionMajor(0), fileVersionMinor(0),
@@ -844,7 +853,6 @@ void CMapLoaderJson::readHeader(const bool complete)
//loading mods
mapHeader->mods = ModVerificationInfo::jsonDeserializeList(header["mods"]);
//todo: multilevel map load support
{
auto levels = handler.enterStruct("mapLevels");
{
@@ -852,10 +860,7 @@ void CMapLoaderJson::readHeader(const bool complete)
handler.serializeInt("height", mapHeader->height);
handler.serializeInt("width", mapHeader->width);
}
{
auto underground = handler.enterStruct("underground");
mapHeader->twoLevel = !underground->getCurrent().isNull();
}
mapHeader->mapLevels = levels->getCurrent().Struct().size();
}
serializeHeader(handler);
@@ -993,14 +998,10 @@ void CMapLoaderJson::readTerrainLevel(const JsonNode & src, const int index)
void CMapLoaderJson::readTerrain()
{
for(int i = 0; i < map->mapLevels; i++)
{
const JsonNode surface = getFromArchive(TERRAIN_FILE_NAMES[0]);
readTerrainLevel(surface, 0);
}
if(map->twoLevel)
{
const JsonNode underground = getFromArchive(TERRAIN_FILE_NAMES[1]);
readTerrainLevel(underground, 1);
const JsonNode node = getFromArchive(getTerrainFilename(i));
readTerrainLevel(node, i);
}
}
@@ -1198,17 +1199,22 @@ void CMapSaverJson::writeHeader()
//write mods
header["mods"] = ModVerificationInfo::jsonSerializeList(mapHeader->mods);
//todo: multilevel map save support
JsonNode & levels = header["mapLevels"];
levels["surface"]["height"].Float() = mapHeader->height;
levels["surface"]["width"].Float() = mapHeader->width;
levels["surface"]["index"].Float() = 0;
auto getName = [](int level){
if(level == 0)
return std::string("surface");
else if(level == 1)
return std::string("underground");
else
return "level-" + std::to_string(level + 1);
};
if(mapHeader->twoLevel)
JsonNode & levels = header["mapLevels"];
for(int i = 0; i < map->mapLevels; i++)
{
levels["underground"]["height"].Float() = mapHeader->height;
levels["underground"]["width"].Float() = mapHeader->width;
levels["underground"]["index"].Float() = 1;
auto name = getName(i);
levels[name]["height"].Float() = mapHeader->height;
levels[name]["width"].Float() = mapHeader->width;
levels[name]["index"].Float() = i;
}
serializeHeader(handler);
@@ -1266,15 +1272,11 @@ JsonNode CMapSaverJson::writeTerrainLevel(const int index)
void CMapSaverJson::writeTerrain()
{
logGlobal->trace("Saving terrain");
//todo: multilevel map save support
JsonNode surface = writeTerrainLevel(0);
addToArchive(surface, TERRAIN_FILE_NAMES[0]);
if(map->twoLevel)
for(int i = 0; i < map->mapLevels; i++)
{
JsonNode underground = writeTerrainLevel(1);
addToArchive(underground, TERRAIN_FILE_NAMES[1]);
JsonNode node = writeTerrainLevel(i);
addToArchive(node, getTerrainFilename(i));
}
}