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

Merge pull request #963 from vcmi/terrain-rewrite

Terrain rewrite
This commit is contained in:
DjWarmonger 2022-09-29 18:24:05 +02:00 committed by GitHub
commit 58a3abb643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
102 changed files with 1190 additions and 715 deletions

View File

@ -88,11 +88,11 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
{
for(pos.y = 0; pos.y < sizes.y; ++pos.y)
{
const TerrainTile* tile = &gs->map->getTile(pos);
if (!tile->terType.isPassable())
const TerrainTile & tile = gs->map->getTile(pos);
if (!tile.terType->isPassable())
continue;
if (tile->terType.isWater())
if (tile.terType->isWater())
{
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if (useFlying)

View File

@ -43,11 +43,11 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
{
for(pos.y=0; pos.y < sizes.y; ++pos.y)
{
const TerrainTile * tile = &gs->map->getTile(pos);
if(!tile->terType.isPassable())
const TerrainTile & tile = gs->map->getTile(pos);
if(!tile.terType->isPassable())
continue;
if(tile->terType.isWater())
if(tile.terType->isWater())
{
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if(useFlying)

View File

@ -37,6 +37,7 @@ void CGameInfo::setFromLib()
spellh = VLC->spellh;
skillh = VLC->skillh;
objtypeh = VLC->objtypeh;
terrainTypeHandler = VLC->terrainTypeHandler;
battleFieldHandler = VLC->battlefieldsHandler;
obstacleHandler = VLC->obstacleHandler;
}

View File

@ -29,6 +29,7 @@ class CConsoleHandler;
class CGameState;
class BattleFieldHandler;
class ObstacleHandler;
class TerrainTypeHandler;
class CMap;
@ -84,6 +85,7 @@ public:
ConstTransitivePtr<CSpellHandler> spellh;
ConstTransitivePtr<CSkillHandler> skillh;
ConstTransitivePtr<CObjectHandler> objh;
ConstTransitivePtr<TerrainTypeHandler> terrainTypeHandler;
ConstTransitivePtr<CObjectClassesHandler> objtypeh;
ConstTransitivePtr<ObstacleHandler> obstacleHandler;
CGeneralTextHandler * generaltexth;

View File

@ -101,27 +101,35 @@ CSoundHandler::CSoundHandler():
};
//predefine terrain set
//TODO: need refactoring - support custom sounds for new terrains and load from json
int h3mTerrId = 0;
for(auto snd :
//TODO: support custom sounds for new terrains and load from json
horseSounds =
{
soundBase::horseDirt, soundBase::horseSand, soundBase::horseGrass,
soundBase::horseSnow, soundBase::horseSwamp, soundBase::horseRough,
soundBase::horseSubterranean, soundBase::horseLava,
soundBase::horseWater, soundBase::horseRock
})
{
horseSounds[Terrain::createTerrainTypeH3M(h3mTerrId++)] = snd;
{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}
};
}
for(auto & terrain : Terrain::Manager::terrains())
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))
if(vstd::contains(horseSounds, terrain.id))
continue;
horseSounds[terrain] = horseSounds.at(Terrain::createTerrainTypeH3M(Terrain::Manager::getInfo(terrain).horseSoundId));
//Use already existing horse sound
horseSounds[terrain.id] = horseSounds.at(terrains[terrain.id].horseSoundId);
}
}
};
void CSoundHandler::init()
{
@ -364,10 +372,13 @@ CMusicHandler::CMusicHandler():
addEntryToSet("enemy-turn", file.getName(), file.getName());
}
for(auto & terrain : Terrain::Manager::terrains())
}
void CMusicHandler::loadTerrainSounds()
{
auto & entry = Terrain::Manager::getInfo(terrain);
addEntryToSet("terrain", terrain, "Music/" + entry.musicFilename);
for (const auto & terrain : CGI->terrainTypeHandler->terrains())
{
addEntryToSet("terrain", terrain.name, "Music/" + terrain.musicFilename);
}
}

View File

@ -61,6 +61,7 @@ public:
CSoundHandler();
void init() override;
void loadHorseSounds();
void release() override;
void setVolume(ui32 percent) override;
@ -83,7 +84,7 @@ public:
// Sets
std::vector<soundBase::soundID> pickupSounds;
std::vector<soundBase::soundID> battleIntroSounds;
std::map<Terrain, soundBase::soundID> horseSounds;
std::map<TerrainId, soundBase::soundID> horseSounds;
};
// Helper //now it looks somewhat useless
@ -139,6 +140,7 @@ public:
void addEntryToSet(const std::string & set, const std::string & entryID, const std::string & musicURI);
void init() override;
void loadTerrainSounds();
void release() override;
void setVolume(ui32 percent) override;

View File

@ -152,6 +152,10 @@ void CPlayerInterface::init(std::shared_ptr<Environment> ENV, std::shared_ptr<CC
{
cb = CB;
env = ENV;
CCS->soundh->loadHorseSounds();
CCS->musich->loadTerrainSounds();
initializeHeroTownList();
// always recreate advmap interface to avoid possible memory-corruption bugs
@ -274,7 +278,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, true);
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->name, true);
if(details.result == TryMoveHero::TELEPORTATION)
{
@ -2742,8 +2746,8 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{
path.convert(0);
Terrain currentTerrain = Terrain("BORDER"); // not init yet
Terrain newTerrain;
TerrainId currentTerrain = Terrain::BORDER; // not init yet
TerrainId newTerrain;
int sh = -1;
auto canStop = [&](CGPathNode * node) -> bool
@ -2798,7 +2802,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
#endif
{
newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType;
newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType->id;
if(newTerrain != currentTerrain)
{
CCS->soundh->stopSound(sh);

View File

@ -456,8 +456,8 @@ CBattleInterface::~CBattleInterface()
if (adventureInt && adventureInt->selection)
{
auto & terrain = LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType;
CCS->musich->playMusicFromSet("terrain", terrain, true);
const auto & terrain = *(LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType);
CCS->musich->playMusicFromSet("terrain", terrain.name, true);
}
animsAreDisplayed.setn(false);
}

View File

@ -135,22 +135,6 @@ EMapAnimRedrawStatus CMapHandler::drawTerrainRectNew(SDL_Surface * targetSurface
void CMapHandler::initTerrainGraphics()
{
static const std::map<std::string, std::string> ROAD_FILES =
{
{ROAD_NAMES[1], "dirtrd"},
{ROAD_NAMES[2], "gravrd"},
{ROAD_NAMES[3], "cobbrd"}
};
static const std::map<std::string, std::string> RIVER_FILES =
{
{RIVER_NAMES[1], "clrrvr"},
{RIVER_NAMES[2], "icyrvr"},
{RIVER_NAMES[3], "mudrvr"},
{RIVER_NAMES[4], "lavrvr"}
};
auto loadFlipped = [](TFlippedAnimations & animation, TFlippedCache & cache, const std::map<std::string, std::string> & files)
{
//no rotation and basic setup
@ -189,14 +173,24 @@ void CMapHandler::initTerrainGraphics()
};
std::map<std::string, std::string> terrainFiles;
for(auto & terrain : Terrain::Manager::terrains())
std::map<std::string, std::string> riverFiles;
std::map<std::string, std::string> roadFiles;
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
terrainFiles[terrain] = Terrain::Manager::getInfo(terrain).tilesFilename;
terrainFiles[terrain.name] = terrain.tilesFilename;
}
for(const auto & river : VLC->terrainTypeHandler->rivers())
{
riverFiles[river.fileName] = river.fileName;
}
for(const auto & road : VLC->terrainTypeHandler->roads())
{
roadFiles[road.fileName] = road.fileName;
}
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
loadFlipped(roadAnimations, roadImages, ROAD_FILES);
loadFlipped(riverAnimations, riverImages, RIVER_FILES);
loadFlipped(riverAnimations, riverImages, riverFiles);
loadFlipped(roadAnimations, roadImages, roadFiles);
// Create enough room for the whole map and its frame
@ -609,10 +603,13 @@ void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const T
ui8 rotation = tinfo.extTileFlags % 4;
if(parent->terrainImages[tinfo.terType].size()<=tinfo.terView)
//TODO: use ui8 instead of string key
auto terrainName = tinfo.terType->name;
if(parent->terrainImages[terrainName].size()<=tinfo.terView)
return;
drawElement(EMapCacheType::TERRAIN, parent->terrainImages[tinfo.terType][tinfo.terView][rotation], nullptr, targetSurf, &destRect);
drawElement(EMapCacheType::TERRAIN, parent->terrainImages[terrainName][tinfo.terView][rotation], nullptr, targetSurf, &destRect);
}
void CMapHandler::CMapWorldViewBlitter::init(const MapDrawingInfo * drawingInfo)
@ -787,21 +784,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 != ROAD_NAMES[0])
if (tinfoUpper && tinfoUpper->roadType->id != 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][tinfoUpper->roadDir][rotation],
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfoUpper->roadType->fileName][tinfoUpper->roadDir][rotation],
&source, targetSurf, &dest);
}
if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile
if(tinfo.roadType->id != 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][tinfo.roadDir][rotation],
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfo.roadType->fileName][tinfo.roadDir][rotation],
&source, targetSurf, &dest);
}
}
@ -810,7 +807,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][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect);
drawElement(EMapCacheType::RIVERS, parent->riverImages[tinfo.riverType->fileName][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect);
}
void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const
@ -861,7 +858,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
if(isVisible || info->showAllTerrain)
{
drawTileTerrain(targetSurf, tinfo, tile);
if(tinfo.riverType != RIVER_NAMES[0])
if(tinfo.riverType->id != River::NO_RIVER)
drawRiver(targetSurf, tinfo);
drawRoad(targetSurf, tinfo, tinfoUpper);
}
@ -1390,7 +1387,7 @@ void CMapHandler::getTerrainDescr(const int3 & pos, std::string & out, bool isRM
}
}
if(!isTile2Terrain || out.empty())
out = CGI->generaltexth->terrainNames[t.terType];
out = CGI->generaltexth->terrainNames[t.terType->id];
if(t.getDiggingStatus(false) == EDiggingStatus::CAN_DIG)
{

View File

@ -390,10 +390,11 @@ 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;
if (tile->blocked && (!tile->visitable))
return parent->colors.find(tile->terType)->second.second;
return colorPair.second;
else
return parent->colors.find(tile->terType)->second.first;
return colorPair.first;
}
void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY)
{
@ -494,30 +495,29 @@ void CMinimapInstance::showAll(SDL_Surface * to)
}
}
std::map<Terrain, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors()
std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors()
{
std::map<Terrain, std::pair<SDL_Color, SDL_Color> > ret;
std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > ret;
for(auto & terrain : Terrain::Manager::terrains())
for(const auto & terrain : CGI->terrainTypeHandler->terrains())
{
auto & m = Terrain::Manager::getInfo(terrain);
SDL_Color normal =
{
ui8(m.minimapUnblocked[0]),
ui8(m.minimapUnblocked[1]),
ui8(m.minimapUnblocked[2]),
ui8(terrain.minimapUnblocked[0]),
ui8(terrain.minimapUnblocked[1]),
ui8(terrain.minimapUnblocked[2]),
ui8(255)
};
SDL_Color blocked =
{
ui8(m.minimapBlocked[0]),
ui8(m.minimapBlocked[1]),
ui8(m.minimapBlocked[2]),
ui8(terrain.minimapBlocked[0]),
ui8(terrain.minimapBlocked[1]),
ui8(terrain.minimapBlocked[2]),
ui8(255)
};
ret[terrain] = std::make_pair(normal, blocked);
ret[terrain.id] = std::make_pair(normal, blocked);
}
return ret;
}

View File

@ -222,7 +222,7 @@ protected:
int level;
//to initialize colors
std::map<Terrain, std::pair<SDL_Color, SDL_Color> > loadColors();
std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > loadColors();
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
@ -233,7 +233,7 @@ protected:
public:
// terrainID -> (normal color, blocked color)
const std::map<Terrain, std::pair<SDL_Color, SDL_Color> > colors;
const std::map<TerrainId, std::pair<SDL_Color, SDL_Color> > colors;
CMinimap(const Rect & position);

View File

@ -1413,7 +1413,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, true);
CCS->musich->playMusicFromSet("terrain", tile->terType->name, true);
}
if(centerView)
centerOn(sel);

View File

@ -1,9 +1,4 @@
{
"terrain" :
{
"undergroundAllow" : ["lava"], //others to be replaced by subterranena
"groundProhibit" : ["subterra"] //to be replaced by dirt
},
"waterZone" :
{
"treasure" :

30
config/rivers.json Normal file
View File

@ -0,0 +1,30 @@
{
"waterRiver":
{
"originalRiverId": 1,
"code": "rw", //must be 2 characters
"animation": "clrrvr",
"delta": "clrdelt"
},
"iceRiver":
{
"originalRiverId": 2,
"code": "ri",
"animation": "icyrvr",
"delta": "icedelt"
},
"mudRiver":
{
"originalRiverId": 3,
"code": "rm",
"animation": "mudrvr",
"delta": "muddelt"
},
"lavaRiver":
{
"originalRiverId": 4,
"code": "rl",
"animation": "lavrvr",
"delta": "lavdelt"
}
}

23
config/roads.json Normal file
View File

@ -0,0 +1,23 @@
{
"dirtRoad":
{
"originalRoadId": 1,
"code": "pd", //must be 2 characters
"animation": "dirtrd",
"moveCost": 75
},
"gravelRoad":
{
"originalRoadId": 2,
"code": "pg",
"animation": "gravrd",
"moveCost": 65
},
"cobblestoneRoad":
{
"originalRoadId": 3,
"code": "pc",
"animation": "cobbrd",
"moveCost": 50
}
}

View File

@ -1,6 +1,7 @@
{
"dirt" :
{
"originalTerrainId": 0,
"moveCost" : 100,
"minimapUnblocked" : [ 82, 56, 8 ],
"minimapBlocked" : [ 57, 40, 8 ],
@ -14,6 +15,7 @@
},
"sand" :
{
"originalTerrainId": 1,
"moveCost" : 150,
"minimapUnblocked" : [ 222, 207, 140 ],
"minimapBlocked" : [ 165, 158, 107 ],
@ -28,6 +30,7 @@
},
"grass" :
{
"originalTerrainId": 2,
"moveCost" : 100,
"minimapUnblocked" : [ 0, 65, 0 ],
"minimapBlocked" : [ 0, 48, 0 ],
@ -40,6 +43,7 @@
},
"snow" :
{
"originalTerrainId": 3,
"moveCost" : 150,
"minimapUnblocked" : [ 181, 199, 198 ],
"minimapBlocked" : [ 140, 158, 156 ],
@ -52,6 +56,7 @@
},
"swamp" :
{
"originalTerrainId": 4,
"moveCost" : 175,
"minimapUnblocked" : [ 74, 134, 107 ],
"minimapBlocked" : [ 33, 89, 66 ],
@ -64,6 +69,7 @@
},
"rough" :
{
"originalTerrainId": 5,
"moveCost" : 125,
"minimapUnblocked" : [ 132, 113, 49 ],
"minimapBlocked" : [ 99, 81, 33 ],
@ -76,6 +82,7 @@
},
"subterra" :
{
"originalTerrainId": 6,
"moveCost" : 100,
"minimapUnblocked" : [ 132, 48, 0 ],
"minimapBlocked" : [ 90, 8, 0 ],
@ -90,11 +97,13 @@
},
"lava" :
{
"originalTerrainId": 7,
"moveCost" : 100,
"minimapUnblocked" : [ 74, 73, 74 ],
"minimapBlocked" : [ 41, 40, 41 ],
"music" : "Lava.mp3",
"tiles" : "LAVATL",
"type" : ["SUB", "SURFACE"],
"code" : "lv",
"river" : "rl",
"battleFields" : ["lava"],
@ -103,6 +112,7 @@
},
"water" :
{
"originalTerrainId": 8,
"moveCost" : 100,
"minimapUnblocked" : [ 8, 81, 148 ],
"minimapBlocked" : [ 8, 81, 148 ],
@ -120,6 +130,7 @@
},
"rock" :
{
"originalTerrainId": 9,
"moveCost" : -1,
"minimapUnblocked" : [ 0, 0, 0 ],
"minimapBlocked" : [ 0, 0, 0 ],

View File

@ -285,22 +285,22 @@ std::string CCreature::nodeName() const
return "\"" + namePl + "\"";
}
bool CCreature::isItNativeTerrain(const Terrain & terrain) const
bool CCreature::isItNativeTerrain(TerrainId terrain) const
{
auto native = getNativeTerrain();
return native == terrain || native == Terrain::ANY;
return native == terrain || native == Terrain::ANY_TERRAIN;
}
Terrain CCreature::getNativeTerrain() const
TerrainId CCreature::getNativeTerrain() const
{
const std::string cachingStringBlocksRetaliation = "type_NO_TERRAIN_PENALTY";
static const auto selectorBlocksRetaliation = Selector::type()(Bonus::NO_TERRAIN_PENALTY);
const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY";
static const auto selectorNoTerrainPenalty = Selector::type()(Bonus::NO_TERRAIN_PENALTY);
//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(selectorBlocksRetaliation, selectorBlocksRetaliation)
? Terrain::ANY
: (Terrain)(*VLC->townh)[faction]->nativeTerrain;
return hasBonus(selectorNoTerrainPenalty, selectorNoTerrainPenalty)
? Terrain::ANY_TERRAIN
: (*VLC->townh)[faction]->nativeTerrain;
}
void CCreature::updateFrom(const JsonNode & data)

View File

@ -121,14 +121,14 @@ public:
ArtifactID warMachine;
bool isItNativeTerrain(const Terrain & terrain) const;
bool isItNativeTerrain(TerrainId terrain) const;
/**
Returns creature native terrain considering some terrain bonuses.
@param considerBonus is used to avoid Dead Lock when this method is called inside getAllBonuses
considerBonus = true is called from Pathfinder and fills actual nativeTerrain considering bonus(es).
considerBonus = false is called on Battle init and returns already prepared nativeTerrain without Bonus system calling.
*/
Terrain getNativeTerrain() const;
TerrainId getNativeTerrain() const;
int32_t getIndex() const override;
int32_t getIconIndex() const override;
const std::string & getName() const override;

View File

@ -577,7 +577,7 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
{
const TerrainTile *tile = getTile(t->bestLocation(), false);
if(!tile || tile->terType.isLand())
if(!tile || tile->terType->isLand())
return EBuildingState::NO_WATER; //lack of water
}

View File

@ -966,8 +966,8 @@ void CGameState::initGrailPosition()
const TerrainTile &t = map->getTile(int3(x, y, z));
if(!t.blocked
&& !t.visitable
&& t.terType.isLand()
&& t.terType.isPassable()
&& t.terType->isLand()
&& t.terType->isPassable()
&& (int)map->grailPos.dist2dSQ(int3(x, y, z)) <= (map->grailRadius * map->grailRadius))
allowedPos.push_back(int3(x,y,z));
}
@ -1921,7 +1921,7 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & r
return BattleField::fromString("sand_shore");
return BattleField::fromString(
*RandomGeneratorUtil::nextItem(Terrain::Manager::getInfo(t.terType).battleFields, rand));
*RandomGeneratorUtil::nextItem(t.terType->battleFields, rand));
}
UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
@ -2103,7 +2103,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->id;
break;
}

View File

@ -338,12 +338,12 @@ CGeneralTextHandler::CGeneralTextHandler()
for(int i = 0; i < h3mTerrainNames.size(); ++i)
{
terrainNames[Terrain::createTerrainTypeH3M(i)] = h3mTerrainNames[i];
terrainNames[i] = h3mTerrainNames[i];
}
for(auto & terrain : Terrain::Manager::terrains())
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(!Terrain::Manager::getInfo(terrain).terrainText.empty())
terrainNames[terrain] = Terrain::Manager::getInfo(terrain).terrainText;
if(!terrain.terrainText.empty())
terrainNames[terrain.id] = terrain.terrainText;
}

View File

@ -124,7 +124,7 @@ public:
std::vector<std::string> advobtxt;
std::vector<std::string> xtrainfo;
std::vector<std::string> restypes; //names of resources
std::map<std::string, std::string> terrainNames;
std::map<TerrainId, std::string> terrainNames;
std::vector<std::string> randsign;
std::vector<std::pair<std::string,std::string>> mines; //first - name; second - event description
std::vector<std::string> seerEmpty;

View File

@ -346,9 +346,9 @@ CHeroHandler::~CHeroHandler() = default;
CHeroHandler::CHeroHandler()
{
loadTerrains();
for(int i = 0; i < Terrain::Manager::terrains().size(); ++i)
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
VLC->modh->identifiers.registerObject("core", "terrain", Terrain::Manager::terrains()[i], i);
VLC->modh->identifiers.registerObject("core", "terrain", terrain.name, terrain.id);
}
loadBallistics();
loadExperience();
@ -974,9 +974,9 @@ ui64 CHeroHandler::reqExp (ui32 level) const
void CHeroHandler::loadTerrains()
{
for(auto & terrain : Terrain::Manager::terrains())
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
terrCosts[terrain] = Terrain::Manager::getInfo(terrain).moveCost;
terrCosts[terrain.id] = terrain.moveCost;
}
}

View File

@ -266,7 +266,7 @@ public:
CHeroClassHandler classes;
//default costs of going through terrains. -1 means terrain is impassable
std::map<Terrain, int> terrCosts;
std::map<TerrainId, int> terrCosts;
struct SBallisticsLevelInfo
{

View File

@ -47,8 +47,8 @@ void NodeStorage::initialize(const PathfinderOptions & options, const CGameState
{
for(pos.y=0; pos.y < sizes.y; ++pos.y)
{
const TerrainTile * tile = &gs->map->getTile(pos);
if(tile->terType.isWater())
const TerrainTile tile = gs->map->getTile(pos);
if(tile.terType->isWater())
{
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if(useFlying)
@ -56,7 +56,7 @@ void NodeStorage::initialize(const PathfinderOptions & options, const CGameState
if(useWaterWalking)
resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
}
if(tile->terType.isLand())
if(tile.terType->isLand())
{
resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
if(useFlying)
@ -1010,10 +1010,10 @@ bool CPathfinderHelper::passOneTurnLimitCheck(const PathNodeInfo & source) const
TurnInfo::BonusCache::BonusCache(TConstBonusListPtr bl)
{
for(int i = 0; i < Terrain::Manager::terrains().size(); ++i)
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
noTerrainPenalty.push_back(static_cast<bool>(
bl->getFirst(Selector::type()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(i)))));
bl->getFirst(Selector::type()(Bonus::NO_TERRAIN_PENALTY).And(Selector::subtype()(terrain.id)))));
}
freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(Bonus::FREE_SHIP_BOARDING)));
@ -1180,7 +1180,7 @@ void CPathfinderHelper::getNeighbours(
continue;
const TerrainTile & hlpt = map->getTile(hlp);
if(!hlpt.terType.isPassable())
if(!hlpt.terType->isPassable())
continue;
// //we cannot visit things from blocked tiles
@ -1190,18 +1190,18 @@ void CPathfinderHelper::getNeighbours(
// }
/// Following condition let us avoid diagonal movement over coast when sailing
if(srct.terType.isWater() && limitCoastSailing && hlpt.terType.isWater() && dir.x && dir.y) //diagonal move through water
if(srct.terType->isWater() && limitCoastSailing && hlpt.terType->isWater() && dir.x && dir.y) //diagonal move through water
{
int3 hlp1 = tile,
hlp2 = tile;
hlp1.x += dir.x;
hlp2.y += dir.y;
if(map->getTile(hlp1).terType.isLand() || map->getTile(hlp2).terType.isLand())
if(map->getTile(hlp1).terType->isLand() || map->getTile(hlp2).terType->isLand())
continue;
}
if(indeterminate(onLand) || onLand == hlpt.terType.isLand())
if(indeterminate(onLand) || onLand == hlpt.terType->isLand())
{
vec.push_back(hlp);
}
@ -1239,7 +1239,7 @@ int CPathfinderHelper::getMovementCost(
{
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::FLYING_MOVEMENT)) / 100.0);
}
else if(dt->terType.isWater())
else if(dt->terType->isWater())
{
if(hero->boat && ct->hasFavorableWinds() && dt->hasFavorableWinds())
ret = static_cast<int>(ret * 0.666);
@ -1267,7 +1267,7 @@ int CPathfinderHelper::getMovementCost(
{
std::vector<int3> vec;
vec.reserve(8); //optimization
getNeighbours(*dt, dst, vec, ct->terType.isLand(), true);
getNeighbours(*dt, dst, vec, ct->terType->isLand(), true);
for(auto & elem : vec)
{
int fcost = getMovementCost(dst, elem, nullptr, nullptr, left, false);

View File

@ -529,7 +529,7 @@ struct DLL_LINKAGE TurnInfo
TConstBonusListPtr bonuses;
mutable int maxMovePointsLand;
mutable int maxMovePointsWater;
Terrain nativeTerrain;
TerrainId nativeTerrain;
TurnInfo(const CGHeroInstance * Hero, const int Turn = 0);
bool isLayerAvailable(const EPathfindingLayer layer) const;

View File

@ -331,11 +331,11 @@ bool CStack::canBeHealed() const
bool CStack::isOnNativeTerrain() const
{
//this code is called from CreatureTerrainLimiter::limit on battle start
auto res = nativeTerrain == Terrain::ANY || nativeTerrain == battle->getTerrainType();
auto res = nativeTerrain == Terrain::ANY_TERRAIN || nativeTerrain == battle->getTerrainType();
return res;
}
bool CStack::isOnTerrain(const Terrain & terrain) const
bool CStack::isOnTerrain(TerrainId terrain) const
{
return battle->getTerrainType() == terrain;
}

View File

@ -31,7 +31,7 @@ public:
ui32 ID; //unique ID of stack
const CCreature * type;
Terrain nativeTerrain; //tmp variable to save native terrain value on battle init
TerrainId nativeTerrain; //tmp variable to save native terrain value on battle init
ui32 baseAmount;
PlayerColor owner; //owner - player color (255 for neutrals)
@ -53,7 +53,7 @@ public:
bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines
bool isOnNativeTerrain() const;
bool isOnTerrain(const Terrain & terrain) const;
bool isOnTerrain(TerrainId terrain) const;
ui32 level() const;
si32 magicResistance() const override; //include aura of resistance

View File

@ -28,9 +28,9 @@ 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 Terrain CTownHandler::defaultGoodTerrain{"grass"};
const Terrain CTownHandler::defaultEvilTerrain{"lava"};
const Terrain CTownHandler::defaultNeutralTerrain{"rough"};
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 =
{
@ -944,9 +944,9 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES);
}
Terrain CTownHandler::getDefaultTerrainForAlignment(EAlignment::EAlignment alignment) const
TerrainId CTownHandler::getDefaultTerrainForAlignment(EAlignment::EAlignment alignment) const
{
Terrain terrain = defaultGoodTerrain;
TerrainId terrain = defaultGoodTerrain;
switch(alignment)
{
@ -985,7 +985,7 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
auto nativeTerrain = source["nativeTerrain"];
faction->nativeTerrain = nativeTerrain.isNull()
? getDefaultTerrainForAlignment(faction->alignment)
: Terrain(nativeTerrain.String());
: VLC->terrainTypeHandler->getInfoByName(nativeTerrain.String())->id;
if (!source["town"].isNull())
{

View File

@ -187,7 +187,7 @@ public:
TFaction index;
Terrain nativeTerrain;
TerrainId nativeTerrain;
EAlignment::EAlignment alignment;
bool preferUndergroundPlacement;
@ -360,9 +360,9 @@ 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 Terrain defaultGoodTerrain;
const static Terrain defaultEvilTerrain;
const static Terrain defaultNeutralTerrain;
const static TerrainId defaultGoodTerrain;
const static TerrainId defaultEvilTerrain;
const static TerrainId defaultNeutralTerrain;
static TPropagatorPtr & emptyPropagator();
@ -393,7 +393,7 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
void loadPuzzle(CFaction & faction, const JsonNode & source);
Terrain getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
TerrainId getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
void loadRandomFaction();

View File

@ -681,10 +681,6 @@ enum class ETeleportChannelType
MIXED
};
static std::vector<std::string> RIVER_NAMES {"", "rw", "ri", "rm", "rl"};
static std::vector<std::string> ROAD_NAMES {"", "pd", "pg", "pc"};
class Obj
{
public:
@ -837,6 +833,56 @@ public:
ID_LIKE_OPERATORS(Obj, Obj::EObj)
namespace Terrain
{
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
};
}
namespace Road
{
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
};
}
namespace SecSkillLevel
{
enum SecSkillLevel
@ -1188,6 +1234,9 @@ 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;

View File

@ -2109,9 +2109,13 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
}
CreatureTerrainLimiter::CreatureTerrainLimiter()
: terrainType()
: terrainType(Terrain::NATIVE_TERRAIN)
{
}
CreatureTerrainLimiter::CreatureTerrainLimiter(TerrainId terrain):
terrainType(terrain)
{
}
int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
@ -2119,10 +2123,15 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
const CStack *stack = retrieveStackBattle(&context.node);
if(stack)
{
if(terrainType.isNative())//terrainType not specified = native
if (terrainType == Terrain::NATIVE_TERRAIN)//terrainType not specified = native
{
return !stack->isOnNativeTerrain();
}
else
{
return !stack->isOnTerrain(terrainType);
}
}
return true;
//TODO neutral creatues
}
@ -2130,7 +2139,8 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
std::string CreatureTerrainLimiter::toString() const
{
boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
fmt % (terrainType.isNative() ? "native" : static_cast<std::string>(terrainType));
auto terrainName = VLC->terrainTypeHandler->terrains()[terrainType].name;
fmt % (terrainType == Terrain::NATIVE_TERRAIN ? "native" : terrainName);
return fmt.str();
}
@ -2139,8 +2149,8 @@ JsonNode CreatureTerrainLimiter::toJsonNode() const
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
root["type"].String() = "CREATURE_TERRAIN_LIMITER";
if(!terrainType.isNative())
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainType));
auto terrainName = VLC->terrainTypeHandler->terrains()[terrainType].name;
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainName));
return root;
}

View File

@ -1062,9 +1062,9 @@ public:
class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain
{
public:
Terrain terrainType;
TerrainId terrainType;
CreatureTerrainLimiter();
CreatureTerrainLimiter(const Terrain& terrain);
CreatureTerrainLimiter(TerrainId terrain);
int limit(const BonusLimitationContext &context) const override;
virtual std::string toString() const override;

View File

@ -52,7 +52,7 @@ void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
for (int yd = 0; yd < gs->map->height; yd++)
{
tinfo = getTile(int3 (xd,yd,zd));
if (tinfo->terType.isLand() && tinfo->terType.isPassable() && !tinfo->blocked) //land and free
if (tinfo->terType->isLand() && tinfo->terType->isPassable() && !tinfo->blocked) //land and free
tiles.push_back (int3 (xd,yd,zd));
}
}
@ -119,8 +119,8 @@ void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3, ShashInt3> &
{
for (int yd = 0; yd < gs->map->height; yd++)
{
if ((getTile (int3 (xd,yd,zd))->terType.isWater() && water)
|| (getTile (int3 (xd,yd,zd))->terType.isLand() && land))
if ((getTile (int3 (xd,yd,zd))->terType->isWater() && water)
|| (getTile (int3 (xd,yd,zd))->terType->isLand() && land))
tiles.insert(int3(xd,yd,zd));
}
}

View File

@ -703,13 +703,13 @@ DLL_LINKAGE void GiveHero::applyGs(CGameState *gs)
DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
{
Terrain terrainType;
TerrainId terrainType = Terrain::BORDER;
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(Terrain::WATER).front();
const int3 previousXAxisTile = int3(pos.x - 1, pos.y, pos.z);
assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile));
@ -718,7 +718,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
else
{
const TerrainTile & t = gs->map->getTile(pos);
terrainType = t.terType;
terrainType = t.terType->id;
}
CGObjectInstance *o = nullptr;
@ -726,7 +726,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 = Terrain::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

@ -68,7 +68,7 @@ std::vector<BattleHex> ObstacleInfo::getBlocked(BattleHex hex) const
return ret;
}
bool ObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & battlefield) const
bool ObstacleInfo::isAppropriate(const TerrainId terrainType, const BattleField & battlefield) const
{
auto bgInfo = battlefield.getInfo();
@ -86,7 +86,7 @@ ObstacleInfo * ObstacleHandler::loadFromJson(const std::string & scope, const Js
info->width = json["width"].Integer();
info->height = json["height"].Integer();
for(auto & t : json["allowedTerrain"].Vector())
info->allowedTerrains.emplace_back(t.String());
info->allowedTerrains.emplace_back(VLC->terrainTypeHandler->getInfoByName(t.String())->id);
for(auto & t : json["specialBattlefields"].Vector())
info->allowedSpecialBfields.emplace_back(t.String());
info->blockedTiles = json["blockedTiles"].convertTo<std::vector<si16>>();

View File

@ -33,7 +33,7 @@ public:
si32 iconIndex;
std::string identifier;
std::string appearAnimation, animation, dissapearAnimation;
std::vector<Terrain> allowedTerrains;
std::vector<TerrainId> allowedTerrains;
std::vector<std::string> allowedSpecialBfields;
//TODO: here is extra field to implement it's logic in the future but save backward compatibility
@ -52,7 +52,7 @@ public:
std::vector<BattleHex> getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
bool isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const;
bool isAppropriate(const TerrainId terrainType, const BattleField & specialBattlefield) const;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -20,7 +20,7 @@ namespace PathfinderUtil
using ELayer = EPathfindingLayer;
template<EPathfindingLayer::EEPathfindingLayer layer>
CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile * tinfo, FoW fow, const PlayerColor player, const CGameState * gs)
CGPathNode::EAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile & tinfo, FoW fow, const PlayerColor player, const CGameState * gs)
{
if(!(*fow)[pos.z][pos.x][pos.y])
return CGPathNode::BLOCKED;
@ -29,15 +29,15 @@ namespace PathfinderUtil
{
case ELayer::LAND:
case ELayer::SAIL:
if(tinfo->visitable)
if(tinfo.visitable)
{
if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != player) //non-owned hero stands on Sanctuary
if(tinfo.visitableObjects.front()->ID == Obj::SANCTUARY && tinfo.visitableObjects.back()->ID == Obj::HERO && tinfo.visitableObjects.back()->tempOwner != player) //non-owned hero stands on Sanctuary
{
return CGPathNode::BLOCKED;
}
else
{
for(const CGObjectInstance * obj : tinfo->visitableObjects)
for(const CGObjectInstance * obj : tinfo.visitableObjects)
{
if(obj->blockVisit)
return CGPathNode::BLOCKVIS;
@ -48,7 +48,7 @@ namespace PathfinderUtil
}
}
}
else if(tinfo->blocked)
else if(tinfo.blocked)
{
return CGPathNode::BLOCKED;
}
@ -61,13 +61,13 @@ namespace PathfinderUtil
break;
case ELayer::WATER:
if(tinfo->blocked || tinfo->terType.isLand())
if(tinfo.blocked || tinfo.terType->isLand())
return CGPathNode::BLOCKED;
break;
case ELayer::AIR:
if(tinfo->blocked || tinfo->terType.isLand())
if(tinfo.blocked || tinfo.terType->isLand())
return CGPathNode::FLYABLE;
break;

View File

@ -19,31 +19,24 @@ VCMI_LIB_NAMESPACE_BEGIN
//("allowedTerrain"\s*:\s*\[.*)9(.*\],\n)
//\1"rock"\2
const Terrain Terrain::ANY("ANY");
Terrain Terrain::createTerrainTypeH3M(int tId)
{
static std::array<std::string, 10> terrainsH3M
{
"dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
};
return Terrain(terrainsH3M.at(tId));
}
Terrain Terrain::createTerrainByCode(const std::string & typeCode)
{
for(const auto & terrain : Manager::terrains())
{
if(Manager::getInfo(terrain).typeCode == typeCode)
return terrain;
}
return Terrain::ANY;
}
Terrain::Manager::Manager()
TerrainTypeHandler::TerrainTypeHandler()
{
auto allConfigs = VLC->modh->getActiveMods();
allConfigs.insert(allConfigs.begin(), "core");
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")))
@ -52,8 +45,9 @@ Terrain::Manager::Manager()
JsonNode terrs(mod, ResourceID("config/terrains.json"));
for(auto & terr : terrs.Struct())
{
Terrain::Info info;
info.moveCost = terr.second["moveCost"].Integer();
TerrainType info(terr.first); //set name
info.moveCost = static_cast<int>(terr.second["moveCost"].Integer());
const JsonVector &unblockedVec = terr.second["minimapUnblocked"].Vector();
info.minimapUnblocked =
{
@ -74,42 +68,47 @@ Terrain::Manager::Manager()
if(terr.second["type"].isNull())
{
info.type = Terrain::Info::Type::Land;
info.passabilityType = TerrainType::PassabilityType::LAND | TerrainType::PassabilityType::SURFACE;
}
else
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.type = Terrain::Info::Type::Land;
if(s == "WATER") info.type = Terrain::Info::Type::Water;
if(s == "ROCK") info.type = Terrain::Info::Type::Rock;
if(s == "SUB") info.type = Terrain::Info::Type::Subterranean;
}
if(terr.second["rockTerrain"].isNull())
{
info.rockTerrain = "rock";
}
else
{
info.rockTerrain = terr.second["rockTerrain"].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_NAMES[0];
info.river = River::NO_RIVER;
}
else
{
info.river = terr.second["river"].String();
info.river = getRiverByCode(terr.second["river"].String())->id;
}
if(terr.second["horseSoundId"].isNull())
{
info.horseSoundId = 9; //rock sound as default
info.horseSoundId = Terrain::ROCK; //rock sound as default
}
else
{
info.horseSoundId = terr.second["horseSoundId"].Integer();
info.horseSoundId = static_cast<int>(terr.second["horseSoundId"].Float());
}
if(!terr.second["text"].isNull())
@ -135,14 +134,6 @@ Terrain::Manager::Manager()
}
}
if(!terr.second["prohibitTransitions"].isNull())
{
for(auto & t : terr.second["prohibitTransitions"].Vector())
{
info.prohibitTransitions.emplace_back(t.String());
}
}
info.transitionRequired = false;
if(!terr.second["transitionRequired"].isNull())
{
@ -155,103 +146,360 @@ Terrain::Manager::Manager()
info.terrainViewPatterns = terr.second["terrainViewPatterns"].String();
}
terrainInfo[terr.first] = info;
if(!terrainId.count(terr.first))
if(!terr.second["originalTerrainId"].isNull())
{
terrainId[terr.first] = terrainVault.size();
terrainVault.push_back(terr.first);
//place in reserved slot
info.id = (TerrainId)(terr.second["originalTerrainId"].Float());
objects[info.id] = info;
}
}
}
}
Terrain::Manager & Terrain::Manager::get()
else
{
static Terrain::Manager manager;
return manager;
//append at the end
info.id = static_cast<TerrainId>(objects.size());
objects.push_back(info);
}
TerrainId id = info.id;
const std::vector<Terrain> & Terrain::Manager::terrains()
//Update terrain with this id in the future, after all terrain types are populated
if(!terr.second["prohibitTransitions"].isNull())
{
return Terrain::Manager::get().terrainVault;
}
int Terrain::Manager::id(const Terrain & terrain)
for(auto & t : terr.second["prohibitTransitions"].Vector())
{
if(terrain.name == "ANY") return -3;
if(terrain.name == "WRONG") return -2;
if(terrain.name == "BORDER") return -1;
return Terrain::Manager::get().terrainId.at(terrain);
}
const Terrain::Info & Terrain::Manager::getInfo(const Terrain & terrain)
std::string prohibitedTerrainName = t.String();
resolveLater.push_back([this, prohibitedTerrainName, id]()
{
return Terrain::Manager::get().terrainInfo.at(static_cast<std::string>(terrain));
//FIXME: is that reference to the element in vector?
objects[id].prohibitTransitions.emplace_back(getInfoByName(prohibitedTerrainName)->id);
});
}
}
std::ostream & operator<<(std::ostream & os, const Terrain terrainType)
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.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.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->fileName] = 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->fileName] = 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);
}
Terrain::operator std::string() const
TerrainType::operator std::string() const
{
return name;
}
Terrain::Terrain(const std::string & _name) : name(_name)
{}
Terrain& Terrain::operator=(const std::string & _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)
{
name = _name;
}
TerrainType& TerrainType::operator=(const TerrainType & other)
{
battleFields = other.battleFields;
prohibitTransitions = other.prohibitTransitions;
minimapBlocked = other.minimapBlocked;
minimapUnblocked = other.minimapUnblocked;
name = other.name;
musicFilename = other.musicFilename;
tilesFilename = other.tilesFilename;
terrainText = other.terrainText;
typeCode = other.typeCode;
terrainViewPatterns = other.terrainViewPatterns;
rockTerrain = other.rockTerrain;
river = other.river;
id = other.id;
moveCost = other.moveCost;
horseSoundId = other.horseSoundId;
passabilityType = other.passabilityType;
transitionRequired = other.transitionRequired;
return *this;
}
bool operator==(const Terrain & l, const Terrain & r)
bool TerrainType::operator==(const TerrainType& other)
{
return l.name == r.name;
return id == other.id;
}
bool operator!=(const Terrain & l, const Terrain & r)
bool TerrainType::operator!=(const TerrainType& other)
{
return l.name != r.name;
return id != other.id;
}
bool operator<(const Terrain & l, const Terrain & r)
bool TerrainType::operator<(const TerrainType& other)
{
return l.name < r.name;
return id < other.id;
}
int Terrain::id() const
{
return Terrain::Manager::id(*this);
}
bool Terrain::isLand() const
bool TerrainType::isLand() const
{
return !isWater();
}
bool Terrain::isWater() const
bool TerrainType::isWater() const
{
return Terrain::Manager::getInfo(*this).type == Terrain::Info::Type::Water;
return passabilityType & PassabilityType::WATER;
}
bool Terrain::isPassable() const
bool TerrainType::isPassable() const
{
return Terrain::Manager::getInfo(*this).type != Terrain::Info::Type::Rock;
return !(passabilityType & PassabilityType::ROCK);
}
bool Terrain::isUnderground() const
bool TerrainType::isSurface() const
{
return Terrain::Manager::getInfo(*this).type == Terrain::Info::Type::Subterranean;
return passabilityType & PassabilityType::SURFACE;
}
bool Terrain::isNative() const
bool TerrainType::isUnderground() const
{
return name.empty();
return passabilityType & PassabilityType::SUBTERRANEAN;
}
bool Terrain::isTransitionRequired() const
bool TerrainType::isTransitionRequired() const
{
return Terrain::Manager::getInfo(*this).transitionRequired;
return transitionRequired;
}
RiverType::RiverType(const std::string & fileName, const std::string & code, RiverId id):
fileName(fileName),
code(code),
id(id)
{
}
RiverType& RiverType::operator=(const RiverType& other)
{
fileName = other.fileName;
code = other.code;
deltaName = other.deltaName;
id = other.id;
return *this;
}
RoadType::RoadType(const std::string& fileName, const std::string& code, RoadId id):
fileName(fileName),
code(code),
id(id),
movementCost(GameConstants::BASE_MOVEMENT_COST)
{
}
RoadType& RoadType::operator=(const RoadType& other)
{
fileName = other.fileName;
code = other.code;
id = other.id;
movementCost = other.movementCost;
return *this;
}
VCMI_LIB_NAMESPACE_END

View File

@ -16,93 +16,184 @@
VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE Terrain
class DLL_LINKAGE TerrainType
{
public:
friend class Manager;
struct Info
enum PassabilityType : ui8
{
enum class Type
{
Land, Water, Subterranean, Rock
LAND = 1,
WATER = 2,
SURFACE = 4,
SUBTERRANEAN = 8,
ROCK = 16
};
int moveCost;
bool transitionRequired;
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;
std::string rockTerrain;
std::string river;
RiverId river;
TerrainId id;
TerrainId rockTerrain;
int moveCost;
int horseSoundId;
Type type;
std::vector<std::string> battleFields;
std::vector<Terrain> prohibitTransitions;
};
ui8 passabilityType;
bool transitionRequired;
class DLL_LINKAGE Manager
{
public:
static const std::vector<Terrain> & terrains();
static const Info & getInfo(const Terrain &);
static int id(const Terrain &);
TerrainType(const std::string & name = "");
private:
static Manager & get();
Manager();
TerrainType& operator=(const TerrainType & other);
std::unordered_map<std::string, Info> terrainInfo;
std::vector<Terrain> terrainVault;
std::map<Terrain, int> terrainId;
};
/*enum EETerrainType
{
ANY_TERRAIN = -3,
WRONG = -2, BORDER = -1, DIRT, SAND, GRASS, SNOW, SWAMP,
ROUGH, SUBTERRANEAN, LAVA, WATER, ROCK // ROCK is also intended to be max value.
};*/
Terrain(const std::string & _type = "");
static Terrain createTerrainTypeH3M(int tId);
static Terrain createTerrainByCode(const std::string & typeCode);
int id() const; //TODO: has to be completely removed
Terrain& operator=(const std::string & _type);
DLL_LINKAGE friend bool operator==(const Terrain & l, const Terrain & r);
DLL_LINKAGE friend bool operator!=(const Terrain & l, const Terrain & r);
DLL_LINKAGE friend bool operator<(const Terrain & l, const Terrain & r);
static const Terrain ANY;
bool operator==(const TerrainType & other);
bool operator!=(const TerrainType & other);
bool operator<(const TerrainType & other);
bool isLand() const;
bool isWater() const;
bool isPassable() const; //ROCK
bool isPassable() const;
bool isSurface() const;
bool isUnderground() const;
bool isNative() const;
bool isTransitionRequired() 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;
}
protected:
std::string name;
};
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const Terrain terrainType);
class DLL_LINKAGE RiverType
{
public:
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);
RiverType& operator=(const RiverType & other);
template <typename Handler> void serialize(Handler& h, const int version)
{
h & fileName;
h & code;
h & deltaName;
h & id;
}
};
class DLL_LINKAGE RoadType
{
public:
std::string fileName;
std::string code;
RoadId id;
ui8 movementCost;
RoadType(const std::string & fileName = "", const std::string& code = "", RoadId id = Road::NO_ROAD);
RoadType& operator=(const RoadType & other);
template <typename Handler> void serialize(Handler& h, const int version)
{
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

View File

@ -197,6 +197,8 @@ void LibClasses::init(bool onlyEssential)
createHandler(bth, "Bonus type", pomtime);
createHandler(terrainTypeHandler, "Terrain", pomtime);
createHandler(generaltexth, "General text", pomtime);
createHandler(heroh, "Hero", pomtime);

View File

@ -29,6 +29,7 @@ class CContentHandler;
class BattleFieldHandler;
class IBonusTypeHandler;
class CBonusTypeHandler;
class TerrainTypeHandler;
class ObstacleHandler;
class CTerrainViewPatternConfig;
class CRmgTemplateStorage;
@ -85,6 +86,7 @@ public:
CTownHandler * townh;
CGeneralTextHandler * generaltexth;
CModHandler * modh;
TerrainTypeHandler * terrainTypeHandler;
CTerrainViewPatternConfig * terviewh;
CRmgTemplateStorage * tplh;
BattleFieldHandler * battlefieldsHandler;
@ -125,6 +127,7 @@ public:
h & skillh;
h & battlefieldsHandler;
h & obstacleHandler;
h & terrainTypeHandler;
if(!h.saving)
{

View File

@ -191,7 +191,7 @@ struct RangeGenerator
std::function<int()> myRand;
};
BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
{
CMP_stack cmpst;
auto curB = new BattleInfo();
@ -565,7 +565,7 @@ BattleField BattleInfo::getBattlefieldType() const
return battlefieldType;
}
Terrain BattleInfo::getTerrainType() const
TerrainId BattleInfo::getTerrainType() const
{
return terrainType;
}

View File

@ -20,7 +20,6 @@ VCMI_LIB_NAMESPACE_BEGIN
class CStack;
class CStackInstance;
class CStackBasicDescriptor;
class Terrain;
class BattleField;
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
@ -40,7 +39,7 @@ public:
SiegeInfo si;
BattleField battlefieldType; //like !!BA:B
Terrain terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy)
TerrainId terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy)
ui8 tacticsSide; //which side is requested to play tactics phase
ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
@ -76,7 +75,7 @@ public:
battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
BattleField getBattlefieldType() const override;
Terrain getTerrainType() const override;
TerrainId getTerrainType() const override;
ObstacleCList getAllObstacles() const override;
@ -141,7 +140,7 @@ public:
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
void localInit();
static BattleInfo * setupBattle(const int3 & tile, const Terrain & terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
static BattleInfo * setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
ui8 whatSide(PlayerColor player) const;

View File

@ -49,7 +49,7 @@ BattleField BattleProxy::getBattlefieldType() const
return subject->battleGetBattlefieldType();
}
Terrain BattleProxy::getTerrainType() const
TerrainId BattleProxy::getTerrainType() const
{
return subject->battleTerrainType();
}

View File

@ -32,7 +32,7 @@ public:
battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
BattleField getBattlefieldType() const override;
Terrain getTerrainType() const override;
TerrainId getTerrainType() const override;
ObstacleCList getAllObstacles() const override;

View File

@ -16,9 +16,9 @@
VCMI_LIB_NAMESPACE_BEGIN
Terrain CBattleInfoEssentials::battleTerrainType() const
TerrainId CBattleInfoEssentials::battleTerrainType() const
{
RETURN_IF_NOT_BATTLE(Terrain());
RETURN_IF_NOT_BATTLE(TerrainId());
return getBattle()->getTerrainType();
}

View File

@ -48,7 +48,7 @@ public:
BattlePerspective::BattlePerspective battleGetMySide() const;
const IBonusBearer * getBattleNode() const;
Terrain battleTerrainType() const override;
TerrainId battleTerrainType() const override;
BattleField battleGetBattlefieldType() const override;
int32_t battleGetEnchanterCounter(ui8 side) const;

View File

@ -10,13 +10,13 @@
#pragma once
#include "GameConstants.h"
#include "BattleHex.h"
VCMI_LIB_NAMESPACE_BEGIN
struct CObstacleInstance;
class BattleField;
class Terrain;
namespace battle
{
@ -40,7 +40,7 @@ public:
virtual scripting::Pool * getContextPool() const = 0;
#endif
virtual Terrain battleTerrainType() const = 0;
virtual TerrainId battleTerrainType() const = 0;
virtual BattleField battleGetBattlefieldType() const = 0;
///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw

View File

@ -44,7 +44,7 @@ public:
virtual battle::Units getUnitsIf(battle::UnitFilter predicate) const = 0;
virtual BattleField getBattlefieldType() const = 0;
virtual Terrain getTerrainType() const = 0;
virtual TerrainId getTerrainType() const = 0;
virtual ObstacleCList getAllObstacles() const = 0;

View File

@ -81,32 +81,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 != ROAD_NAMES[0] && from.roadType != ROAD_NAMES[0])
if(dest.roadType->id && from.roadType->id)
{
int roadPos = std::min(vstd::find_pos(ROAD_NAMES, dest.roadType), vstd::find_pos(ROAD_NAMES, from.roadType)); //used road ID
switch(roadPos)
{
case 1:
ret = 75;
break;
case 2:
ret = 65;
break;
case 3:
ret = 50;
break;
default:
logGlobal->error("Unknown road type: %d", roadPos);
break;
ret = std::max(dest.roadType->movementCost, from.roadType->movementCost);
}
}
else if(ti->nativeTerrain != from.terType //the terrain is not native
&& ti->nativeTerrain != Terrain::ANY //no special creature bonus
&& !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType.id()) //no special movement bonus
)
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
{
ret = VLC->heroh->terrCosts[from.terType];
ret = VLC->heroh->terrCosts[from.terType->id];
ret -= ti->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING);
if(ret < GameConstants::BASE_MOVEMENT_COST)
ret = GameConstants::BASE_MOVEMENT_COST;
@ -114,7 +98,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
return (ui32)ret;
}
Terrain CGHeroInstance::getNativeTerrain() const
TerrainId CGHeroInstance::getNativeTerrain() const
{
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
// This is clearly bug in H3 however intended behaviour is not clear.
@ -122,18 +106,18 @@ Terrain CGHeroInstance::getNativeTerrain() const
// will always have best penalty without any influence from player-defined stacks order
// TODO: What should we do if all hero stacks are neutral creatures?
Terrain nativeTerrain("BORDER");
TerrainId nativeTerrain = Terrain::BORDER;
for(auto stack : stacks)
{
Terrain stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
TerrainId stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
if(stackNativeTerrain == Terrain("BORDER"))
if(stackNativeTerrain == Terrain::BORDER) //where does this value come from?
continue;
if(nativeTerrain == Terrain("BORDER"))
if(nativeTerrain == Terrain::BORDER)
nativeTerrain = stackNativeTerrain;
else if(nativeTerrain != stackNativeTerrain)
return Terrain("BORDER");
return Terrain::BORDER;
}
return nativeTerrain;
}
@ -531,7 +515,8 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
if (ID != Obj::PRISON)
{
auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
auto terrain = cb->gameState()->getTile(visitablePos())->terType->id;
auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(terrain, this);
if (customApp)
appearance = customApp;
}

View File

@ -157,7 +157,7 @@ public:
bool needsLastStack()const override;
ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
Terrain getNativeTerrain() const;
TerrainId getNativeTerrain() const;
ui32 getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day

View File

@ -1132,8 +1132,9 @@ void CGTownInstance::setType(si32 ID, si32 subID)
void CGTownInstance::updateAppearance()
{
auto terrain = cb->gameState()->getTile(visitablePos())->terType->id;
//FIXME: not the best way to do this
auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(terrain, this);
if (app)
appearance = app;
}

View File

@ -493,9 +493,16 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
tmpl->id = Obj(type);
tmpl->subid = subtype;
tmpl->stringID = entry.first; // FIXME: create "fullID" - type.object.template?
try
{
tmpl->readJson(entry.second);
templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl));
}
catch (const std::exception & e)
{
logGlobal->warn("Failed to load terrains for object %s: %s", entry.first, e.what());
}
}
if (input["name"].isNull())
objectName = name;
@ -583,7 +590,7 @@ BattleField AObjectTypeHandler::getBattlefield() const
return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE;
}
std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplates(TerrainId terrainType) const
{
std::vector<std::shared_ptr<const ObjectTemplate>> templates = getTemplates();
std::vector<std::shared_ptr<const ObjectTemplate>> filtered;
@ -600,7 +607,7 @@ std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplat
return filtered;
}
std::shared_ptr<const ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
std::shared_ptr<const ObjectTemplate> AObjectTypeHandler::getOverride(TerrainId terrainType, const CGObjectInstance * object) const
{
std::vector<std::shared_ptr<const ObjectTemplate>> ret = getTemplates(terrainType);
for (const auto & tmpl: ret)

View File

@ -184,11 +184,11 @@ public:
/// returns all templates matching parameters
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const;
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates(const Terrain & terrainType) const;
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates(const TerrainId terrainType) const;
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
std::shared_ptr<const ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
std::shared_ptr<const ObjectTemplate> getOverride(TerrainId terrainType, const CGObjectInstance * object) const;
BattleField getBattlefield() const;

View File

@ -208,8 +208,8 @@ 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).empty())
appearance = handler->getTemplates(tile.terType)[0];
if(!handler->getTemplates(tile.terType->id).empty())
appearance = handler->getTemplates(tile.terType->id)[0];
else
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
if (ID == Obj::HERO)
@ -436,7 +436,7 @@ int3 IBoatGenerator::bestLocation() const
{
if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
{
if(tile->terType.isWater() && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
if(tile->terType->isWater() && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
return o->pos + offset;
}
}

View File

@ -80,7 +80,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, object);
auto templ = getOverride(object->cb->getTile(object->pos)->terType->id, object);
if(templ)
object->appearance = templ;
}

View File

@ -157,20 +157,20 @@ 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() == 9); // all terrains but rock
for(size_t i = 0; i < 9; i++)
assert(terrStr.size() == Terrain::ROCK - 1); // all terrains but rock
for(TerrainId i = Terrain::FIRST_REGULAR_TERRAIN; i < Terrain::ROCK; i++)
{
if (terrStr[8-i] == '1')
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
allowedTerrains.insert(i);
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain("water")))
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain::WATER))
{
for(auto & terrain : Terrain::Manager::terrains())
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain);
allowedTerrains.insert(terrain.id);
}
}
@ -231,19 +231,19 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
reader.readUInt16();
ui16 terrMask = reader.readUInt16();
for(size_t i = 0; i < 9; i++)
for(size_t i = Terrain::FIRST_REGULAR_TERRAIN; i < Terrain::ROCK; i++)
{
if (((terrMask >> i) & 1 ) != 0)
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
allowedTerrains.insert(i);
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain("water")))
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain::WATER))
{
for(auto & terrain : Terrain::Manager::terrains())
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain);
allowedTerrains.insert(terrain.id);
}
}
@ -287,22 +287,21 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
if(withTerrain && !node["allowedTerrains"].isNull())
{
for(auto& entry : node["allowedTerrains"].Vector())
allowedTerrains.insert(entry.String());
allowedTerrains.insert(VLC->terrainTypeHandler->getInfoByName(entry.String())->id);
}
else
{
for(auto & i : Terrain::Manager::terrains())
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
{
if(!i.isPassable() || i.isWater())
if(!terrain.isPassable() || terrain.isWater())
continue;
allowedTerrains.insert(i);
allowedTerrains.insert(terrain.id);
}
}
if(withTerrain && allowedTerrains.empty())
logGlobal->warn("Loaded template without allowed terrains!");
auto charToTile = [&](const char & ch) -> ui8
{
switch (ch)
@ -371,7 +370,7 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
if(withTerrain)
{
//assumed that ROCK and WATER terrains are not included
if(allowedTerrains.size() < (Terrain::Manager::terrains().size() - 2))
if(allowedTerrains.size() < (VLC->terrainTypeHandler->terrains().size() - 2))
{
JsonVector & data = node["allowedTerrains"].Vector();
@ -558,9 +557,9 @@ void ObjectTemplate::calculateVisitableOffset()
visitableOffset = int3(0, 0, 0);
}
bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
bool ObjectTemplate::canBePlacedAt(TerrainId terrain) const
{
return allowedTerrains.count(terrain) != 0;
return vstd::contains(allowedTerrains, terrain);
}
void ObjectTemplate::recalculate()

View File

@ -18,7 +18,6 @@ class CBinaryReader;
class CLegacyConfigParser;
class JsonNode;
class int3;
class Terrain;
class DLL_LINKAGE ObjectTemplate
{
@ -34,7 +33,7 @@ class DLL_LINKAGE ObjectTemplate
/// directions from which object can be entered, format same as for moveDir in CGHeroInstance(but 0 - 7)
ui8 visitDir;
/// list of terrains on which this object can be placed
std::set<Terrain> allowedTerrains;
std::set<TerrainId> allowedTerrains;
void afterLoadFixup();
@ -101,7 +100,7 @@ public:
};
// Checks if object can be placed on specific terrain
bool canBePlacedAt(Terrain terrain) const;
bool canBePlacedAt(TerrainId terrain) const;
ObjectTemplate();
//custom copy constructor is required

View File

@ -158,14 +158,14 @@ CDrawLinesOperation::CDrawLinesOperation(CMap * map, const CTerrainSelection & t
}
///CDrawRoadsOperation
CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen):
CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, CRandomGenerator * gen):
CDrawLinesOperation(map, terrainSel,gen),
roadType(roadType)
{
}
///CDrawRiversOperation
CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & riverType, CRandomGenerator * gen):
CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RiverId riverType, CRandomGenerator * gen):
CDrawLinesOperation(map, terrainSel, gen),
riverType(riverType)
{
@ -338,12 +338,12 @@ std::string CDrawRiversOperation::getLabel() const
void CDrawRoadsOperation::executeTile(TerrainTile & tile)
{
tile.roadType = roadType;
tile.roadType = const_cast<RoadType*>(&VLC->terrainTypeHandler->roads()[roadType]);
}
void CDrawRiversOperation::executeTile(TerrainTile & tile)
{
tile.riverType = riverType;
tile.riverType = const_cast<RiverType*>(&VLC->terrainTypeHandler->rivers()[riverType]);
}
bool CDrawRoadsOperation::canApplyPattern(const LinePattern & pattern) const
@ -358,22 +358,22 @@ bool CDrawRiversOperation::canApplyPattern(const LinePattern & pattern) const
bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
{
return tile.roadType != ROAD_NAMES[0];
return tile.roadType->id != Road::NO_ROAD;
}
bool CDrawRiversOperation::needUpdateTile(const TerrainTile & tile) const
{
return tile.riverType != RIVER_NAMES[0];
return tile.riverType->id != River::NO_RIVER;
}
bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
{
return map->getTile(pos).roadType != ROAD_NAMES[0];
return map->getTile(pos).roadType->id != Road::NO_ROAD;
}
bool CDrawRiversOperation::tileHasSomething(const int3& pos) const
{
return map->getTile(pos).riverType != RIVER_NAMES[0];
return map->getTile(pos).riverType->id != River::NO_RIVER;
}
void CDrawRoadsOperation::updateTile(TerrainTile & tile, const LinePattern & pattern, const int flip)

View File

@ -63,7 +63,7 @@ protected:
class CDrawRoadsOperation : public CDrawLinesOperation
{
public:
CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen);
CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, CRandomGenerator * gen);
std::string getLabel() const override;
protected:
@ -74,13 +74,13 @@ protected:
void updateTile(TerrainTile & tile, const CDrawLinesOperation::LinePattern & pattern, const int flip) override;
private:
std::string roadType;
RoadId roadType;
};
class CDrawRiversOperation : public CDrawLinesOperation
{
public:
CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen);
CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, CRandomGenerator * gen);
std::string getLabel() const override;
protected:
@ -91,7 +91,7 @@ protected:
void updateTile(TerrainTile & tile, const CDrawLinesOperation::LinePattern & pattern, const int flip) override;
private:
std::string riverType;
RiverId riverType;
};
VCMI_LIB_NAMESPACE_END

View File

@ -125,22 +125,28 @@ CCastleEvent::CCastleEvent() : town(nullptr)
}
TerrainTile::TerrainTile() : terType("BORDER"), terView(0), riverType(RIVER_NAMES[0]),
riverDir(0), roadType(ROAD_NAMES[0]), roadDir(0), extTileFlags(0), visitable(false),
TerrainTile::TerrainTile():
terType(nullptr),
terView(0),
riverType(const_cast<RiverType*>(&VLC->terrainTypeHandler->rivers()[River::NO_RIVER])),
riverDir(0),
roadType(const_cast<RoadType*>(&VLC->terrainTypeHandler->roads()[Road::NO_ROAD])),
roadDir(0),
extTileFlags(0),
visitable(false),
blocked(false)
{
}
bool TerrainTile::entrableTerrain(const TerrainTile * from) const
{
return entrableTerrain(from ? from->terType.isLand() : true, from ? from->terType.isWater() : true);
return entrableTerrain(from ? from->terType->isLand() : true, from ? from->terType->isWater() : true);
}
bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const
{
return terType.isPassable()
&& ((allowSea && terType.isWater()) || (allowLand && terType.isLand()));
return terType->isPassable()
&& ((allowSea && terType->isWater()) || (allowLand && terType->isLand()));
}
bool TerrainTile::isClear(const TerrainTile * from) const
@ -166,7 +172,7 @@ CGObjectInstance * TerrainTile::topVisitableObj(bool excludeTop) const
EDiggingStatus TerrainTile::getDiggingStatus(const bool excludeTop) const
{
if(terType.isWater() || !terType.isPassable())
if(terType->isWater() || !terType->isPassable())
return EDiggingStatus::WRONG_TERRAIN;
int allowedBlocked = excludeTop ? 1 : 0;
@ -183,7 +189,7 @@ bool TerrainTile::hasFavorableWinds() const
bool TerrainTile::isWater() const
{
return terType.isWater();
return terType->isWater();
}
void CMapHeader::setupEvents()

View File

@ -82,11 +82,11 @@ struct DLL_LINKAGE TerrainTile
EDiggingStatus getDiggingStatus(const bool excludeTop = true) const;
bool hasFavorableWinds() const;
Terrain terType;
TerrainType * terType;
ui8 terView;
std::string riverType;
RiverType * riverType;
ui8 riverDir;
std::string roadType; //TODO: switch to ui8
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

@ -126,19 +126,19 @@ void CMapEditManager::clearTerrain(CRandomGenerator * gen)
execute(make_unique<CClearTerrainOperation>(map, gen ? gen : &(this->gen)));
}
void CMapEditManager::drawTerrain(Terrain terType, CRandomGenerator * gen)
void CMapEditManager::drawTerrain(TerrainId terType, CRandomGenerator * gen)
{
execute(make_unique<CDrawTerrainOperation>(map, terrainSel, terType, gen ? gen : &(this->gen)));
terrainSel.clearSelection();
}
void CMapEditManager::drawRoad(const std::string & roadType, CRandomGenerator* gen)
void CMapEditManager::drawRoad(RoadId roadType, CRandomGenerator* gen)
{
execute(make_unique<CDrawRoadsOperation>(map, terrainSel, roadType, gen ? gen : &(this->gen)));
terrainSel.clearSelection();
}
void CMapEditManager::drawRiver(const std::string & riverType, CRandomGenerator* gen)
void CMapEditManager::drawRiver(RiverId riverType, CRandomGenerator* gen)
{
execute(make_unique<CDrawRiversOperation>(map, terrainSel, riverType, gen ? gen : &(this->gen)));
terrainSel.clearSelection();

View File

@ -72,13 +72,13 @@ public:
void clearTerrain(CRandomGenerator * gen = nullptr);
/// Draws terrain at the current terrain selection. The selection will be cleared automatically.
void drawTerrain(Terrain terType, CRandomGenerator * gen = nullptr);
void drawTerrain(TerrainId terType, CRandomGenerator * gen = nullptr);
/// Draws roads at the current terrain selection. The selection will be cleared automatically.
void drawRoad(const std::string & roadType, CRandomGenerator * gen = nullptr);
void drawRoad(RoadId roadType, CRandomGenerator * gen = nullptr);
/// Draws rivers at the current terrain selection. The selection will be cleared automatically.
void drawRiver(const std::string & riverType, CRandomGenerator * gen = nullptr);
void drawRiver(RiverId riverType, CRandomGenerator * gen = nullptr);
void insertObject(CGObjectInstance * obj);
void insertObjects(std::set<CGObjectInstance *> & objects);

View File

@ -83,8 +83,11 @@ void CComposedOperation::addOperation(std::unique_ptr<CMapOperation>&& operation
operations.push_back(std::move(operation));
}
CDrawTerrainOperation::CDrawTerrainOperation(CMap* map, const CTerrainSelection& terrainSel, Terrain terType, CRandomGenerator* gen)
: CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen)
CDrawTerrainOperation::CDrawTerrainOperation(CMap* map, const CTerrainSelection& terrainSel, TerrainId terType, CRandomGenerator* gen):
CMapOperation(map),
terrainSel(terrainSel),
terType(terType),
gen(gen)
{
}
@ -94,7 +97,7 @@ void CDrawTerrainOperation::execute()
for(const auto & pos : terrainSel.getSelectedItems())
{
auto & tile = map->getTile(pos);
tile.terType = terType;
tile.terType = const_cast<TerrainType*>(&VLC->terrainTypeHandler->terrains()[terType]);
invalidateTerrainViews(pos);
}
@ -151,7 +154,7 @@ void CDrawTerrainOperation::updateTerrainTypes()
rect.forEach([&](const int3& posToTest)
{
auto & terrainTile = map->getTile(posToTest);
if(centerTile.terType != terrainTile.terType)
if(centerTile.terType->id != terrainTile.terType->id)
{
auto formerTerType = terrainTile.terType;
terrainTile.terType = centerTile.terType;
@ -254,7 +257,7 @@ void CDrawTerrainOperation::updateTerrainViews()
{
for(const auto & pos : invalidatedTerViews)
{
const auto & patterns = VLC->terviewh->getTerrainViewPatterns(map->getTile(pos).terType);
const auto & patterns = VLC->terviewh->getTerrainViewPatterns(map->getTile(pos).terType->id);
// Detect a pattern which fits best
int bestPattern = -1;
@ -342,7 +345,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
int cy = pos.y + (i / 3) - 1;
int3 currentPos(cx, cy, pos.z);
bool isAlien = false;
Terrain terType;
TerrainType * terType = nullptr;
if(!map->isInTheMap(currentPos))
{
// position is not in the map, so take the ter type from the neighbor tile
@ -375,7 +378,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
else
{
terType = map->getTile(currentPos).terType;
if(terType != centerTerType && (terType.isPassable() || centerTerType.isPassable()))
if(terType != centerTerType && (terType->isPassable() || centerTerType->isPassable()))
{
isAlien = true;
}
@ -390,9 +393,9 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
{
if(recDepth == 0 && map->isInTheMap(currentPos))
{
if(terType == centerTerType)
if(terType->id == centerTerType->id)
{
const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(centerTerType, rule.name);
const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(centerTerType->id, rule.name);
if(auto p = patternForRule)
{
auto rslt = validateTerrainView(currentPos, &(*p), 1);
@ -419,18 +422,18 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
bool nativeTestOk, nativeTestStrongOk;
nativeTestOk = nativeTestStrongOk = (rule.isNativeStrong() || rule.isNativeRule()) && !isAlien;
if(centerTerType == Terrain("dirt"))
if(centerTerType->id == Terrain::DIRT)
{
nativeTestOk = rule.isNativeRule() && !terType.isTransitionRequired();
nativeTestOk = rule.isNativeRule() && !terType->isTransitionRequired();
bool sandTestOk = (rule.isSandRule() || rule.isTransition())
&& terType.isTransitionRequired();
&& terType->isTransitionRequired();
applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk || nativeTestStrongOk);
}
else if(centerTerType == Terrain("sand"))
else if(centerTerType->id == Terrain::SAND)
{
applyValidationRslt(true);
}
else if(centerTerType.isTransitionRequired()) //water, rock and some special terrains require sand transition
else if(centerTerType->isTransitionRequired()) //water, rock and some special terrains require sand transition
{
bool sandTestOk = (rule.isSandRule() || rule.isTransition())
&& isAlien;
@ -439,9 +442,9 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
else
{
bool dirtTestOk = (rule.isDirtRule() || rule.isTransition())
&& isAlien && !terType.isTransitionRequired();
&& isAlien && !terType->isTransitionRequired();
bool sandTestOk = (rule.isSandRule() || rule.isTransition())
&& terType.isTransitionRequired();
&& terType->isTransitionRequired();
if(transitionReplacement.empty() && rule.isTransition()
&& (dirtTestOk || sandTestOk))
@ -504,7 +507,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
auto valid = validateTerrainView(pos, ptrConfig->getTerrainTypePatternById("n1")).result;
// Special validity check for rock & water
if(valid && (terType.isWater() || !terType.isPassable()))
if(valid && (terType->isWater() || !terType->isPassable()))
{
static const std::string patternIds[] = { "s1", "s2" };
for(auto & patternId : patternIds)
@ -514,7 +517,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
}
}
// Additional validity check for non rock OR water
else if(!valid && (terType.isLand() && terType.isPassable()))
else if(!valid && (terType->isLand() && terType->isPassable()))
{
static const std::string patternIds[] = { "n2", "n3" };
for (auto & patternId : patternIds)
@ -548,12 +551,12 @@ CClearTerrainOperation::CClearTerrainOperation(CMap* map, CRandomGenerator* gen)
{
CTerrainSelection terrainSel(map);
terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain("water"), gen));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain::WATER, gen));
if(map->twoLevel)
{
terrainSel.clearSelection();
terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain("rock"), gen));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain::ROCK, gen));
}
}

View File

@ -63,7 +63,7 @@ private:
class CDrawTerrainOperation : public CMapOperation
{
public:
CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, Terrain terType, CRandomGenerator * gen);
CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, TerrainId terType, CRandomGenerator * gen);
void execute() override;
void undo() override;
@ -100,7 +100,7 @@ private:
ValidationResult validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth = 0) const;
CTerrainSelection terrainSel;
Terrain terType;
TerrainId terType;
CRandomGenerator* gen;
std::set<int3> invalidatedTerViews;
};

View File

@ -270,9 +270,9 @@ CTerrainViewPatternConfig::~CTerrainViewPatternConfig()
}
const std::vector<CTerrainViewPatternConfig::TVPVector> & CTerrainViewPatternConfig::getTerrainViewPatterns(const Terrain & terrain) const
const std::vector<CTerrainViewPatternConfig::TVPVector> & CTerrainViewPatternConfig::getTerrainViewPatterns(TerrainId terrain) const
{
auto iter = terrainViewPatterns.find(Terrain::Manager::getInfo(terrain).terrainViewPatterns);
auto iter = terrainViewPatterns.find(VLC->terrainTypeHandler->terrains()[terrain].terrainViewPatterns);
if (iter == terrainViewPatterns.end())
return terrainViewPatterns.at("normal");
return iter->second;
@ -295,7 +295,7 @@ boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getTerrai
return boost::optional<const TerrainViewPattern&>();
}
boost::optional<const CTerrainViewPatternConfig::TVPVector &> CTerrainViewPatternConfig::getTerrainViewPatternsById(const Terrain & terrain, const std::string & id) const
boost::optional<const CTerrainViewPatternConfig::TVPVector &> CTerrainViewPatternConfig::getTerrainViewPatternsById(TerrainId terrain, const std::string & id) const
{
const std::vector<TVPVector> & groupPatterns = getTerrainViewPatterns(terrain);
for (const TVPVector & patternFlips : groupPatterns)
@ -357,7 +357,7 @@ void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int
{
auto debugTile = map->getTile(debugPos);
std::string terType = static_cast<std::string>(debugTile.terType).substr(0, 6);
std::string terType = debugTile.terType->name.substr(0, 6);
line += terType;
line.insert(line.end(), PADDED_LENGTH - terType.size(), ' ');
}

View File

@ -217,9 +217,9 @@ public:
CTerrainViewPatternConfig();
~CTerrainViewPatternConfig();
const std::vector<TVPVector> & getTerrainViewPatterns(const Terrain & terrain) const;
const std::vector<TVPVector> & getTerrainViewPatterns(TerrainId terrain) const;
boost::optional<const TerrainViewPattern &> getTerrainViewPatternById(std::string patternId, const std::string & id) const;
boost::optional<const TVPVector &> getTerrainViewPatternsById(const Terrain & terrain, const std::string & id) const;
boost::optional<const TVPVector &> getTerrainViewPatternsById(TerrainId terrain, const std::string & id) const;
const TVPVector * getTerrainTypePatternById(const std::string & id) const;
void flipPattern(TerrainViewPattern & pattern, int flip) const;

View File

@ -923,30 +923,28 @@ 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;
for(pos.z = 0; pos.z < 2; ++pos.z)
for(pos.z = 0; pos.z < map->levels(); ++pos.z)
{
if(pos.z == 1 && !map->twoLevel)
{
break;
}
//OH3 format is [z][y][x]
for(pos.y = 0; pos.y < map->height; pos.y++)
{
for(pos.x = 0; pos.x < map->width; pos.x++)
{
auto & tile = map->getTile(pos);
tile.terType = Terrain::createTerrainTypeH3M(reader.readUInt8());
tile.terType = const_cast<TerrainType*>(&terrains[reader.readUInt8()]);
tile.terView = reader.readUInt8();
tile.riverType = RIVER_NAMES[reader.readUInt8()];
tile.riverType = const_cast<RiverType*>(&rivers[reader.readUInt8()]);
tile.riverDir = reader.readUInt8();
tile.roadType = ROAD_NAMES[reader.readUInt8()];
tile.roadType = const_cast<RoadType*>(&roads[reader.readUInt8()]);
tile.roadDir = reader.readUInt8();
tile.extTileFlags = reader.readUInt8();
tile.blocked = ((!tile.terType.isPassable() || tile.terType == Terrain("BORDER") ) ? true : false); //underground tiles are always blocked
tile.blocked = ((!tile.terType->isPassable() || tile.terType->id == Terrain::BORDER ) ? true : false); //underground tiles are always blocked
tile.visitable = 0;
}
}

View File

@ -943,11 +943,13 @@ void CMapLoaderJson::readHeader(const bool complete)
}
void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile)
{
try
{
using namespace TerrainDetail;
{//terrain type
const std::string typeCode = src.substr(0, 2);
tile.terType = Terrain::createTerrainByCode(typeCode);
tile.terType = const_cast<TerrainType*>(VLC->terrainTypeHandler->getInfoByCode(typeCode));
}
int startPos = 2; //0+typeCode fixed length
{//terrain view
@ -971,21 +973,27 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
if (startPos >= src.size())
return;
bool hasRoad = true;
//FIXME: check without exceptions?
{//road type
const std::string typeCode = src.substr(startPos, 2);
startPos += 2;
if(vstd::find_pos(ROAD_NAMES, typeCode) < 0)
try
{
if(vstd::find_pos(RIVER_NAMES, typeCode) < 0)
throw std::runtime_error("Invalid river type in "+src);
else
tile.roadType = const_cast<RoadType*>(VLC->terrainTypeHandler->getRoadByCode(typeCode));
}
catch (const std::exception& e) //it's not a road, it's a river
{
tile.riverType = typeCode;
try
{
tile.riverType = const_cast<RiverType*>(VLC->terrainTypeHandler->getRiverByCode(typeCode));
hasRoad = false;
}
catch (const std::exception& e)
{
throw std::runtime_error("Invalid river type in " + src);
}
}
else
tile.roadType = typeCode;
}
if (hasRoad)
{//road dir
@ -1013,9 +1021,7 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
{//river type
const std::string typeCode = src.substr(startPos, 2);
startPos += 2;
if(vstd::find_pos(RIVER_NAMES, typeCode) < 0)
throw std::runtime_error("Invalid river type in "+src);
tile.riverType = typeCode;
tile.riverType = const_cast<RiverType*>(VLC->terrainTypeHandler->getRiverByCode(typeCode));
}
{//river dir
int pos = startPos;
@ -1036,6 +1042,11 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
tile.extTileFlags |= (flip << 2);
}
}
catch (const std::exception & e)
{
logGlobal->error("Failed to read terrain tile: %s");
}
}
void CMapLoaderJson::readTerrainLevel(const JsonNode & src, const int index)
{
@ -1278,12 +1289,12 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile)
out.setf(std::ios::dec, std::ios::basefield);
out.unsetf(std::ios::showbase);
out << Terrain::Manager::getInfo(tile.terType).typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
out << tile.terType->typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
if(tile.roadType != ROAD_NAMES[0])
if(tile.roadType->id != Road::NO_ROAD)
out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
if(tile.riverType != RIVER_NAMES[0])
if(tile.riverType->id != River::NO_RIVER)
out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
return out.str();

View File

@ -48,16 +48,7 @@ void CMapGenerator::loadConfig()
{
static const ResourceID path("config/randomMap.json");
JsonNode randomMapJson(path);
for(auto& s : randomMapJson["terrain"]["undergroundAllow"].Vector())
{
if(!s.isNull())
config.terrainUndergroundAllowed.emplace_back(s.String());
}
for(auto& s : randomMapJson["terrain"]["groundProhibit"].Vector())
{
if(!s.isNull())
config.terrainGroundProhibit.emplace_back(s.String());
}
config.shipyardGuard = randomMapJson["waterZone"]["shipyard"]["value"].Integer();
for(auto & treasure : randomMapJson["waterZone"]["treasure"].Vector())
{

View File

@ -34,8 +34,6 @@ class DLL_LINKAGE CMapGenerator: public Load::Progress
public:
struct Config
{
std::vector<Terrain> terrainUndergroundAllowed;
std::vector<Terrain> terrainGroundProhibit;
std::vector<CTreasureInfo> waterTreasure;
int shipyardGuard;
int mineExtraResources;

View File

@ -69,12 +69,13 @@ class TerrainEncoder
public:
static si32 decode(const std::string & identifier)
{
return vstd::find_pos(Terrain::Manager::terrains(), identifier);
return VLC->terrainTypeHandler->getInfoByCode(identifier)->id;
}
static std::string encode(const si32 index)
{
return (index >=0 && index < Terrain::Manager::terrains().size()) ? static_cast<std::string>(Terrain::Manager::terrains()[index]) : "<INVALID TERRAIN>";
const auto& terrains = VLC->terrainTypeHandler->terrains();
return (index >=0 && index < terrains.size()) ? terrains[index].name : "<INVALID TERRAIN>";
}
};
@ -151,9 +152,9 @@ ZoneOptions::ZoneOptions()
terrainTypeLikeZone(NO_ZONE),
treasureLikeZone(NO_ZONE)
{
for(auto & terr : Terrain::Manager::terrains())
for(const auto & terr : VLC->terrainTypeHandler->terrains())
if(terr.isLand() && terr.isPassable())
terrainTypes.insert(terr);
terrainTypes.insert(terr.id);
}
ZoneOptions & ZoneOptions::operator=(const ZoneOptions & other)
@ -216,12 +217,12 @@ boost::optional<int> ZoneOptions::getOwner() const
return owner;
}
const std::set<Terrain> & ZoneOptions::getTerrainTypes() const
const std::set<TerrainId> & ZoneOptions::getTerrainTypes() const
{
return terrainTypes;
}
void ZoneOptions::setTerrainTypes(const std::set<Terrain> & value)
void ZoneOptions::setTerrainTypes(const std::set<TerrainId> & value)
{
//assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
// value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
@ -376,7 +377,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
terrainTypes.clear();
for(auto ttype : node.Vector())
{
terrainTypes.emplace(ttype.String());
terrainTypes.emplace(VLC->terrainTypeHandler->getInfoByName(ttype.String())->id);
}
}
}

View File

@ -105,8 +105,8 @@ public:
void setSize(int value);
boost::optional<int> getOwner() const;
const std::set<Terrain> & getTerrainTypes() const;
void setTerrainTypes(const std::set<Terrain> & value);
const std::set<TerrainId> & getTerrainTypes() const;
void setTerrainTypes(const std::set<TerrainId> & value);
const CTownInfo & getPlayerTowns() const;
const CTownInfo & getNeutralTowns() const;
@ -146,7 +146,7 @@ protected:
CTownInfo playerTowns;
CTownInfo neutralTowns;
bool matchTerrainToTown;
std::set<Terrain> terrainTypes;
std::set<TerrainId> terrainTypes;
bool townsAreSameType;
std::set<TFaction> townTypes;

View File

@ -193,16 +193,17 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
else
{
auto & tt = (*VLC->townh)[faction]->nativeTerrain;
if(tt == Terrain("dirt"))
if(tt == Terrain::DIRT)
{
//any / random
zonesToPlace.push_back(zone);
}
else
{
if(tt.isUnderground())
const auto & terrainType = VLC->terrainTypeHandler->terrains()[tt];
if(terrainType.isUnderground() && !terrainType.isSurface())
{
//underground
//underground only
zonesOnLevel[1]++;
levels[zone.first] = 1;
}
@ -573,7 +574,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("subterra"));
paintZoneTerrain(*zone.second, *rand, map, Terrain::SUBTERRANEAN);
}
}
logGlobal->info("Finished zone colouring");

View File

@ -84,8 +84,9 @@ void ConnectionsPlacer::selfSideDirectConnection(const rmg::ZoneConnection & con
//1. Try to make direct connection
//Do if it's not prohibited by terrain settings
bool directProhibited = vstd::contains(Terrain::Manager::getInfo(zone.getTerrainType()).prohibitTransitions, otherZone->getTerrainType())
|| vstd::contains(Terrain::Manager::getInfo(otherZone->getTerrainType()).prohibitTransitions, zone.getTerrainType());
const auto& terrains = VLC->terrainTypeHandler->terrains();
bool directProhibited = vstd::contains(terrains[zone.getTerrainType()].prohibitTransitions, otherZone->getTerrainType())
|| vstd::contains(terrains[otherZone->getTerrainType()].prohibitTransitions, zone.getTerrainType());
auto directConnectionIterator = dNeighbourZones.find(otherZoneId);
if(!directProhibited && directConnectionIterator != dNeighbourZones.end())
{

View File

@ -95,14 +95,14 @@ void createBorder(RmgMap & gen, Zone & zone)
}
}
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, const Terrain & terrainType)
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrain)
{
auto v = zone.getArea().getTilesVector();
map.getEditManager()->getTerrainSelection().setSelection(v);
map.getEditManager()->drawTerrain(terrainType, &generator);
map.getEditManager()->drawTerrain(terrain, &generator);
}
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, const Terrain & terrain)
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId terrain)
{
auto factories = VLC->objtypeh->knownSubObjects(ObjID);
vstd::erase_if(factories, [ObjID, &terrain](si32 f)
@ -118,10 +118,10 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
if(zone.getType()==ETemplateZoneType::WATER)
{
//collect all water terrain types
std::vector<Terrain> waterTerrains;
for(auto & terrain : Terrain::Manager::terrains())
std::vector<TerrainId> waterTerrains;
for(const auto & terrain : VLC->terrainTypeHandler->terrains())
if(terrain.isWater())
waterTerrains.push_back(terrain);
waterTerrains.push_back(terrain.id);
zone.setTerrainType(*RandomGeneratorUtil::nextItem(waterTerrains, gen.rand));
}
@ -136,25 +136,21 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
zone.setTerrainType(*RandomGeneratorUtil::nextItem(zone.getTerrainTypes(), gen.rand));
}
//TODO: allow new types of terrain?
{
//Now, replace disallowed terrains on surface and in the underground
const auto & terrainType = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()];
if(zone.isUnderground())
{
if(!vstd::contains(gen.getConfig().terrainUndergroundAllowed, zone.getTerrainType()))
if(!terrainType.isUnderground())
{
//collect all underground terrain types
std::vector<Terrain> undegroundTerrains;
for(auto & terrain : Terrain::Manager::terrains())
if(terrain.isUnderground())
undegroundTerrains.push_back(terrain);
zone.setTerrainType(*RandomGeneratorUtil::nextItem(undegroundTerrains, gen.rand));
zone.setTerrainType(Terrain::SUBTERRANEAN);
}
}
else
{
if(vstd::contains(gen.getConfig().terrainGroundProhibit, zone.getTerrainType()) || zone.getTerrainType().isUnderground())
zone.setTerrainType(Terrain("dirt"));
if (!terrainType.isSurface())
{
zone.setTerrainType(Terrain::DIRT);
}
}
}
@ -170,7 +166,7 @@ void createObstaclesCommon2(RmgMap & map, CRandomGenerator & generator)
for(int y = 0; y < map.map().height; y++)
{
int3 tile(x, y, 1);
if(!map.map().getTile(tile).terType.isPassable())
if(!map.map().getTile(tile).terType->isPassable())
{
map.setOccupied(tile, ETileType::USED);
}

View File

@ -42,11 +42,11 @@ rmg::Tileset collectDistantTiles(const Zone & zone, int distance);
void createBorder(RmgMap & gen, Zone & zone);
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, const Terrain & terrainType);
void paintZoneTerrain(const Zone & zone, CRandomGenerator & generator, RmgMap & map, TerrainId terrainType);
void initTerrainType(Zone & zone, CMapGenerator & gen);
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, const Terrain & terrain);
int chooseRandomAppearance(CRandomGenerator & generator, si32 ObjID, TerrainId terrain);
VCMI_LIB_NAMESPACE_END

View File

@ -26,7 +26,7 @@
VCMI_LIB_NAMESPACE_BEGIN
void ObstacleProxy::collectPossibleObstacles(const Terrain & terrain)
void ObstacleProxy::collectPossibleObstacles(TerrainId terrain)
{
//get all possible obstacles for this terrain
for(auto primaryID : VLC->objtypeh->knownObjects())

View File

@ -26,7 +26,7 @@ public:
rmg::Area blockedArea;
void collectPossibleObstacles(const Terrain & terrain);
void collectPossibleObstacles(TerrainId terrain);
void placeObstacles(CMap * map, CRandomGenerator & rand);

View File

@ -26,13 +26,6 @@ VCMI_LIB_NAMESPACE_BEGIN
const int RIVER_DELTA_ID = 143;
const int RIVER_DELTA_SUBTYPE = 0;
const std::map<std::string, std::string> RIVER_DELTA_TEMPLATE_NAME
{
{RIVER_NAMES[1], "clrdelt"},
{RIVER_NAMES[2], "icedelt"},
{RIVER_NAMES[3], "muddelt"},
{RIVER_NAMES[4], "lavdelt"}
};
const std::array<std::array<int, 25>, 4> deltaTemplates
{
@ -93,7 +86,7 @@ void RiverPlacer::init()
void RiverPlacer::drawRivers()
{
map.getEditManager()->getTerrainSelection().setSelection(rivers.getTilesVector());
map.getEditManager()->drawRiver(Terrain::Manager::getInfo(zone.getTerrainType()).river, &generator.rand);
map.getEditManager()->drawRiver(VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river, &generator.rand);
}
char RiverPlacer::dump(const int3 & t)
@ -202,7 +195,7 @@ void RiverPlacer::preprocess()
//calculate delta positions
if(connectedToWaterZoneId > -1)
{
auto river = Terrain::Manager::getInfo(zone.getTerrainType()).river;
auto river = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river;
auto & a = neighbourZonesTiles[connectedToWaterZoneId];
auto availableArea = zone.areaPossible() + zone.freePaths();
for(auto & tileToProcess : availableArea.getTilesVector())
@ -240,7 +233,7 @@ void RiverPlacer::preprocess()
deltaOrientations[p] = templateId + 1;
//specific case: deltas for ice rivers amd mud rivers are messed :(
if(river == RIVER_NAMES[2])
if(river == River::ICY_RIVER)
{
switch(deltaOrientations[p])
{
@ -258,7 +251,7 @@ void RiverPlacer::preprocess()
break;
}
}
if(river == RIVER_NAMES[3])
if(river == River::MUD_RIVER)
{
switch(deltaOrientations[p])
{
@ -328,8 +321,9 @@ void RiverPlacer::preprocess()
void RiverPlacer::connectRiver(const int3 & tile)
{
auto river = Terrain::Manager::getInfo(zone.getTerrainType()).river;
if(river.empty() || river == RIVER_NAMES[0])
auto riverType = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].river;
const auto & river = VLC->terrainTypeHandler->rivers()[riverType];
if(river.id == River::NO_RIVER)
return;
rmg::Area roads;
@ -386,9 +380,10 @@ void RiverPlacer::connectRiver(const int3 & tile)
if(tmplates.size() > 3)
{
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));
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));
std::string targetTemplateName = RIVER_DELTA_TEMPLATE_NAME.at(river) + 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(Terrain::GRASS, &generator.rand);
auto tmpl = mapGenOptions.getMapTemplate();
zones.clear();
@ -231,7 +231,7 @@ void RmgMap::setOccupied(const int3 &tile, ETileType::ETileType state)
tiles[tile.x][tile.y][tile.z].setOccupied(state);
}
void RmgMap::setRoad(const int3& tile, const std::string & roadType)
void RmgMap::setRoad(const int3& tile, RoadId roadType)
{
assertOnMap(tile);

View File

@ -46,7 +46,7 @@ public:
bool isOnMap(const int3 & tile) const;
void setOccupied(const int3 &tile, ETileType::ETileType state);
void setRoad(const int3 &tile, const std::string & roadType);
void setRoad(const int3 &tile, RoadId roadType);
TileInfo getTile(const int3 & tile) const;

View File

@ -105,13 +105,17 @@ void Object::Instance::setPositionRaw(const int3 & position)
dObject.pos = dPosition + dParent.getPosition();
}
void Object::Instance::setTemplate(const Terrain & terrain)
void Object::Instance::setTemplate(const TerrainId & terrain)
{
if(dObject.appearance->id == Obj::NO_OBJ)
{
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
auto terrainName = VLC->terrainTypeHandler->terrains()[terrain].name;
if (templates.empty())
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % dObject.ID % dObject.subID % static_cast<std::string>(terrain)));
{
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();
}
@ -255,7 +259,7 @@ void Object::setPosition(const int3 & position)
i.setPositionRaw(i.getPosition());
}
void Object::setTemplate(const Terrain & terrain)
void Object::setTemplate(const TerrainId & terrain)
{
for(auto& i : dInstances)
i.setTemplate(terrain);
@ -291,11 +295,12 @@ void Object::Instance::finalize(RmgMap & map)
if (dObject.appearance->id == Obj::NO_OBJ)
{
auto terrainType = map.map().getTile(getPosition(true)).terType;
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType);
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType->id);
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));
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->name));
setTemplate(terrainType);
setTemplate(terrainType->id);
}
for(auto & tile : getBlockedArea().getTilesVector())

View File

@ -18,7 +18,6 @@ VCMI_LIB_NAMESPACE_BEGIN
class CGObjectInstance;
class RmgMap;
class Terrain;
namespace rmg {
class Object
@ -36,7 +35,7 @@ public:
int3 getVisitablePosition() const;
bool isVisitableFrom(const int3 & tile) const;
const Area & getAccessibleArea() const;
void setTemplate(const Terrain & terrain); //cache invalidation
void setTemplate(const TerrainId & terrain); //cache invalidation
int3 getPosition(bool isAbsolute = false) const;
void setPosition(const int3 & position); //cache invalidation
@ -72,7 +71,7 @@ public:
const int3 & getPosition() const;
void setPosition(const int3 & position);
void setTemplate(const Terrain & terrain);
void setTemplate(const TerrainId & terrain);
const Area & getArea() const; //lazy cache invalidation

View File

@ -71,7 +71,8 @@ void RoadPlacer::drawRoads(bool secondary)
zone.areaPossible().subtract(roads);
zone.freePaths().unite(roads);
map.getEditManager()->getTerrainSelection().setSelection(roads.getTilesVector());
std::string roadType = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
std::string roadCode = (secondary ? generator.getConfig().secondaryRoadType : generator.getConfig().defaultRoadType);
RoadId roadType = VLC->terrainTypeHandler->getRoadByCode(roadCode)->id;
map.getEditManager()->drawRoad(roadType, &generator.rand);
}

View File

@ -24,8 +24,8 @@ VCMI_LIB_NAMESPACE_BEGIN
void RockPlacer::process()
{
rockTerrain = Terrain::Manager::getInfo(zone.getTerrainType()).rockTerrain;
assert(!rockTerrain.isPassable());
rockTerrain = VLC->terrainTypeHandler->terrains()[zone.getTerrainType()].rockTerrain;
assert(!VLC->terrainTypeHandler->terrains()[rockTerrain].isPassable());
accessibleArea = zone.freePaths() + zone.areaUsed();
if(auto * m = zone.getModificator<ObjectManager>())
@ -78,7 +78,7 @@ void RockPlacer::postProcess()
//finally mark rock tiles as occupied, spawn no obstacles there
rockArea = zone.area().getSubarea([this](const int3 & t)
{
return !map.map().getTile(t).terType.isPassable();
return !map.map().getTile(t).terType->isPassable();
});
zone.areaUsed().unite(rockArea);
@ -97,7 +97,7 @@ void RockPlacer::init()
char RockPlacer::dump(const int3 & t)
{
if(!map.map().getTile(t).terType.isPassable())
if(!map.map().getTile(t).terType->isPassable())
{
return zone.area().contains(t) ? 'R' : 'E';
}

View File

@ -28,7 +28,7 @@ public:
protected:
rmg::Area rockArea, accessibleArea;
Terrain rockTerrain;
TerrainId rockTerrain;
};
VCMI_LIB_NAMESPACE_END

View File

@ -46,7 +46,7 @@ bool TileInfo::isFree() const
bool TileInfo::isRoad() const
{
return roadType != ROAD_NAMES[0];
return roadType != Road::NO_ROAD;
}
bool TileInfo::isUsed() const
@ -63,19 +63,19 @@ ETileType::ETileType TileInfo::getTileType() const
return occupied;
}
Terrain TileInfo::getTerrainType() const
TerrainId TileInfo::getTerrainType() const
{
return terrain;
}
void TileInfo::setTerrainType(Terrain value)
void TileInfo::setTerrainType(TerrainId type)
{
terrain = value;
terrain = type;
}
void TileInfo::setRoadType(const std::string & value)
void TileInfo::setRoadType(RoadId type)
{
roadType = value;
roadType = type;
// setOccupied(ETileType::FREE);
}

View File

@ -30,16 +30,16 @@ public:
bool isUsed() const;
bool isRoad() const;
void setOccupied(ETileType::ETileType value);
Terrain getTerrainType() const;
TerrainId getTerrainType() const;
ETileType::ETileType getTileType() const;
void setTerrainType(Terrain value);
void setTerrainType(TerrainId value);
void setRoadType(const std::string & value);
void setRoadType(RoadId type);
private:
float nearestObjectDistance;
ETileType::ETileType occupied;
Terrain terrain;
std::string roadType;
TerrainId terrain;
RoadId roadType;
};
VCMI_LIB_NAMESPACE_END

View File

@ -813,7 +813,7 @@ ObjectInfo::ObjectInfo()
}
void ObjectInfo::setTemplate(si32 type, si32 subtype, Terrain terrainType)
void ObjectInfo::setTemplate(si32 type, si32 subtype, TerrainId terrainType)
{
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
if(!templHandler)

View File

@ -28,7 +28,7 @@ struct ObjectInfo
//ui32 maxPerMap; //unused
std::function<CGObjectInstance *()> generateObject;
void setTemplate(si32 type, si32 subtype, Terrain terrain);
void setTemplate(si32 type, si32 subtype, TerrainId terrain);
ObjectInfo();

View File

@ -53,7 +53,7 @@ void WaterProxy::process()
for(auto & t : z.second->area().getTilesVector())
{
if(map.map().getTile(t).terType == zone.getTerrainType())
if(map.map().getTile(t).terType->id == 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(Terrain::GRASS),
map(map),
generator(generator)
{
@ -134,12 +134,12 @@ void Zone::setTownType(si32 town)
townType = town;
}
const Terrain & Zone::getTerrainType() const
TerrainId Zone::getTerrainType() const
{
return terrainType;
}
void Zone::setTerrainType(const Terrain & terrain)
void Zone::setTerrainType(TerrainId terrain)
{
terrainType = terrain;
}

View File

@ -100,8 +100,8 @@ public:
si32 getTownType() const;
void setTownType(si32 town);
const Terrain & getTerrainType() const;
void setTerrainType(const Terrain & terrain);
TerrainId getTerrainType() const;
void setTerrainType(TerrainId terrain);
void connectPath(const rmg::Path & path);
rmg::Path searchPath(const rmg::Area & src, bool onlyStraight, std::function<bool(const int3 &)> areafilter = AREA_NO_FILTER) const;
@ -140,7 +140,7 @@ protected:
//template info
si32 townType;
Terrain terrainType;
TerrainId terrainType;
};

View File

@ -88,7 +88,7 @@ int BattleCbProxy::getTerrainType(lua_State * L)
if(!S.tryGet(1, object))
return S.retVoid();
return LuaStack::quickRetStr(L, object->battleTerrainType());
return LuaStack::quickRetInt(L, object->battleTerrainType());
}
int BattleCbProxy::getUnitByPos(lua_State * L)

View File

@ -1933,7 +1933,7 @@ void CGameHandler::newTurn()
hth.id = h->id;
auto ti = make_unique<TurnInfo>(h, 1);
// TODO: this code executed when bonuses of previous day not yet updated (this happen in NewTurn::applyGs). See issue 2356
hth.move = h->maxMovePointsCached(gs->map->getTile(h->getPosition(false)).terType.isLand(), ti.get());
hth.move = h->maxMovePointsCached(gs->map->getTile(h->getPosition(false)).terType->isLand(), ti.get());
hth.mana = h->getManaNewTurn();
n.heroes.insert(hth);
@ -2240,10 +2240,10 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
{
battleResult.set(nullptr);
const auto t = getTile(tile);
Terrain terrain = t->terType;
const auto & t = *getTile(tile);
TerrainId terrain = t.terType->id;
if (gs->map->isCoastalTile(tile)) //coastal tile is always ground
terrain = Terrain("sand");
terrain = Terrain::SAND;
BattleField terType = gs->battleGetBattlefieldType(tile, getRandomGenerator());
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
@ -2340,7 +2340,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
const bool disembarking = h->boat && t.terType.isLand() && !t.blocked;
const bool disembarking = h->boat && t.terType->isLand() && !t.blocked;
//result structure for start - movement failed, no move points used
TryMoveHero tmh;
@ -2362,11 +2362,11 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
//it's a rock or blocked and not visitable tile
//OR hero is on land and dest is water and (there is not present only one object - boat)
if (((!t.terType.isPassable() || (t.blocked && !t.visitable && !canFly))
if (((!t.terType->isPassable() || (t.blocked && !t.visitable && !canFly))
&& complain("Cannot move hero, destination tile is blocked!"))
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType.isWater() && (t.visitableObjects.size() < 1 || (t.visitableObjects.back()->ID != Obj::BOAT && t.visitableObjects.back()->ID != Obj::HERO))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276)
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType->isWater() && (t.visitableObjects.size() < 1 || (t.visitableObjects.back()->ID != Obj::BOAT && t.visitableObjects.back()->ID != Obj::HERO))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276)
&& complain("Cannot move hero, destination tile is on water!"))
|| ((h->boat && t.terType.isLand() && t.blocked)
|| ((h->boat && t.terType->isLand() && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!"))
|| ((distance(h->pos, dst) >= 1.5 && !teleporting)
&& complain("Tiles are not neighboring!"))

View File

@ -191,9 +191,9 @@ public:
int3 tile(4,4,0);
const auto t = gameCallback->getTile(tile);
const auto & t = *gameCallback->getTile(tile);
Terrain terrain = t->terType;
TerrainId terrain = t.terType->id;
BattleField terType = BattleField::fromString("grass_hills");
//send info about battles

View File

@ -33,30 +33,30 @@ TEST(MapManager, DrawTerrain_Type)
// 1x1 Blow up
editManager->getTerrainSelection().select(int3(5, 5, 0));
editManager->drawTerrain(Terrain("grass"));
editManager->drawTerrain(Terrain::GRASS);
static const int3 squareCheck[] = { int3(5,5,0), int3(5,4,0), int3(4,4,0), int3(4,5,0) };
for(int i = 0; i < ARRAY_COUNT(squareCheck); ++i)
{
EXPECT_EQ(map->getTile(squareCheck[i]).terType, Terrain("grass"));
EXPECT_EQ(map->getTile(squareCheck[i]).terType->id, Terrain::GRASS);
}
// Concat to square
editManager->getTerrainSelection().select(int3(6, 5, 0));
editManager->drawTerrain(Terrain("grass"));
EXPECT_EQ(map->getTile(int3(6, 4, 0)).terType, Terrain("grass"));
editManager->drawTerrain(Terrain::GRASS);
EXPECT_EQ(map->getTile(int3(6, 4, 0)).terType->id, Terrain::GRASS);
editManager->getTerrainSelection().select(int3(6, 5, 0));
editManager->drawTerrain(Terrain("lava"));
EXPECT_EQ(map->getTile(int3(4, 4, 0)).terType, Terrain("grass"));
EXPECT_EQ(map->getTile(int3(7, 4, 0)).terType, Terrain("lava"));
editManager->drawTerrain(Terrain::LAVA);
EXPECT_EQ(map->getTile(int3(4, 4, 0)).terType->id, Terrain::GRASS);
EXPECT_EQ(map->getTile(int3(7, 4, 0)).terType->id, Terrain::LAVA);
// Special case water,rock
editManager->getTerrainSelection().selectRange(MapRect(int3(10, 10, 0), 10, 5));
editManager->drawTerrain(Terrain("grass"));
editManager->drawTerrain(Terrain::GRASS);
editManager->getTerrainSelection().selectRange(MapRect(int3(15, 17, 0), 10, 5));
editManager->drawTerrain(Terrain("grass"));
editManager->drawTerrain(Terrain::GRASS);
editManager->getTerrainSelection().select(int3(21, 16, 0));
editManager->drawTerrain(Terrain("grass"));
EXPECT_EQ(map->getTile(int3(20, 15, 0)).terType, Terrain("grass"));
editManager->drawTerrain(Terrain::GRASS);
EXPECT_EQ(map->getTile(int3(20, 15, 0)).terType->id, Terrain::GRASS);
// Special case non water,rock
static const int3 diagonalCheck[] = { int3(31,42,0), int3(32,42,0), int3(32,43,0), int3(33,43,0), int3(33,44,0),
@ -66,17 +66,17 @@ TEST(MapManager, DrawTerrain_Type)
{
editManager->getTerrainSelection().select(diagonalCheck[i]);
}
editManager->drawTerrain(Terrain("grass"));
EXPECT_EQ(map->getTile(int3(35, 44, 0)).terType, Terrain("water"));
editManager->drawTerrain(Terrain::GRASS);
EXPECT_EQ(map->getTile(int3(35, 44, 0)).terType->id, Terrain::WATER);
// Rock case
editManager->getTerrainSelection().selectRange(MapRect(int3(1, 1, 1), 15, 15));
editManager->drawTerrain(Terrain("subterra"));
editManager->drawTerrain(Terrain::SUBTERRANEAN);
std::vector<int3> vec({ int3(6, 6, 1), int3(7, 6, 1), int3(8, 6, 1), int3(5, 7, 1), int3(6, 7, 1), int3(7, 7, 1),
int3(8, 7, 1), int3(4, 8, 1), int3(5, 8, 1), int3(6, 8, 1)});
editManager->getTerrainSelection().setSelection(vec);
editManager->drawTerrain(Terrain("rock"));
EXPECT_TRUE(!map->getTile(int3(5, 6, 1)).terType.isPassable() || !map->getTile(int3(7, 8, 1)).terType.isPassable());
editManager->drawTerrain(Terrain::ROCK);
EXPECT_TRUE(!map->getTile(int3(5, 6, 1)).terType->isPassable() || !map->getTile(int3(7, 8, 1)).terType->isPassable());
//todo: add checks here and enable, also use smaller size
#if 0
@ -143,7 +143,7 @@ TEST(MapManager, DrawTerrain_View)
int3 pos((si32)posVector[0].Float(), (si32)posVector[1].Float(), (si32)posVector[2].Float());
const auto & originalTile = originalMap->getTile(pos);
editManager->getTerrainSelection().selectRange(MapRect(pos, 1, 1));
editManager->drawTerrain(originalTile.terType, &gen);
editManager->drawTerrain(originalTile.terType->id, &gen);
const auto & tile = map->getTile(pos);
bool isInRange = false;
for(const auto & range : mapping)

Some files were not shown because too many files have changed in this diff Show More