1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-22 22:13:35 +02:00

Merge pull request #1409 from IvanSavenko/translate_terrain

Refactoring of terrain handlers
This commit is contained in:
Ivan Savenko 2023-01-18 00:12:31 +02:00 committed by GitHub
commit c400416058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 1354 additions and 1168 deletions

View File

@ -20,7 +20,7 @@
#include "../lib/StringConstants.h"
#include "../lib/CRandomGenerator.h"
#include "../lib/VCMIDirs.h"
#include "../lib/Terrain.h"
#include "../lib/TerrainHandler.h"
#define VCMI_SOUND_NAME(x)
#define VCMI_SOUND_FILE(y) #y,
@ -89,36 +89,6 @@ CSoundHandler::CSoundHandler():
soundBase::battle02, soundBase::battle03, soundBase::battle04,
soundBase::battle05, soundBase::battle06, soundBase::battle07
};
//predefine terrain set
//TODO: support custom sounds for new terrains and load from json
horseSounds =
{
{Terrain::DIRT, soundBase::horseDirt},
{Terrain::SAND, soundBase::horseSand},
{Terrain::GRASS, soundBase::horseGrass},
{Terrain::SNOW, soundBase::horseSnow},
{Terrain::SWAMP, soundBase::horseSwamp},
{Terrain::ROUGH, soundBase::horseRough},
{Terrain::SUBTERRANEAN, soundBase::horseSubterranean},
{Terrain::LAVA, soundBase::horseLava},
{Terrain::WATER, soundBase::horseWater},
{Terrain::ROCK, soundBase::horseRock}
};
}
void CSoundHandler::loadHorseSounds()
{
const auto & terrains = CGI->terrainTypeHandler->terrains();
for(const auto & terrain : terrains)
{
//since all sounds are hardcoded, let's keep it
if(vstd::contains(horseSounds, terrain.id))
continue;
//Use already existing horse sound
horseSounds[terrain.id] = horseSounds.at(terrains[terrain.id].horseSoundId);
}
}
void CSoundHandler::init()
@ -368,9 +338,9 @@ CMusicHandler::CMusicHandler():
void CMusicHandler::loadTerrainMusicThemes()
{
for (const auto & terrain : CGI->terrainTypeHandler->terrains())
for (const auto & terrain : CGI->terrainTypeHandler->objects)
{
addEntryToSet("terrain_" + terrain.name, "Music/" + terrain.musicFilename);
addEntryToSet("terrain_" + terrain->getJsonKey(), "Music/" + terrain->musicFilename);
}
}

View File

@ -11,7 +11,6 @@
#include "../lib/CConfigHandler.h"
#include "../lib/CSoundBase.h"
#include "../lib/Terrain.h"
struct _Mix_Music;
struct SDL_RWops;
@ -61,7 +60,6 @@ public:
CSoundHandler();
void init() override;
void loadHorseSounds();
void release() override;
void setVolume(ui32 percent) override;
@ -84,7 +82,6 @@ public:
// Sets
std::vector<soundBase::soundID> pickupSounds;
std::vector<soundBase::soundID> battleIntroSounds;
std::map<TerrainId, soundBase::soundID> horseSounds;
};
// Helper //now it looks somewhat useless

View File

@ -61,6 +61,8 @@
#include "windows/InfoWindows.h"
#include "../lib/UnlockGuard.h"
#include "../lib/CPathfinder.h"
#include "../lib/RoadHandler.h"
#include "../lib/TerrainHandler.h"
#include <SDL.h>
#include "CServerHandler.h"
// FIXME: only needed for CGameState::mutex
@ -156,7 +158,6 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
cb = CB;
env = ENV;
CCS->soundh->loadHorseSounds();
CCS->musich->loadTerrainMusicThemes();
initializeHeroTownList();
@ -260,7 +261,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
{
updateAmbientSounds();
//We may need to change music - select new track, music handler will change it if needed
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->name, true, false);
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->getJsonKey(), true, false);
if(details.result == TryMoveHero::TELEPORTATION)
{
@ -436,7 +437,7 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
adventureInt->select(newSelection, true);
else if (adventureInt->selection == hero)
adventureInt->selection = nullptr;
if (vstd::contains(paths, hero))
paths.erase(hero);
}
@ -2372,8 +2373,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
for (auto & elem : path.nodes)
elem.coord = h->convertFromVisitablePos(elem.coord);
TerrainId currentTerrain = Terrain::BORDER; // not init yet
TerrainId currentTerrain = ETerrainId::NONE;
TerrainId newTerrain;
bool wasOnRoad = true;
int sh = -1;
auto canStop = [&](CGPathNode * node) -> bool
@ -2389,13 +2391,18 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
for (i=(int)path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || !canStop(&path.nodes[i])); i--)
{
int3 currentCoord = path.nodes[i].coord;
int3 prevCoord = path.nodes[i].coord;
int3 nextCoord = path.nodes[i-1].coord;
auto currentObject = getObj(currentCoord, currentCoord == h->pos);
auto prevRoad = cb->getTile(h->convertToVisitablePos(prevCoord))->roadType;
auto nextRoad = cb->getTile(h->convertToVisitablePos(nextCoord))->roadType;
bool movingOnRoad = prevRoad->getId() != Road::NO_ROAD && nextRoad->getId() != Road::NO_ROAD;
auto prevObject = getObj(prevCoord, prevCoord == h->pos);
auto nextObjectTop = getObj(nextCoord, false);
auto nextObject = getObj(nextCoord, true);
auto destTeleportObj = getDestTeleportObj(currentObject, nextObjectTop, nextObject);
auto destTeleportObj = getDestTeleportObj(prevObject, nextObjectTop, nextObject);
if (isTeleportAction(path.nodes[i-1].action) && destTeleportObj != nullptr)
{
CCS->soundh->stopSound(sh);
@ -2410,7 +2417,10 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
}
if(i != path.nodes.size() - 1)
{
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
if (movingOnRoad)
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(currentTerrain)->horseSound, -1);
else
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(currentTerrain)->horseSoundPenalty, -1);
}
continue;
}
@ -2428,12 +2438,16 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
#endif
{
newTerrain = cb->getTile(h->convertToVisitablePos(currentCoord))->terType->id;
if(newTerrain != currentTerrain)
newTerrain = cb->getTile(h->convertToVisitablePos(prevCoord))->terType->getId();
if(newTerrain != currentTerrain || wasOnRoad != movingOnRoad)
{
CCS->soundh->stopSound(sh);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);
if (movingOnRoad)
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(newTerrain)->horseSound, -1);
else
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(newTerrain)->horseSoundPenalty, -1);
currentTerrain = newTerrain;
wasOnRoad = movingOnRoad;
}
}

View File

@ -41,6 +41,7 @@
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/NetPacks.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/TerrainHandler.h"
CondSh<BattleAction *> BattleInterface::givenCommand(nullptr);
@ -136,8 +137,8 @@ BattleInterface::~BattleInterface()
if (adventureInt && adventureInt->selection)
{
//FIXME: this should be moved to adventureInt which should restore correct track based on selection/active player
const auto & terrain = *(LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType);
CCS->musich->playMusicFromSet("terrain", terrain.name, true, false);
const auto * terrain = LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType;
CCS->musich->playMusicFromSet("terrain", terrain->getJsonKey(), true, false);
}
// may happen if user decided to close game while in battle

View File

@ -29,6 +29,7 @@
#include "../../lib/rmg/CMapGenOptions.h"
#include "../../lib/CModHandler.h"
#include "../../lib/rmg/CRmgTemplateStorage.h"
#include "../../lib/RoadHandler.h"
RandomMapTab::RandomMapTab():
InterfaceObjectConfigurable()
@ -108,12 +109,12 @@ RandomMapTab::RandomMapTab():
GH.pushIntT<TeamAlignmentsWidget>(*this);
});
for(auto road : VLC->terrainTypeHandler->roads())
for(auto road : VLC->roadTypeHandler->objects)
{
std::string cbRoadType = "selectRoad_" + road.name;
std::string cbRoadType = "selectRoad_" + road->getJsonKey();
addCallback(cbRoadType, [&, road](bool on)
{
mapGenOptions->setRoadEnabled(road.name, on);
mapGenOptions->setRoadEnabled(road->getJsonKey(), on);
updateMapInfoByHost();
});
}
@ -283,11 +284,11 @@ void RandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
else
w->addTextOverlay(readText(variables["defaultTemplate"]), EFonts::FONT_SMALL);
}
for(auto r : VLC->terrainTypeHandler->roads())
for(auto r : VLC->roadTypeHandler->objects)
{
if(auto w = widget<CToggleButton>(r.name))
if(auto w = widget<CToggleButton>(r->getJsonKey()))
{
w->setSelected(opts->isRoadEnabled(r.name));
w->setSelected(opts->isRoadEnabled(r->getJsonKey()));
}
}
}

View File

@ -30,7 +30,9 @@
#include "CMT.h"
#include "CMusicHandler.h"
#include "../lib/CRandomGenerator.h"
#include "../lib/Terrain.h"
#include "../lib/RoadHandler.h"
#include "../lib/RiverHandler.h"
#include "../lib/TerrainHandler.h"
#include "../lib/filesystem/ResourceID.h"
#include "../lib/JsonDetail.h"
@ -175,17 +177,17 @@ void CMapHandler::initTerrainGraphics()
std::map<std::string, std::string> terrainFiles;
std::map<std::string, std::string> riverFiles;
std::map<std::string, std::string> roadFiles;
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
for(const auto & terrain : VLC->terrainTypeHandler->objects)
{
terrainFiles[terrain.name] = terrain.tilesFilename;
terrainFiles[terrain->getJsonKey()] = terrain->tilesFilename;
}
for(const auto & river : VLC->terrainTypeHandler->rivers())
for(const auto & river : VLC->riverTypeHandler->objects)
{
riverFiles[river.fileName] = river.fileName;
riverFiles[river->getJsonKey()] = river->tilesFilename;
}
for(const auto & road : VLC->terrainTypeHandler->roads())
for(const auto & road : VLC->roadTypeHandler->objects)
{
roadFiles[road.fileName] = road.fileName;
roadFiles[road->getJsonKey()] = road->tilesFilename;
}
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
@ -606,7 +608,7 @@ void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const T
ui8 rotation = tinfo.extTileFlags % 4;
//TODO: use ui8 instead of string key
auto terrainName = tinfo.terType->name;
auto terrainName = tinfo.terType->getJsonKey();
if(parent->terrainImages[terrainName].size()<=tinfo.terView)
return;
@ -786,21 +788,21 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
void CMapHandler::CMapBlitter::drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const
{
if (tinfoUpper && tinfoUpper->roadType->id != Road::NO_ROAD)
if (tinfoUpper && tinfoUpper->roadType->getId() != Road::NO_ROAD)
{
ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4;
Rect source(0, tileSize / 2, tileSize, tileSize / 2);
Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2);
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfoUpper->roadType->fileName][tinfoUpper->roadDir][rotation],
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfoUpper->roadType->getJsonKey()][tinfoUpper->roadDir][rotation],
&source, targetSurf, &dest);
}
if(tinfo.roadType->id != Road::NO_ROAD) //print road from this tile
if(tinfo.roadType->getId() != Road::NO_ROAD) //print road from this tile
{
ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
Rect source(0, 0, tileSize, halfTileSizeCeil);
Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, tileSize / 2);
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfo.roadType->fileName][tinfo.roadDir][rotation],
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfo.roadType->getJsonKey()][tinfo.roadDir][rotation],
&source, targetSurf, &dest);
}
}
@ -809,7 +811,7 @@ void CMapHandler::CMapBlitter::drawRiver(SDL_Surface * targetSurf, const Terrain
{
Rect destRect(realTileRect);
ui8 rotation = (tinfo.extTileFlags >> 2) % 4;
drawElement(EMapCacheType::RIVERS, parent->riverImages[tinfo.riverType->fileName][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect);
drawElement(EMapCacheType::RIVERS, parent->riverImages[tinfo.riverType->getJsonKey()][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect);
}
void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const
@ -860,7 +862,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
if(isVisible || info->showAllTerrain)
{
drawTileTerrain(targetSurf, tinfo, tile);
if(tinfo.riverType->id != River::NO_RIVER)
if(tinfo.riverType->getId() != River::NO_RIVER)
drawRiver(targetSurf, tinfo);
drawRoad(targetSurf, tinfo, tinfoUpper);
}
@ -1388,8 +1390,9 @@ void CMapHandler::getTerrainDescr(const int3 & pos, std::string & out, bool isRM
break;
}
}
if(!isTile2Terrain || out.empty())
out = CGI->generaltexth->terrainNames[t.terType->id];
out = t.terType->getNameTranslated();
if(t.getDiggingStatus(false) == EDiggingStatus::CAN_DIG)
{
@ -1485,4 +1488,3 @@ TerrainTileObject::TerrainTileObject(const CGObjectInstance * obj_, SDL_Rect rec
TerrainTileObject::~TerrainTileObject()
{
}

View File

@ -41,7 +41,7 @@
#include "../../lib/CHeroHandler.h"
#include "../../lib/CModHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/Terrain.h"
#include "../../lib/TerrainHandler.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/JsonNode.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
@ -391,7 +391,7 @@ const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos)
}
// else - use terrain color (blocked version or normal)
const auto & colorPair = parent->colors.find(tile->terType->id)->second;
const auto & colorPair = parent->colors.find(tile->terType->getId())->second;
if (tile->blocked && (!tile->visitable))
return colorPair.second;
else
@ -500,25 +500,25 @@ std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors()
{
std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > ret;
for(const auto & terrain : CGI->terrainTypeHandler->terrains())
for(const auto & terrain : CGI->terrainTypeHandler->objects)
{
SDL_Color normal =
{
ui8(terrain.minimapUnblocked[0]),
ui8(terrain.minimapUnblocked[1]),
ui8(terrain.minimapUnblocked[2]),
ui8(terrain->minimapUnblocked[0]),
ui8(terrain->minimapUnblocked[1]),
ui8(terrain->minimapUnblocked[2]),
ui8(255)
};
SDL_Color blocked =
{
ui8(terrain.minimapBlocked[0]),
ui8(terrain.minimapBlocked[1]),
ui8(terrain.minimapBlocked[2]),
ui8(terrain->minimapBlocked[0]),
ui8(terrain->minimapBlocked[1]),
ui8(terrain->minimapBlocked[2]),
ui8(255)
};
ret[terrain.id] = std::make_pair(normal, blocked);
ret[terrain->getId()] = std::make_pair(normal, blocked);
}
return ret;
}

View File

@ -11,7 +11,6 @@
#include "ObjectLists.h"
#include "../../lib/FunctionList.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -53,6 +53,7 @@
#include "../../lib/VCMI_Lib.h"
#include "../../lib/StartInfo.h"
#include "../../lib/mapping/CMapInfo.h"
#include "../../lib/TerrainHandler.h"
#define ADVOPT (conf.go()->ac)
using namespace CSDL_Ext;
@ -1414,7 +1415,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
auto pos = sel->visitablePos();
auto tile = LOCPLINT->cb->getTile(pos);
if(tile)
CCS->musich->playMusicFromSet("terrain", tile->terType->name, true, false);
CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false);
}
if(centerView)
centerOn(sel);

View File

@ -191,8 +191,10 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/ObstacleHandler.cpp
${MAIN_LIB_DIR}/StartInfo.cpp
${MAIN_LIB_DIR}/ResourceSet.cpp
${MAIN_LIB_DIR}/RiverHandler.cpp
${MAIN_LIB_DIR}/RoadHandler.cpp
${MAIN_LIB_DIR}/ScriptHandler.cpp
${MAIN_LIB_DIR}/Terrain.cpp
${MAIN_LIB_DIR}/TerrainHandler.cpp
${MAIN_LIB_DIR}/VCMIDirs.cpp
${MAIN_LIB_DIR}/VCMI_Lib.cpp
@ -439,11 +441,13 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/ObstacleHandler.h
${MAIN_LIB_DIR}/PathfinderUtil.h
${MAIN_LIB_DIR}/ResourceSet.h
${MAIN_LIB_DIR}/RiverHandler.h
${MAIN_LIB_DIR}/RoadHandler.h
${MAIN_LIB_DIR}/ScriptHandler.h
${MAIN_LIB_DIR}/ScopeGuard.h
${MAIN_LIB_DIR}/StartInfo.h
${MAIN_LIB_DIR}/StringConstants.h
${MAIN_LIB_DIR}/Terrain.h
${MAIN_LIB_DIR}/TerrainHandler.h
${MAIN_LIB_DIR}/UnlockGuard.h
${MAIN_LIB_DIR}/VCMIDirs.h
${MAIN_LIB_DIR}/vcmi_endian.h

View File

@ -10,6 +10,9 @@
"hero" : 156,
"spell" : 81,
"object" : 256,
"terrain" : 10,
"river" : 5,
"road" : 4,
"mapVersion" : 28 // max supported version, SoD
},

View File

@ -3,6 +3,7 @@
{
"name" : "Neutral",
"index" : 9,
"nativeTerrain" : "none",
"alignment" : "neutral",
"creatureBackground" :
{

View File

@ -85,6 +85,14 @@
[
"config/terrains.json"
],
"roads":
[
"config/roads.json"
],
"rivers":
[
"config/rivers.json"
],
"battlefields":
[
"config/battlefields.json"

View File

@ -42,4 +42,4 @@
"value" : [2000, 5333, 8666, 12000],
"rewardValue" : [5000, 10000, 15000, 20000]
}
}
}

View File

@ -1,30 +1,34 @@
{
"waterRiver":
{
"originalRiverId": 1,
"code": "rw", //must be 2 characters
"animation": "clrrvr",
"index": 1,
"text" : "Water river",
"shortIdentifier": "rw", //must be 2 characters
"tilesFilename": "clrrvr",
"delta": "clrdelt"
},
"iceRiver":
{
"originalRiverId": 2,
"code": "ri",
"animation": "icyrvr",
"index": 2,
"text" : "Ice river",
"shortIdentifier": "ri",
"tilesFilename": "icyrvr",
"delta": "icedelt"
},
"mudRiver":
{
"originalRiverId": 3,
"code": "rm",
"animation": "mudrvr",
"index": 3,
"text" : "Mud river",
"shortIdentifier": "rm",
"tilesFilename": "mudrvr",
"delta": "muddelt"
},
"lavaRiver":
{
"originalRiverId": 4,
"code": "rl",
"animation": "lavrvr",
"index": 4,
"text" : "Lava river",
"shortIdentifier": "rl",
"tilesFilename": "lavrvr",
"delta": "lavdelt"
}
}
}

View File

@ -1,23 +1,26 @@
{
"dirtRoad":
{
"originalRoadId": 1,
"code": "pd", //must be 2 characters
"animation": "dirtrd",
"index": 1,
"text" : "Dirt road",
"shortIdentifier": "pd", //must be 2 characters
"tilesFilename": "dirtrd",
"moveCost": 75
},
"gravelRoad":
{
"originalRoadId": 2,
"code": "pg",
"animation": "gravrd",
"index": 2,
"text" : "Gravel road",
"shortIdentifier": "pg",
"tilesFilename": "gravrd",
"moveCost": 65
},
"cobblestoneRoad":
{
"originalRoadId": 3,
"code": "pc",
"animation": "cobbrd",
"index": 3,
"text" : "Cobblestone road",
"shortIdentifier": "pc",
"tilesFilename": "cobbrd",
"moveCost": 50
}
}
}

View File

@ -31,7 +31,7 @@
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI faction format",
"description": "Json format for defining new faction (aka towns) in VCMI",
"required" : [ "name", "alignment", "creatureBackground" ],
"required" : [ "name", "alignment", "creatureBackground", "nativeTerrain" ],
"dependencies" : {
"town" : [ "puzzleMap" ]
},

37
config/schemas/river.json Normal file
View File

@ -0,0 +1,37 @@
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI river format",
"description" : "Format used to define new rivers in VCMI",
"required" : [ "text", "shortIdentifier", "tilesFilename", "delta" ],
"additionalProperties" : false,
"properties":{
"index" :
{
"type": "number",
"description": "Internal, do not use"
},
"text":
{
"type": "string",
"description": "Human-readable name of the river"
},
"shortIdentifier":
{
"type": "string",
"description": "Two-letters unique indentifier for this road. Used in map format"
},
"tilesFilename":
{
"type": "string",
"description": "Name of file with river graphics",
"format": "defFile"
},
"delta":
{
"type": "string",
"description": "Name of file with river delta graphics"
}
}
}

37
config/schemas/road.json Normal file
View File

@ -0,0 +1,37 @@
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI road format",
"description" : "Format used to define new roads in VCMI",
"required" : [ "text", "shortIdentifier", "tilesFilename", "moveCost" ],
"additionalProperties" : false,
"properties":{
"index" :
{
"type": "number",
"description": "Internal, do not use"
},
"text":
{
"type": "string",
"description": "Human-readable name of the road"
},
"shortIdentifier":
{
"type": "string",
"description": "Two-letters unique indentifier for this road. Used in map format"
},
"tilesFilename":
{
"type": "string",
"description": "Name of file with road graphics",
"format": "defFile"
},
"moveCost":
{
"type": "number",
"description": "How many movement points needed to move hero"
}
}
}

View File

@ -3,10 +3,20 @@
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI terrain format",
"description" : "Format used to define new terrains in VCMI",
"required" : [ "tiles", "code", "moveCost" ],
"required" : [ "text", "moveCost", "minimapUnblocked", "minimapBlocked", "music", "tiles", "type", "horseSound", "horseSoundPenalty", "shortIdentifier", "battleFields" ],
"additionalProperties" : false,
"properties":{
"index" :
{
"type": "number",
"description": "Internal, do not use"
},
"text":
{
"type": "string",
"description": "Human-readable name of this terrain"
},
"moveCost":
{
"type": "number",
@ -47,9 +57,13 @@
},
"type":
{
"type": "string",
"type": "array",
"description": "Type of this terrain. Can be land, water, subterranean or rock",
"enum": ["LAND", "WATER", "SUB", "ROCK"]
"items":
{
"enum": ["LAND", "WATER", "SUB", "ROCK", "SURFACE"],
"type": "string"
}
},
"rockTerrain":
{
@ -59,23 +73,22 @@
"river":
{
"type": "string",
"description": "River type which should be used for that terrain",
"enum": ["", "rw", "ri", "rm", "rl"]
"description": "River type which should be used for that terrain"
},
"horseSoundId":
{
"type": "number",
"description": "Id of horse sound to be played when hero is moving across terrain"
},
"text":
"horseSound":
{
"type": "string",
"description": "Text to be shown when mouse if over terrain"
"description": "Hero movement sound for this terrain, version for moving on tiles with road"
},
"code":
"horseSoundPenalty":
{
"type": "string",
"description": "Two-letters unique indentifier for this terrain. Used for terrain serializaion"
"description": "Hero movement sound for this terrain, version for moving on tiles without road"
},
"shortIdentifier":
{
"type": "string",
"description": "Two-letters unique indentifier for this terrain. Used for map format"
},
"battleFields":
{
@ -86,6 +99,24 @@
"type": "string"
}
},
"sounds":
{
"type": "object",
"description": "list of sounds for this terrain",
"additionalProperties" : false,
"properties":
{
"ambient" :
{
"type": "array",
"description": "list of ambient sounds for this terrain",
"items":
{
"type": "string"
}
}
}
},
"prohibitTransitions":
{
"type": "array",

View File

@ -1,146 +1,162 @@
{
"dirt" :
{
"originalTerrainId": 0,
"index": 0,
"moveCost" : 100,
"minimapUnblocked" : [ 82, 56, 8 ],
"minimapBlocked" : [ 57, 40, 8 ],
"music" : "Dirt.mp3",
"tiles" : "DIRTTL",
"code" : "dt",
"river" : "rm",
"type" : ["SURFACE"],
"shortIdentifier" : "dt",
"river" : "mudRiver",
"battleFields" : ["dirt_birches", "dirt_hills", "dirt_pines"],
"terrainViewPatterns" : "dirt",
"horseSoundId" : 0
"horseSound" : "horse00",
"horseSoundPenalty" : "horse20"
},
"sand" :
{
"originalTerrainId": 1,
"index": 1,
"moveCost" : 150,
"minimapUnblocked" : [ 222, 207, 140 ],
"minimapBlocked" : [ 165, 158, 107 ],
"music" : "Sand.mp3",
"tiles" : "SANDTL",
"code" : "sa",
"river" : "rm",
"type" : ["SURFACE"],
"shortIdentifier" : "sa",
"river" : "mudRiver",
"battleFields" : ["sand_mesas"],
"transitionRequired" : true,
"terrainViewPatterns" : "sand",
"horseSoundId" : 1
"horseSound" : "horse01",
"horseSoundPenalty" : "horse21"
},
"grass" :
{
"originalTerrainId": 2,
"index": 2,
"moveCost" : 100,
"minimapUnblocked" : [ 0, 65, 0 ],
"minimapBlocked" : [ 0, 48, 0 ],
"music" : "Grass.mp3",
"tiles" : "GRASTL",
"code" : "gr",
"river" : "rw",
"type" : ["SURFACE"],
"shortIdentifier" : "gr",
"river" : "waterRiver",
"battleFields" : ["grass_hills", "grass_pines"],
"horseSoundId" : 2
"horseSound" : "horse02",
"horseSoundPenalty" : "horse22"
},
"snow" :
{
"originalTerrainId": 3,
"index": 3,
"moveCost" : 150,
"minimapUnblocked" : [ 181, 199, 198 ],
"minimapBlocked" : [ 140, 158, 156 ],
"music" : "Snow.mp3",
"tiles" : "SNOWTL",
"code" : "sn",
"river" : "ri",
"type" : ["SURFACE"],
"shortIdentifier" : "sn",
"river" : "iceRiver",
"battleFields" : ["snow_mountains", "snow_trees"],
"horseSoundId" : 3
"horseSound" : "horse03",
"horseSoundPenalty" : "horse23"
},
"swamp" :
{
"originalTerrainId": 4,
"index": 4,
"moveCost" : 175,
"minimapUnblocked" : [ 74, 134, 107 ],
"minimapBlocked" : [ 33, 89, 66 ],
"music" : "Swamp.mp3",
"tiles" : "SWMPTL",
"code" : "sw",
"river" : "rw",
"type" : ["SURFACE"],
"shortIdentifier" : "sw",
"river" : "waterRiver",
"battleFields" : ["swamp_trees"],
"horseSoundId" : 4
"horseSound" : "horse04",
"horseSoundPenalty" : "horse24"
},
"rough" :
{
"originalTerrainId": 5,
"index": 5,
"moveCost" : 125,
"minimapUnblocked" : [ 132, 113, 49 ],
"minimapBlocked" : [ 99, 81, 33 ],
"music" : "Rough.mp3",
"tiles" : "ROUGTL",
"code" : "rg",
"river" : "rm",
"type" : ["SURFACE"],
"shortIdentifier" : "rg",
"river" : "mudRiver",
"battleFields" : ["rough"],
"horseSoundId" : 5
"horseSound" : "horse05",
"horseSoundPenalty" : "horse25"
},
"subterra" :
{
"originalTerrainId": 6,
"index": 6,
"moveCost" : 100,
"minimapUnblocked" : [ 132, 48, 0 ],
"minimapBlocked" : [ 90, 8, 0 ],
"music" : "Underground.mp3",
"tiles" : "SUBBTL",
"type" : "SUB",
"code" : "sb",
"river" : "rw",
"type" : [ "SUB" ],
"shortIdentifier" : "sb",
"river" : "waterRiver",
"battleFields" : ["subterranean"],
"rockTerrain" : "rock",
"horseSoundId" : 6
"horseSound" : "horse06",
"horseSoundPenalty" : "horse26"
},
"lava" :
{
"originalTerrainId": 7,
"index": 7,
"moveCost" : 100,
"minimapUnblocked" : [ 74, 73, 74 ],
"minimapBlocked" : [ 41, 40, 41 ],
"music" : "Lava.mp3",
"tiles" : "LAVATL",
"type" : ["SUB", "SURFACE"],
"code" : "lv",
"river" : "rl",
"shortIdentifier" : "lv",
"river" : "lavaRiver",
"battleFields" : ["lava"],
"rockTerrain" : "rock",
"horseSoundId" : 7
"horseSound" : "horse07",
"horseSoundPenalty" : "horse27"
},
"water" :
{
"originalTerrainId": 8,
"index": 8,
"moveCost" : 100,
"minimapUnblocked" : [ 8, 81, 148 ],
"minimapBlocked" : [ 8, 81, 148 ],
"music" : "Water.mp3",
"tiles" : "WATRTL",
"type" : "WATER",
"code" : "wt",
"type" : [ "WATER" ],
"shortIdentifier" : "wt",
"battleFields" : ["ship"],
"transitionRequired" : true,
"terrainViewPatterns" : "water",
"horseSoundId" : 8,
"horseSound" : "horse08",
"horseSoundPenalty" : "horse28",
"sounds": {
"ambient": ["LOOPOCEA"]
}
},
"rock" :
{
"originalTerrainId": 9,
"index": 9,
"moveCost" : -1,
"minimapUnblocked" : [ 0, 0, 0 ],
"minimapBlocked" : [ 0, 0, 0 ],
"music" : "Underground.mp3", // Impossible in H3
"tiles" : "ROCKTL",
"type" : "ROCK",
"code" : "rc",
"type" : [ "ROCK" ],
"shortIdentifier" : "rc",
"battleFields" : ["rocklands"],
"transitionRequired" : true,
"terrainViewPatterns" : "rock",
"horseSoundId" : 9
"horseSound" : "horse09",
"horseSoundPenalty" : "horse29"
}
}

View File

@ -14,7 +14,6 @@
#include "HeroBonus.h"
#include "GameConstants.h"
#include "IHandlerBase.h"
#include "Terrain.h"
#include "battle/BattleHex.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -16,7 +16,6 @@
#include "CGameState.h"
#include "CTownHandler.h"
#include "CModHandler.h"
#include "Terrain.h"
#include "StringConstants.h"
#include "serializer/JsonDeserializer.h"
#include "serializer/JsonUpdater.h"
@ -288,7 +287,7 @@ std::string CCreature::nodeName() const
bool CCreature::isItNativeTerrain(TerrainId terrain) const
{
auto native = getNativeTerrain();
return native == terrain || native == Terrain::ANY_TERRAIN;
return native == terrain || native == ETerrainId::ANY_TERRAIN;
}
TerrainId CCreature::getNativeTerrain() const
@ -299,7 +298,7 @@ TerrainId CCreature::getNativeTerrain() const
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
//and in the CGHeroInstance::getNativeTerrain() to setup mevement bonuses or/and penalties.
return hasBonus(selectorNoTerrainPenalty, selectorNoTerrainPenalty)
? TerrainId(Terrain::ANY_TERRAIN)
? TerrainId(ETerrainId::ANY_TERRAIN)
: (*VLC->townh)[faction]->nativeTerrain;
}

View File

@ -19,7 +19,6 @@
#include "JsonNode.h"
#include "IHandlerBase.h"
#include "CRandomGenerator.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -17,6 +17,7 @@
#include "battle/BattleInfo.h" // for BattleInfo
#include "NetPacks.h" // for InfoWindow
#include "CModHandler.h"
#include "TerrainHandler.h"
#include "spells/CSpellHandler.h"
#include "mapping/CMap.h"
#include "CPlayerState.h"

View File

@ -20,6 +20,7 @@
#include "CHeroHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "CModHandler.h"
#include "TerrainHandler.h"
#include "CSkillHandler.h"
#include "mapping/CMap.h"
#include "mapping/CMapService.h"
@ -1944,8 +1945,7 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & r
if(map->isCoastalTile(tile)) //coastal tile is always ground
return BattleField::fromString("sand_shore");
return BattleField::fromString(
*RandomGeneratorUtil::nextItem(t.terType->battleFields, rand));
return BattleField(*RandomGeneratorUtil::nextItem(t.terType->battleFields, rand));
}
@ -2135,7 +2135,7 @@ void CGameState::updateRumor()
rumorId = *RandomGeneratorUtil::nextItem(sRumorTypes, rand);
if(rumorId == RumorState::RUMOR_GRAIL)
{
rumorExtra = getTile(map->grailPos)->terType->id;
rumorExtra = getTile(map->grailPos)->terType->getIndex();
break;
}

View File

@ -18,7 +18,6 @@
#include "GameConstants.h"
#include "mapObjects/CQuest.h"
#include "VCMI_Lib.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -420,7 +419,6 @@ CGeneralTextHandler::CGeneralTextHandler():
advobtxt (*this, "core.advevent" ),
xtrainfo (*this, "core.xtrainfo" ),
restypes (*this, "core.restypes" ),
terrainNames (*this, "core.terrname" ),
randsign (*this, "core.randsign" ),
overview (*this, "core.overview" ),
arraytxt (*this, "core.arraytxt" ),
@ -452,7 +450,6 @@ CGeneralTextHandler::CGeneralTextHandler():
readToVector("core.advevent", "DATA/ADVEVENT.TXT" );
readToVector("core.xtrainfo", "DATA/XTRAINFO.TXT" );
readToVector("core.restypes", "DATA/RESTYPES.TXT" );
readToVector("core.terrname", "DATA/TERRNAME.TXT" );
readToVector("core.randsign", "DATA/RANDSIGN.TXT" );
readToVector("core.crgen1", "DATA/CRGEN1.TXT" );
readToVector("core.crgen4", "DATA/CRGEN4.TXT" );

View File

@ -207,7 +207,6 @@ public:
LegacyTextContainer advobtxt;
LegacyTextContainer xtrainfo;
LegacyTextContainer restypes; //names of resources
LegacyTextContainer terrainNames;
LegacyTextContainer randsign;
LegacyTextContainer seerEmpty;
LegacyTextContainer seerNames;

View File

@ -19,7 +19,6 @@
#include "CCreatureHandler.h"
#include "CModHandler.h"
#include "CTownHandler.h"
#include "Terrain.h"
#include "mapObjects/CObjectHandler.h" //for hero specialty
#include "CSkillHandler.h"
#include <math.h>
@ -345,11 +344,6 @@ CHeroHandler::~CHeroHandler() = default;
CHeroHandler::CHeroHandler()
{
loadTerrains();
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
VLC->modh->identifiers.registerObject(CModHandler::scopeBuiltin(), "terrain", terrain.name, terrain.id);
}
loadBallistics();
loadExperience();
}
@ -972,14 +966,6 @@ ui64 CHeroHandler::reqExp (ui32 level) const
}
}
void CHeroHandler::loadTerrains()
{
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
terrCosts[terrain.id] = terrain.moveCost;
}
}
std::vector<bool> CHeroHandler::getDefaultAllowed() const
{
// Look Data/HOTRAITS.txt for reference

View File

@ -18,7 +18,6 @@
#include "GameConstants.h"
#include "HeroBonus.h"
#include "IHandlerBase.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -260,7 +259,6 @@ class DLL_LINKAGE CHeroHandler : public CHandlerBase<HeroTypeID, HeroType, CHero
void loadExperience();
void loadBallistics();
void loadTerrains();
public:
CHeroClassHandler classes;

View File

@ -25,6 +25,9 @@
#include "spells/CSpellHandler.h"
#include "CSkillHandler.h"
#include "ScriptHandler.h"
#include "RoadHandler.h"
#include "RiverHandler.h"
#include "TerrainHandler.h"
#include "BattleFieldHandler.h"
#include "ObstacleHandler.h"
@ -465,6 +468,9 @@ void CContentHandler::init()
handlers.insert(std::make_pair("scripts", ContentTypeHandler(VLC->scriptHandler, "script")));
#endif
handlers.insert(std::make_pair("battlefields", ContentTypeHandler(VLC->battlefieldsHandler, "battlefield")));
handlers.insert(std::make_pair("terrains", ContentTypeHandler(VLC->terrainTypeHandler, "terrain")));
handlers.insert(std::make_pair("rivers", ContentTypeHandler(VLC->riverTypeHandler, "river")));
handlers.insert(std::make_pair("roads", ContentTypeHandler(VLC->roadTypeHandler, "road")));
handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler, "obstacle")));
//TODO: any other types of moddables?
}

View File

@ -1000,10 +1000,10 @@ bool CPathfinderHelper::passOneTurnLimitCheck(const PathNodeInfo & source) const
TurnInfo::BonusCache::BonusCache(TConstBonusListPtr bl)
{
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
for(const auto & terrain : VLC->terrainTypeHandler->objects)
{
noTerrainPenalty.push_back(static_cast<bool>(
bl->getFirst(Selector::type()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain.id)))));
bl->getFirst(Selector::type()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain->getIndex())))));
}
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FREE_SHIP_BOARDING)));

View File

@ -13,7 +13,6 @@
#include "IGameCallback.h"
#include "HeroBonus.h"
#include "int3.h"
#include "Terrain.h"
#include <boost/heap/fibonacci_heap.hpp>

View File

@ -333,7 +333,7 @@ bool CStack::canBeHealed() const
bool CStack::isOnNativeTerrain() const
{
//this code is called from CreatureTerrainLimiter::limit on battle start
auto res = nativeTerrain == Terrain::ANY_TERRAIN || nativeTerrain == battle->getTerrainType();
auto res = nativeTerrain == ETerrainId::ANY_TERRAIN || nativeTerrain == battle->getTerrainType();
return res;
}

View File

@ -14,7 +14,6 @@
#include "CCreatureHandler.h" //todo: remove
#include "battle/BattleHex.h"
#include "mapObjects/CGHeroInstance.h" // for commander serialization
#include "Terrain.h"
#include "battle/CUnitState.h"

View File

@ -28,10 +28,6 @@ VCMI_LIB_NAMESPACE_BEGIN
const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number
const TerrainId CTownHandler::defaultGoodTerrain(Terrain::GRASS);
const TerrainId CTownHandler::defaultEvilTerrain(Terrain::LAVA);
const TerrainId CTownHandler::defaultNeutralTerrain(Terrain::ROUGH);
const std::map<std::string, CBuilding::EBuildMode> CBuilding::MODES =
{
{ "normal", CBuilding::BUILD_NORMAL },
@ -951,22 +947,6 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES);
}
TerrainId CTownHandler::getDefaultTerrainForAlignment(EAlignment::EAlignment alignment) const
{
TerrainId terrain = defaultGoodTerrain;
switch(alignment)
{
case EAlignment::EAlignment::EVIL:
terrain = defaultEvilTerrain;
break;
case EAlignment::EAlignment::NEUTRAL:
terrain = defaultNeutralTerrain;
break;
}
return terrain;
}
CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode & source, const std::string & identifier, size_t index)
{
auto faction = new CFaction();
@ -987,11 +967,17 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
auto preferUndergound = source["preferUndergroundPlacement"];
faction->preferUndergroundPlacement = preferUndergound.isNull() ? false : preferUndergound.Bool();
//Contructor is not called here, but operator=
auto nativeTerrain = source["nativeTerrain"];
faction->nativeTerrain = nativeTerrain.isNull()
? getDefaultTerrainForAlignment(faction->alignment)
: VLC->terrainTypeHandler->getInfoByName(nativeTerrain.String())->id;
// NOTE: semi-workaround - normally, towns are supposed to have native terrains.
// Towns without one are exceptions. So, vcmi requires nativeTerrain to be defined
// But allows it to be defined with explicit value of "none" if town should not have native terrain
// This is better than allowing such terrain-less towns silently, leading to issues with RMG
faction->nativeTerrain = ETerrainId::NONE;
if ( !source["nativeTerrain"].isNull() && source["nativeTerrain"].String() != "none")
{
VLC->modh->identifiers.requestIdentifier("terrain", source["nativeTerrain"], [=](int32_t index){
faction->nativeTerrain = TerrainId(index);
});
}
if (!source["town"].isNull())
{

View File

@ -20,7 +20,6 @@
#include "LogicalExpression.h"
#include "battle/BattleHex.h"
#include "HeroBonus.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -364,10 +363,6 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
std::vector<BuildingRequirementsHelper> requirementsToLoad;
std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden.
const static TerrainId defaultGoodTerrain;
const static TerrainId defaultEvilTerrain;
const static TerrainId defaultNeutralTerrain;
static TPropagatorPtr & emptyPropagator();
void initializeRequirements();
@ -397,7 +392,6 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
void loadPuzzle(CFaction & faction, const JsonNode & source);
TerrainId getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
void loadRandomFaction();

View File

@ -149,12 +149,6 @@ STRONG_INLINE bool operator>=(const A & a, const B & b) \
ID_LIKE_OPERATORS_INTERNAL(ENUM_NAME, CLASS_NAME, a, b.num)
#define OP_DECL_INT(CLASS_NAME, OP) \
bool operator OP (const CLASS_NAME & b) const \
{ \
return num OP b.num; \
}
#define INSTID_LIKE_CLASS_COMMON(CLASS_NAME, NUMERIC_NAME) \
public: \
CLASS_NAME() : BaseForID<CLASS_NAME, NUMERIC_NAME>(-1) {} \
@ -204,15 +198,79 @@ public:
num += change;
}
typedef BaseForID<Derived, NumericType> __SelfType;
OP_DECL_INT(__SelfType, ==)
OP_DECL_INT(__SelfType, !=)
OP_DECL_INT(__SelfType, <)
OP_DECL_INT(__SelfType, >)
OP_DECL_INT(__SelfType, <=)
OP_DECL_INT(__SelfType, >=)
bool operator == (const BaseForID & b) const { return num == b.num; }
bool operator <= (const BaseForID & b) const { return num <= b.num; }
bool operator >= (const BaseForID & b) const { return num >= b.num; }
bool operator != (const BaseForID & b) const { return num != b.num; }
bool operator < (const BaseForID & b) const { return num < b.num; }
bool operator > (const BaseForID & b) const { return num > b.num; }
BaseForID & operator++() { ++num; return *this; }
};
template < typename T>
class Identifier : public IdTag
{
public:
using EnumType = T;
using NumericType = typename std::underlying_type<EnumType>::type;
private:
NumericType num;
public:
NumericType getNum() const
{
return num;
}
EnumType toEnum() const
{
return static_cast<EnumType>(num);
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & num;
}
explicit Identifier(NumericType _num = -1)
{
num = _num;
}
/* implicit */ Identifier(EnumType _num)
{
num = static_cast<NumericType>(_num);
}
void advance(int change)
{
num += change;
}
bool operator == (const Identifier & b) const { return num == b.num; }
bool operator <= (const Identifier & b) const { return num >= b.num; }
bool operator >= (const Identifier & b) const { return num <= b.num; }
bool operator != (const Identifier & b) const { return num != b.num; }
bool operator < (const Identifier & b) const { return num < b.num; }
bool operator > (const Identifier & b) const { return num > b.num; }
Identifier & operator++()
{
++num;
return *this;
}
Identifier operator++(int)
{
Identifier ret(*this);
++num;
return ret;
}
};
template<typename Der, typename Num>
std::ostream & operator << (std::ostream & os, BaseForID<Der, Num> id);
@ -224,6 +282,14 @@ std::ostream & operator << (std::ostream & os, BaseForID<Der, Num> id)
return os << static_cast<Number>(id.getNum());
}
template<typename EnumType>
std::ostream & operator << (std::ostream & os, Identifier<EnumType> id)
{
//We use common type with short to force char and unsigned char to be promoted and formatted as numbers.
typedef typename std::common_type<short, typename Identifier<EnumType>::NumericType>::type Number;
return os << static_cast<Number>(id.getNum());
}
class ArtifactInstanceID : public BaseForID<ArtifactInstanceID, si32>
{
INSTID_LIKE_CLASS_COMMON(ArtifactInstanceID, si32)
@ -830,55 +896,26 @@ public:
ID_LIKE_OPERATORS(Obj, Obj::EObj)
namespace Terrain
enum class Road : int8_t
{
enum ETerrain : si8
{
NATIVE_TERRAIN = -4,
ANY_TERRAIN = -3,
WRONG = -2,
BORDER = -1,
FIRST_REGULAR_TERRAIN = 0,
DIRT = 0,
SAND,
GRASS,
SNOW,
SWAMP,
ROUGH,
SUBTERRANEAN,
LAVA,
WATER,
ROCK,
ORIGINAL_TERRAIN_COUNT
};
}
NO_ROAD = 0,
FIRST_REGULAR_ROAD = 1,
DIRT_ROAD = 1,
GRAVEL_ROAD = 2,
COBBLESTONE_ROAD = 3,
ORIGINAL_ROAD_COUNT //+1
};
namespace Road
enum class River : int8_t
{
enum ERoad : ui8
{
NO_ROAD = 0,
FIRST_REGULAR_ROAD = 1,
DIRT_ROAD = 1,
GRAVEL_ROAD = 2,
COBBLESTONE_ROAD = 3,
ORIGINAL_ROAD_COUNT //+1
};
}
namespace River
{
enum ERiver : ui8
{
NO_RIVER = 0,
FIRST_REGULAR_RIVER = 1,
WATER_RIVER = 1,
ICY_RIVER = 2,
MUD_RIVER = 3,
LAVA_RIVER = 4,
ORIGINAL_RIVER_COUNT //+1
};
}
NO_RIVER = 0,
FIRST_REGULAR_RIVER = 1,
WATER_RIVER = 1,
ICY_RIVER = 2,
MUD_RIVER = 3,
LAVA_RIVER = 4,
ORIGINAL_RIVER_COUNT //+1
};
namespace SecSkillLevel
{
@ -1182,7 +1219,29 @@ class BattleField : public BaseForID<BattleField, si32>
DLL_LINKAGE static BattleField fromString(std::string identifier);
};
enum class ETerrainId {
NATIVE_TERRAIN = -4,
ANY_TERRAIN = -3,
NONE = -1,
FIRST_REGULAR_TERRAIN = 0,
DIRT = 0,
SAND,
GRASS,
SNOW,
SWAMP,
ROUGH,
SUBTERRANEAN,
LAVA,
WATER,
ROCK,
ORIGINAL_REGULAR_TERRAIN_COUNT = ROCK
};
using TerrainId = Identifier<ETerrainId>;
using RoadId = Identifier<Road>;
using RiverId = Identifier<River>;
class ObstacleInfo;
class Obstacle : public BaseForID<Obstacle, si32>
{
@ -1240,9 +1299,6 @@ typedef si64 TExpType;
typedef std::pair<si64, si64> TDmgRange;
typedef si32 TBonusSubtype;
typedef si32 TQuantity;
typedef si8 TerrainId;
typedef si8 RoadId;
typedef si8 RiverId;
typedef int TRmgTemplateZoneId;
@ -1250,6 +1306,5 @@ typedef int TRmgTemplateZoneId;
#undef ID_LIKE_OPERATORS
#undef ID_LIKE_OPERATORS_INTERNAL
#undef INSTID_LIKE_CLASS_COMMON
#undef OP_DECL_INT
VCMI_LIB_NAMESPACE_END

View File

@ -22,6 +22,7 @@
#include "CStack.h"
#include "CArtHandler.h"
#include "CModHandler.h"
#include "TerrainHandler.h"
#include "StringConstants.h"
#include "battle/BattleInfo.h"
@ -2106,7 +2107,7 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
}
CreatureTerrainLimiter::CreatureTerrainLimiter()
: terrainType(Terrain::NATIVE_TERRAIN)
: terrainType(ETerrainId::NATIVE_TERRAIN)
{
}
@ -2120,7 +2121,7 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
const CStack *stack = retrieveStackBattle(&context.node);
if(stack)
{
if (terrainType == Terrain::NATIVE_TERRAIN)//terrainType not specified = native
if (terrainType == ETerrainId::NATIVE_TERRAIN)//terrainType not specified = native
{
return !stack->isOnNativeTerrain();
}
@ -2136,8 +2137,8 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
std::string CreatureTerrainLimiter::toString() const
{
boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
auto terrainName = VLC->terrainTypeHandler->terrains()[terrainType].name;
fmt % (terrainType == Terrain::NATIVE_TERRAIN ? "native" : terrainName);
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
fmt % (terrainType == ETerrainId::NATIVE_TERRAIN ? "native" : terrainName);
return fmt.str();
}
@ -2146,7 +2147,7 @@ JsonNode CreatureTerrainLimiter::toJsonNode() const
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
root["type"].String() = "CREATURE_TERRAIN_LIMITER";
auto terrainName = VLC->terrainTypeHandler->terrains()[terrainType].name;
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainName));
return root;

View File

@ -11,7 +11,6 @@
#include "GameConstants.h"
#include "JsonNode.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -32,6 +32,9 @@
#include "CPlayerState.h"
#include "CSkillHandler.h"
#include "ScriptHandler.h"
#include "RoadHandler.h"
#include "RiverHandler.h"
#include "TerrainHandler.h"
#include "serializer/Connection.h"

View File

@ -27,6 +27,7 @@
#include "mapping/CMapInfo.h"
#include "StartInfo.h"
#include "CPlayerState.h"
#include "TerrainHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -720,13 +721,13 @@ DLL_LINKAGE void GiveHero::applyGs(CGameState *gs)
DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
{
TerrainId terrainType = Terrain::BORDER;
TerrainId terrainType = ETerrainId::NONE;
if(ID == Obj::BOAT && !gs->isInTheMap(pos)) //special handling for bug #3060 - pos outside map but visitablePos is not
{
CGObjectInstance testObject = CGObjectInstance();
testObject.pos = pos;
testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(Terrain::WATER).front();
testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(ETerrainId::WATER).front();
const int3 previousXAxisTile = int3(pos.x - 1, pos.y, pos.z);
assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile));
@ -735,7 +736,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
else
{
const TerrainTile & t = gs->map->getTile(pos);
terrainType = t.terType->id;
terrainType = t.terType->getId();
}
CGObjectInstance *o = nullptr;
@ -743,7 +744,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
{
case Obj::BOAT:
o = new CGBoat();
terrainType = Terrain::WATER; //TODO: either boat should only spawn on water, or all water objects should be handled this way
terrainType = ETerrainId::WATER; //TODO: either boat should only spawn on water, or all water objects should be handled this way
break;
case Obj::MONSTER: //probably more options will be needed
o = new CGCreature();

View File

@ -10,6 +10,7 @@
#include "StdInc.h"
#include "ObstacleHandler.h"
#include "BattleFieldHandler.h"
#include "CModHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -86,8 +87,13 @@ ObstacleInfo * ObstacleHandler::loadFromJson(const std::string & scope, const Js
info->width = json["width"].Integer();
info->height = json["height"].Integer();
for(auto & t : json["allowedTerrains"].Vector())
info->allowedTerrains.emplace_back(VLC->terrainTypeHandler->getInfoByName(t.String())->id);
{
VLC->modh->identifiers.requestIdentifier("terrain", t, [info](int32_t identifier){
info->allowedTerrains.emplace_back(identifier);
});
}
for(auto & t : json["specialBattlefields"].Vector())
info->allowedSpecialBfields.emplace_back(t.String());
info->blockedTiles = json["blockedTiles"].convertTo<std::vector<si16>>();
info->isAbsoluteObstacle = json["absolute"].Bool();

View File

@ -13,7 +13,6 @@
#include <vcmi/Entity.h>
#include "GameConstants.h"
#include "IHandlerBase.h"
#include "Terrain.h"
#include "battle/BattleHex.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -9,6 +9,8 @@
*/
#pragma once
#include "TerrainHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "mapping/CMapDefines.h"
#include "CGameState.h"

78
lib/RiverHandler.cpp Normal file
View File

@ -0,0 +1,78 @@
/*
* Terrain.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 "RiverHandler.h"
#include "CModHandler.h"
#include "CGeneralTextHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
RiverTypeHandler::RiverTypeHandler()
{
objects.push_back(new RiverType);
}
RiverType * RiverTypeHandler::loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index)
{
RiverType * info = new RiverType;
info->id = RiverId(index);
if (identifier.find(':') == std::string::npos)
info->identifier = scope + ":" + identifier;
else
info->identifier = identifier;
info->tilesFilename = json["tilesFilename"].String();
info->shortIdentifier = json["shortIdentifier"].String();
info->deltaName = json["delta"].String();
VLC->generaltexth->registerString(info->getNameTextID(), json["text"].String());
return info;
}
const std::vector<std::string> & RiverTypeHandler::getTypeNames() const
{
static const std::vector<std::string> typeNames = { "river" };
return typeNames;
}
std::vector<JsonNode> RiverTypeHandler::loadLegacyData(size_t dataSize)
{
objects.resize(dataSize);
return {};
}
std::vector<bool> RiverTypeHandler::getDefaultAllowed() const
{
return {};
}
std::string RiverType::getNameTextID() const
{
return TextIdentifier( "river", identifier, "name" ).get();
}
std::string RiverType::getNameTranslated() const
{
return VLC->generaltexth->translate(getNameTextID());
}
RiverType::RiverType():
id(River::NO_RIVER),
identifier("core:empty")
{}
VCMI_LIB_NAMESPACE_END

79
lib/RiverHandler.h Normal file
View File

@ -0,0 +1,79 @@
/*
* TerrainHandler.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 <vcmi/EntityService.h>
#include <vcmi/Entity.h>
#include "GameConstants.h"
#include "IHandlerBase.h"
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE RiverType : public EntityT<RiverId>
{
friend class RiverTypeHandler;
std::string identifier;
RiverId id;
const std::string & getName() const override { return identifier;}
public:
int32_t getIndex() const override { return id.getNum(); }
int32_t getIconIndex() const override { return 0; }
const std::string & getJsonKey() const override { return identifier;}
void registerIcons(const IconRegistar & cb) const override {}
RiverId getId() const override { return id;}
void updateFrom(const JsonNode & data) {};
std::string getNameTextID() const;
std::string getNameTranslated() const;
std::string tilesFilename;
std::string shortIdentifier;
std::string deltaName;
RiverType();
template <typename Handler> void serialize(Handler& h, const int version)
{
h & tilesFilename;
h & identifier;
h & deltaName;
h & id;
}
};
class DLL_LINKAGE RiverTypeService : public EntityServiceT<RiverId, RiverType>
{
public:
};
class DLL_LINKAGE RiverTypeHandler : public CHandlerBase<RiverId, RiverType, RiverType, RiverTypeService>
{
public:
virtual RiverType * loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index) override;
RiverTypeHandler();
virtual const std::vector<std::string> & getTypeNames() const override;
virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
virtual std::vector<bool> getDefaultAllowed() const override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & objects;
}
};
VCMI_LIB_NAMESPACE_END

78
lib/RoadHandler.cpp Normal file
View File

@ -0,0 +1,78 @@
/*
* Terrain.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 "RoadHandler.h"
#include "CModHandler.h"
#include "CGeneralTextHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
RoadTypeHandler::RoadTypeHandler()
{
objects.push_back(new RoadType);
}
RoadType * RoadTypeHandler::loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index)
{
RoadType * info = new RoadType;
info->id = RoadId(index);
if (identifier.find(':') == std::string::npos)
info->identifier = scope + ":" + identifier;
else
info->identifier = identifier;
info->tilesFilename = json["tilesFilename"].String();
info->shortIdentifier = json["shortIdentifier"].String();
info->movementCost = json["moveCost"].Integer();
VLC->generaltexth->registerString(info->getNameTextID(), json["text"].String());
return info;
}
const std::vector<std::string> & RoadTypeHandler::getTypeNames() const
{
static const std::vector<std::string> typeNames = { "road" };
return typeNames;
}
std::vector<JsonNode> RoadTypeHandler::loadLegacyData(size_t dataSize)
{
objects.resize(dataSize);
return {};
}
std::vector<bool> RoadTypeHandler::getDefaultAllowed() const
{
return {};
}
std::string RoadType::getNameTextID() const
{
return TextIdentifier( "road", identifier, "name" ).get();
}
std::string RoadType::getNameTranslated() const
{
return VLC->generaltexth->translate(getNameTextID());
}
RoadType::RoadType():
id(Road::NO_ROAD),
identifier("core:empty"),
movementCost(GameConstants::BASE_MOVEMENT_COST)
{}
VCMI_LIB_NAMESPACE_END

79
lib/RoadHandler.h Normal file
View File

@ -0,0 +1,79 @@
/*
* TerrainHandler.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 <vcmi/EntityService.h>
#include <vcmi/Entity.h>
#include "GameConstants.h"
#include "IHandlerBase.h"
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE RoadType : public EntityT<RoadId>
{
friend class RoadTypeHandler;
std::string identifier;
RoadId id;
const std::string & getName() const override { return identifier;}
public:
int32_t getIndex() const override { return id.getNum(); }
int32_t getIconIndex() const override { return 0; }
const std::string & getJsonKey() const override { return identifier;}
void registerIcons(const IconRegistar & cb) const override {}
RoadId getId() const override { return id;}
void updateFrom(const JsonNode & data) {};
std::string getNameTextID() const;
std::string getNameTranslated() const;
std::string tilesFilename;
std::string shortIdentifier;
ui8 movementCost;
RoadType();
template <typename Handler> void serialize(Handler& h, const int version)
{
h & tilesFilename;
h & identifier;
h & id;
h & movementCost;
}
};
class DLL_LINKAGE RoadTypeService : public EntityServiceT<RoadId, RoadType>
{
public:
};
class DLL_LINKAGE RoadTypeHandler : public CHandlerBase<RoadId, RoadType, RoadType, RoadTypeService>
{
public:
virtual RoadType * loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index) override;
RoadTypeHandler();
virtual const std::vector<std::string> & getTypeNames() const override;
virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
virtual std::vector<bool> getDefaultAllowed() const override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & objects;
}
};
VCMI_LIB_NAMESPACE_END

View File

@ -1,473 +0,0 @@
/*
* Terrain.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 "Terrain.h"
#include "VCMI_Lib.h"
#include "CModHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
//regular expression to change id for string at config
//("allowedTerrain"\s*:\s*\[.*)9(.*\],\n)
//\1"rock"\2
TerrainTypeHandler::TerrainTypeHandler()
{
auto allConfigs = VLC->modh->getActiveMods();
allConfigs.insert(allConfigs.begin(), CModHandler::scopeBuiltin());
initRivers(allConfigs);
recreateRiverMaps();
initRoads(allConfigs);
recreateRoadMaps();
initTerrains(allConfigs); //maps will be populated inside
}
void TerrainTypeHandler::initTerrains(const std::vector<std::string> & allConfigs)
{
std::vector<std::function<void()>> resolveLater;
objects.resize(Terrain::ORIGINAL_TERRAIN_COUNT); //make space for original terrains
for(auto & mod : allConfigs)
{
if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/terrains.json")))
continue;
JsonNode terrs(mod, ResourceID("config/terrains.json"));
for(auto & terr : terrs.Struct())
{
TerrainType info(terr.first); //set name
info.moveCost = static_cast<int>(terr.second["moveCost"].Integer());
const JsonVector &unblockedVec = terr.second["minimapUnblocked"].Vector();
info.minimapUnblocked =
{
ui8(unblockedVec[0].Float()),
ui8(unblockedVec[1].Float()),
ui8(unblockedVec[2].Float())
};
const JsonVector &blockedVec = terr.second["minimapBlocked"].Vector();
info.minimapBlocked =
{
ui8(blockedVec[0].Float()),
ui8(blockedVec[1].Float()),
ui8(blockedVec[2].Float())
};
info.musicFilename = terr.second["music"].String();
info.tilesFilename = terr.second["tiles"].String();
if(terr.second["type"].isNull())
{
info.passabilityType = TerrainType::PassabilityType::LAND | TerrainType::PassabilityType::SURFACE;
}
else if (terr.second["type"].getType() == JsonNode::JsonType::DATA_VECTOR)
{
for(const auto& node : terr.second["type"].Vector())
{
//Set bits
auto s = node.String();
if (s == "LAND") info.passabilityType |= TerrainType::PassabilityType::LAND;
if (s == "WATER") info.passabilityType |= TerrainType::PassabilityType::WATER;
if (s == "ROCK") info.passabilityType |= TerrainType::PassabilityType::ROCK;
if (s == "SURFACE") info.passabilityType |= TerrainType::PassabilityType::SURFACE;
if (s == "SUB") info.passabilityType |= TerrainType::PassabilityType::SUBTERRANEAN;
}
}
else //should be string - one option only
{
auto s = terr.second["type"].String();
if (s == "LAND") info.passabilityType = TerrainType::PassabilityType::LAND;
if (s == "WATER") info.passabilityType = TerrainType::PassabilityType::WATER;
if (s == "ROCK") info.passabilityType = TerrainType::PassabilityType::ROCK;
if (s == "SURFACE") info.passabilityType = TerrainType::PassabilityType::SURFACE;
if (s == "SUB") info.passabilityType = TerrainType::PassabilityType::SUBTERRANEAN;
}
if(terr.second["river"].isNull())
{
info.river = River::NO_RIVER;
}
else
{
info.river = getRiverByCode(terr.second["river"].String())->id;
}
if(terr.second["horseSoundId"].isNull())
{
info.horseSoundId = Terrain::ROCK; //rock sound as default
}
else
{
info.horseSoundId = static_cast<int>(terr.second["horseSoundId"].Float());
}
if(!terr.second["text"].isNull())
{
info.terrainText = terr.second["text"].String();
}
if(terr.second["code"].isNull())
{
info.typeCode = terr.first.substr(0, 2);
}
else
{
info.typeCode = terr.second["code"].String();
assert(info.typeCode.length() == 2);
}
if(!terr.second["battleFields"].isNull())
{
for(auto & t : terr.second["battleFields"].Vector())
{
info.battleFields.emplace_back(t.String());
}
}
info.transitionRequired = false;
if(!terr.second["transitionRequired"].isNull())
{
info.transitionRequired = terr.second["transitionRequired"].Bool();
}
info.terrainViewPatterns = "normal";
if(!terr.second["terrainViewPatterns"].isNull())
{
info.terrainViewPatterns = terr.second["terrainViewPatterns"].String();
}
if(!terr.second["originalTerrainId"].isNull())
{
//place in reserved slot
info.id = (TerrainId)(terr.second["originalTerrainId"].Float());
objects[info.id] = info;
}
else
{
//append at the end
info.id = static_cast<TerrainId>(objects.size());
objects.push_back(info);
}
TerrainId id = info.id;
//Update terrain with this id in the future, after all terrain types are populated
if(!terr.second["prohibitTransitions"].isNull())
{
for(auto & t : terr.second["prohibitTransitions"].Vector())
{
std::string prohibitedTerrainName = t.String();
resolveLater.push_back([this, prohibitedTerrainName, id]()
{
//FIXME: is that reference to the element in vector?
objects[id].prohibitTransitions.emplace_back(getInfoByName(prohibitedTerrainName)->id);
});
}
}
if(terr.second["rockTerrain"].isNull())
{
objects[id].rockTerrain = Terrain::ROCK;
}
else
{
auto rockTerrainName = terr.second["rockTerrain"].String();
resolveLater.push_back([this, rockTerrainName, id]()
{
//FIXME: is that reference to the element in vector?
objects[id].rockTerrain = getInfoByName(rockTerrainName)->id;
});
}
}
}
for(size_t i = Terrain::FIRST_REGULAR_TERRAIN; i < Terrain::ORIGINAL_TERRAIN_COUNT; i++)
{
//Make sure that original terrains are loaded
assert(objects[i].id != Terrain::WRONG);
}
recreateTerrainMaps();
for(auto& functor : resolveLater)
{
functor();
}
}
void TerrainTypeHandler::initRivers(const std::vector<std::string> & allConfigs)
{
riverTypes.resize(River::ORIGINAL_RIVER_COUNT); //make space for original rivers
//First object will be default NO_RIVER
for(auto & mod : allConfigs)
{
if (!CResourceHandler::get(mod)->existsResource(ResourceID("config/rivers.json")))
continue;
JsonNode rivs(mod, ResourceID("config/rivers.json"));
for(auto & river : rivs.Struct())
{
RiverType info;
info.name = river.first;
info.fileName = river.second["animation"].String();
info.code = river.second["code"].String();
info.deltaName = river.second["delta"].String();
if (!river.second["originalRiverId"].isNull())
{
info.id = static_cast<RiverId>(river.second["originalRiverId"].Float());
riverTypes[info.id] = info;
}
else
{
info.id = static_cast<RiverId>(riverTypes.size());
riverTypes.push_back(info);
}
}
}
recreateRiverMaps();
}
void TerrainTypeHandler::initRoads(const std::vector<std::string> & allConfigs)
{
roadTypes.resize(Road::ORIGINAL_ROAD_COUNT); //make space for original rivers
//first object will be default NO_ROAD
for(auto & mod : allConfigs)
{
if (!CResourceHandler::get(mod)->existsResource(ResourceID("config/roads.json")))
continue;
JsonNode rds(mod, ResourceID("config/roads.json"));
for(auto & road : rds.Struct())
{
RoadType info;
info.name = road.first;
info.fileName = road.second["animation"].String();
info.code = road.second["code"].String();
info.movementCost = static_cast<ui8>(road.second["moveCost"].Float());
if (!road.second["originalRoadId"].isNull())
{
info.id = static_cast<RoadId>(road.second["originalRoadId"].Float());
roadTypes[info.id] = info;
}
else
{
info.id = static_cast<RoadId>(roadTypes.size());
roadTypes.push_back(info);
}
}
}
recreateRoadMaps();
}
void TerrainTypeHandler::recreateTerrainMaps()
{
//This assumes the vector will never be updated or reallocated in the future
for(size_t i = 0; i < objects.size(); i++)
{
const auto * terrainInfo = &objects[i];
terrainInfoByName[terrainInfo->name] = terrainInfo;
terrainInfoByCode[terrainInfo->typeCode] = terrainInfo;
terrainInfoById[terrainInfo->id] = terrainInfo;
}
}
void TerrainTypeHandler::recreateRiverMaps()
{
for(size_t i = River::FIRST_REGULAR_RIVER ; i < riverTypes.size(); i++)
{
const auto * riverInfo = &riverTypes[i];
riverInfoByName[riverInfo->name] = riverInfo;
riverInfoByCode[riverInfo->code] = riverInfo;
riverInfoById[riverInfo->id] = riverInfo;
}
}
void TerrainTypeHandler::recreateRoadMaps()
{
for(size_t i = Road::FIRST_REGULAR_ROAD ; i < roadTypes.size(); i++)
{
const auto * roadInfo = &roadTypes[i];
roadInfoByName[roadInfo->name] = roadInfo;
roadInfoByCode[roadInfo->code] = roadInfo;
roadInfoById[roadInfo->id] = roadInfo;
}
}
const std::vector<TerrainType> & TerrainTypeHandler::terrains() const
{
//FIXME: somehow make it non-copyable? Pointers must point to original data and not its copy
return objects;
}
const std::vector<RiverType>& TerrainTypeHandler::rivers() const
{
return riverTypes;
}
const std::vector<RoadType>& TerrainTypeHandler::roads() const
{
return roadTypes;
}
const TerrainType* TerrainTypeHandler::getInfoByName(const std::string& terrainName) const
{
return terrainInfoByName.at(terrainName);
}
const TerrainType* TerrainTypeHandler::getInfoByCode(const std::string& terrainCode) const
{
return terrainInfoByCode.at(terrainCode);
}
const TerrainType* TerrainTypeHandler::getInfoById(TerrainId id) const
{
return terrainInfoById.at(id);
}
const RiverType* TerrainTypeHandler::getRiverByName(const std::string& riverName) const
{
return riverInfoByName.at(riverName);
}
const RiverType* TerrainTypeHandler::getRiverByCode(const std::string& riverCode) const
{
return riverInfoByCode.at(riverCode);
}
const RiverType* TerrainTypeHandler::getRiverById(RiverId id) const
{
return riverInfoById.at(id);
}
const RoadType* TerrainTypeHandler::getRoadByName(const std::string& roadName) const
{
return roadInfoByName.at(roadName);
}
const RoadType* TerrainTypeHandler::getRoadByCode(const std::string& roadCode) const
{
return roadInfoByCode.at(roadCode);
}
const RoadType* TerrainTypeHandler::getRoadById(RoadId id) const
{
return roadInfoById.at(id);
}
std::ostream & operator<<(std::ostream & os, const TerrainType & terrainType)
{
return os << static_cast<const std::string &>(terrainType);
}
TerrainType::operator std::string() const
{
return name;
}
TerrainType::TerrainType(const std::string& _name):
minimapBlocked({0,0,0}), //black
minimapUnblocked({ 128,128,128 }), //grey
name(_name),
river(River::NO_RIVER),
id(Terrain::WRONG),
rockTerrain(Terrain::ROCK),
moveCost(GameConstants::BASE_MOVEMENT_COST),
horseSoundId(0),
passabilityType(0),
transitionRequired(false)
{
}
bool TerrainType::operator==(const TerrainType& other)
{
return id == other.id;
}
bool TerrainType::operator!=(const TerrainType& other)
{
return id != other.id;
}
bool TerrainType::operator<(const TerrainType& other)
{
return id < other.id;
}
bool TerrainType::isLand() const
{
return !isWater();
}
bool TerrainType::isWater() const
{
return passabilityType & PassabilityType::WATER;
}
bool TerrainType::isPassable() const
{
return !(passabilityType & PassabilityType::ROCK);
}
bool TerrainType::isSurface() const
{
return passabilityType & PassabilityType::SURFACE;
}
bool TerrainType::isUnderground() const
{
return passabilityType & PassabilityType::SUBTERRANEAN;
}
bool TerrainType::isSurfaceCartographerCompatible() const
{
return isSurface();
}
bool TerrainType::isUndergroundCartographerCompatible() const
{
return isLand() && isPassable() && !isSurface();
}
bool TerrainType::isTransitionRequired() const
{
return transitionRequired;
}
RiverType::RiverType(const std::string & fileName, const std::string & code, RiverId id):
fileName(fileName),
code(code),
id(id)
{
}
RoadType::RoadType(const std::string& fileName, const std::string& code, RoadId id):
fileName(fileName),
code(code),
id(id),
movementCost(GameConstants::BASE_MOVEMENT_COST)
{
}
VCMI_LIB_NAMESPACE_END

View File

@ -1,204 +0,0 @@
/*
* Terrain.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 "ConstTransitivePtr.h"
#include "GameConstants.h"
#include "JsonNode.h"
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE TerrainType
{
public:
enum PassabilityType : ui8
{
LAND = 1,
WATER = 2,
SURFACE = 4,
SUBTERRANEAN = 8,
ROCK = 16
};
std::vector<std::string> battleFields;
std::vector<TerrainId> prohibitTransitions;
std::array<int, 3> minimapBlocked;
std::array<int, 3> minimapUnblocked;
std::string name;
std::string musicFilename;
std::string tilesFilename;
std::string terrainText;
std::string typeCode;
std::string terrainViewPatterns;
RiverId river;
TerrainId id;
TerrainId rockTerrain;
int moveCost;
int horseSoundId;
ui8 passabilityType;
bool transitionRequired;
TerrainType(const std::string & name = "");
bool operator==(const TerrainType & other);
bool operator!=(const TerrainType & other);
bool operator<(const TerrainType & other);
bool isLand() const;
bool isWater() const;
bool isPassable() const;
bool isSurface() const;
bool isUnderground() const;
bool isTransitionRequired() const;
bool isSurfaceCartographerCompatible() const;
bool isUndergroundCartographerCompatible() const;
operator std::string() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & battleFields;
h & prohibitTransitions;
h & minimapBlocked;
h & minimapUnblocked;
h & name;
h & musicFilename;
h & tilesFilename;
h & terrainText;
h & typeCode;
h & terrainViewPatterns;
h & rockTerrain;
h & river;
h & id;
h & moveCost;
h & horseSoundId;
h & passabilityType;
h & transitionRequired;
}
};
class DLL_LINKAGE RiverType
{
public:
std::string name;
std::string fileName;
std::string code;
std::string deltaName;
RiverId id;
RiverType(const std::string & fileName = "", const std::string & code = "", RiverId id = River::NO_RIVER);
template <typename Handler> void serialize(Handler& h, const int version)
{
if(version >= 806)
{
h & name;
}
h & fileName;
h & code;
h & deltaName;
h & id;
}
};
class DLL_LINKAGE RoadType
{
public:
std::string name;
std::string fileName;
std::string code;
RoadId id;
ui8 movementCost;
RoadType(const std::string & fileName = "", const std::string& code = "", RoadId id = Road::NO_ROAD);
template <typename Handler> void serialize(Handler& h, const int version)
{
if(version >= 806)
{
h & name;
}
h & fileName;
h & code;
h & id;
h & movementCost;
}
};
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const TerrainType & terrainType);
class DLL_LINKAGE TerrainTypeHandler //TODO: public IHandlerBase ?
{
public:
TerrainTypeHandler();
~TerrainTypeHandler() {};
const std::vector<TerrainType> & terrains() const;
const TerrainType * getInfoByName(const std::string & terrainName) const;
const TerrainType * getInfoByCode(const std::string & terrainCode) const;
const TerrainType * getInfoById(TerrainId id) const;
const std::vector<RiverType> & rivers() const;
const RiverType * getRiverByName(const std::string & riverName) const;
const RiverType * getRiverByCode(const std::string & riverCode) const;
const RiverType * getRiverById(RiverId id) const;
const std::vector<RoadType> & roads() const;
const RoadType * getRoadByName(const std::string & roadName) const;
const RoadType * getRoadByCode(const std::string & roadCode) const;
const RoadType * getRoadById(RoadId id) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & objects;
h & riverTypes;
h & roadTypes;
if (!h.saving)
{
recreateTerrainMaps();
recreateRiverMaps();
recreateRoadMaps();
}
}
private:
std::vector<TerrainType> objects;
std::vector<RiverType> riverTypes;
std::vector<RoadType> roadTypes;
std::unordered_map<std::string, const TerrainType*> terrainInfoByName;
std::unordered_map<std::string, const TerrainType*> terrainInfoByCode;
std::unordered_map<TerrainId, const TerrainType*> terrainInfoById;
std::unordered_map<std::string, const RiverType*> riverInfoByName;
std::unordered_map<std::string, const RiverType*> riverInfoByCode;
std::unordered_map<RiverId, const RiverType*> riverInfoById;
std::unordered_map<std::string, const RoadType*> roadInfoByName;
std::unordered_map<std::string, const RoadType*> roadInfoByCode;
std::unordered_map<RoadId, const RoadType*> roadInfoById;
void initTerrains(const std::vector<std::string> & allConfigs);
void initRivers(const std::vector<std::string> & allConfigs);
void initRoads(const std::vector<std::string> & allConfigs);
void recreateTerrainMaps();
void recreateRiverMaps();
void recreateRoadMaps();
};
VCMI_LIB_NAMESPACE_END

191
lib/TerrainHandler.cpp Normal file
View File

@ -0,0 +1,191 @@
/*
* Terrain.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 "TerrainHandler.h"
#include "CModHandler.h"
#include "CGeneralTextHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
TerrainType * TerrainTypeHandler::loadFromJson( const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
{
TerrainType * info = new TerrainType;
info->id = TerrainId(index);
if (identifier.find(':') == std::string::npos)
info->identifier = scope + ":" + identifier;
else
info->identifier = identifier;
info->moveCost = static_cast<int>(json["moveCost"].Integer());
info->musicFilename = json["music"].String();
info->tilesFilename = json["tiles"].String();
info->horseSound = json["horseSound"].String();
info->horseSoundPenalty = json["horseSoundPenalty"].String();
info->transitionRequired = json["transitionRequired"].Bool();
info->terrainViewPatterns = json["terrainViewPatterns"].String();
VLC->generaltexth->registerString(info->getNameTextID(), json["text"].String());
const JsonVector & unblockedVec = json["minimapUnblocked"].Vector();
info->minimapUnblocked =
{
ui8(unblockedVec[0].Float()),
ui8(unblockedVec[1].Float()),
ui8(unblockedVec[2].Float())
};
const JsonVector &blockedVec = json["minimapBlocked"].Vector();
info->minimapBlocked =
{
ui8(blockedVec[0].Float()),
ui8(blockedVec[1].Float()),
ui8(blockedVec[2].Float())
};
info->passabilityType = 0;
for(const auto& node : json["type"].Vector())
{
//Set bits
auto s = node.String();
if (s == "LAND") info->passabilityType |= TerrainType::PassabilityType::LAND;
if (s == "WATER") info->passabilityType |= TerrainType::PassabilityType::WATER;
if (s == "ROCK") info->passabilityType |= TerrainType::PassabilityType::ROCK;
if (s == "SURFACE") info->passabilityType |= TerrainType::PassabilityType::SURFACE;
if (s == "SUB") info->passabilityType |= TerrainType::PassabilityType::SUBTERRANEAN;
}
info->river = River::NO_RIVER;
if(!json["river"].isNull())
{
VLC->modh->identifiers.requestIdentifier("river", json["river"], [info](int32_t identifier)
{
info->river = RiverId(identifier);
});
}
info->shortIdentifier = json["shortIdentifier"].String();
assert(info->shortIdentifier.length() == 2);
for(auto & t : json["battleFields"].Vector())
{
VLC->modh->identifiers.requestIdentifier("battlefield", t, [info](int32_t identifier)
{
info->battleFields.emplace_back(identifier);
});
}
for(auto & t : json["prohibitTransitions"].Vector())
{
VLC->modh->identifiers.requestIdentifier("terrain", t, [info](int32_t identifier)
{
info->prohibitTransitions.emplace_back(identifier);
});
}
info->rockTerrain = ETerrainId::ROCK;
if(!json["rockTerrain"].isNull())
{
VLC->modh->identifiers.requestIdentifier("terrain", json["rockTerrain"], [info](int32_t identifier)
{
info->rockTerrain = TerrainId(identifier);
});
}
return info;
}
const std::vector<std::string> & TerrainTypeHandler::getTypeNames() const
{
static const std::vector<std::string> typeNames = { "terrain" };
return typeNames;
}
std::vector<JsonNode> TerrainTypeHandler::loadLegacyData(size_t dataSize)
{
objects.resize(dataSize);
CLegacyConfigParser terrainParser("DATA/TERRNAME.TXT");
std::vector<JsonNode> result;
do
{
JsonNode terrain;
terrain["text"].String() = terrainParser.readString();
result.push_back(terrain);
}
while (terrainParser.endLine());
return result;
}
std::vector<bool> TerrainTypeHandler::getDefaultAllowed() const
{
return {};
}
bool TerrainType::isLand() const
{
return !isWater();
}
bool TerrainType::isWater() const
{
return passabilityType & PassabilityType::WATER;
}
bool TerrainType::isPassable() const
{
return !(passabilityType & PassabilityType::ROCK);
}
bool TerrainType::isSurface() const
{
return passabilityType & PassabilityType::SURFACE;
}
bool TerrainType::isUnderground() const
{
return passabilityType & PassabilityType::SUBTERRANEAN;
}
bool TerrainType::isSurfaceCartographerCompatible() const
{
return isSurface();
}
bool TerrainType::isUndergroundCartographerCompatible() const
{
return isLand() && isPassable() && !isSurface();
}
bool TerrainType::isTransitionRequired() const
{
return transitionRequired;
}
std::string TerrainType::getNameTextID() const
{
return TextIdentifier( "terrain", identifier, "name" ).get();
}
std::string TerrainType::getNameTranslated() const
{
return VLC->generaltexth->translate(getNameTextID());
}
TerrainType::TerrainType()
{}
VCMI_LIB_NAMESPACE_END

122
lib/TerrainHandler.h Normal file
View File

@ -0,0 +1,122 @@
/*
* TerrainHandler.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 <vcmi/EntityService.h>
#include <vcmi/Entity.h>
#include "GameConstants.h"
#include "IHandlerBase.h"
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE TerrainType : public EntityT<TerrainId>
{
friend class TerrainTypeHandler;
std::string identifier;
TerrainId id;
ui8 passabilityType;
const std::string & getName() const override { return identifier;}
public:
int32_t getIndex() const override { return id.getNum(); }
int32_t getIconIndex() const override { return 0; }
const std::string & getJsonKey() const override { return identifier;}
void registerIcons(const IconRegistar & cb) const override {}
TerrainId getId() const override { return id;}
void updateFrom(const JsonNode & data) {};
std::string getNameTextID() const;
std::string getNameTranslated() const;
enum PassabilityType : ui8
{
LAND = 1,
WATER = 2,
SURFACE = 4,
SUBTERRANEAN = 8,
ROCK = 16
};
std::vector<BattleField> battleFields;
std::vector<TerrainId> prohibitTransitions;
std::array<int, 3> minimapBlocked;
std::array<int, 3> minimapUnblocked;
std::string shortIdentifier;
std::string musicFilename;
std::string tilesFilename;
std::string terrainViewPatterns;
std::string horseSound;
std::string horseSoundPenalty;
TerrainId rockTerrain;
RiverId river;
int moveCost;
bool transitionRequired;
TerrainType();
bool isLand() const;
bool isWater() const;
bool isPassable() const;
bool isSurface() const;
bool isUnderground() const;
bool isTransitionRequired() const;
bool isSurfaceCartographerCompatible() const;
bool isUndergroundCartographerCompatible() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & battleFields;
h & prohibitTransitions;
h & minimapBlocked;
h & minimapUnblocked;
h & identifier;
h & musicFilename;
h & tilesFilename;
h & shortIdentifier;
h & terrainViewPatterns;
h & rockTerrain;
h & river;
h & id;
h & moveCost;
h & horseSound;
h & horseSoundPenalty;
h & passabilityType;
h & transitionRequired;
}
};
class DLL_LINKAGE TerrainTypeService : public EntityServiceT<TerrainId, TerrainType>
{
public:
};
class DLL_LINKAGE TerrainTypeHandler : public CHandlerBase<TerrainId, TerrainType, TerrainType, TerrainTypeService>
{
public:
virtual TerrainType * loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index) override;
virtual const std::vector<std::string> & getTypeNames() const override;
virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
virtual std::vector<bool> getDefaultAllowed() const override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & objects;
}
};
VCMI_LIB_NAMESPACE_END

View File

@ -18,6 +18,9 @@
#include "CHeroHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "CTownHandler.h"
#include "RoadHandler.h"
#include "RiverHandler.h"
#include "TerrainHandler.h"
#include "CBuildingHandler.h"
#include "spells/CSpellHandler.h"
#include "spells/effects/Registry.h"
@ -197,6 +200,8 @@ void LibClasses::init(bool onlyEssential)
createHandler(bth, "Bonus type", pomtime);
createHandler(roadTypeHandler, "Road", pomtime);
createHandler(riverTypeHandler, "River", pomtime);
createHandler(terrainTypeHandler, "Terrain", pomtime);
createHandler(generaltexth, "General text", pomtime);

View File

@ -30,6 +30,8 @@ class BattleFieldHandler;
class IBonusTypeHandler;
class CBonusTypeHandler;
class TerrainTypeHandler;
class RoadTypeHandler;
class RiverTypeHandler;
class ObstacleHandler;
class CTerrainViewPatternConfig;
class CRmgTemplateStorage;
@ -86,7 +88,11 @@ public:
CTownHandler * townh;
CGeneralTextHandler * generaltexth;
CModHandler * modh;
TerrainTypeHandler * terrainTypeHandler;
RoadTypeHandler * roadTypeHandler;
RiverTypeHandler * riverTypeHandler;
CTerrainViewPatternConfig * terviewh;
CRmgTemplateStorage * tplh;
BattleFieldHandler * battlefieldsHandler;
@ -127,6 +133,8 @@ public:
h & skillh;
h & battlefieldsHandler;
h & obstacleHandler;
h & roadTypeHandler;
h & riverTypeHandler;
h & terrainTypeHandler;
if(!h.saving)

View File

@ -15,7 +15,6 @@
#include "../filesystem/Filesystem.h"
#include "../mapObjects/CGTownInstance.h"
#include "../CGeneralTextHandler.h"
#include "../Terrain.h"
#include "../BattleFieldHandler.h"
#include "../ObstacleHandler.h"

View File

@ -10,7 +10,6 @@
#include "StdInc.h"
#include "BattleProxy.h"
#include "Unit.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -17,6 +17,8 @@
#include "../NetPacks.h"
#include "../CGeneralTextHandler.h"
#include "../CHeroHandler.h"
#include "../TerrainHandler.h"
#include "../RoadHandler.h"
#include "../CModHandler.h"
#include "../CSoundBase.h"
#include "../spells/CSpellHandler.h"
@ -81,16 +83,16 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
int64_t ret = GameConstants::BASE_MOVEMENT_COST;
//if there is road both on dest and src tiles - use road movement cost
if(dest.roadType->id && from.roadType->id)
if(dest.roadType->getId() != Road::NO_ROAD && from.roadType->getId() != Road::NO_ROAD)
{
ret = std::max(dest.roadType->movementCost, from.roadType->movementCost);
}
else if(ti->nativeTerrain != from.terType->id &&//the terrain is not native
ti->nativeTerrain != Terrain::ANY_TERRAIN && //no special creature bonus
!ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType->id)) //no special movement bonus
else if(ti->nativeTerrain != from.terType->getId() &&//the terrain is not native
ti->nativeTerrain != ETerrainId::ANY_TERRAIN && //no special creature bonus
!ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType->getIndex())) //no special movement bonus
{
ret = VLC->heroh->terrCosts[from.terType->id];
ret = VLC->heroh->terrCosts[from.terType->getId()];
ret -= ti->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING);
if(ret < GameConstants::BASE_MOVEMENT_COST)
ret = GameConstants::BASE_MOVEMENT_COST;
@ -104,20 +106,21 @@ TerrainId CGHeroInstance::getNativeTerrain() const
// This is clearly bug in H3 however intended behaviour is not clear.
// Current VCMI behaviour will ignore neutrals in calculations so army in VCMI
// will always have best penalty without any influence from player-defined stacks order
// and army that consist solely from neutral will always be considered to be on native terrain
// TODO: What should we do if all hero stacks are neutral creatures?
TerrainId nativeTerrain = Terrain::BORDER;
TerrainId nativeTerrain = ETerrainId::ANY_TERRAIN;
for(auto stack : stacks)
{
TerrainId stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
if(stackNativeTerrain == Terrain::BORDER) //where does this value come from?
if(stackNativeTerrain == ETerrainId::NONE)
continue;
if(nativeTerrain == Terrain::BORDER)
if(nativeTerrain == ETerrainId::ANY_TERRAIN)
nativeTerrain = stackNativeTerrain;
else if(nativeTerrain != stackNativeTerrain)
return Terrain::BORDER;
return ETerrainId::NONE;
}
return nativeTerrain;
}
@ -519,7 +522,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
if (ID != Obj::PRISON)
{
auto terrain = cb->gameState()->getTile(visitablePos())->terType->id;
auto terrain = cb->gameState()->getTile(visitablePos())->terType->getId();
auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(terrain, this);
if (customApp)
appearance = customApp;

View File

@ -20,6 +20,7 @@
#include "../CGameState.h"
#include "../mapping/CMap.h"
#include "../CPlayerState.h"
#include "../TerrainHandler.h"
#include "../serializer/JsonSerializeFormat.h"
#include "../HeroBonus.h"
@ -1132,7 +1133,7 @@ void CGTownInstance::setType(si32 ID, si32 subID)
void CGTownInstance::updateAppearance()
{
auto terrain = cb->gameState()->getTile(visitablePos())->terType->id;
auto terrain = cb->gameState()->getTile(visitablePos())->terType->getId();
//FIXME: not the best way to do this
auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(terrain, this);
if (app)

View File

@ -15,7 +15,6 @@
#include "../ConstTransitivePtr.h"
#include "../IHandlerBase.h"
#include "../JsonNode.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -20,6 +20,7 @@
#include "../CGameState.h"
#include "../StringConstants.h"
#include "../mapping/CMap.h"
#include "../TerrainHandler.h"
#include "CObjectClassesHandler.h"
#include "CGTownInstance.h"
@ -207,13 +208,13 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
logGlobal->error("Unknown object type %d:%d at %s", ID, subID, visitablePos().toString());
return;
}
if(!handler->getTemplates(tile.terType->id).empty())
if(!handler->getTemplates(tile.terType->getId()).empty())
{
appearance = handler->getTemplates(tile.terType->id)[0];
appearance = handler->getTemplates(tile.terType->getId())[0];
}
else
{
logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", ID, subID, visitablePos().toString(), tile.terType->name);
logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", ID, subID, visitablePos().toString(), tile.terType->getNameTranslated());
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
}

View File

@ -13,6 +13,7 @@
#include "CGTownInstance.h"
#include "CGHeroInstance.h"
#include "CBank.h"
#include "../TerrainHandler.h"
#include "../mapping/CMap.h"
#include "../CHeroHandler.h"
#include "../CCreatureHandler.h"
@ -84,7 +85,7 @@ CGObjectInstance * CTownInstanceConstructor::create(std::shared_ptr<const Object
void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
{
auto templ = getOverride(object->cb->getTile(object->pos)->terType->id, object);
auto templ = getOverride(object->cb->getTile(object->pos)->terType->getId(), object);
if(templ)
object->appearance = templ;
}

View File

@ -19,7 +19,7 @@
#include "CObjectHandler.h"
#include "../CModHandler.h"
#include "../JsonNode.h"
#include "../Terrain.h"
#include "../TerrainHandler.h"
#include "CRewardableConstructor.h"
@ -157,22 +157,15 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
// so these two fields can be interpreted as "strong affinity" and "weak affinity" towards terrains
std::string & terrStr = strings[4]; // allowed terrains, 1 = object can be placed on this terrain
assert(terrStr.size() == Terrain::ROCK); // all terrains but rock - counting from 0
for(TerrainId i = Terrain::FIRST_REGULAR_TERRAIN; i < Terrain::ROCK; i++)
assert(terrStr.size() == TerrainId(ETerrainId::ROCK).getNum()); // all terrains but rock - counting from 0
for(TerrainId i = TerrainId(0); i < ETerrainId::ORIGINAL_REGULAR_TERRAIN_COUNT; ++i)
{
if (terrStr[8-i] == '1')
if (terrStr[8-i.getNum()] == '1')
allowedTerrains.insert(i);
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain::WATER))
{
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain.id);
}
}
anyTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
id = Obj(boost::lexical_cast<int>(strings[5]));
subid = boost::lexical_cast<int>(strings[6]);
@ -231,21 +224,14 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
reader.readUInt16();
ui16 terrMask = reader.readUInt16();
for(size_t i = Terrain::FIRST_REGULAR_TERRAIN; i < Terrain::ROCK; i++)
for(TerrainId i = ETerrainId::FIRST_REGULAR_TERRAIN; i < ETerrainId::ORIGINAL_REGULAR_TERRAIN_COUNT; ++i)
{
if (((terrMask >> i) & 1 ) != 0)
if (((terrMask >> i.getNum()) & 1 ) != 0)
allowedTerrains.insert(i);
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain::WATER))
{
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain.id);
}
}
anyTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
id = Obj(reader.readUInt32());
subid = reader.readUInt32();
@ -288,28 +274,17 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
{
for(auto& entry : node["allowedTerrains"].Vector())
{
try {
allowedTerrains.insert(VLC->terrainTypeHandler->getInfoByName(entry.String())->id);
}
catch (const std::out_of_range & )
{
logGlobal->warn("Failed to find terrain '%s' for object '%s'", entry.String(), animationFile);
}
VLC->modh->identifiers.requestIdentifier("terrain", entry, [this](int32_t identifier){
allowedTerrains.insert(TerrainId(identifier));
});
}
anyTerrain = false;
}
else
{
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(!terrain.isPassable() || terrain.isWater())
continue;
allowedTerrains.insert(terrain.id);
}
anyTerrain = true;
}
if(withTerrain && allowedTerrains.empty())
logGlobal->warn("Loaded template %s without allowed terrains!", animationFile);
auto charToTile = [&](const char & ch) -> ui8
{
switch (ch)
@ -378,14 +353,14 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
if(withTerrain)
{
//assumed that ROCK and WATER terrains are not included
if(allowedTerrains.size() < (VLC->terrainTypeHandler->terrains().size() - 2))
if(allowedTerrains.size() < (VLC->terrainTypeHandler->objects.size() - 2))
{
JsonVector & data = node["allowedTerrains"].Vector();
for(auto type : allowedTerrains)
{
JsonNode value(JsonNode::JsonType::DATA_STRING);
value.String() = type;
value.String() = VLC->terrainTypeHandler->getById(type)->getJsonKey();
data.push_back(value);
}
}
@ -565,9 +540,14 @@ void ObjectTemplate::calculateVisitableOffset()
visitableOffset = int3(0, 0, 0);
}
bool ObjectTemplate::canBePlacedAt(TerrainId terrain) const
bool ObjectTemplate::canBePlacedAt(TerrainId terrainID) const
{
return vstd::contains(allowedTerrains, terrain);
if (anyTerrain)
{
auto const & terrain = VLC->terrainTypeHandler->getById(terrainID);
return terrain->isLand() && terrain->isPassable();
}
return vstd::contains(allowedTerrains, terrainID);
}
void ObjectTemplate::recalculate()

View File

@ -35,6 +35,9 @@ class DLL_LINKAGE ObjectTemplate
/// list of terrains on which this object can be placed
std::set<TerrainId> allowedTerrains;
/// or, allow placing object on any terrain
bool anyTerrain;
void afterLoadFixup();
public:

View File

@ -12,6 +12,9 @@
#include "CDrawRoadsOperation.h"
#include "CMap.h"
#include "../RoadHandler.h"
#include "../RiverHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
const std::vector<CDrawLinesOperation::LinePattern> CDrawLinesOperation::patterns =
@ -338,12 +341,12 @@ std::string CDrawRiversOperation::getLabel() const
void CDrawRoadsOperation::executeTile(TerrainTile & tile)
{
tile.roadType = const_cast<RoadType*>(&VLC->terrainTypeHandler->roads()[roadType]);
tile.roadType = const_cast<RoadType*>(VLC->roadTypeHandler->getByIndex(roadType.getNum()));
}
void CDrawRiversOperation::executeTile(TerrainTile & tile)
{
tile.riverType = const_cast<RiverType*>(&VLC->terrainTypeHandler->rivers()[riverType]);
tile.riverType = const_cast<RiverType*>(VLC->riverTypeHandler->getByIndex(riverType.getNum()));
}
bool CDrawRoadsOperation::canApplyPattern(const LinePattern & pattern) const
@ -358,22 +361,22 @@ bool CDrawRiversOperation::canApplyPattern(const LinePattern & pattern) const
bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
{
return tile.roadType->id != Road::NO_ROAD;
return tile.roadType->getId() != Road::NO_ROAD;
}
bool CDrawRiversOperation::needUpdateTile(const TerrainTile & tile) const
{
return tile.riverType->id != River::NO_RIVER;
return tile.riverType->getId() != River::NO_RIVER;
}
bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
{
return map->getTile(pos).roadType->id != Road::NO_ROAD;
return map->getTile(pos).roadType->getId() != Road::NO_ROAD;
}
bool CDrawRiversOperation::tileHasSomething(const int3& pos) const
{
return map->getTile(pos).riverType->id != River::NO_RIVER;
return map->getTile(pos).riverType->getId() != River::NO_RIVER;
}
void CDrawRoadsOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip)

View File

@ -80,7 +80,7 @@ private:
class CDrawRiversOperation : public CDrawLinesOperation
{
public:
CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, CRandomGenerator * gen);
CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RiverId roadType, CRandomGenerator * gen);
std::string getLabel() const override;
protected:

View File

@ -15,6 +15,9 @@
#include "../CCreatureHandler.h"
#include "../CTownHandler.h"
#include "../CHeroHandler.h"
#include "../RiverHandler.h"
#include "../RoadHandler.h"
#include "../TerrainHandler.h"
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../CGeneralTextHandler.h"
@ -128,9 +131,9 @@ CCastleEvent::CCastleEvent() : town(nullptr)
TerrainTile::TerrainTile():
terType(nullptr),
terView(0),
riverType(const_cast<RiverType*>(&VLC->terrainTypeHandler->rivers()[River::NO_RIVER])),
riverType(VLC->riverTypeHandler->getById(River::NO_RIVER)),
riverDir(0),
roadType(const_cast<RoadType*>(&VLC->terrainTypeHandler->roads()[Road::NO_ROAD])),
roadType(VLC->roadTypeHandler->getById(Road::NO_ROAD)),
roadDir(0),
extTileFlags(0),
visitable(false),

View File

@ -12,6 +12,10 @@
VCMI_LIB_NAMESPACE_BEGIN
class TerrainType;
class RiverType;
class RoadType;
/// The map event is an event which e.g. gives or takes resources of a specific
/// amount to/from players and can appear regularly or once a time.
class DLL_LINKAGE CMapEvent
@ -82,11 +86,11 @@ struct DLL_LINKAGE TerrainTile
EDiggingStatus getDiggingStatus(const bool excludeTop = true) const;
bool hasFavorableWinds() const;
TerrainType * terType;
const TerrainType * terType;
ui8 terView;
RiverType * riverType;
const RiverType * riverType;
ui8 riverDir;
RoadType * roadType;
const RoadType * roadType;
ui8 roadDir;
/// first two bits - how to rotate terrain graphic (next two - river graphic, next two - road);
/// 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect

View File

@ -12,7 +12,6 @@
#include "../GameConstants.h"
#include "CMapOperation.h"
#include "Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -12,6 +12,7 @@
#include "CMapOperation.h"
#include "../VCMI_Lib.h"
#include "../TerrainHandler.h"
#include "CMap.h"
#include "MapEditUtils.h"
@ -97,7 +98,7 @@ void CDrawTerrainOperation::execute()
for(const auto & pos : terrainSel.getSelectedItems())
{
auto & tile = map->getTile(pos);
tile.terType = const_cast<TerrainType*>(&VLC->terrainTypeHandler->terrains()[terType]);
tile.terType = const_cast<TerrainType*>(VLC->terrainTypeHandler->getById(terType));
invalidateTerrainViews(pos);
}
@ -154,7 +155,7 @@ void CDrawTerrainOperation::updateTerrainTypes()
rect.forEach([&](const int3& posToTest)
{
auto & terrainTile = map->getTile(posToTest);
if(centerTile.terType->id != terrainTile.terType->id)
if(centerTile.terType->getId() != terrainTile.terType->getId())
{
auto formerTerType = terrainTile.terType;
terrainTile.terType = centerTile.terType;
@ -257,7 +258,7 @@ void CDrawTerrainOperation::updateTerrainViews()
{
for(const auto & pos : invalidatedTerViews)
{
const auto & patterns = VLC->terviewh->getTerrainViewPatterns(map->getTile(pos).terType->id);
const auto & patterns = VLC->terviewh->getTerrainViewPatterns(map->getTile(pos).terType->getId());
// Detect a pattern which fits best
int bestPattern = -1;
@ -345,7 +346,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
int cy = pos.y + (i / 3) - 1;
int3 currentPos(cx, cy, pos.z);
bool isAlien = false;
TerrainType * terType = nullptr;
const TerrainType * terType = nullptr;
if(!map->isInTheMap(currentPos))
{
// position is not in the map, so take the ter type from the neighbor tile
@ -393,9 +394,9 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
{
if(recDepth == 0 && map->isInTheMap(currentPos))
{
if(terType->id == centerTerType->id)
if(terType->getId() == centerTerType->getId())
{
const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(centerTerType->id, rule.name);
const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(centerTerType->getId(), rule.name);
if(auto p = patternForRule)
{
auto rslt = validateTerrainView(currentPos, &(*p), 1);
@ -422,14 +423,14 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
bool nativeTestOk, nativeTestStrongOk;
nativeTestOk = nativeTestStrongOk = (rule.isNativeStrong() || rule.isNativeRule()) && !isAlien;
if(centerTerType->id == Terrain::DIRT)
if(centerTerType->getId() == ETerrainId::DIRT)
{
nativeTestOk = rule.isNativeRule() && !terType->isTransitionRequired();
bool sandTestOk = (rule.isSandRule() || rule.isTransition())
&& terType->isTransitionRequired();
applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk || nativeTestStrongOk);
}
else if(centerTerType->id == Terrain::SAND)
else if(centerTerType->getId() == ETerrainId::SAND)
{
applyValidationRslt(true);
}
@ -551,12 +552,12 @@ CClearTerrainOperation::CClearTerrainOperation(CMap* map, CRandomGenerator* gen)
{
CTerrainSelection terrainSel(map);
terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain::WATER, gen));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::WATER, gen));
if(map->twoLevel)
{
terrainSel.clearSelection();
terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain::ROCK, gen));
addOperation(std::make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainId::ROCK, gen));
}
}

View File

@ -13,6 +13,7 @@
#include "../filesystem/Filesystem.h"
#include "../JsonNode.h"
#include "../TerrainHandler.h"
#include "CMap.h"
#include "CMapOperation.h"
@ -272,7 +273,7 @@ CTerrainViewPatternConfig::~CTerrainViewPatternConfig()
const std::vector<CTerrainViewPatternConfig::TVPVector> & CTerrainViewPatternConfig::getTerrainViewPatterns(TerrainId terrain) const
{
auto iter = terrainViewPatterns.find(VLC->terrainTypeHandler->terrains()[terrain].terrainViewPatterns);
auto iter = terrainViewPatterns.find(VLC->terrainTypeHandler->getById(terrain)->terrainViewPatterns);
if (iter == terrainViewPatterns.end())
return terrainViewPatterns.at("normal");
return iter->second;
@ -357,7 +358,7 @@ void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int
{
auto debugTile = map->getTile(debugPos);
std::string terType = debugTile.terType->name.substr(0, 6);
std::string terType = debugTile.terType->shortIdentifier;
line += terType;
line.insert(line.end(), PADDED_LENGTH - terType.size(), ' ');
}

View File

@ -12,7 +12,7 @@
#include "../int3.h"
#include "../CRandomGenerator.h"
#include "Terrain.h"
#include "../GameConstants.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -24,6 +24,9 @@
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/MapObjects.h"
#include "../VCMI_Lib.h"
#include "../TerrainHandler.h"
#include "../RoadHandler.h"
#include "../RiverHandler.h"
#include "../NetPacksBase.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -923,9 +926,6 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
void CMapLoaderH3M::readTerrain()
{
map->initTerrain();
const auto & terrains = VLC->terrainTypeHandler->terrains();
const auto & rivers = VLC->terrainTypeHandler->rivers();
const auto & roads = VLC->terrainTypeHandler->roads();
// Read terrain
int3 pos;
@ -937,15 +937,17 @@ void CMapLoaderH3M::readTerrain()
for(pos.x = 0; pos.x < map->width; pos.x++)
{
auto & tile = map->getTile(pos);
tile.terType = const_cast<TerrainType*>(&terrains[reader.readUInt8()]);
tile.terType = const_cast<TerrainType*>(VLC->terrainTypeHandler->getByIndex(reader.readUInt8()));
tile.terView = reader.readUInt8();
tile.riverType = const_cast<RiverType*>(&rivers[reader.readUInt8()]);
tile.riverType = const_cast<RiverType*>(VLC->riverTypeHandler->getByIndex(reader.readUInt8()));
tile.riverDir = reader.readUInt8();
tile.roadType = const_cast<RoadType*>(&roads[reader.readUInt8()]);
tile.roadType = const_cast<RoadType*>(VLC->roadTypeHandler->getByIndex(reader.readUInt8()));
tile.roadDir = reader.readUInt8();
tile.extTileFlags = reader.readUInt8();
tile.blocked = ((!tile.terType->isPassable() || tile.terType->id == Terrain::BORDER ) ? true : false); //underground tiles are always blocked
tile.blocked = !tile.terType->isPassable();
tile.visitable = 0;
assert(tile.terType->getId() != ETerrainId::NONE);
}
}
}

View File

@ -19,6 +19,9 @@
#include "../CHeroHandler.h"
#include "../CTownHandler.h"
#include "../VCMI_Lib.h"
#include "../RiverHandler.h"
#include "../RoadHandler.h"
#include "../TerrainHandler.h"
#include "../mapObjects/ObjectTemplate.h"
#include "../mapObjects/CObjectHandler.h"
#include "../mapObjects/CObjectClassesHandler.h"
@ -346,6 +349,37 @@ CMapFormatJson::CMapFormatJson():
}
TerrainType * CMapFormatJson::getTerrainByCode( std::string code)
{
for ( auto const & object : VLC->terrainTypeHandler->objects)
{
if (object->shortIdentifier == code)
return const_cast<TerrainType *>(object.get());
}
return nullptr;
}
RiverType * CMapFormatJson::getRiverByCode( std::string code)
{
for ( auto const & object : VLC->riverTypeHandler->objects)
{
if (object->shortIdentifier == code)
return const_cast<RiverType *>(object.get());
}
return nullptr;
}
RoadType * CMapFormatJson::getRoadByCode( std::string code)
{
for ( auto const & object : VLC->roadTypeHandler->objects)
{
if (object->shortIdentifier == code)
return const_cast<RoadType *>(object.get());
}
return nullptr;
}
void CMapFormatJson::serializeAllowedFactions(JsonSerializeFormat & handler, std::set<TFaction> & value)
{
//TODO: unify allowed factions with others - make them std::vector<bool>
@ -949,7 +983,7 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
using namespace TerrainDetail;
{//terrain type
const std::string typeCode = src.substr(0, 2);
tile.terType = const_cast<TerrainType*>(VLC->terrainTypeHandler->getInfoByCode(typeCode));
tile.terType = getTerrainByCode(typeCode);
}
int startPos = 2; //0+typeCode fixed length
{//terrain view
@ -979,13 +1013,13 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
startPos += 2;
try
{
tile.roadType = const_cast<RoadType*>(VLC->terrainTypeHandler->getRoadByCode(typeCode));
tile.roadType = getRoadByCode(typeCode);
}
catch (const std::exception&) //it's not a road, it's a river
{
try
{
tile.riverType = const_cast<RiverType*>(VLC->terrainTypeHandler->getRiverByCode(typeCode));
tile.riverType = getRiverByCode(typeCode);
hasRoad = false;
}
catch (const std::exception&)
@ -1021,7 +1055,7 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
{//river type
const std::string typeCode = src.substr(startPos, 2);
startPos += 2;
tile.riverType = const_cast<RiverType*>(VLC->terrainTypeHandler->getRiverByCode(typeCode));
tile.riverType = getRiverByCode(typeCode);
}
{//river dir
int pos = startPos;
@ -1289,12 +1323,12 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile)
out.setf(std::ios::dec, std::ios::basefield);
out.unsetf(std::ios::showbase);
out << tile.terType->typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
out << tile.terType->shortIdentifier << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
if(tile.roadType->id != Road::NO_ROAD)
if(tile.roadType->getId() != Road::NO_ROAD)
out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
if(tile.riverType->id != River::NO_RIVER)
if(tile.riverType->getId() != River::NO_RIVER)
out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
return out.str();

View File

@ -26,6 +26,9 @@ struct TerrainTile;
struct PlayerInfo;
class CGObjectInstance;
class AObjectTypeHandler;
class TerrainType;
class RoadType;
class RiverType;
class JsonSerializeFormat;
class JsonDeserializer;
@ -57,6 +60,10 @@ protected:
CMapFormatJson();
static TerrainType * getTerrainByCode( std::string code);
static RiverType * getRiverByCode( std::string code);
static RoadType * getRoadByCode( std::string code);
void serializeAllowedFactions(JsonSerializeFormat & handler, std::set<TFaction> & value);
///common part of header saving/loading

View File

@ -22,6 +22,9 @@
#include "../CHeroHandler.h"
#include "../spells/CSpellHandler.h"
#include "../CTownHandler.h"
#include "../RoadHandler.h"
#include "../RiverHandler.h"
#include "../TerrainHandler.h"
#include "../mapping/CCampaignHandler.h"
#include "../NetPacks.h"
#include "../mapObjects/CObjectClassesHandler.h"

View File

@ -16,7 +16,8 @@
#include "../mapping/CMap.h"
#include "../VCMI_Lib.h"
#include "../CTownHandler.h"
#include "../Terrain.h"
#include "../CModHandler.h"
#include "../TerrainHandler.h"
#include "../serializer/JsonSerializeFormat.h"
#include "../StringConstants.h"
@ -69,13 +70,12 @@ class TerrainEncoder
public:
static si32 decode(const std::string & identifier)
{
return VLC->terrainTypeHandler->getInfoByCode(identifier)->id;
return *VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), "terrain", identifier);
}
static std::string encode(const si32 index)
{
const auto& terrains = VLC->terrainTypeHandler->terrains();
return (index >=0 && index < terrains.size()) ? terrains[index].name : "<INVALID TERRAIN>";
return VLC->terrainTypeHandler->getByIndex(index)->getJsonKey();
}
};
@ -152,9 +152,9 @@ ZoneOptions::ZoneOptions()
terrainTypeLikeZone(NO_ZONE),
treasureLikeZone(NO_ZONE)
{
for(const auto & terr : VLC->terrainTypeHandler->terrains())
if(terr.isLand() && terr.isPassable())
terrainTypes.insert(terr.id);
for(const auto & terr : VLC->terrainTypeHandler->objects)
if(terr->isLand() && terr->isPassable())
terrainTypes.insert(terr->getId());
}
ZoneOptions & ZoneOptions::operator=(const ZoneOptions & other)
@ -224,7 +224,7 @@ const std::set<TerrainId> & ZoneOptions::getTerrainTypes() const
void ZoneOptions::setTerrainTypes(const std::set<TerrainId> & value)
{
//assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
//assert(value.find(ETerrainType::NONE) == value.end() &&
// value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
terrainTypes = value;
}
@ -365,7 +365,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
for(auto & ttype : terrainTypes)
{
JsonNode n;
n.String() = ttype;
n.String() = VLC->terrainTypeHandler->getById(ttype)->getJsonKey();
node.Vector().push_back(n);
}
}
@ -377,7 +377,10 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
terrainTypes.clear();
for(auto ttype : node.Vector())
{
terrainTypes.emplace(VLC->terrainTypeHandler->getInfoByName(ttype.String())->id);
VLC->modh->identifiers.requestIdentifier("terrain", ttype, [this](int32_t identifier)
{
terrainTypes.emplace(identifier);
});
}
}
}

View File

@ -13,7 +13,6 @@
#include "../int3.h"
#include "../GameConstants.h"
#include "../ResourceSet.h"
#include "../Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -11,6 +11,7 @@
#include "StdInc.h"
#include "../CRandomGenerator.h"
#include "CZonePlacer.h"
#include "../TerrainHandler.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "CMapGenOptions.h"
@ -194,15 +195,15 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
else
{
auto & tt = (*VLC->townh)[faction]->nativeTerrain;
if(tt == Terrain::DIRT)
if(tt == ETerrainId::NONE)
{
//any / random
zonesToPlace.push_back(zone);
}
else
{
const auto & terrainType = VLC->terrainTypeHandler->terrains()[tt];
if(terrainType.isUnderground() && !terrainType.isSurface())
const auto & terrainType = VLC->terrainTypeHandler->getById(tt);
if(terrainType->isUnderground() && !terrainType->isSurface())
{
//underground only
zonesOnLevel[1]++;
@ -580,7 +581,7 @@ void CZonePlacer::assignZones(CRandomGenerator * rand)
//make sure that terrain inside zone is not a rock
//FIXME: reorder actions?
paintZoneTerrain(*zone.second, *rand, map, Terrain::SUBTERRANEAN);
paintZoneTerrain(*zone.second, *rand, map, ETerrainId::SUBTERRANEAN);
}
}
logGlobal->info("Finished zone colouring");

View File

@ -12,6 +12,7 @@
#include "ConnectionsPlacer.h"
#include "CMapGenerator.h"
#include "RmgMap.h"
#include "../TerrainHandler.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "../mapObjects/CObjectClassesHandler.h"
@ -84,9 +85,11 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
//1. Try to make direct connection
//Do if it's not prohibited by terrain settings
const auto& terrains = VLC->terrainTypeHandler->terrains();
bool directProhibited = vstd::contains(terrains[zone.getTerrainType()].prohibitTransitions, otherZone->getTerrainType())
|| vstd::contains(terrains[otherZone->getTerrainType()].prohibitTransitions, zone.getTerrainType());
const auto * ourTerrain = VLC->terrainTypeHandler->getById(zone.getTerrainType());
const auto * otherTerrain = VLC->terrainTypeHandler->getById(otherZone->getTerrainType());
bool directProhibited = vstd::contains(ourTerrain->prohibitTransitions, otherZone->getTerrainType())
|| vstd::contains(otherTerrain->prohibitTransitions, zone.getTerrainType());
auto directConnectionIterator = dNeighbourZones.find(otherZoneId);
if(!directProhibited && directConnectionIterator != dNeighbourZones.end())
{

View File

@ -21,6 +21,7 @@
#include "RmgMap.h"
#include "TileInfo.h"
#include "RmgPath.h"
#include "../TerrainHandler.h"
#include "../CTownHandler.h"
#include "../mapping/CMapEditManager.h"
#include "../mapping/CMap.h"
@ -119,9 +120,9 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
{
//collect all water terrain types
std::vector<TerrainId> waterTerrains;
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
if(terrain.isWater())
waterTerrains.push_back(terrain.id);
for(const auto & terrain : VLC->terrainTypeHandler->objects)
if(terrain->isWater())
waterTerrains.push_back(terrain->getId());
zone.setTerrainType(*RandomGeneratorUtil::nextItem(waterTerrains, gen.rand));
}
@ -137,20 +138,20 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
}
//Now, replace disallowed terrains on surface and in the underground
const auto & terrainType = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()];
const auto & terrainType = VLC->terrainTypeHandler->getById(zone.getTerrainType());
if(zone.isUnderground())
{
if(!terrainType.isUnderground())
if(!terrainType->isUnderground())
{
zone.setTerrainType(Terrain::SUBTERRANEAN);
zone.setTerrainType(ETerrainId::SUBTERRANEAN);
}
}
else
{
if (!terrainType.isSurface())
if (!terrainType->isSurface())
{
zone.setTerrainType(Terrain::DIRT);
zone.setTerrainType(ETerrainId::DIRT);
}
}
}

View File

@ -13,6 +13,8 @@
#include "Functions.h"
#include "CMapGenerator.h"
#include "RmgMap.h"
#include "../RiverHandler.h"
#include "../TerrainHandler.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "../mapObjects/CObjectClassesHandler.h"
@ -86,7 +88,7 @@ void RiverPlacer::init()
void RiverPlacer::drawRivers()
{
map.getEditManager()->getTerrainSelection().setSelection(rivers.getTilesVector());
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river, &generator.rand);
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->getById(zone.getTerrainType())->river, &generator.rand);
}
char RiverPlacer::dump(const int3 & t)
@ -195,7 +197,7 @@ void RiverPlacer::preprocess()
//calculate delta positions
if(connectedToWaterZoneId > -1)
{
auto river = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river;
auto river = VLC->terrainTypeHandler->getById(zone.getTerrainType())->river;
auto & a = neighbourZonesTiles[connectedToWaterZoneId];
auto availableArea = zone.areaPossible() + zone.freePaths();
for(auto & tileToProcess : availableArea.getTilesVector())
@ -321,9 +323,9 @@ void RiverPlacer::preprocess()
void RiverPlacer::connectRiver(const int3 & tile)
{
auto riverType = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river;
const auto & river = VLC->terrainTypeHandler->rivers()[riverType];
if(river.id == River::NO_RIVER)
auto riverType = VLC->terrainTypeHandler->getById(zone.getTerrainType())->river;
const auto * river = VLC->riverTypeHandler->getById(riverType);
if(river->getId() == River::NO_RIVER)
return;
rmg::Area roads;
@ -381,9 +383,9 @@ void RiverPlacer::connectRiver(const int3 & tile)
{
if(tmplates.size() % 4 != 0)
throw rmgException(boost::to_string(boost::format("River templates for (%d,%d) at terrain %s, river %s are incorrect") %
RIVER_DELTA_ID % RIVER_DELTA_SUBTYPE % zone.getTerrainType() % river.code));
RIVER_DELTA_ID % RIVER_DELTA_SUBTYPE % zone.getTerrainType() % river->shortIdentifier));
std::string targetTemplateName = river.deltaName + std::to_string(deltaOrientations[pos]) + ".def";
std::string targetTemplateName = river->deltaName + std::to_string(deltaOrientations[pos]) + ".def";
for(auto & templ : tmplates)
{
if(templ->animationFile == targetTemplateName)

View File

@ -84,7 +84,7 @@ void RmgMap::initTiles(CMapGenerator & generator)
getEditManager()->clearTerrain(&generator.rand);
getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
getEditManager()->drawTerrain(Terrain::GRASS, &generator.rand);
getEditManager()->drawTerrain(ETerrainId::GRASS, &generator.rand);
auto tmpl = mapGenOptions.getMapTemplate();
zones.clear();

View File

@ -18,6 +18,7 @@
#include "../mapObjects/CommonConstructors.h"
#include "../mapObjects/MapObjects.h" //needed to resolve templates for CommonConstructors.h
#include "Functions.h"
#include "../TerrainHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -121,7 +122,7 @@ void Object::Instance::setTemplate(TerrainId terrain)
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
if (templates.empty())
{
auto terrainName = VLC->terrainTypeHandler->terrains()[terrain].name;
auto terrainName = VLC->terrainTypeHandler->getById(terrain)->getNameTranslated();
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % terrainName));
}
dObject.appearance = templates.front();
@ -293,14 +294,14 @@ void Object::Instance::finalize(RmgMap & map)
if (!dObject.appearance)
{
auto terrainType = map.map().getTile(getPosition(true)).terType;
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->id);
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->getId());
if (templates.empty())
{
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % dObject.ID % dObject.subID % getPosition(true).toString() % terrainType));
}
else
{
setTemplate(terrainType->id);
setTemplate(terrainType->getId());
}
}

View File

@ -16,6 +16,7 @@
#include "RmgMap.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "../CModHandler.h"
#include "RmgPath.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -78,8 +79,9 @@ void RoadPlacer::drawRoads(bool secondary)
zone.areaPossible().subtract(roads);
zone.freePaths().unite(roads);
map.getEditManager()->getTerrainSelection().setSelection(roads.getTilesVector());
std::string roadName = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
RoadId roadType = VLC->terrainTypeHandler->getRoadByName(roadName)->id;
RoadId roadType(*VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), "road", roadName));
map.getEditManager()->drawRoad(roadType, &generator.rand);
}

View File

@ -17,6 +17,7 @@
#include "RmgMap.h"
#include "CMapGenerator.h"
#include "Functions.h"
#include "../TerrainHandler.h"
#include "../CRandomGenerator.h"
#include "../mapping/CMapEditManager.h"
@ -24,8 +25,8 @@ VCMI_LIB_NAMESPACE_BEGIN
void RockPlacer::process()
{
rockTerrain = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].rockTerrain;
assert(!VLC->terrainTypeHandler->terrains()[rockTerrain].isPassable());
rockTerrain = VLC->terrainTypeHandler->getById(zone.getTerrainType())->rockTerrain;
assert(!VLC->terrainTypeHandler->getById(rockTerrain)->isPassable());
accessibleArea = zone.freePaths() + zone.areaUsed();
if(auto * m = zone.getModificator<ObjectManager>())

View File

@ -11,7 +11,6 @@
#pragma once
#include "../GameConstants.h"
#include "../Terrain.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@ -12,6 +12,7 @@
#include "WaterProxy.h"
#include "CMapGenerator.h"
#include "RmgMap.h"
#include "../TerrainHandler.h"
#include "../mapping/CMap.h"
#include "../mapping/CMapEditManager.h"
#include "../mapObjects/CObjectClassesHandler.h"
@ -44,7 +45,7 @@ void WaterProxy::process()
{
MAYBE_UNUSED(t);
assert(map.isOnMap(t));
assert(map.map().getTile(t).terType->id == zone.getTerrainType());
assert(map.map().getTile(t).terType->getId() == zone.getTerrainType());
}
for(auto z : map.getZones())
@ -54,7 +55,7 @@ void WaterProxy::process()
for(auto & t : z.second->area().getTilesVector())
{
if(map.map().getTile(t).terType->id == zone.getTerrainType())
if(map.map().getTile(t).terType->getId() == zone.getTerrainType())
{
z.second->areaPossible().erase(t);
z.second->area().erase(t);

View File

@ -28,7 +28,7 @@ std::function<bool(const int3 &)> AREA_NO_FILTER = [](const int3 & t)
Zone::Zone(RmgMap & map, CMapGenerator & generator)
: ZoneOptions(),
townType(ETownType::NEUTRAL),
terrainType(Terrain::GRASS),
terrainType(ETerrainId::GRASS),
map(map),
generator(generator)
{

View File

@ -14,8 +14,8 @@
VCMI_LIB_NAMESPACE_BEGIN
const ui32 SERIALIZATION_VERSION = 807;
const ui32 MINIMAL_SERIALIZATION_VERSION = 805;
const ui32 SERIALIZATION_VERSION = 810;
const ui32 MINIMAL_SERIALIZATION_VERSION = 810;
const std::string SAVEGAME_MAGIC = "VCMISVG";
class CHero;

View File

@ -21,12 +21,15 @@
#include "../lib/VCMI_Lib.h"
#include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/CConfigHandler.h"
#include "../lib/CModHandler.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/GameConstants.h"
#include "../lib/mapping/CMapService.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapping/CMapEditManager.h"
#include "../lib/Terrain.h"
#include "../lib/RoadHandler.h"
#include "../lib/RiverHandler.h"
#include "../lib/TerrainHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/filesystem/CFilesystemLoader.h"
@ -542,32 +545,32 @@ void MainWindow::loadObjectsTree()
{
ui->terrainFilterCombo->addItem("");
//adding terrains
for(auto & terrain : VLC->terrainTypeHandler->terrains())
for(auto & terrain : VLC->terrainTypeHandler->objects)
{
QPushButton *b = new QPushButton(QString::fromStdString(terrain.name));
QPushButton *b = new QPushButton(QString::fromStdString(terrain->getNameTranslated()));
ui->terrainLayout->addWidget(b);
connect(b, &QPushButton::clicked, this, [this, terrain]{ terrainButtonClicked(terrain.id); });
connect(b, &QPushButton::clicked, this, [this, terrain]{ terrainButtonClicked(terrain->getId()); });
//filter
ui->terrainFilterCombo->addItem(QString::fromStdString(terrain));
ui->terrainFilterCombo->addItem(QString::fromStdString(terrain->getNameTranslated()));
}
//add spacer to keep terrain button on the top
ui->terrainLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
//adding roads
for(auto & road : VLC->terrainTypeHandler->roads())
for(auto & road : VLC->roadTypeHandler->objects)
{
QPushButton *b = new QPushButton(QString::fromStdString(road.fileName));
QPushButton *b = new QPushButton(QString::fromStdString(road->getNameTranslated()));
ui->roadLayout->addWidget(b);
connect(b, &QPushButton::clicked, this, [this, road]{ roadOrRiverButtonClicked(road.id, true); });
connect(b, &QPushButton::clicked, this, [this, road]{ roadOrRiverButtonClicked(road->getIndex(), true); });
}
//add spacer to keep terrain button on the top
ui->roadLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
//adding rivers
for(auto & river : VLC->terrainTypeHandler->rivers())
for(auto & river : VLC->riverTypeHandler->objects)
{
QPushButton *b = new QPushButton(QString::fromStdString(river.fileName));
QPushButton *b = new QPushButton(QString::fromStdString(river->getNameTranslated()));
ui->riverLayout->addWidget(b);
connect(b, &QPushButton::clicked, this, [this, river]{ roadOrRiverButtonClicked(river.id, false); });
connect(b, &QPushButton::clicked, this, [this, river]{ roadOrRiverButtonClicked(river->getIndex(), false); });
}
//add spacer to keep terrain button on the top
ui->riverLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
@ -930,7 +933,13 @@ void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1)
if(!objectBrowser)
return;
objectBrowser->terrain = arg1.isEmpty() ? TerrainId(Terrain::ANY_TERRAIN) : VLC->terrainTypeHandler->getInfoByName(arg1.toStdString())->id;
objectBrowser->terrain = TerrainId(ETerrainId::ANY_TERRAIN);
if (!arg1.isEmpty())
{
for (auto const & terrain : VLC->terrainTypeHandler->objects)
if (terrain->getJsonKey() == arg1.toStdString())
objectBrowser->terrain = terrain->getId();
}
objectBrowser->invalidate();
objectBrowser->sort(0);
}
@ -1122,7 +1131,7 @@ void MainWindow::on_actionUpdate_appearance_triggered()
if(handler->isStaticObject())
{
staticObjects.insert(obj);
if(obj->appearance->canBePlacedAt(terrain->id))
if(obj->appearance->canBePlacedAt(terrain->getId()))
{
controller.scene(mapLevel)->selectionObjectsView.deselectObject(obj);
continue;
@ -1133,13 +1142,13 @@ void MainWindow::on_actionUpdate_appearance_triggered()
}
else
{
auto app = handler->getOverride(terrain->id, obj);
auto app = handler->getOverride(terrain->getId(), obj);
if(!app)
{
if(obj->appearance->canBePlacedAt(terrain->id))
if(obj->appearance->canBePlacedAt(terrain->getId()))
continue;
auto templates = handler->getTemplates(terrain->id);
auto templates = handler->getTemplates(terrain->getId());
if(templates.empty())
{
++errors;

View File

@ -4,7 +4,6 @@
#include <QGraphicsScene>
#include <QStandardItemModel>
#include "mapcontroller.h"
#include "../lib/Terrain.h"
#include "resourceExtractor/ResourceConverter.h"
class ObjectBrowser;

View File

@ -14,7 +14,7 @@
#include "../lib/mapping/CMapService.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapping/CMapEditManager.h"
#include "../lib/Terrain.h"
#include "../lib/TerrainHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/rmg/ObstaclePlacer.h"
#include "../lib/CSkillHandler.h"
@ -408,7 +408,7 @@ void MapController::commitObstacleFill(int level)
if(tl.blocked || tl.visitable)
continue;
terrainSelected[tl.terType->id].blockedArea.add(t);
terrainSelected[tl.terType->getId()].blockedArea.add(t);
}
for(auto & sel : terrainSelected)

View File

@ -13,7 +13,6 @@
#include "maphandler.h"
#include "mapview.h"
#include "../lib/mapping/CMap.h"
#include "../lib/Terrain.h"
class MainWindow;
class MapController

View File

@ -12,6 +12,9 @@
#include "StdInc.h"
#include "maphandler.h"
#include "graphics.h"
#include "../lib/RoadHandler.h"
#include "../lib/RiverHandler.h"
#include "../lib/TerrainHandler.h"
#include "../lib/mapping/CMap.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
@ -78,17 +81,17 @@ void MapHandler::initTerrainGraphics()
std::map<std::string, std::string> terrainFiles;
std::map<std::string, std::string> roadFiles;
std::map<std::string, std::string> riverFiles;
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
for(const auto & terrain : VLC->terrainTypeHandler->objects)
{
terrainFiles[terrain.name] = terrain.tilesFilename;
terrainFiles[terrain->getJsonKey()] = terrain->tilesFilename;
}
for(const auto & river : VLC->terrainTypeHandler->rivers())
for(const auto & river : VLC->riverTypeHandler->objects)
{
riverFiles[river.fileName] = river.fileName;
riverFiles[river->getJsonKey()] = river->tilesFilename;
}
for(const auto & road : VLC->terrainTypeHandler->roads())
for(const auto & road : VLC->roadTypeHandler->objects)
{
roadFiles[road.fileName] = road.fileName;
roadFiles[road->getJsonKey()] = road->tilesFilename;
}
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
@ -101,8 +104,7 @@ void MapHandler::drawTerrainTile(QPainter & painter, int x, int y, int z)
auto & tinfo = map->getTile(int3(x, y, z));
ui8 rotation = tinfo.extTileFlags % 4;
//TODO: use ui8 instead of string key
auto terrainName = tinfo.terType->name;
auto terrainName = tinfo.terType->getJsonKey();
if(terrainImages.at(terrainName).size() <= tinfo.terView)
return;
@ -116,9 +118,9 @@ void MapHandler::drawRoad(QPainter & painter, int x, int y, int z)
auto & tinfo = map->getTile(int3(x, y, z));
auto * tinfoUpper = map->isInTheMap(int3(x, y - 1, z)) ? &map->getTile(int3(x, y - 1, z)) : nullptr;
if(tinfoUpper && tinfoUpper->roadType->id != Road::NO_ROAD)
if(tinfoUpper && tinfoUpper->roadType->getId() != Road::NO_ROAD)
{
auto roadName = tinfoUpper->roadType->fileName;
auto roadName = tinfoUpper->roadType->getJsonKey();
QRect source(0, tileSize / 2, tileSize, tileSize / 2);
ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4;
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
@ -128,9 +130,9 @@ void MapHandler::drawRoad(QPainter & painter, int x, int y, int z)
}
}
if(tinfo.roadType->id != Road::NO_ROAD) //print road from this tile
if(tinfo.roadType->getId() != Road::NO_ROAD) //print road from this tile
{
auto roadName = tinfo.roadType->fileName;
auto roadName = tinfo.roadType->getJsonKey();;
QRect source(0, 0, tileSize, tileSize / 2);
ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
@ -145,11 +147,11 @@ void MapHandler::drawRiver(QPainter & painter, int x, int y, int z)
{
auto & tinfo = map->getTile(int3(x, y, z));
if(tinfo.riverType->id == River::NO_RIVER)
if(tinfo.riverType->getId() == River::NO_RIVER)
return;
//TODO: use ui8 instead of string key
auto riverName = tinfo.riverType->fileName;
auto riverName = tinfo.riverType->getJsonKey();
if(riverImages.at(riverName).size() <= tinfo.riverDir)
return;

View File

@ -13,7 +13,7 @@
#include "../lib/mapObjects/CObjectClassesHandler.h"
ObjectBrowserProxyModel::ObjectBrowserProxyModel(QObject *parent)
: QSortFilterProxyModel{parent}, terrain(Terrain::ANY_TERRAIN)
: QSortFilterProxyModel{parent}, terrain(ETerrainId::ANY_TERRAIN)
{
}
@ -33,7 +33,7 @@ bool ObjectBrowserProxyModel::filterAcceptsRow(int source_row, const QModelIndex
if(!filterAcceptsRowText(source_row, source_parent))
return false;
if(terrain == Terrain::ANY_TERRAIN)
if(terrain == ETerrainId::ANY_TERRAIN)
return result;
auto data = item->data().toJsonObject();

View File

@ -11,7 +11,7 @@
#pragma once
#include <QSortFilterProxyModel>
#include "../lib/Terrain.h"
#include "../lib/GameConstants.h"
class ObjectBrowserProxyModel : public QSortFilterProxyModel
{

View File

@ -38,6 +38,7 @@
#include "../lib/VCMIDirs.h"
#include "../lib/ScopeGuard.h"
#include "../lib/CSoundBase.h"
#include "../lib/TerrainHandler.h"
#include "CGameHandler.h"
#include "CVCMIServer.h"
#include "../lib/CCreatureSet.h"
@ -2242,9 +2243,9 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
battleResult.set(nullptr);
const auto & t = *getTile(tile);
TerrainId terrain = t.terType->id;
TerrainId terrain = t.terType->getId();
if (gs->map->isCoastalTile(tile)) //coastal tile is always ground
terrain = Terrain::SAND;
terrain = ETerrainId::SAND;
BattleField terType = gs->battleGetBattlefieldType(tile, getRandomGenerator());
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)