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

New terrain support - part 1 (#755)

Initial support of new terrains
This commit is contained in:
Nordsoft91 2022-06-20 17:39:50 +03:00 committed by Andrii Danylchenko
parent 205bb09880
commit aaa07e4d2e
103 changed files with 1066 additions and 1472 deletions

View File

@ -88,24 +88,22 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
for(pos.z = 0; pos.z < sizes.z; ++pos.z) for(pos.z = 0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile * tile = &gs->map->getTile(pos); const TerrainTile * tile = &gs->map->getTile(pos);
switch(tile->terType) if(!tile->terType.isPassable())
continue;
if(tile->terType.isWater())
{ {
case ETerrainType::ROCK:
break;
case ETerrainType::WATER:
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
if(useWaterWalking) if(useWaterWalking)
resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
break; }
else
default: {
resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
break;
} }
} }
} }
@ -1428,4 +1426,4 @@ std::string AIPath::toString() const
str << node.targetHero->name << "[" << std::hex << node.chainMask << std::dec << "]" << "->" << node.coord.toString() << "; "; str << node.targetHero->name << "[" << std::hex << node.chainMask << std::dec << "]" << "->" << node.coord.toString() << "; ";
return str.str(); return str.str();
} }

View File

@ -70,7 +70,7 @@ int ChainActor::maxMovePoints(CGPathNode::ELayer layer)
{ {
#if AI_TRACE_LEVEL > 0 #if AI_TRACE_LEVEL > 0
if(!hero) if(!hero)
throw std::exception("Asking movement points for static actor"); throw std::logic_error("Asking movement points for static actor");
#endif #endif
return hero->maxMovePointsCached(layer, tiCache.get()); return hero->maxMovePointsCached(layer, tiCache.get());

View File

@ -46,24 +46,22 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
for(pos.z=0; pos.z < sizes.z; ++pos.z) for(pos.z=0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile * tile = &gs->map->getTile(pos); const TerrainTile * tile = &gs->map->getTile(pos);
switch(tile->terType) if(!tile->terType.isPassable())
continue;
if(tile->terType.isWater())
{ {
case ETerrainType::ROCK:
break;
case ETerrainType::WATER:
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
if(useWaterWalking) if(useWaterWalking)
resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
break; }
else
default: {
resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
break;
} }
} }
} }

View File

@ -347,11 +347,6 @@ public:
h & visitableObjs; h & visitableObjs;
h & alreadyVisited; h & alreadyVisited;
h & reservedObjs; h & reservedObjs;
if (version < 788 && !h.saving)
{
TResources saving;
h & saving; //mind the ambiguity
}
h & status; h & status;
h & battlename; h & battlename;
h & heroesUnableToExplore; h & heroesUnableToExplore;

View File

@ -19,6 +19,7 @@
#include "../lib/StringConstants.h" #include "../lib/StringConstants.h"
#include "../lib/CRandomGenerator.h" #include "../lib/CRandomGenerator.h"
#include "../lib/VCMIDirs.h" #include "../lib/VCMIDirs.h"
#include "../lib/Terrain.h"
#define VCMI_SOUND_NAME(x) #define VCMI_SOUND_NAME(x)
#define VCMI_SOUND_FILE(y) #y, #define VCMI_SOUND_FILE(y) #y,
@ -92,20 +93,34 @@ CSoundHandler::CSoundHandler():
soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07 soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07
}; };
horseSounds = // must be the same order as terrains (see ETerrainType);
{
soundBase::horseDirt, soundBase::horseSand, soundBase::horseGrass,
soundBase::horseSnow, soundBase::horseSwamp, soundBase::horseRough,
soundBase::horseSubterranean, soundBase::horseLava,
soundBase::horseWater, soundBase::horseRock
};
battleIntroSounds = battleIntroSounds =
{ {
soundBase::battle00, soundBase::battle01, soundBase::battle00, soundBase::battle01,
soundBase::battle02, soundBase::battle03, soundBase::battle04, soundBase::battle02, soundBase::battle03, soundBase::battle04,
soundBase::battle05, soundBase::battle06, soundBase::battle07 soundBase::battle05, soundBase::battle06, soundBase::battle07
}; };
//predefine terrain set
//TODO: need refactoring - support custom sounds for new terrains and load from json
int h3mTerrId = 0;
for(auto snd :
{
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;
}
for(auto & terrain : Terrain::Manager::terrains())
{
//since all sounds are hardcoded, let's keep it
if(vstd::contains(horseSounds, terrain))
continue;
horseSounds[terrain] = horseSounds.at(Terrain::createTerrainTypeH3M(Terrain::Manager::getInfo(terrain).horseSoundId));
}
}; };
void CSoundHandler::init() void CSoundHandler::init()
@ -341,26 +356,22 @@ CMusicHandler::CMusicHandler():
return true; return true;
}); });
int battleMusicID = 0;
int AIThemeID = 0;
for(const ResourceID & file : mp3files) for(const ResourceID & file : mp3files)
{ {
if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat")) if(boost::algorithm::istarts_with(file.getName(), "MUSIC/Combat"))
addEntryToSet("battle", battleMusicID++, file.getName()); addEntryToSet("battle", file.getName(), file.getName());
else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme")) else if(boost::algorithm::istarts_with(file.getName(), "MUSIC/AITheme"))
addEntryToSet("enemy-turn", AIThemeID++, file.getName()); addEntryToSet("enemy-turn", file.getName(), file.getName());
} }
JsonNode terrains(ResourceID("config/terrains.json")); for(auto & terrain : Terrain::Manager::terrains())
for (auto entry : terrains.Struct())
{ {
int terrIndex = vstd::find_pos(GameConstants::TERRAIN_NAMES, entry.first); auto & entry = Terrain::Manager::getInfo(terrain);
addEntryToSet("terrain", terrIndex, "Music/" + entry.second["music"].String()); addEntryToSet("terrain", terrain, "Music/" + entry.musicFilename);
} }
} }
void CMusicHandler::addEntryToSet(std::string set, int musicID, std::string musicURI) void CMusicHandler::addEntryToSet(const std::string & set, const std::string & musicID, const std::string & musicURI)
{ {
musicsSet[set][musicID] = musicURI; musicsSet[set][musicID] = musicURI;
} }
@ -388,7 +399,7 @@ void CMusicHandler::release()
CAudioBase::release(); CAudioBase::release();
} }
void CMusicHandler::playMusic(std::string musicURI, bool loop) void CMusicHandler::playMusic(const std::string & musicURI, bool loop)
{ {
if (current && current->isTrack(musicURI)) if (current && current->isTrack(musicURI))
return; return;
@ -396,7 +407,7 @@ void CMusicHandler::playMusic(std::string musicURI, bool loop)
queueNext(this, "", musicURI, loop); queueNext(this, "", musicURI, loop);
} }
void CMusicHandler::playMusicFromSet(std::string whichSet, bool loop) void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop)
{ {
auto selectedSet = musicsSet.find(whichSet); auto selectedSet = musicsSet.find(whichSet);
if (selectedSet == musicsSet.end()) if (selectedSet == musicsSet.end())
@ -412,8 +423,7 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, bool loop)
queueNext(this, whichSet, "", loop); queueNext(this, whichSet, "", loop);
} }
void CMusicHandler::playMusicFromSet(const std::string & whichSet, const std::string & entryID, bool loop)
void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loop)
{ {
auto selectedSet = musicsSet.find(whichSet); auto selectedSet = musicsSet.find(whichSet);
if (selectedSet == musicsSet.end()) if (selectedSet == musicsSet.end())
@ -425,7 +435,7 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loo
auto selectedEntry = selectedSet->second.find(entryID); auto selectedEntry = selectedSet->second.find(entryID);
if (selectedEntry == selectedSet->second.end()) if (selectedEntry == selectedSet->second.end())
{ {
logGlobal->error("Error: playing non-existing entry %d from set: %s", entryID, whichSet); logGlobal->error("Error: playing non-existing entry %s from set: %s", entryID, whichSet);
return; return;
} }
@ -452,7 +462,7 @@ void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
} }
} }
void CMusicHandler::queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped) void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped)
{ {
try try
{ {
@ -552,7 +562,7 @@ bool MusicEntry::play()
if (!setName.empty()) if (!setName.empty())
{ {
auto set = owner->musicsSet[setName]; const auto & set = owner->musicsSet[setName];
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second); load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
} }

View File

@ -16,6 +16,7 @@ struct _Mix_Music;
struct SDL_RWops; struct SDL_RWops;
typedef struct _Mix_Music Mix_Music; typedef struct _Mix_Music Mix_Music;
struct Mix_Chunk; struct Mix_Chunk;
class Terrain;
class CAudioBase { class CAudioBase {
protected: protected:
@ -81,8 +82,8 @@ public:
// Sets // Sets
std::vector<soundBase::soundID> pickupSounds; std::vector<soundBase::soundID> pickupSounds;
std::vector<soundBase::soundID> horseSounds;
std::vector<soundBase::soundID> battleIntroSounds; std::vector<soundBase::soundID> battleIntroSounds;
std::map<Terrain, soundBase::soundID> horseSounds;
}; };
// Helper //now it looks somewhat useless // Helper //now it looks somewhat useless
@ -118,6 +119,7 @@ public:
class CMusicHandler: public CAudioBase class CMusicHandler: public CAudioBase
{ {
private: private:
//update volume on configuration change //update volume on configuration change
SettingsListener listener; SettingsListener listener;
void onVolumeChange(const JsonNode &volumeNode); void onVolumeChange(const JsonNode &volumeNode);
@ -125,26 +127,27 @@ private:
std::unique_ptr<MusicEntry> current; std::unique_ptr<MusicEntry> current;
std::unique_ptr<MusicEntry> next; std::unique_ptr<MusicEntry> next;
void queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped); void queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped);
void queueNext(std::unique_ptr<MusicEntry> queued); void queueNext(std::unique_ptr<MusicEntry> queued);
std::map<std::string, std::map<int, std::string> > musicsSet; std::map<std::string, std::map<std::string, std::string>> musicsSet;
public: public:
CMusicHandler(); CMusicHandler();
/// add entry with URI musicURI in set. Track will have ID musicID /// add entry with URI musicURI in set. Track will have ID musicID
void addEntryToSet(std::string set, int musicID, std::string musicURI); void addEntryToSet(const std::string & set, const std::string & entryID, const std::string & musicURI);
void init() override; void init() override;
void release() override; void release() override;
void setVolume(ui32 percent) override; void setVolume(ui32 percent) override;
/// play track by URI, if loop = true music will be looped /// play track by URI, if loop = true music will be looped
void playMusic(std::string musicURI, bool loop); void playMusic(const std::string & musicURI, bool loop);
/// play random track from this set /// play random track from this set
void playMusicFromSet(std::string musicSet, bool loop); void playMusicFromSet(const std::string & musicSet, bool loop);
/// play specific track from set /// play specific track from set
void playMusicFromSet(std::string musicSet, int entryID, bool loop); void playMusicFromSet(const std::string & musicSet, const std::string & entryID, bool loop);
void stopMusic(int fade_ms=1000); void stopMusic(int fade_ms=1000);
void musicFinishedCallback(); void musicFinishedCallback();

View File

@ -1351,12 +1351,6 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version ) template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
{ {
if(version < 774 && !h.saving)
{
bool observerInDuelMode = false;
h & observerInDuelMode;
}
h & wanderingHeroes; h & wanderingHeroes;
h & towns; h & towns;
h & sleepingHeroes; h & sleepingHeroes;
@ -2742,8 +2736,8 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
{ {
path.convert(0); path.convert(0);
ETerrainType currentTerrain = ETerrainType::BORDER; // not init yet Terrain currentTerrain = Terrain("BORDER"); // not init yet
ETerrainType newTerrain; Terrain newTerrain;
int sh = -1; int sh = -1;
auto canStop = [&](CGPathNode * node) -> bool auto canStop = [&](CGPathNode * node) -> bool
@ -2779,7 +2773,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
destinationTeleportPos = int3(-1); destinationTeleportPos = int3(-1);
} }
if(i != path.nodes.size() - 1) if(i != path.nodes.size() - 1)
{
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1); sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
}
continue; continue;
} }
@ -2797,7 +2793,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
#endif #endif
{ {
newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType; newTerrain = cb->getTile(CGHeroInstance::convertPosition(currentCoord, false))->terType;
if (newTerrain != currentTerrain) if(newTerrain != currentTerrain)
{ {
CCS->soundh->stopSound(sh); CCS->soundh->stopSound(sh);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1); sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);

View File

@ -274,12 +274,6 @@ void CClient::serialize(BinarySerializer & h, const int version)
void CClient::serialize(BinaryDeserializer & h, const int version) void CClient::serialize(BinaryDeserializer & h, const int version)
{ {
assert(!h.saving); assert(!h.saving);
if(version < 787)
{
bool hotSeat = false;
h & hotSeat;
}
ui8 players = 0; ui8 players = 0;
h & players; h & players;
@ -337,11 +331,7 @@ void CClient::serialize(BinaryDeserializer & h, const int version)
{ {
JsonNode scriptsState; JsonNode scriptsState;
if(version >= 800) h & scriptsState;
{
h & scriptsState;
}
clientScripts->serializeState(h.saving, scriptsState); clientScripts->serializeState(h.saving, scriptsState);
} }

View File

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

View File

@ -20,6 +20,7 @@
#include "../lib/CGameState.h" #include "../lib/CGameState.h"
#include "../lib/CHeroHandler.h" #include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h" #include "../lib/CTownHandler.h"
#include "../lib/CModHandler.h"
#include "Graphics.h" #include "Graphics.h"
#include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
@ -29,6 +30,9 @@
#include "CMT.h" #include "CMT.h"
#include "CMusicHandler.h" #include "CMusicHandler.h"
#include "../lib/CRandomGenerator.h" #include "../lib/CRandomGenerator.h"
#include "../lib/Terrain.h"
#include "../lib/filesystem/ResourceID.h"
#include "../lib/JsonDetail.h"
#define ADVOPT (conf.go()->ac) #define ADVOPT (conf.go()->ac)
@ -142,79 +146,68 @@ EMapAnimRedrawStatus CMapHandler::drawTerrainRectNew(SDL_Surface * targetSurface
void CMapHandler::initTerrainGraphics() void CMapHandler::initTerrainGraphics()
{ {
static const std::vector<std::string> TERRAIN_FILES = static const std::map<std::string, std::string> ROAD_FILES =
{ {
"DIRTTL", {ROAD_NAMES[1], "dirtrd"},
"SANDTL", {ROAD_NAMES[2], "gravrd"},
"GRASTL", {ROAD_NAMES[3], "cobbrd"}
"SNOWTL",
"SWMPTL",
"ROUGTL",
"SUBBTL",
"LAVATL",
"WATRTL",
"ROCKTL"
}; };
static const std::vector<std::string> ROAD_FILES = static const std::map<std::string, std::string> RIVER_FILES =
{ {
"dirtrd", {RIVER_NAMES[1], "clrrvr"},
"gravrd", {RIVER_NAMES[2], "icyrvr"},
"cobbrd" {RIVER_NAMES[3], "mudrvr"},
{RIVER_NAMES[4], "lavrvr"}
}; };
static const std::vector<std::string> RIVER_FILES = auto loadFlipped = [](TFlippedAnimations & animation, TFlippedCache & cache, const std::map<std::string, std::string> & files)
{ {
"clrrvr",
"icyrvr",
"mudrvr",
"lavrvr"
};
auto loadFlipped = [](int types, TFlippedAnimations & animation, TFlippedCache & cache, const std::vector<std::string> & files)
{
animation.resize(types);
cache.resize(types);
//no rotation and basic setup //no rotation and basic setup
for(int i = 0; i < types; i++) for(auto & type : files)
{ {
animation[i][0] = make_unique<CAnimation>(files[i]); animation[type.first][0] = make_unique<CAnimation>(type.second);
animation[i][0]->preload(); animation[type.first][0]->preload();
const size_t views = animation[i][0]->size(0); const size_t views = animation[type.first][0]->size(0);
cache[i].resize(views); cache[type.first].resize(views);
for(int j = 0; j < views; j++) for(int j = 0; j < views; j++)
cache[i][j][0] = animation[i][0]->getImage(j); cache[type.first][j][0] = animation[type.first][0]->getImage(j);
} }
for(int rotation = 1; rotation < 4; rotation++) for(int rotation = 1; rotation < 4; rotation++)
{ {
for(int i = 0; i < types; i++) for(auto & type : files)
{ {
animation[i][rotation] = make_unique<CAnimation>(files[i]); animation[type.first][rotation] = make_unique<CAnimation>(type.second);
animation[i][rotation]->preload(); animation[type.first][rotation]->preload();
const size_t views = animation[i][rotation]->size(0); const size_t views = animation[type.first][rotation]->size(0);
for(int j = 0; j < views; j++) for(int j = 0; j < views; j++)
{ {
auto image = animation[i][rotation]->getImage(j); auto image = animation[type.first][rotation]->getImage(j);
if(rotation == 2 || rotation == 3) if(rotation == 2 || rotation == 3)
image->horizontalFlip(); image->horizontalFlip();
if(rotation == 1 || rotation == 3) if(rotation == 1 || rotation == 3)
image->verticalFlip(); image->verticalFlip();
cache[i][j][rotation] = image; cache[type.first][j][rotation] = image;
} }
} }
} }
}; };
loadFlipped(GameConstants::TERRAIN_TYPES, terrainAnimations, terrainImages, TERRAIN_FILES); std::map<std::string, std::string> terrainFiles;
loadFlipped(3, roadAnimations, roadImages, ROAD_FILES); for(auto & terrain : Terrain::Manager::terrains())
loadFlipped(4, riverAnimations, riverImages, RIVER_FILES); {
terrainFiles[terrain] = Terrain::Manager::getInfo(terrain).tilesFilename;
}
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
loadFlipped(roadAnimations, roadImages, ROAD_FILES);
loadFlipped(riverAnimations, riverImages, RIVER_FILES);
// Create enough room for the whole map and its frame // Create enough room for the whole map and its frame
@ -626,6 +619,9 @@ void CMapHandler::CMapBlitter::drawTileTerrain(SDL_Surface * targetSurf, const T
Rect destRect(realTileRect); Rect destRect(realTileRect);
ui8 rotation = tinfo.extTileFlags % 4; ui8 rotation = tinfo.extTileFlags % 4;
if(parent->terrainImages[tinfo.terType].size()<=tinfo.terView)
return;
drawElement(EMapCacheType::TERRAIN, parent->terrainImages[tinfo.terType][tinfo.terView][rotation], nullptr, targetSurf, &destRect); drawElement(EMapCacheType::TERRAIN, parent->terrainImages[tinfo.terType][tinfo.terView][rotation], nullptr, targetSurf, &destRect);
} }
@ -802,21 +798,21 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
void CMapHandler::CMapBlitter::drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const void CMapHandler::CMapBlitter::drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const
{ {
if (tinfoUpper && tinfoUpper->roadType != ERoadType::NO_ROAD) if (tinfoUpper && tinfoUpper->roadType != ROAD_NAMES[0])
{ {
ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4; ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4;
Rect source(0, tileSize / 2, tileSize, tileSize / 2); Rect source(0, tileSize / 2, tileSize, tileSize / 2);
Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2); Rect dest(realPos.x, realPos.y, tileSize, tileSize / 2);
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfoUpper->roadType - 1][tinfoUpper->roadDir][rotation], drawElement(EMapCacheType::ROADS, parent->roadImages[tinfoUpper->roadType][tinfoUpper->roadDir][rotation],
&source, targetSurf, &dest); &source, targetSurf, &dest);
} }
if(tinfo.roadType != ERoadType::NO_ROAD) //print road from this tile if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile
{ {
ui8 rotation = (tinfo.extTileFlags >> 4) % 4; ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
Rect source(0, 0, tileSize, halfTileSizeCeil); Rect source(0, 0, tileSize, halfTileSizeCeil);
Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, tileSize / 2); Rect dest(realPos.x, realPos.y + tileSize / 2, tileSize, tileSize / 2);
drawElement(EMapCacheType::ROADS, parent->roadImages[tinfo.roadType - 1][tinfo.roadDir][rotation], drawElement(EMapCacheType::ROADS, parent->roadImages[tinfo.roadType][tinfo.roadDir][rotation],
&source, targetSurf, &dest); &source, targetSurf, &dest);
} }
} }
@ -825,7 +821,7 @@ void CMapHandler::CMapBlitter::drawRiver(SDL_Surface * targetSurf, const Terrain
{ {
Rect destRect(realTileRect); Rect destRect(realTileRect);
ui8 rotation = (tinfo.extTileFlags >> 2) % 4; ui8 rotation = (tinfo.extTileFlags >> 2) % 4;
drawElement(EMapCacheType::RIVERS, parent->riverImages[tinfo.riverType-1][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect); drawElement(EMapCacheType::RIVERS, parent->riverImages[tinfo.riverType][tinfo.riverDir][rotation], nullptr, targetSurf, &destRect);
} }
void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const void CMapHandler::CMapBlitter::drawFow(SDL_Surface * targetSurf) const
@ -876,7 +872,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
if(isVisible || info->showAllTerrain) if(isVisible || info->showAllTerrain)
{ {
drawTileTerrain(targetSurf, tinfo, tile); drawTileTerrain(targetSurf, tinfo, tile);
if (tinfo.riverType) if(tinfo.riverType != RIVER_NAMES[0])
drawRiver(targetSurf, tinfo); drawRiver(targetSurf, tinfo);
drawRoad(targetSurf, tinfo, tinfoUpper); drawRoad(targetSurf, tinfo, tinfoUpper);
} }
@ -1326,13 +1322,13 @@ bool CMapHandler::canStartHeroMovement()
void CMapHandler::updateWater() //shift colors in palettes of water tiles void CMapHandler::updateWater() //shift colors in palettes of water tiles
{ {
for(auto & elem : terrainImages[7]) for(auto & elem : terrainImages["lava"])
{ {
for(auto img : elem) for(auto img : elem)
img->shiftPalette(246, 9); img->shiftPalette(246, 9);
} }
for(auto & elem : terrainImages[8]) for(auto & elem : terrainImages["water"])
{ {
for(auto img : elem) for(auto img : elem)
{ {
@ -1341,7 +1337,7 @@ void CMapHandler::updateWater() //shift colors in palettes of water tiles
} }
} }
for(auto & elem : riverImages[0]) for(auto & elem : riverImages["clrrvr"])
{ {
for(auto img : elem) for(auto img : elem)
{ {
@ -1350,7 +1346,7 @@ void CMapHandler::updateWater() //shift colors in palettes of water tiles
} }
} }
for(auto & elem : riverImages[2]) for(auto & elem : riverImages["mudrvr"])
{ {
for(auto img : elem) for(auto img : elem)
{ {
@ -1360,7 +1356,7 @@ void CMapHandler::updateWater() //shift colors in palettes of water tiles
} }
} }
for(auto & elem : riverImages[3]) for(auto & elem : riverImages["lavrvr"])
{ {
for(auto img : elem) for(auto img : elem)
img->shiftPalette(240, 9); img->shiftPalette(240, 9);

View File

@ -354,8 +354,8 @@ public:
//terrain graphics //terrain graphics
//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013 //FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013
typedef std::vector<std::array<std::shared_ptr<CAnimation>, 4>> TFlippedAnimations; //[type, rotation] typedef std::map<std::string, std::array<std::shared_ptr<CAnimation>, 4>> TFlippedAnimations; //[type, rotation]
typedef std::vector<std::vector<std::array<std::shared_ptr<IImage>, 4>>> TFlippedCache;//[type, view type, rotation] typedef std::map<std::string, std::vector<std::array<std::shared_ptr<IImage>, 4>>> TFlippedCache;//[type, view type, rotation]
TFlippedAnimations terrainAnimations;//[terrain type, rotation] TFlippedAnimations terrainAnimations;//[terrain type, rotation]
TFlippedCache terrainImages;//[terrain type, view type, rotation] TFlippedCache terrainImages;//[terrain type, view type, rotation]

View File

@ -42,6 +42,7 @@
#include "../../lib/CHeroHandler.h" #include "../../lib/CHeroHandler.h"
#include "../../lib/CModHandler.h" #include "../../lib/CModHandler.h"
#include "../../lib/CTownHandler.h" #include "../../lib/CTownHandler.h"
#include "../../lib/Terrain.h"
#include "../../lib/filesystem/Filesystem.h" #include "../../lib/filesystem/Filesystem.h"
#include "../../lib/JsonNode.h" #include "../../lib/JsonNode.h"
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
@ -494,41 +495,30 @@ void CMinimapInstance::showAll(SDL_Surface * to)
} }
} }
std::map<int, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors(std::string from) std::map<Terrain, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors()
{ {
std::map<int, std::pair<SDL_Color, SDL_Color> > ret; std::map<Terrain, std::pair<SDL_Color, SDL_Color> > ret;
const JsonNode config(ResourceID(from, EResType::TEXT)); for(auto & terrain : Terrain::Manager::terrains())
for(auto &m : config.Struct())
{ {
auto index = boost::find(GameConstants::TERRAIN_NAMES, m.first); auto & m = Terrain::Manager::getInfo(terrain);
if (index == std::end(GameConstants::TERRAIN_NAMES))
{
logGlobal->error("Error: unknown terrain in terrains.json: %s", m.first);
continue;
}
int terrainID = static_cast<int>(index - std::begin(GameConstants::TERRAIN_NAMES));
const JsonVector &unblockedVec = m.second["minimapUnblocked"].Vector();
SDL_Color normal = SDL_Color normal =
{ {
ui8(unblockedVec[0].Float()), ui8(m.minimapUnblocked[0]),
ui8(unblockedVec[1].Float()), ui8(m.minimapUnblocked[1]),
ui8(unblockedVec[2].Float()), ui8(m.minimapUnblocked[2]),
ui8(255) ui8(255)
}; };
const JsonVector &blockedVec = m.second["minimapBlocked"].Vector();
SDL_Color blocked = SDL_Color blocked =
{ {
ui8(blockedVec[0].Float()), ui8(m.minimapBlocked[0]),
ui8(blockedVec[1].Float()), ui8(m.minimapBlocked[1]),
ui8(blockedVec[2].Float()), ui8(m.minimapBlocked[2]),
ui8(255) ui8(255)
}; };
ret.insert(std::make_pair(terrainID, std::make_pair(normal, blocked))); ret[terrain] = std::make_pair(normal, blocked);
} }
return ret; return ret;
} }
@ -536,7 +526,7 @@ std::map<int, std::pair<SDL_Color, SDL_Color> > CMinimap::loadColors(std::string
CMinimap::CMinimap(const Rect & position) CMinimap::CMinimap(const Rect & position)
: CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()), : CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()),
level(0), level(0),
colors(loadColors("config/terrains.json")) colors(loadColors())
{ {
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
pos.w = position.w; pos.w = position.w;

View File

@ -30,6 +30,7 @@ struct InfoAboutTown;
class CHeroTooltip; class CHeroTooltip;
class CTownTooltip; class CTownTooltip;
class CTextBox; class CTextBox;
class Terrain;
/// Base UI Element for hero\town lists /// Base UI Element for hero\town lists
class CList : public CIntObject class CList : public CIntObject
@ -216,7 +217,7 @@ protected:
int level; int level;
//to initialize colors //to initialize colors
std::map<int, std::pair<SDL_Color, SDL_Color> > loadColors(std::string from); std::map<Terrain, std::pair<SDL_Color, SDL_Color> > loadColors();
void clickLeft(tribool down, bool previousState) override; void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override; void clickRight(tribool down, bool previousState) override;
@ -227,7 +228,7 @@ protected:
public: public:
// terrainID -> (normal color, blocked color) // terrainID -> (normal color, blocked color)
const std::map<int, std::pair<SDL_Color, SDL_Color> > colors; const std::map<Terrain, std::pair<SDL_Color, SDL_Color> > colors;
CMinimap(const Rect & position); CMinimap(const Rect & position);

View File

@ -265,7 +265,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect, SDL_Surface * to)
{-1, 1, 2, 23, -1, 3, 22, 21, 12} {-1, 1, 2, 23, -1, 3, 22, 21, 12}
}; //table of magic values TODO meaning, change variable name }; //table of magic values TODO meaning, change variable name
for (int i=0; i < (int)currentPath->nodes.size()-1; ++i) for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i)
{ {
const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord;
if(curPos.z != adventureInt->position.z) if(curPos.z != adventureInt->position.z)

View File

@ -80,5 +80,9 @@
"skills" : "skills" :
[ [
"config/skills.json" "config/skills.json"
],
"terrains":
[
"config/terrains.json"
] ]
} }

View File

@ -14,7 +14,7 @@
"obstacles" : [ "obstacles" : [
{ {
"id" : 0, "id" : 0,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -24,7 +24,7 @@
}, },
{ {
"id" : 1, "id" : 1,
"allowedTerrain" : [0, 1, 5, 6], "allowedTerrain" : ["dirt", "sand", "rough", "subterra"],
"specialBattlefields" : [0], "specialBattlefields" : [0],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -34,7 +34,7 @@
}, },
{ {
"id" : 2, "id" : 2,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 2, "height" : 2,
@ -44,7 +44,7 @@
}, },
{ {
"id" : 3, "id" : 3,
"allowedTerrain" : [0, 5], "allowedTerrain" : ["dirt", "rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -54,7 +54,7 @@
}, },
{ {
"id" : 4, "id" : 4,
"allowedTerrain" : [0, 5, 6], "allowedTerrain" : ["dirt", "rough", "subterra"],
"specialBattlefields" : [0, 1], "specialBattlefields" : [0, 1],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -64,7 +64,7 @@
}, },
{ {
"id" : 5, "id" : 5,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 2, "height" : 2,
@ -74,7 +74,7 @@
}, },
{ {
"id" : 6, "id" : 6,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -84,7 +84,7 @@
}, },
{ {
"id" : 7, "id" : 7,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -94,7 +94,7 @@
}, },
{ {
"id" : 8, "id" : 8,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -104,7 +104,7 @@
}, },
{ {
"id" : 9, "id" : 9,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -114,7 +114,7 @@
}, },
{ {
"id" : 10, "id" : 10,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -124,7 +124,7 @@
}, },
{ {
"id" : 11, "id" : 11,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -134,7 +134,7 @@
}, },
{ {
"id" : 12, "id" : 12,
"allowedTerrain" : [0, 5], "allowedTerrain" : ["dirt", "rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -144,7 +144,7 @@
}, },
{ {
"id" : 13, "id" : 13,
"allowedTerrain" : [0, 5], "allowedTerrain" : ["dirt", "rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -154,7 +154,7 @@
}, },
{ {
"id" : 14, "id" : 14,
"allowedTerrain" : [0, 5], "allowedTerrain" : ["dirt", "rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -164,7 +164,7 @@
}, },
{ {
"id" : 15, "id" : 15,
"allowedTerrain" : [0, 5], "allowedTerrain" : ["dirt", "rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -174,7 +174,7 @@
}, },
{ {
"id" : 16, "id" : 16,
"allowedTerrain" : [1], "allowedTerrain" : ["sand"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 4, "height" : 4,
@ -184,7 +184,7 @@
}, },
{ {
"id" : 17, "id" : 17,
"allowedTerrain" : [1], "allowedTerrain" : ["sand"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -194,7 +194,7 @@
}, },
{ {
"id" : 18, "id" : 18,
"allowedTerrain" : [1], "allowedTerrain" : ["sand"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 2, "height" : 2,
@ -204,7 +204,7 @@
}, },
{ {
"id" : 19, "id" : 19,
"allowedTerrain" : [2, 4], "allowedTerrain" : ["grass", "swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -214,7 +214,7 @@
}, },
{ {
"id" : 20, "id" : 20,
"allowedTerrain" : [2, 4], "allowedTerrain" : ["grass", "swamp"],
"specialBattlefields" : [2], "specialBattlefields" : [2],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -224,7 +224,7 @@
}, },
{ {
"id" : 21, "id" : 21,
"allowedTerrain" : [2, 4], "allowedTerrain" : ["grass", "swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 1, "width" : 1,
"height" : 1, "height" : 1,
@ -234,7 +234,7 @@
}, },
{ {
"id" : 22, "id" : 22,
"allowedTerrain" : [2], "allowedTerrain" : ["grass"],
"specialBattlefields" : [2], "specialBattlefields" : [2],
"width" : 6, "width" : 6,
"height" : 2, "height" : 2,
@ -244,7 +244,7 @@
}, },
{ {
"id" : 23, "id" : 23,
"allowedTerrain" : [2], "allowedTerrain" : ["grass"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 7, "width" : 7,
"height" : 1, "height" : 1,
@ -254,7 +254,7 @@
}, },
{ {
"id" : 24, "id" : 24,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 1, "height" : 1,
@ -264,7 +264,7 @@
}, },
{ {
"id" : 25, "id" : 25,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 1, "height" : 1,
@ -274,7 +274,7 @@
}, },
{ {
"id" : 26, "id" : 26,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -284,7 +284,7 @@
}, },
{ {
"id" : 27, "id" : 27,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 1, "height" : 1,
@ -294,7 +294,7 @@
}, },
{ {
"id" : 28, "id" : 28,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 1, "height" : 1,
@ -304,7 +304,7 @@
}, },
{ {
"id" : 29, "id" : 29,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -314,7 +314,7 @@
}, },
{ {
"id" : 30, "id" : 30,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -324,7 +324,7 @@
}, },
{ {
"id" : 31, "id" : 31,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -334,7 +334,7 @@
}, },
{ {
"id" : 32, "id" : 32,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 7, "width" : 7,
"height" : 2, "height" : 2,
@ -344,7 +344,7 @@
}, },
{ {
"id" : 33, "id" : 33,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 5, "height" : 5,
@ -354,7 +354,7 @@
}, },
{ {
"id" : 34, "id" : 34,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -364,7 +364,7 @@
}, },
{ {
"id" : 35, "id" : 35,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 8, "width" : 8,
"height" : 3, "height" : 3,
@ -374,7 +374,7 @@
}, },
{ {
"id" : 36, "id" : 36,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 2, "width" : 2,
"height" : 1, "height" : 1,
@ -384,7 +384,7 @@
}, },
{ {
"id" : 37, "id" : 37,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 1, "height" : 1,
@ -394,7 +394,7 @@
}, },
{ {
"id" : 38, "id" : 38,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 4, "height" : 4,
@ -404,7 +404,7 @@
}, },
{ {
"id" : 39, "id" : 39,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 3, "height" : 3,
@ -414,7 +414,7 @@
}, },
{ {
"id" : 40, "id" : 40,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 2, "width" : 2,
"height" : 2, "height" : 2,
@ -424,7 +424,7 @@
}, },
{ {
"id" : 41, "id" : 41,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 4, "width" : 4,
"height" : 3, "height" : 3,
@ -434,7 +434,7 @@
}, },
{ {
"id" : 42, "id" : 42,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -444,7 +444,7 @@
}, },
{ {
"id" : 43, "id" : 43,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -454,7 +454,7 @@
}, },
{ {
"id" : 44, "id" : 44,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -464,7 +464,7 @@
}, },
{ {
"id" : 45, "id" : 45,
"allowedTerrain" : [6], "allowedTerrain" : ["subterra"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -474,7 +474,7 @@
}, },
{ {
"id" : 46, "id" : 46,
"allowedTerrain" : [6], "allowedTerrain" : ["subterra"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -484,7 +484,7 @@
}, },
{ {
"id" : 47, "id" : 47,
"allowedTerrain" : [6], "allowedTerrain" : ["subterra"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 3, "height" : 3,
@ -494,7 +494,7 @@
}, },
{ {
"id" : 48, "id" : 48,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 3, "height" : 3,
@ -504,7 +504,7 @@
}, },
{ {
"id" : 49, "id" : 49,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 2, "height" : 2,
@ -514,7 +514,7 @@
}, },
{ {
"id" : 50, "id" : 50,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 3, "height" : 3,
@ -524,7 +524,7 @@
}, },
{ {
"id" : 51, "id" : 51,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 2, "height" : 2,
@ -534,7 +534,7 @@
}, },
{ {
"id" : 52, "id" : 52,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 4, "width" : 4,
"height" : 4, "height" : 4,
@ -544,7 +544,7 @@
}, },
{ {
"id" : 53, "id" : 53,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 3, "height" : 3,
@ -554,7 +554,7 @@
}, },
{ {
"id" : 54, "id" : 54,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 5, "width" : 5,
"height" : 3, "height" : 3,
@ -564,7 +564,7 @@
}, },
{ {
"id" : 55, "id" : 55,
"allowedTerrain" : [8], "allowedTerrain" : ["water"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 3, "width" : 3,
"height" : 3, "height" : 3,
@ -926,7 +926,7 @@
"absoluteObstacles" : [ "absoluteObstacles" : [
{ {
"id" : 0, "id" : 0,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 124, "width" : 124,
"height" : 254, "height" : 254,
@ -935,7 +935,7 @@
}, },
{ {
"id" : 1, "id" : 1,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 256, "width" : 256,
"height" : 254, "height" : 254,
@ -944,7 +944,7 @@
}, },
{ {
"id" : 2, "id" : 2,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 168, "width" : 168,
"height" : 212, "height" : 212,
@ -953,7 +953,7 @@
}, },
{ {
"id" : 3, "id" : 3,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 124, "width" : 124,
"height" : 254, "height" : 254,
@ -962,7 +962,7 @@
}, },
{ {
"id" : 4, "id" : 4,
"allowedTerrain" : [0], "allowedTerrain" : ["dirt"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 146, "width" : 146,
"height" : 254, "height" : 254,
@ -971,7 +971,7 @@
}, },
{ {
"id" : 5, "id" : 5,
"allowedTerrain" : [2], "allowedTerrain" : ["grass"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 173, "width" : 173,
"height" : 221, "height" : 221,
@ -980,7 +980,7 @@
}, },
{ {
"id" : 6, "id" : 6,
"allowedTerrain" : [2], "allowedTerrain" : ["grass"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 180, "width" : 180,
"height" : 264, "height" : 264,
@ -989,7 +989,7 @@
}, },
{ {
"id" : 7, "id" : 7,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 166, "width" : 166,
"height" : 255, "height" : 255,
@ -998,7 +998,7 @@
}, },
{ {
"id" : 8, "id" : 8,
"allowedTerrain" : [3], "allowedTerrain" : ["snow"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 302, "width" : 302,
"height" : 172, "height" : 172,
@ -1007,7 +1007,7 @@
}, },
{ {
"id" : 9, "id" : 9,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 300, "width" : 300,
"height" : 170, "height" : 170,
@ -1016,7 +1016,7 @@
}, },
{ {
"id" : 10, "id" : 10,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 278, "width" : 278,
"height" : 171, "height" : 171,
@ -1025,7 +1025,7 @@
}, },
{ {
"id" : 11, "id" : 11,
"allowedTerrain" : [4], "allowedTerrain" : ["swamp"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 256, "width" : 256,
"height" : 254, "height" : 254,
@ -1034,7 +1034,7 @@
}, },
{ {
"id" : 12, "id" : 12,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 124, "width" : 124,
"height" : 254, "height" : 254,
@ -1043,7 +1043,7 @@
}, },
{ {
"id" : 13, "id" : 13,
"allowedTerrain" : [7], "allowedTerrain" : ["lava"],
"specialBattlefields" : [], "specialBattlefields" : [],
"width" : 256, "width" : 256,
"height" : 128, "height" : 128,
@ -1052,7 +1052,7 @@
}, },
{ {
"id" : 14, "id" : 14,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 186, "width" : 186,
"height" : 212, "height" : 212,
@ -1061,7 +1061,7 @@
}, },
{ {
"id" : 15, "id" : 15,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 347, "width" : 347,
"height" : 174, "height" : 174,
@ -1070,7 +1070,7 @@
}, },
{ {
"id" : 16, "id" : 16,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 294, "width" : 294,
"height" : 169, "height" : 169,
@ -1079,7 +1079,7 @@
}, },
{ {
"id" : 17, "id" : 17,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 165, "width" : 165,
"height" : 257, "height" : 257,
@ -1088,7 +1088,7 @@
}, },
{ {
"id" : 18, "id" : 18,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 208, "width" : 208,
"height" : 268, "height" : 268,
@ -1097,7 +1097,7 @@
}, },
{ {
"id" : 19, "id" : 19,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 252, "width" : 252,
"height" : 254, "height" : 254,
@ -1106,7 +1106,7 @@
}, },
{ {
"id" : 20, "id" : 20,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 278, "width" : 278,
"height" : 128, "height" : 128,
@ -1115,7 +1115,7 @@
}, },
{ {
"id" : 21, "id" : 21,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 208, "width" : 208,
"height" : 268, "height" : 268,
@ -1124,7 +1124,7 @@
}, },
{ {
"id" : 22, "id" : 22,
"allowedTerrain" : [5], "allowedTerrain" : ["rough"],
"specialBattlefields" : [1], "specialBattlefields" : [1],
"width" : 168, "width" : 168,
"height" : 212, "height" : 212,

View File

@ -2,7 +2,7 @@
"terrain" : "terrain" :
{ {
"undergroundAllow" : ["lava"], //others to be replaced by subterranena "undergroundAllow" : ["lava"], //others to be replaced by subterranena
"groundProhibit" : ["subterranean"] //to be replaced by dirt "groundProhibit" : ["subterra"] //to be replaced by dirt
}, },
"waterZone" : "waterZone" :
{ {
@ -31,7 +31,7 @@
"extraResourcesLimit" : 3 "extraResourcesLimit" : 3
}, },
"minGuardStrength" : 2000, "minGuardStrength" : 2000,
"defaultRoadType" : "cobblestone_road", "defaultRoadType" : "pc", //pd - dirt, pg - gravel, pc - cobblestone
"treasureValueLimit" : 20000, //generate pandora with gold for treasure above this limit "treasureValueLimit" : 20000, //generate pandora with gold for treasure above this limit
"prisons" : "prisons" :
{ {

View File

@ -4,69 +4,92 @@
"moveCost" : 100, "moveCost" : 100,
"minimapUnblocked" : [ 82, 56, 8 ], "minimapUnblocked" : [ 82, 56, 8 ],
"minimapBlocked" : [ 57, 40, 8 ], "minimapBlocked" : [ 57, 40, 8 ],
"music" : "Dirt.mp3" "music" : "Dirt.mp3",
"tiles" : "DIRTTL",
"code" : "dt"
}, },
"sand" : "sand" :
{ {
"moveCost" : 150, "moveCost" : 150,
"minimapUnblocked" : [ 222, 207, 140 ], "minimapUnblocked" : [ 222, 207, 140 ],
"minimapBlocked" : [ 165, 158, 107 ], "minimapBlocked" : [ 165, 158, 107 ],
"music" : "Sand.mp3" "music" : "Sand.mp3",
"tiles" : "SANDTL",
"code" : "sa"
}, },
"grass" : "grass" :
{ {
"moveCost" : 100, "moveCost" : 100,
"minimapUnblocked" : [ 0, 65, 0 ], "minimapUnblocked" : [ 0, 65, 0 ],
"minimapBlocked" : [ 0, 48, 0 ], "minimapBlocked" : [ 0, 48, 0 ],
"music" : "Grass.mp3" "music" : "Grass.mp3",
"tiles" : "GRASTL",
"code" : "gr"
}, },
"snow" : "snow" :
{ {
"moveCost" : 150, "moveCost" : 150,
"minimapUnblocked" : [ 181, 199, 198 ], "minimapUnblocked" : [ 181, 199, 198 ],
"minimapBlocked" : [ 140, 158, 156 ], "minimapBlocked" : [ 140, 158, 156 ],
"music" : "Snow.mp3" "music" : "Snow.mp3",
"tiles" : "SNOWTL",
"code" : "sn"
}, },
"swamp" : "swamp" :
{ {
"moveCost" : 175, "moveCost" : 175,
"minimapUnblocked" : [ 74, 134, 107 ], "minimapUnblocked" : [ 74, 134, 107 ],
"minimapBlocked" : [ 33, 89, 66 ], "minimapBlocked" : [ 33, 89, 66 ],
"music" : "Swamp.mp3" "music" : "Swamp.mp3",
"tiles" : "SWMPTL",
"code" : "sw"
}, },
"rough" : "rough" :
{ {
"moveCost" : 125, "moveCost" : 125,
"minimapUnblocked" : [ 132, 113, 49 ], "minimapUnblocked" : [ 132, 113, 49 ],
"minimapBlocked" : [ 99, 81, 33 ], "minimapBlocked" : [ 99, 81, 33 ],
"music" : "Rough.mp3" "music" : "Rough.mp3",
"tiles" : "ROUGTL",
"code" : "rg"
}, },
"subterra" : "subterra" :
{ {
"moveCost" : 100, "moveCost" : 100,
"minimapUnblocked" : [ 132, 48, 0 ], "minimapUnblocked" : [ 132, 48, 0 ],
"minimapBlocked" : [ 90, 8, 0 ], "minimapBlocked" : [ 90, 8, 0 ],
"music" : "Underground.mp3" "music" : "Underground.mp3",
"tiles" : "SUBBTL",
"type" : "SUB",
"code" : "sb"
}, },
"lava" : "lava" :
{ {
"moveCost" : 100, "moveCost" : 100,
"minimapUnblocked" : [ 74, 73, 74 ], "minimapUnblocked" : [ 74, 73, 74 ],
"minimapBlocked" : [ 41, 40, 41 ], "minimapBlocked" : [ 41, 40, 41 ],
"music" : "Lava.mp3" "music" : "Lava.mp3",
"tiles" : "LAVATL",
"code" : "lv"
}, },
"water" : "water" :
{ {
"moveCost" : 100, "moveCost" : 100,
"minimapUnblocked" : [ 8, 81, 148 ], "minimapUnblocked" : [ 8, 81, 148 ],
"minimapBlocked" : [ 8, 81, 148 ], "minimapBlocked" : [ 8, 81, 148 ],
"music" : "Water.mp3" "music" : "Water.mp3",
"tiles" : "WATRTL",
"type" : "WATER",
"code" : "wt"
}, },
"rock" : "rock" :
{ {
"moveCost" : -1, "moveCost" : -1,
"minimapUnblocked" : [ 0, 0, 0 ], "minimapUnblocked" : [ 0, 0, 0 ],
"minimapBlocked" : [ 0, 0, 0 ], "minimapBlocked" : [ 0, 0, 0 ],
"music" : "Underground.mp3" // Impossible in H3 "music" : "Underground.mp3", // Impossible in H3
"tiles" : "ROCKTL",
"type" : "ROCK",
"code" : "rc"
} }
} }

View File

@ -102,19 +102,8 @@ public:
h & constituentOf; h & constituentOf;
h & aClass; h & aClass;
h & id; h & id;
if(version >= 759) h & identifier;
{ h & warMachine;
h & identifier;
}
if(version >= 771)
{
h & warMachine;
}
else if(!h.saving)
{
fillWarMachine();
}
} }
CArtifact(); CArtifact();

View File

@ -16,6 +16,7 @@
#include "CGameState.h" #include "CGameState.h"
#include "CTownHandler.h" #include "CTownHandler.h"
#include "CModHandler.h" #include "CModHandler.h"
#include "Terrain.h"
#include "StringConstants.h" #include "StringConstants.h"
#include "serializer/JsonDeserializer.h" #include "serializer/JsonDeserializer.h"
#include "serializer/JsonUpdater.h" #include "serializer/JsonUpdater.h"
@ -282,13 +283,13 @@ std::string CCreature::nodeName() const
return "\"" + namePl + "\""; return "\"" + namePl + "\"";
} }
bool CCreature::isItNativeTerrain(ETerrainType::EETerrainType terrain) const bool CCreature::isItNativeTerrain(const Terrain & terrain) const
{ {
auto native = getNativeTerrain(); auto native = getNativeTerrain();
return native == terrain || native == ETerrainType::ANY_TERRAIN; return native == terrain || native == Terrain::ANY;
} }
ETerrainType::EETerrainType CCreature::getNativeTerrain() const Terrain CCreature::getNativeTerrain() const
{ {
const std::string cachingStringBlocksRetaliation = "type_NO_TERRAIN_PENALTY"; const std::string cachingStringBlocksRetaliation = "type_NO_TERRAIN_PENALTY";
static const auto selectorBlocksRetaliation = Selector::type()(Bonus::NO_TERRAIN_PENALTY); static const auto selectorBlocksRetaliation = Selector::type()(Bonus::NO_TERRAIN_PENALTY);
@ -296,8 +297,8 @@ ETerrainType::EETerrainType CCreature::getNativeTerrain() const
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses //this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
//and in the CGHeroInstance::getNativeTerrain() to setup mevement bonuses or/and penalties. //and in the CGHeroInstance::getNativeTerrain() to setup mevement bonuses or/and penalties.
return hasBonus(selectorBlocksRetaliation, selectorBlocksRetaliation) return hasBonus(selectorBlocksRetaliation, selectorBlocksRetaliation)
? ETerrainType::ANY_TERRAIN ? Terrain::ANY
: (ETerrainType::EETerrainType)(*VLC->townh)[faction]->nativeTerrain; : (Terrain)(*VLC->townh)[faction]->nativeTerrain;
} }
void CCreature::updateFrom(const JsonNode & data) void CCreature::updateFrom(const JsonNode & data)
@ -1340,11 +1341,6 @@ void CCreatureHandler::removeBonusesFromAllCreatures()
allCreatures.removeBonuses(Selector::all); allCreatures.removeBonuses(Selector::all);
} }
void CCreatureHandler::restoreAllCreaturesNodeType794()
{
allCreatures.setNodeType(CBonusSystemNode::ENodeTypes::ALL_CREATURES);
}
void CCreatureHandler::buildBonusTreeForTiers() void CCreatureHandler::buildBonusTreeForTiers()
{ {
for(CCreature * c : objects) for(CCreature * c : objects)

View File

@ -24,6 +24,7 @@ class CLegacyConfigParser;
class CCreatureHandler; class CCreatureHandler;
class CCreature; class CCreature;
class JsonSerializeFormat; class JsonSerializeFormat;
class Terrain;
class DLL_LINKAGE CCreature : public Creature, public CBonusSystemNode class DLL_LINKAGE CCreature : public Creature, public CBonusSystemNode
{ {
@ -118,14 +119,14 @@ public:
ArtifactID warMachine; ArtifactID warMachine;
bool isItNativeTerrain(ETerrainType::EETerrainType terrain) const; bool isItNativeTerrain(const Terrain & terrain) const;
/** /**
Returns creature native terrain considering some terrain bonuses. Returns creature native terrain considering some terrain bonuses.
@param considerBonus is used to avoid Dead Lock when this method is called inside getAllBonuses @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 = 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. considerBonus = false is called on Battle init and returns already prepared nativeTerrain without Bonus system calling.
*/ */
ETerrainType::EETerrainType getNativeTerrain() const; Terrain getNativeTerrain() const;
int32_t getIndex() const override; int32_t getIndex() const override;
int32_t getIconIndex() const override; int32_t getIconIndex() const override;
const std::string & getName() const override; const std::string & getName() const override;
@ -211,18 +212,8 @@ public:
h & doubleWide; h & doubleWide;
h & special; h & special;
if(version>=759) h & identifier;
{ h & warMachine;
h & identifier;
}
if(version >= 771)
{
h & warMachine;
}
else if(!h.saving)
{
fillWarMachine();
}
} }
CCreature(); CCreature();
@ -281,7 +272,6 @@ public:
void addBonusForTier(int tier, const std::shared_ptr<Bonus> & b); //tier must be <1-7> void addBonusForTier(int tier, const std::shared_ptr<Bonus> & b); //tier must be <1-7>
void addBonusForAllCreatures(const std::shared_ptr<Bonus> & b); //due to CBonusSystem::addNewBonus(const std::shared_ptr<Bonus>& b); void addBonusForAllCreatures(const std::shared_ptr<Bonus> & b); //due to CBonusSystem::addNewBonus(const std::shared_ptr<Bonus>& b);
void removeBonusesFromAllCreatures(); void removeBonusesFromAllCreatures();
void restoreAllCreaturesNodeType794(); //restore ALL_CREATURES node type for old saves
CCreatureHandler(); CCreatureHandler();
~CCreatureHandler(); ~CCreatureHandler();

View File

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

View File

@ -963,8 +963,8 @@ void CGameState::initGrailPosition()
const TerrainTile &t = map->getTile(int3(i, j, k)); const TerrainTile &t = map->getTile(int3(i, j, k));
if(!t.blocked if(!t.blocked
&& !t.visitable && !t.visitable
&& t.terType != ETerrainType::WATER && t.terType.isLand()
&& t.terType != ETerrainType::ROCK && t.terType.isPassable()
&& (int)map->grailPos.dist2dSQ(int3(i, j, k)) <= (map->grailRadius * map->grailRadius)) && (int)map->grailPos.dist2dSQ(int3(i, j, k)) <= (map->grailRadius * map->grailRadius))
allowedPos.push_back(int3(i,j,k)); allowedPos.push_back(int3(i,j,k));
} }
@ -1940,31 +1940,31 @@ BFieldType CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & ra
if(map->isCoastalTile(tile)) //coastal tile is always ground if(map->isCoastalTile(tile)) //coastal tile is always ground
return BFieldType::SAND_SHORE; return BFieldType::SAND_SHORE;
switch(t.terType) if(t.terType == Terrain("dirt"))
{
case ETerrainType::DIRT:
return BFieldType(rand.nextInt(3, 5)); return BFieldType(rand.nextInt(3, 5));
case ETerrainType::SAND: if(t.terType == Terrain("sand"))
return BFieldType::SAND_MESAS; //TODO: coast support return BFieldType::SAND_MESAS; //TODO: coast support
case ETerrainType::GRASS: if(t.terType == Terrain("grass"))
return BFieldType(rand.nextInt(6, 7)); return BFieldType(rand.nextInt(6, 7));
case ETerrainType::SNOW: if(t.terType == Terrain("snow"))
return BFieldType(rand.nextInt(10, 11)); return BFieldType(rand.nextInt(10, 11));
case ETerrainType::SWAMP: if(t.terType == Terrain("swamp"))
return BFieldType::SWAMP_TREES; return BFieldType::SWAMP_TREES;
case ETerrainType::ROUGH: if(t.terType == Terrain("rough"))
return BFieldType::ROUGH; return BFieldType::ROUGH;
case ETerrainType::SUBTERRANEAN: if(t.terType.isUnderground())
return BFieldType::SUBTERRANEAN; return BFieldType::SUBTERRANEAN;
case ETerrainType::LAVA: if(t.terType == Terrain("lava"))
return BFieldType::LAVA; return BFieldType::LAVA;
case ETerrainType::WATER: if(t.terType.isWater())
return BFieldType::SHIP; return BFieldType::SHIP;
case ETerrainType::ROCK: if(!t.terType.isPassable())
return BFieldType::ROCKLANDS; return BFieldType::ROCKLANDS;
default:
return BFieldType::NONE; //TODO: STUB, support new battlegrounds
} return BFieldType::DIRT_HILLS;
return BFieldType::NONE;
} }
UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack) UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
@ -2145,7 +2145,7 @@ void CGameState::updateRumor()
rumorId = *RandomGeneratorUtil::nextItem(sRumorTypes, rand); rumorId = *RandomGeneratorUtil::nextItem(sRumorTypes, rand);
if(rumorId == RumorState::RUMOR_GRAIL) if(rumorId == RumorState::RUMOR_GRAIL)
{ {
rumorExtra = getTile(map->grailPos)->terType; rumorExtra = getTile(map->grailPos)->terType.id();
break; break;
} }

View File

@ -227,14 +227,7 @@ public:
h & hpool; h & hpool;
h & globalEffects; h & globalEffects;
h & rand; h & rand;
if(version >= 755) //save format backward compatibility h & rumor;
{
h & rumor;
}
else if(!h.saving)
{
rumor = RumorState();
}
BONUS_TREE_DESERIALIZATION_FIX BONUS_TREE_DESERIALIZATION_FIX
} }

View File

@ -17,6 +17,7 @@
#include "CModHandler.h" #include "CModHandler.h"
#include "GameConstants.h" #include "GameConstants.h"
#include "VCMI_Lib.h" #include "VCMI_Lib.h"
#include "Terrain.h"
size_t Unicode::getCharacterSize(char firstByte) size_t Unicode::getCharacterSize(char firstByte)
{ {
@ -309,6 +310,7 @@ void CGeneralTextHandler::readToVector(std::string sourceName, std::vector<std::
CGeneralTextHandler::CGeneralTextHandler() CGeneralTextHandler::CGeneralTextHandler()
{ {
std::vector<std::string> h3mTerrainNames;
readToVector("DATA/VCDESC.TXT", victoryConditions); readToVector("DATA/VCDESC.TXT", victoryConditions);
readToVector("DATA/LCDESC.TXT", lossCondtions); readToVector("DATA/LCDESC.TXT", lossCondtions);
readToVector("DATA/TCOMMAND.TXT", tcommands); readToVector("DATA/TCOMMAND.TXT", tcommands);
@ -317,7 +319,7 @@ CGeneralTextHandler::CGeneralTextHandler()
readToVector("DATA/ADVEVENT.TXT", advobtxt); readToVector("DATA/ADVEVENT.TXT", advobtxt);
readToVector("DATA/XTRAINFO.TXT", xtrainfo); readToVector("DATA/XTRAINFO.TXT", xtrainfo);
readToVector("DATA/RESTYPES.TXT", restypes); readToVector("DATA/RESTYPES.TXT", restypes);
readToVector("DATA/TERRNAME.TXT", terrainNames); readToVector("DATA/TERRNAME.TXT", h3mTerrainNames);
readToVector("DATA/RANDSIGN.TXT", randsign); readToVector("DATA/RANDSIGN.TXT", randsign);
readToVector("DATA/CRGEN1.TXT", creGens); readToVector("DATA/CRGEN1.TXT", creGens);
readToVector("DATA/CRGEN4.TXT", creGens4); readToVector("DATA/CRGEN4.TXT", creGens4);
@ -331,6 +333,17 @@ CGeneralTextHandler::CGeneralTextHandler()
readToVector("DATA/HEROSCRN.TXT", heroscrn); readToVector("DATA/HEROSCRN.TXT", heroscrn);
readToVector("DATA/TENTCOLR.TXT", tentColors); readToVector("DATA/TENTCOLR.TXT", tentColors);
readToVector("DATA/SKILLLEV.TXT", levels); readToVector("DATA/SKILLLEV.TXT", levels);
for(int i = 0; i < h3mTerrainNames.size(); ++i)
{
terrainNames[Terrain::createTerrainTypeH3M(i)] = h3mTerrainNames[i];
}
for(auto & terrain : Terrain::Manager::terrains())
{
if(!Terrain::Manager::getInfo(terrain).terrainText.empty())
terrainNames[terrain] = Terrain::Manager::getInfo(terrain).terrainText;
}
static const char * QE_MOD_COMMANDS = "DATA/QECOMMANDS.TXT"; static const char * QE_MOD_COMMANDS = "DATA/QECOMMANDS.TXT";
if (CResourceHandler::get()->existsResource(ResourceID(QE_MOD_COMMANDS, EResType::TEXT))) if (CResourceHandler::get()->existsResource(ResourceID(QE_MOD_COMMANDS, EResType::TEXT)))

View File

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

View File

@ -19,6 +19,7 @@
#include "CCreatureHandler.h" #include "CCreatureHandler.h"
#include "CModHandler.h" #include "CModHandler.h"
#include "CTownHandler.h" #include "CTownHandler.h"
#include "Terrain.h"
#include "mapObjects/CObjectHandler.h" //for hero specialty #include "mapObjects/CObjectHandler.h" //for hero specialty
#include "CSkillHandler.h" #include "CSkillHandler.h"
#include <math.h> #include <math.h>
@ -176,7 +177,7 @@ std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const
return ret; return ret;
} }
bool CObstacleInfo::isAppropriate(ETerrainType terrainType, int specialBattlefield) const bool CObstacleInfo::isAppropriate(Terrain terrainType, int specialBattlefield) const
{ {
if(specialBattlefield != -1) if(specialBattlefield != -1)
return vstd::contains(allowedSpecialBfields, specialBattlefield); return vstd::contains(allowedSpecialBfields, specialBattlefield);
@ -376,9 +377,9 @@ CHeroHandler::CHeroHandler()
{ {
loadObstacles(); loadObstacles();
loadTerrains(); loadTerrains();
for (int i = 0; i < GameConstants::TERRAIN_TYPES; ++i) for(int i = 0; i < Terrain::Manager::terrains().size(); ++i)
{ {
VLC->modh->identifiers.registerObject("core", "terrain", GameConstants::TERRAIN_NAMES[i], i); VLC->modh->identifiers.registerObject("core", "terrain", Terrain::Manager::terrains()[i], i);
} }
loadBallistics(); loadBallistics();
loadExperience(); loadExperience();
@ -826,7 +827,8 @@ void CHeroHandler::loadObstacles()
obi.defName = obs["defname"].String(); obi.defName = obs["defname"].String();
obi.width = static_cast<si32>(obs["width"].Float()); obi.width = static_cast<si32>(obs["width"].Float());
obi.height = static_cast<si32>(obs["height"].Float()); obi.height = static_cast<si32>(obs["height"].Float());
obi.allowedTerrains = obs["allowedTerrain"].convertTo<std::vector<ETerrainType> >(); for(auto & t : obs["allowedTerrain"].Vector())
obi.allowedTerrains.emplace_back(t.String());
obi.allowedSpecialBfields = obs["specialBattlefields"].convertTo<std::vector<BFieldType> >(); obi.allowedSpecialBfields = obs["specialBattlefields"].convertTo<std::vector<BFieldType> >();
obi.blockedTiles = obs["blockedTiles"].convertTo<std::vector<si16> >(); obi.blockedTiles = obs["blockedTiles"].convertTo<std::vector<si16> >();
obi.isAbsoluteObstacle = absolute; obi.isAbsoluteObstacle = absolute;
@ -1029,11 +1031,10 @@ ui64 CHeroHandler::reqExp (ui32 level) const
void CHeroHandler::loadTerrains() void CHeroHandler::loadTerrains()
{ {
const JsonNode config(ResourceID("config/terrains.json")); for(auto & terrain : Terrain::Manager::terrains())
{
terrCosts.reserve(GameConstants::TERRAIN_TYPES); terrCosts[terrain] = Terrain::Manager::getInfo(terrain).moveCost;
for(const std::string & name : GameConstants::TERRAIN_NAMES) }
terrCosts.push_back((int)config[name]["moveCost"].Float());
} }
std::vector<bool> CHeroHandler::getDefaultAllowed() const std::vector<bool> CHeroHandler::getDefaultAllowed() const

View File

@ -26,6 +26,7 @@ struct BattleHex;
class JsonNode; class JsonNode;
class CRandomGenerator; class CRandomGenerator;
class JsonSerializeFormat; class JsonSerializeFormat;
class Terrain;
struct SSpecialtyInfo struct SSpecialtyInfo
{ si32 type; { si32 type;
@ -119,15 +120,7 @@ public:
h & initialArmy; h & initialArmy;
h & heroClass; h & heroClass;
h & secSkillsInit; h & secSkillsInit;
if(version >= 781) h & specialty;
{
h & specialty;
}
else
{
h & specDeprecated;
h & specialtyDeprecated;
}
h & spells; h & spells;
h & haveSpellBook; h & haveSpellBook;
h & sex; h & sex;
@ -141,14 +134,8 @@ public:
h & iconSpecLarge; h & iconSpecLarge;
h & portraitSmall; h & portraitSmall;
h & portraitLarge; h & portraitLarge;
if(version >= 759) h & identifier;
{ h & battleImage;
h & identifier;
}
if(version >= 790)
{
h & battleImage;
}
} }
}; };
@ -211,16 +198,7 @@ public:
h & identifier; h & identifier;
h & name; h & name;
h & faction; h & faction;
if(version >= 800) h & id;
{
h & id;
}
else
{
ui8 old_id = 0;
h & old_id;
id = HeroClassID(old_id);
}
h & defaultTavernChance; h & defaultTavernChance;
h & primarySkillInitial; h & primarySkillInitial;
h & primarySkillLowLevel; h & primarySkillLowLevel;
@ -248,7 +226,7 @@ struct DLL_LINKAGE CObstacleInfo
{ {
si32 ID; si32 ID;
std::string defName; std::string defName;
std::vector<ETerrainType> allowedTerrains; std::vector<Terrain> allowedTerrains;
std::vector<BFieldType> allowedSpecialBfields; std::vector<BFieldType> allowedSpecialBfields;
ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same
@ -257,7 +235,7 @@ struct DLL_LINKAGE CObstacleInfo
std::vector<BattleHex> getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex' std::vector<BattleHex> getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
bool isAppropriate(ETerrainType terrainType, int specialBattlefield = -1) const; bool isAppropriate(Terrain terrainType, int specialBattlefield = -1) const;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
@ -315,7 +293,7 @@ public:
CHeroClassHandler classes; CHeroClassHandler classes;
//default costs of going through terrains. -1 means terrain is impassable //default costs of going through terrains. -1 means terrain is impassable
std::vector<int> terrCosts; std::map<Terrain, int> terrCosts;
struct SBallisticsLevelInfo struct SBallisticsLevelInfo
{ {

View File

@ -163,6 +163,7 @@ set(lib_SRCS
StartInfo.cpp StartInfo.cpp
ResourceSet.cpp ResourceSet.cpp
ScriptHandler.cpp ScriptHandler.cpp
Terrain.cpp
VCMIDirs.cpp VCMIDirs.cpp
VCMI_Lib.cpp VCMI_Lib.cpp
@ -385,6 +386,7 @@ set(lib_HEADERS
ScopeGuard.h ScopeGuard.h
StartInfo.h StartInfo.h
StringConstants.h StringConstants.h
Terrain.h
UnlockGuard.h UnlockGuard.h
VCMIDirs.h VCMIDirs.h
vcmi_endian.h vcmi_endian.h

View File

@ -303,32 +303,9 @@ public:
h & ALL_CREATURES_GET_DOUBLE_MONTHS; h & ALL_CREATURES_GET_DOUBLE_MONTHS;
h & MAX_HEROES_AVAILABLE_PER_PLAYER; h & MAX_HEROES_AVAILABLE_PER_PLAYER;
h & MAX_HEROES_ON_MAP_PER_PLAYER; h & MAX_HEROES_ON_MAP_PER_PLAYER;
if(version >= 756) h & WINNING_HERO_WITH_NO_TROOPS_RETREATS;
{ h & BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE;
h & WINNING_HERO_WITH_NO_TROOPS_RETREATS; h & NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS;
}
else if(!h.saving)
{
WINNING_HERO_WITH_NO_TROOPS_RETREATS = true;
}
if(version >= 776)
{
h & BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE;
}
else if(!h.saving)
{
BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE = true;
}
if(version >= 791)
{
h & NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS;
}
else if(!h.saving)
{
NO_RANDOM_SPECIAL_WEEKS_AND_MONTHS = false;
}
} }
} settings; } settings;

View File

@ -46,24 +46,19 @@ void NodeStorage::initialize(const PathfinderOptions & options, const CGameState
for(pos.z=0; pos.z < sizes.z; ++pos.z) for(pos.z=0; pos.z < sizes.z; ++pos.z)
{ {
const TerrainTile * tile = &gs->map->getTile(pos); const TerrainTile * tile = &gs->map->getTile(pos);
switch(tile->terType) if(tile->terType.isWater())
{ {
case ETerrainType::ROCK:
break;
case ETerrainType::WATER:
resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
if(useWaterWalking) if(useWaterWalking)
resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
break; }
if(tile->terType.isLand())
default: {
resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
if(useFlying) if(useFlying)
resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs)); resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
break;
} }
} }
} }
@ -1012,8 +1007,7 @@ bool CPathfinderHelper::passOneTurnLimitCheck(const PathNodeInfo & source) const
TurnInfo::BonusCache::BonusCache(TConstBonusListPtr bl) TurnInfo::BonusCache::BonusCache(TConstBonusListPtr bl)
{ {
noTerrainPenalty.reserve(ETerrainType::ROCK); for(int i = 0; i < Terrain::Manager::terrains().size(); ++i)
for(int i = 0; i < ETerrainType::ROCK; i++)
{ {
noTerrainPenalty.push_back(static_cast<bool>( 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()(i)))));
@ -1179,7 +1173,7 @@ void CPathfinderHelper::getNeighbours(
continue; continue;
const TerrainTile & hlpt = map->getTile(hlp); const TerrainTile & hlpt = map->getTile(hlp);
if(hlpt.terType == ETerrainType::ROCK) if(!hlpt.terType.isPassable())
continue; continue;
// //we cannot visit things from blocked tiles // //we cannot visit things from blocked tiles
@ -1189,18 +1183,18 @@ void CPathfinderHelper::getNeighbours(
// } // }
/// Following condition let us avoid diagonal movement over coast when sailing /// Following condition let us avoid diagonal movement over coast when sailing
if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && 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, int3 hlp1 = tile,
hlp2 = tile; hlp2 = tile;
hlp1.x += dir.x; hlp1.x += dir.x;
hlp2.y += dir.y; hlp2.y += dir.y;
if(map->getTile(hlp1).terType != ETerrainType::WATER || map->getTile(hlp2).terType != ETerrainType::WATER) if(map->getTile(hlp1).terType.isLand() || map->getTile(hlp2).terType.isLand())
continue; continue;
} }
if(indeterminate(onLand) || onLand == (hlpt.terType != ETerrainType::WATER)) if(indeterminate(onLand) || onLand == hlpt.terType.isLand())
{ {
vec.push_back(hlp); vec.push_back(hlp);
} }
@ -1238,7 +1232,7 @@ int CPathfinderHelper::getMovementCost(
{ {
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::FLYING_MOVEMENT)) / 100.0); ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::FLYING_MOVEMENT)) / 100.0);
} }
else if(dt->terType == ETerrainType::WATER) else if(dt->terType.isWater())
{ {
if(hero->boat && ct->hasFavorableWinds() && dt->hasFavorableWinds()) if(hero->boat && ct->hasFavorableWinds() && dt->hasFavorableWinds())
ret = static_cast<int>(ret * 0.666); ret = static_cast<int>(ret * 0.666);
@ -1266,7 +1260,7 @@ int CPathfinderHelper::getMovementCost(
{ {
std::vector<int3> vec; std::vector<int3> vec;
vec.reserve(8); //optimization vec.reserve(8); //optimization
getNeighbours(*dt, dst, vec, ct->terType != ETerrainType::WATER, true); getNeighbours(*dt, dst, vec, ct->terType.isLand(), true);
for(auto & elem : vec) for(auto & elem : vec)
{ {
int fcost = getMovementCost(dst, elem, nullptr, nullptr, left, false); int fcost = getMovementCost(dst, elem, nullptr, nullptr, left, false);

View File

@ -13,6 +13,7 @@
#include "IGameCallback.h" #include "IGameCallback.h"
#include "HeroBonus.h" #include "HeroBonus.h"
#include "int3.h" #include "int3.h"
#include "Terrain.h"
#include <boost/heap/fibonacci_heap.hpp> #include <boost/heap/fibonacci_heap.hpp>
@ -521,7 +522,7 @@ struct DLL_LINKAGE TurnInfo
TConstBonusListPtr bonuses; TConstBonusListPtr bonuses;
mutable int maxMovePointsLand; mutable int maxMovePointsLand;
mutable int maxMovePointsWater; mutable int maxMovePointsWater;
ETerrainType::EETerrainType nativeTerrain; Terrain nativeTerrain;
TurnInfo(const CGHeroInstance * Hero, const int Turn = 0); TurnInfo(const CGHeroInstance * Hero, const int Turn = 0);
bool isLayerAvailable(const EPathfindingLayer layer) const; bool isLayerAvailable(const EPathfindingLayer layer) const;

View File

@ -67,14 +67,6 @@ public:
h & dwellings; h & dwellings;
h & quests; h & quests;
h & visitedObjects; h & visitedObjects;
if(version < 760)
{
//was: h & getBonusList();
BonusList junk;
h & junk;
}
h & status; h & status;
h & daysWithoutCastle; h & daysWithoutCastle;
h & enteredLosingCheatCode; h & enteredLosingCheatCode;

View File

@ -35,12 +35,9 @@ public:
template <typename Handler> void serialize(Handler & h, const int version) template <typename Handler> void serialize(Handler & h, const int version)
{ {
h & description; h & description;
if(version >= 785) h & iconSmall;
{ h & iconMedium;
h & iconSmall; h & iconLarge;
h & iconMedium;
h & iconLarge;
}
h & effects; h & effects;
} }
}; };
@ -78,10 +75,7 @@ public:
h & id; h & id;
h & identifier; h & identifier;
h & name; h & name;
if(version >= 785) h & gainChance;
{
h & gainChance;
}
h & levels; h & levels;
} }

View File

@ -32,7 +32,7 @@ CStack::CStack(const CStackInstance * Base, PlayerColor O, int I, ui8 Side, Slot
slot(S), slot(S),
side(Side), side(Side),
initialPosition(), initialPosition(),
nativeTerrain(ETerrainType::WRONG) nativeTerrain()
{ {
health.init(); //??? health.init(); //???
} }
@ -40,7 +40,7 @@ CStack::CStack(const CStackInstance * Base, PlayerColor O, int I, ui8 Side, Slot
CStack::CStack() CStack::CStack()
: CBonusSystemNode(STACK_BATTLE), : CBonusSystemNode(STACK_BATTLE),
CUnitState(), CUnitState(),
nativeTerrain(ETerrainType::WRONG) nativeTerrain()
{ {
base = nullptr; base = nullptr;
type = nullptr; type = nullptr;
@ -328,11 +328,11 @@ bool CStack::canBeHealed() const
bool CStack::isOnNativeTerrain() const bool CStack::isOnNativeTerrain() const
{ {
//this code is called from CreatureTerrainLimiter::limit on battle start //this code is called from CreatureTerrainLimiter::limit on battle start
auto res = nativeTerrain == ETerrainType::ANY_TERRAIN || nativeTerrain == battle->getTerrainType(); auto res = nativeTerrain == Terrain::ANY || nativeTerrain == battle->getTerrainType();
return res; return res;
} }
bool CStack::isOnTerrain(int terrain) const bool CStack::isOnTerrain(const Terrain & terrain) const
{ {
return battle->getTerrainType() == terrain; return battle->getTerrainType() == terrain;
} }

View File

@ -14,6 +14,7 @@
#include "CCreatureHandler.h" //todo: remove #include "CCreatureHandler.h" //todo: remove
#include "battle/BattleHex.h" #include "battle/BattleHex.h"
#include "mapObjects/CGHeroInstance.h" // for commander serialization #include "mapObjects/CGHeroInstance.h" // for commander serialization
#include "Terrain.h"
#include "battle/CUnitState.h" #include "battle/CUnitState.h"
@ -28,7 +29,7 @@ public:
ui32 ID; //unique ID of stack ui32 ID; //unique ID of stack
const CCreature * type; const CCreature * type;
ETerrainType::EETerrainType nativeTerrain; //tmp variable to save native terrain value on battle init Terrain nativeTerrain; //tmp variable to save native terrain value on battle init
ui32 baseAmount; ui32 baseAmount;
PlayerColor owner; //owner - player color (255 for neutrals) PlayerColor owner; //owner - player color (255 for neutrals)
@ -50,7 +51,7 @@ public:
bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines
bool isOnNativeTerrain() const; bool isOnNativeTerrain() const;
bool isOnTerrain(int terrain) const; bool isOnTerrain(const Terrain & terrain) const;
ui32 level() const; ui32 level() const;
si32 magicResistance() const override; //include aura of resistance si32 magicResistance() const override; //include aura of resistance

View File

@ -26,6 +26,10 @@
const int NAMES_PER_TOWN=16; // number of town names per faction in H3 files. Json can define any number 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 std::map<std::string, CBuilding::EBuildMode> CBuilding::MODES = const std::map<std::string, CBuilding::EBuildMode> CBuilding::MODES =
{ {
{ "normal", CBuilding::BUILD_NORMAL }, { "normal", CBuilding::BUILD_NORMAL },
@ -77,135 +81,11 @@ si32 CBuilding::getDistance(BuildingID buildID) const
return -1; return -1;
} }
void CBuilding::deserializeFix()
{
//default value for mode was broken, have to fix it here for old saves (v777 and older)
switch(mode)
{
case BUILD_NORMAL:
case BUILD_AUTO:
case BUILD_SPECIAL:
case BUILD_GRAIL:
break;
default:
mode = BUILD_NORMAL;
break;
}
}
void CBuilding::addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList) void CBuilding::addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList)
{ {
bonusList.push_back(b); bonusList.push_back(b);
} }
const JsonNode & CBuilding::getCurrentFactionForUpdateRoutine() const
{
const auto & faction = town->faction->identifier;
const auto & factionsContent = (*VLC->modh->content)["factions"];
const auto & coreData = factionsContent.modData.at("core");
const auto & coreFactions = coreData.modData;
const auto & currentFaction = coreFactions[faction];
if(currentFaction.isNull())
{
const auto index = faction.find(':');
const std::string factionDir = index == std::string::npos ? faction : faction.substr(0, index);
const auto it = factionsContent.modData.find(factionDir);
if(it == factionsContent.modData.end())
{
logMod->warn("Warning: Update old save failed: Faction: '%s' is not found.", factionDir);
return currentFaction;
}
const std::string modFaction = index == std::string::npos ? faction : faction.substr(index + 1);
return it->second.modData[modFaction];
}
return currentFaction;
}
void CBuilding::update792()
{
subId = BuildingSubID::NONE;
height = ETowerHeight::HEIGHT_NO_TOWER;
if(!bid.IsSpecialOrGrail() || town == nullptr || town->faction == nullptr || town->faction->identifier.empty())
return;
const auto buildingName = CTownHandler::getMappedValue<std::string, BuildingID>(bid, std::string(), MappedKeys::BUILDING_TYPES_TO_NAMES);
if(buildingName.empty())
return;
auto & currentFaction = getCurrentFactionForUpdateRoutine();
if(!currentFaction.isNull() && currentFaction.getType() == JsonNode::JsonType::DATA_STRUCT)
{
const auto & buildings = currentFaction["town"]["buildings"];
const auto & currentBuilding = buildings[buildingName];
subId = CTownHandler::getMappedValue<BuildingSubID::EBuildingSubID>(currentBuilding["type"], BuildingSubID::NONE, MappedKeys::SPECIAL_BUILDINGS);
height = subId == BuildingSubID::LOOKOUT_TOWER || bid == BuildingID::GRAIL
? CTownHandler::getMappedValue<CBuilding::ETowerHeight>(currentBuilding["height"], CBuilding::HEIGHT_NO_TOWER, CBuilding::TOWER_TYPES)
: height = CBuilding::HEIGHT_NO_TOWER;
}
}
void CBuilding::update794()
{
if(bid == BuildingID::TAVERN || subId == BuildingSubID::BROTHERHOOD_OF_SWORD)
{
VLC->townh->addBonusesForVanilaBuilding(this);
return;
}
if(!bid.IsSpecialOrGrail())
return;
VLC->townh->addBonusesForVanilaBuilding(this);
if(!buildingBonuses.empty() //addBonusesForVanilaBuilding has done all work
|| town->faction == nullptr //or faction data is not valid
|| town->faction->identifier.empty())
return;
const auto buildingName = CTownHandler::getMappedValue<std::string, BuildingID>(bid, std::string(), MappedKeys::BUILDING_TYPES_TO_NAMES, false);
if(buildingName.empty())
return;
auto & currentFaction = getCurrentFactionForUpdateRoutine();
if(currentFaction.isNull() || currentFaction.getType() != JsonNode::JsonType::DATA_STRUCT)
return;
const auto & buildings = currentFaction["town"]["buildings"];
const auto & currentBuilding = buildings[buildingName];
CTownHandler::loadSpecialBuildingBonuses(currentBuilding["bonuses"], buildingBonuses, this);
CTownHandler::loadSpecialBuildingBonuses(currentBuilding["onVisitBonuses"], onVisitBonuses, this);
if(!onVisitBonuses.empty())
{
if(subId == BuildingSubID::NONE)
subId = BuildingSubID::CUSTOM_VISITING_BONUS;
for(auto & bonus : onVisitBonuses)
bonus->sid = Bonus::getSid32(town->faction->index, bid);
}
const auto & overriddenBids = currentBuilding["overrides"];
if(overriddenBids.isNull())
return;
auto scope = town->getBuildingScope();
for(auto b : overriddenBids.Vector())
{
auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get());
overrideBids.insert(bid);
}
}
CFaction::CFaction() CFaction::CFaction()
{ {
town = nullptr; town = nullptr;
@ -1062,9 +942,9 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES); assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES);
} }
ETerrainType::EETerrainType CTownHandler::getDefaultTerrainForAlignment(EAlignment::EAlignment alignment) const Terrain CTownHandler::getDefaultTerrainForAlignment(EAlignment::EAlignment alignment) const
{ {
ETerrainType::EETerrainType terrain = defaultGoodTerrain; Terrain terrain = defaultGoodTerrain;
switch(alignment) switch(alignment)
{ {
@ -1095,19 +975,15 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
faction->alignment = EAlignment::NEUTRAL; faction->alignment = EAlignment::NEUTRAL;
else else
faction->alignment = static_cast<EAlignment::EAlignment>(alignment); faction->alignment = static_cast<EAlignment::EAlignment>(alignment);
auto nativeTerrain = source["nativeTerrain"];
int terrainNum = nativeTerrain.isNull()
? -1
: vstd::find_pos(GameConstants::TERRAIN_NAMES, nativeTerrain.String());
auto preferUndergound = source["preferUndergroundPlacement"]; auto preferUndergound = source["preferUndergroundPlacement"];
faction->preferUndergroundPlacement = preferUndergound.isNull() ? false : preferUndergound.Bool(); faction->preferUndergroundPlacement = preferUndergound.isNull() ? false : preferUndergound.Bool();
//Contructor is not called here, but operator= //Contructor is not called here, but operator=
faction->nativeTerrain = terrainNum < 0 auto nativeTerrain = source["nativeTerrain"];
faction->nativeTerrain = nativeTerrain.isNull()
? getDefaultTerrainForAlignment(faction->alignment) ? getDefaultTerrainForAlignment(faction->alignment)
: static_cast<ETerrainType::EETerrainType>(terrainNum); : Terrain(nativeTerrain.String());
if (!source["town"].isNull()) if (!source["town"].isNull())
{ {

View File

@ -20,6 +20,7 @@
#include "LogicalExpression.h" #include "LogicalExpression.h"
#include "battle/BattleHex.h" #include "battle/BattleHex.h"
#include "HeroBonus.h" #include "HeroBonus.h"
#include "Terrain.h"
class CLegacyConfigParser; class CLegacyConfigParser;
class JsonNode; class JsonNode;
@ -111,8 +112,6 @@ public:
} }
void addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList); void addNewBonus(std::shared_ptr<Bonus> b, BonusList & bonusList);
void update792();
void update794();
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
@ -126,33 +125,14 @@ public:
h & requirements; h & requirements;
h & upgrade; h & upgrade;
h & mode; h & mode;
h & subId;
if(version >= 792) h & height;
{ h & overrideBids;
h & subId; h & buildingBonuses;
h & height; h & onVisitBonuses;
}
if(!h.saving && version < 793)
update792(); //adjust height, subId
if(version >= 794)
{
h & overrideBids;
h & buildingBonuses;
h & onVisitBonuses;
}
else if(!h.saving)
update794(); //populate overrideBids, buildingBonuses, onVisitBonuses
if(!h.saving)
deserializeFix();
} }
friend class CTownHandler; friend class CTownHandler;
private:
void deserializeFix();
const JsonNode & getCurrentFactionForUpdateRoutine() const;
}; };
/// This is structure used only by client /// This is structure used only by client
@ -205,7 +185,7 @@ public:
TFaction index; TFaction index;
ETerrainType nativeTerrain; Terrain nativeTerrain;
EAlignment::EAlignment alignment; EAlignment::EAlignment alignment;
bool preferUndergroundPlacement; bool preferUndergroundPlacement;
@ -356,14 +336,7 @@ public:
h & warMachine; h & warMachine;
h & clientInfo; h & clientInfo;
h & moatDamage; h & moatDamage;
if(version >= 758) h & moatHexes;
{
h & moatHexes;
}
else if(!h.saving)
{
moatHexes = defaultMoatHexes();
}
h & defaultTavernChance; h & defaultTavernChance;
} }
@ -385,9 +358,9 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
std::vector<BuildingRequirementsHelper> requirementsToLoad; std::vector<BuildingRequirementsHelper> requirementsToLoad;
std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden. std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden.
const static ETerrainType::EETerrainType defaultGoodTerrain = ETerrainType::EETerrainType::GRASS; const static Terrain defaultGoodTerrain;
const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA; const static Terrain defaultEvilTerrain;
const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH; const static Terrain defaultNeutralTerrain;
static TPropagatorPtr & emptyPropagator(); static TPropagatorPtr & emptyPropagator();
@ -418,7 +391,7 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
void loadPuzzle(CFaction & faction, const JsonNode & source); void loadPuzzle(CFaction & faction, const JsonNode & source);
ETerrainType::EETerrainType getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const; Terrain getDefaultTerrainForAlignment(EAlignment::EAlignment aligment) const;
void loadRandomFaction(); void loadRandomFaction();
@ -450,15 +423,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & objects; h & objects;
h & randomTown;
if(version >= 770)
{
h & randomTown;
}
else if(!h.saving)
{
loadRandomFaction();
}
} }
protected: protected:

View File

@ -236,38 +236,6 @@ std::ostream & operator<<(std::ostream & os, const EActionType actionType)
else return os << it->second; else return os << it->second;
} }
std::ostream & operator<<(std::ostream & os, const ETerrainType terrainType)
{
static const std::map<ETerrainType::EETerrainType, std::string> terrainTypeToString =
{
#define DEFINE_ELEMENT(element) {ETerrainType::element, #element}
DEFINE_ELEMENT(WRONG),
DEFINE_ELEMENT(BORDER),
DEFINE_ELEMENT(DIRT),
DEFINE_ELEMENT(SAND),
DEFINE_ELEMENT(GRASS),
DEFINE_ELEMENT(SNOW),
DEFINE_ELEMENT(SWAMP),
DEFINE_ELEMENT(ROUGH),
DEFINE_ELEMENT(SUBTERRANEAN),
DEFINE_ELEMENT(LAVA),
DEFINE_ELEMENT(WATER),
DEFINE_ELEMENT(ROCK)
#undef DEFINE_ELEMENT
};
auto it = terrainTypeToString.find(terrainType.num);
if (it == terrainTypeToString.end()) return os << "<Unknown type>";
else return os << it->second;
}
std::string ETerrainType::toString() const
{
std::stringstream ss;
ss << *this;
return ss.str();
}
std::ostream & operator<<(std::ostream & os, const EPathfindingLayer pathfindingLayer) std::ostream & operator<<(std::ostream & os, const EPathfindingLayer pathfindingLayer)
{ {
static const std::map<EPathfindingLayer::EEPathfindingLayer, std::string> pathfinderLayerToString static const std::map<EPathfindingLayer::EEPathfindingLayer, std::string> pathfinderLayerToString

View File

@ -61,7 +61,6 @@ namespace GameConstants
const int SKILL_QUANTITY=28; const int SKILL_QUANTITY=28;
const int PRIMARY_SKILLS=4; const int PRIMARY_SKILLS=4;
const int TERRAIN_TYPES=10;
const int RESOURCE_QUANTITY=8; const int RESOURCE_QUANTITY=8;
const int HEROES_PER_TYPE=8; //amount of heroes of each type const int HEROES_PER_TYPE=8; //amount of heroes of each type
@ -678,21 +677,8 @@ enum class ETeleportChannelType
}; };
namespace ERiverType static std::vector<std::string> RIVER_NAMES {"", "rw", "ri", "rm", "rl"};
{ static std::vector<std::string> ROAD_NAMES {"", "pd", "pg", "pc"};
enum ERiverType
{
NO_RIVER, CLEAR_RIVER, ICY_RIVER, MUDDY_RIVER, LAVA_RIVER
};
}
namespace ERoadType
{
enum ERoadType
{
NO_ROAD, DIRT_ROAD, GRAVEL_ROAD, COBBLESTONE_ROAD
};
}
class Obj class Obj
{ {
@ -912,36 +898,6 @@ enum class EActionType : int32_t
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EActionType actionType); DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EActionType actionType);
class DLL_LINKAGE ETerrainType
{
public:
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.
};
ETerrainType(EETerrainType _num = WRONG) : num(_num)
{}
ETerrainType& operator=(EETerrainType _num)
{
num = _num;
return *this;
}
ID_LIKE_CLASS_COMMON(ETerrainType, EETerrainType)
EETerrainType num;
std::string toString() const;
};
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const ETerrainType terrainType);
ID_LIKE_OPERATORS(ETerrainType, ETerrainType::EETerrainType)
class DLL_LINKAGE EDiggingStatus class DLL_LINKAGE EDiggingStatus
{ {
public: public:

View File

@ -2078,13 +2078,8 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
return nodeType == dest->getNodeType(); return nodeType == dest->getNodeType();
} }
CreatureTerrainLimiter::CreatureTerrainLimiter(int TerrainType)
: terrainType(TerrainType)
{
}
CreatureTerrainLimiter::CreatureTerrainLimiter() CreatureTerrainLimiter::CreatureTerrainLimiter()
: terrainType(-1) : terrainType()
{ {
} }
@ -2094,7 +2089,7 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
const CStack *stack = retrieveStackBattle(&context.node); const CStack *stack = retrieveStackBattle(&context.node);
if(stack) if(stack)
{ {
if(terrainType == -1)//terrainType not specified = native if(terrainType.isNative())//terrainType not specified = native
return !stack->isOnNativeTerrain(); return !stack->isOnNativeTerrain();
return !stack->isOnTerrain(terrainType); return !stack->isOnTerrain(terrainType);
} }
@ -2105,7 +2100,7 @@ int CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
std::string CreatureTerrainLimiter::toString() const std::string CreatureTerrainLimiter::toString() const
{ {
boost::format fmt("CreatureTerrainLimiter(terrainType=%s)"); boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
fmt % (terrainType >= 0 ? GameConstants::TERRAIN_NAMES[terrainType] : "native"); fmt % (terrainType.isNative() ? "native" : static_cast<std::string>(terrainType));
return fmt.str(); return fmt.str();
} }
@ -2114,8 +2109,8 @@ JsonNode CreatureTerrainLimiter::toJsonNode() const
JsonNode root(JsonNode::JsonType::DATA_STRUCT); JsonNode root(JsonNode::JsonType::DATA_STRUCT);
root["type"].String() = "CREATURE_TERRAIN_LIMITER"; root["type"].String() = "CREATURE_TERRAIN_LIMITER";
if(terrainType >= 0) if(!terrainType.isNative())
root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::TERRAIN_NAMES[terrainType])); root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainType));
return root; return root;
} }

View File

@ -11,6 +11,7 @@
#include "GameConstants.h" #include "GameConstants.h"
#include "JsonNode.h" #include "JsonNode.h"
#include "Terrain.h"
class CCreature; class CCreature;
struct Bonus; struct Bonus;
@ -438,36 +439,15 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
h & val; h & val;
h & sid; h & sid;
h & description; h & description;
if(version >= 783) h & additionalInfo;
{
h & additionalInfo;
}
else
{
additionalInfo.resize(1, -1);
h & additionalInfo[0];
}
h & turnsRemain; h & turnsRemain;
h & valType; h & valType;
if(version >= 784) h & stacking;
{
h & stacking;
}
h & effectRange; h & effectRange;
h & limiter; h & limiter;
h & propagator; h & propagator;
if(version >= 781) h & updater;
{ h & propagationUpdater;
h & updater;
}
if(version >= 801)
{
h & propagationUpdater;
}
if(version < 801 && !h.saving) //Opposite Side bonuses are introduced
{
updateOppositeBonuses();
}
} }
template <typename Ptr> template <typename Ptr>
@ -999,10 +979,7 @@ public:
template <typename Handler> void serialize(Handler & h, const int version) template <typename Handler> void serialize(Handler & h, const int version)
{ {
h & static_cast<ILimiter&>(*this); h & static_cast<ILimiter&>(*this);
if(version >= 786) h & limiters;
{
h & limiters;
}
} }
}; };
@ -1081,9 +1058,9 @@ public:
class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain
{ {
public: public:
int terrainType; Terrain terrainType;
CreatureTerrainLimiter(); CreatureTerrainLimiter();
CreatureTerrainLimiter(int TerrainType); CreatureTerrainLimiter(const Terrain& terrain);
int limit(const BonusLimitationContext &context) const override; int limit(const BonusLimitationContext &context) const override;
virtual std::string toString() const override; virtual std::string toString() const override;

View File

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

View File

@ -57,7 +57,7 @@ public:
}; };
//Internal class for string -> JsonNode conversion //Internal class for string -> JsonNode conversion
class JsonParser class DLL_LINKAGE JsonParser
{ {
std::string errors; // Contains description of all encountered errors std::string errors; // Contains description of all encountered errors
constString input; // Input data constString input; // Input data

View File

@ -59,6 +59,15 @@ JsonNode::JsonNode(const ResourceID & fileURI):
*this = parser.parse(fileURI.getName()); *this = parser.parse(fileURI.getName());
} }
JsonNode::JsonNode(const std::string & idx, const ResourceID & fileURI):
type(JsonType::DATA_NULL)
{
auto file = CResourceHandler::get(idx)->load(fileURI)->readAll();
JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
*this = parser.parse(fileURI.getName());
}
JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax): JsonNode::JsonNode(ResourceID && fileURI, bool &isValidSyntax):
type(JsonType::DATA_NULL) type(JsonType::DATA_NULL)
{ {
@ -711,7 +720,8 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter)
{ {
VLC->modh->identifiers.requestIdentifier("terrain", parameters[0], [=](si32 terrain) VLC->modh->identifiers.requestIdentifier("terrain", parameters[0], [=](si32 terrain)
{ {
terrainLimiter->terrainType = terrain; //TODO: support limiters
//terrainLimiter->terrainType = terrain;
}); });
} }
return terrainLimiter; return terrainLimiter;

View File

@ -60,6 +60,7 @@ public:
//Create tree from JSON file //Create tree from JSON file
explicit JsonNode(ResourceID && fileURI); explicit JsonNode(ResourceID && fileURI);
explicit JsonNode(const ResourceID & fileURI); explicit JsonNode(const ResourceID & fileURI);
explicit JsonNode(const std::string& idx, const ResourceID & fileURI);
explicit JsonNode(ResourceID && fileURI, bool & isValidSyntax); explicit JsonNode(ResourceID && fileURI, bool & isValidSyntax);
//Copy c-tor //Copy c-tor
JsonNode(const JsonNode &copy); JsonNode(const JsonNode &copy);
@ -127,10 +128,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & meta; h & meta;
if(version >= 782) h & flags;
{
h & flags;
}
h & type; h & type;
switch(type) switch(type)
{ {
@ -152,10 +150,7 @@ public:
h & data.Struct; h & data.Struct;
break; break;
case JsonType::DATA_INTEGER: case JsonType::DATA_INTEGER:
if(version >= 770) h & data.Integer;
{
h & data.Integer;
}
break; break;
} }
} }

View File

@ -699,13 +699,13 @@ DLL_LINKAGE void GiveHero::applyGs(CGameState *gs)
DLL_LINKAGE void NewObject::applyGs(CGameState *gs) DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
{ {
ETerrainType terrainType; Terrain terrainType;
if(ID == Obj::BOAT && !gs->isInTheMap(pos)) //special handling for bug #3060 - pos outside map but visitablePos is not if(ID == Obj::BOAT && !gs->isInTheMap(pos)) //special handling for bug #3060 - pos outside map but visitablePos is not
{ {
CGObjectInstance testObject = CGObjectInstance(); CGObjectInstance testObject = CGObjectInstance();
testObject.pos = pos; testObject.pos = pos;
testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(ETerrainType::WATER).front(); testObject.appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(Terrain("water")).front();
const int3 previousXAxisTile = int3(pos.x - 1, pos.y, pos.z); const int3 previousXAxisTile = int3(pos.x - 1, pos.y, pos.z);
assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile)); assert(gs->isInTheMap(previousXAxisTile) && (testObject.visitablePos() == previousXAxisTile));
@ -722,7 +722,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs)
{ {
case Obj::BOAT: case Obj::BOAT:
o = new CGBoat(); o = new CGBoat();
terrainType = ETerrainType::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; break;
case Obj::MONSTER: //probably more options will be needed case Obj::MONSTER: //probably more options will be needed
o = new CGCreature(); o = new CGCreature();

View File

@ -59,13 +59,13 @@ namespace PathfinderUtil
break; break;
case ELayer::WATER: case ELayer::WATER:
if(tinfo->blocked || tinfo->terType != ETerrainType::WATER) if(tinfo->blocked || tinfo->terType.isLand())
return CGPathNode::BLOCKED; return CGPathNode::BLOCKED;
break; break;
case ELayer::AIR: case ELayer::AIR:
if(tinfo->blocked || tinfo->terType == ETerrainType::WATER) if(tinfo->blocked || tinfo->terType.isLand())
return CGPathNode::FLYABLE; return CGPathNode::FLYABLE;
break; break;

View File

@ -56,19 +56,7 @@ struct DLL_LINKAGE PlayerSettings
h & color; h & color;
h & handicap; h & handicap;
h & name; h & name;
if(version < 787) h & connectedPlayerIDs;
{
ui8 oldConnectedId = 0;
h & oldConnectedId;
if(oldConnectedId)
{
connectedPlayerIDs.insert(oldConnectedId);
}
}
else
{
h & connectedPlayerIDs;
}
h & team; h & team;
h & compOnly; h & compOnly;
} }

View File

@ -16,10 +16,6 @@
/// ///
namespace GameConstants namespace GameConstants
{ {
const std::string TERRAIN_NAMES [TERRAIN_TYPES] = {
"dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
};
const std::string RESOURCE_NAMES [RESOURCE_QUANTITY] = { const std::string RESOURCE_NAMES [RESOURCE_QUANTITY] = {
"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril" "wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril"
}; };

204
lib/Terrain.cpp Normal file
View File

@ -0,0 +1,204 @@
/*
* Terrain.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "Terrain.h"
#include "VCMI_Lib.h"
#include "CModHandler.h"
//regular expression to change id for string at config
//("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()
{
auto allConfigs = VLC->modh->getActiveMods();
allConfigs.insert(allConfigs.begin(), "core");
for(auto & mod : allConfigs)
{
if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/terrains.json")))
continue;
JsonNode terrs(mod, ResourceID("config/terrains.json"));
for(auto & terr : terrs.Struct())
{
Terrain::Info info;
info.moveCost = terr.second["moveCost"].Integer();
const JsonVector &unblockedVec = terr.second["minimapUnblocked"].Vector();
info.minimapUnblocked =
{
ui8(unblockedVec[0].Float()),
ui8(unblockedVec[1].Float()),
ui8(unblockedVec[2].Float())
};
const JsonVector &blockedVec = terr.second["minimapBlocked"].Vector();
info.minimapBlocked =
{
ui8(blockedVec[0].Float()),
ui8(blockedVec[1].Float()),
ui8(blockedVec[2].Float())
};
info.musicFilename = terr.second["music"].String();
info.tilesFilename = terr.second["tiles"].String();
if(terr.second["type"].isNull())
{
info.type = Terrain::Info::Type::Land;
}
else
{
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 == "SUB") info.type = Terrain::Info::Type::Subterranean;
if(s == "ROCK") info.type = Terrain::Info::Type::Rock;
}
if(terr.second["horseSoundId"].isNull())
{
info.horseSoundId = 9; //rock sound as default
}
else
{
info.horseSoundId = terr.second["horseSoundId"].Integer();
}
if(!terr.second["text"].isNull())
{
info.terrainText = terr.second["text"].String();
}
if(terr.second["code"].isNull())
{
info.typeCode = terr.first.substr(0, 2);
}
else
{
info.typeCode = terr.second["code"].String();
assert(info.typeCode.length() == 2);
}
terrainInfo[Terrain(terr.first)] = info;
}
}
}
Terrain::Manager & Terrain::Manager::get()
{
static Terrain::Manager manager;
return manager;
}
std::vector<Terrain> Terrain::Manager::terrains()
{
std::vector<Terrain> _terrains;
for(const auto & info : Terrain::Manager::get().terrainInfo)
_terrains.push_back(info.first);
return _terrains;
}
const Terrain::Info & Terrain::Manager::getInfo(const Terrain & terrain)
{
return Terrain::Manager::get().terrainInfo.at(terrain);
}
std::ostream & operator<<(std::ostream & os, const Terrain terrainType)
{
return os << static_cast<const std::string &>(terrainType);
}
Terrain::operator std::string() const
{
return name;
}
Terrain::Terrain(const std::string & _name) : name(_name)
{}
Terrain& Terrain::operator=(const Terrain & _name)
{
name = _name.name;
return *this;
}
Terrain& Terrain::operator=(const std::string & _name)
{
name = _name;
return *this;
}
bool operator==(const Terrain & l, const Terrain & r)
{
return l.name == r.name;
}
bool operator!=(const Terrain & l, const Terrain & r)
{
return l.name != r.name;
}
bool operator<(const Terrain & l, const Terrain & r)
{
return l.name < r.name;
}
int Terrain::id() const
{
if(name == "ANY") return -3;
if(name == "WRONG") return -2;
if(name == "BORDER") return -1;
auto _terrains = Terrain::Manager::terrains();
auto iter = std::find(_terrains.begin(), _terrains.end(), *this);
return iter - _terrains.begin();
}
bool Terrain::isLand() const
{
return !isWater();
}
bool Terrain::isWater() const
{
return Terrain::Manager::getInfo(*this).type == Terrain::Info::Type::Water;
}
bool Terrain::isPassable() const
{
return Terrain::Manager::getInfo(*this).type != Terrain::Info::Type::Rock;
}
bool Terrain::isUnderground() const
{
return Terrain::Manager::getInfo(*this).type == Terrain::Info::Type::Subterranean;
}
bool Terrain::isNative() const
{
return name.empty();
}

93
lib/Terrain.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Terrain.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "ConstTransitivePtr.h"
#include "JsonNode.h"
class DLL_LINKAGE Terrain
{
public:
friend class Manager;
struct Info
{
enum class Type
{
Land, Water, Subterranean, Rock
};
int moveCost;
std::array<int, 3> minimapBlocked;
std::array<int, 3> minimapUnblocked;
std::string musicFilename;
std::string tilesFilename;
std::string terrainText;
std::string typeCode;
int horseSoundId;
Type type;
};
class DLL_LINKAGE Manager
{
public:
static std::vector<Terrain> terrains();
static const Info & getInfo(const Terrain &);
private:
static Manager & get();
Manager();
std::map<Terrain, Info> terrainInfo;
};
/*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 Terrain & _type);
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 isLand() const;
bool isWater() const;
bool isPassable() const; //ROCK
bool isUnderground() const;
bool isNative() const;
operator std::string() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name;
}
protected:
std::string name;
};
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const Terrain terrainType);

View File

@ -288,15 +288,3 @@ void LibClasses::setContent(std::shared_ptr<CContentHandler> content)
{ {
modh->content = content; modh->content = content;
} }
void LibClasses::restoreAllCreaturesNodeType794()
{
creh->restoreAllCreaturesNodeType794();
}
void LibClasses::update800()
{
vstd::clear_pointer(scriptHandler);
scriptHandler = new scripting::ScriptHandler();
}

View File

@ -44,7 +44,6 @@ class DLL_LINKAGE LibClasses : public Services
void makeNull(); //sets all handler pointers to null void makeNull(); //sets all handler pointers to null
std::shared_ptr<CContentHandler> getContent() const; std::shared_ptr<CContentHandler> getContent() const;
void setContent(std::shared_ptr<CContentHandler> content); void setContent(std::shared_ptr<CContentHandler> content);
void restoreAllCreaturesNodeType794();
public: public:
bool IS_AI_ENABLED; //unused? bool IS_AI_ENABLED; //unused?
@ -91,33 +90,20 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
if(version >= 800) h & scriptHandler;//must be first (or second after modh), it can modify factories other handlers depends on
if(!h.saving)
{ {
h & scriptHandler;//must be first (or second after modh), it can modify factories other handlers depends on scriptsLoaded();
if(!h.saving)
{
scriptsLoaded();
}
}
else if(!h.saving)
{
update800();
} }
h & heroh; h & heroh;
h & arth; h & arth;
h & creh; h & creh;
if(!h.saving && version < 794)
restoreAllCreaturesNodeType794();
h & townh; h & townh;
h & objh; h & objh;
h & objtypeh; h & objtypeh;
h & spellh; h & spellh;
if(version >= 777) h & skillh;
{
h & skillh;
}
if(!h.saving) if(!h.saving)
{ {
//modh will be changed and modh->content will be empty after deserialization //modh will be changed and modh->content will be empty after deserialization

View File

@ -15,6 +15,7 @@
#include "../filesystem/Filesystem.h" #include "../filesystem/Filesystem.h"
#include "../mapObjects/CGTownInstance.h" #include "../mapObjects/CGTownInstance.h"
#include "../CGeneralTextHandler.h" #include "../CGeneralTextHandler.h"
#include "../Terrain.h"
//TODO: remove //TODO: remove
#include "../IGameCallback.h" #include "../IGameCallback.h"
@ -186,7 +187,7 @@ struct RangeGenerator
std::function<int()> myRand; std::function<int()> myRand;
}; };
BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town) BattleInfo * BattleInfo::setupBattle(int3 tile, Terrain terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
{ {
CMP_stack cmpst; CMP_stack cmpst;
auto curB = new BattleInfo(); auto curB = new BattleInfo();
@ -610,7 +611,7 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
BattleInfo::BattleInfo() BattleInfo::BattleInfo()
: round(-1), activeStack(-1), town(nullptr), tile(-1,-1,-1), : round(-1), activeStack(-1), town(nullptr), tile(-1,-1,-1),
battlefieldType(BFieldType::NONE), terrainType(ETerrainType::WRONG), battlefieldType(BFieldType::NONE), terrainType(),
tacticsSide(0), tacticDistance(0) tacticsSide(0), tacticDistance(0)
{ {
setBattle(this); setBattle(this);
@ -644,7 +645,7 @@ BFieldType BattleInfo::getBattlefieldType() const
return battlefieldType; return battlefieldType;
} }
ETerrainType BattleInfo::getTerrainType() const Terrain BattleInfo::getTerrainType() const
{ {
return terrainType; return terrainType;
} }

View File

@ -18,6 +18,7 @@
class CStack; class CStack;
class CStackInstance; class CStackInstance;
class CStackBasicDescriptor; class CStackBasicDescriptor;
class Terrain;
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
{ {
@ -36,7 +37,7 @@ public:
SiegeInfo si; SiegeInfo si;
BFieldType battlefieldType; //like !!BA:B BFieldType battlefieldType; //like !!BA:B
ETerrainType terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy) Terrain 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 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) ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
@ -72,7 +73,7 @@ public:
battle::Units getUnitsIf(battle::UnitFilter predicate) const override; battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
BFieldType getBattlefieldType() const override; BFieldType getBattlefieldType() const override;
ETerrainType getTerrainType() const override; Terrain getTerrainType() const override;
ObstacleCList getAllObstacles() const override; ObstacleCList getAllObstacles() const override;
@ -137,7 +138,7 @@ public:
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
void localInit(); void localInit();
static BattleInfo * setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town); static BattleInfo * setupBattle(int3 tile, Terrain terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
ui8 whatSide(PlayerColor player) const; ui8 whatSide(PlayerColor player) const;

View File

@ -10,6 +10,7 @@
#include "StdInc.h" #include "StdInc.h"
#include "BattleProxy.h" #include "BattleProxy.h"
#include "Unit.h" #include "Unit.h"
#include "Terrain.h"
///BattleProxy ///BattleProxy
@ -46,7 +47,7 @@ BFieldType BattleProxy::getBattlefieldType() const
return subject->battleGetBattlefieldType(); return subject->battleGetBattlefieldType();
} }
ETerrainType BattleProxy::getTerrainType() const Terrain BattleProxy::getTerrainType() const
{ {
return subject->battleTerrainType(); return subject->battleTerrainType();
} }

View File

@ -30,7 +30,7 @@ public:
battle::Units getUnitsIf(battle::UnitFilter predicate) const override; battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
BFieldType getBattlefieldType() const override; BFieldType getBattlefieldType() const override;
ETerrainType getTerrainType() const override; Terrain getTerrainType() const override;
ObstacleCList getAllObstacles() const override; ObstacleCList getAllObstacles() const override;

View File

@ -14,9 +14,9 @@
#include "../NetPacks.h" #include "../NetPacks.h"
#include "../mapObjects/CGTownInstance.h" #include "../mapObjects/CGTownInstance.h"
ETerrainType CBattleInfoEssentials::battleTerrainType() const Terrain CBattleInfoEssentials::battleTerrainType() const
{ {
RETURN_IF_NOT_BATTLE(ETerrainType::WRONG); RETURN_IF_NOT_BATTLE(Terrain());
return getBattle()->getTerrainType(); return getBattle()->getTerrainType();
} }

View File

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

View File

@ -14,7 +14,7 @@
struct CObstacleInstance; struct CObstacleInstance;
class BFieldType; class BFieldType;
class ETerrainType; class Terrain;
namespace battle namespace battle
{ {
@ -34,7 +34,7 @@ class DLL_LINKAGE IBattleInfoCallback
public: public:
virtual scripting::Pool * getContextPool() const = 0; virtual scripting::Pool * getContextPool() const = 0;
virtual ETerrainType battleTerrainType() const = 0; virtual Terrain battleTerrainType() const = 0;
virtual BFieldType battleGetBattlefieldType() const = 0; virtual BFieldType battleGetBattlefieldType() const = 0;
///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw ///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw

View File

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

View File

@ -79,28 +79,28 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
int64_t ret = GameConstants::BASE_MOVEMENT_COST; int64_t ret = GameConstants::BASE_MOVEMENT_COST;
//if there is road both on dest and src tiles - use road movement cost //if there is road both on dest and src tiles - use road movement cost
if(dest.roadType != ERoadType::NO_ROAD && from.roadType != ERoadType::NO_ROAD) if(dest.roadType != ROAD_NAMES[0] && from.roadType != ROAD_NAMES[0])
{ {
int road = std::min(dest.roadType,from.roadType); //used road ID int roadPos = std::min(vstd::find_pos(ROAD_NAMES, dest.roadType), vstd::find_pos(ROAD_NAMES, from.roadType)); //used road ID
switch(road) switch(roadPos)
{ {
case ERoadType::DIRT_ROAD: case 1:
ret = 75; ret = 75;
break; break;
case ERoadType::GRAVEL_ROAD: case 2:
ret = 65; ret = 65;
break; break;
case ERoadType::COBBLESTONE_ROAD: case 3:
ret = 50; ret = 50;
break; break;
default: default:
logGlobal->error("Unknown road type: %d", road); logGlobal->error("Unknown road type: %d", roadPos);
break; break;
} }
} }
else if(ti->nativeTerrain != from.terType //the terrain is not native else if(ti->nativeTerrain != from.terType //the terrain is not native
&& ti->nativeTerrain != ETerrainType::ANY_TERRAIN //no special creature bonus && ti->nativeTerrain != Terrain::ANY //no special creature bonus
&& !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType) //no special movement bonus && !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType.id()) //no special movement bonus
) )
{ {
static const CSelector selectorPATHFINDING = Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING); static const CSelector selectorPATHFINDING = Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING);
@ -114,7 +114,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
return (ui32)ret; return (ui32)ret;
} }
ETerrainType::EETerrainType CGHeroInstance::getNativeTerrain() const Terrain CGHeroInstance::getNativeTerrain() const
{ {
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army. // 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. // This is clearly bug in H3 however intended behaviour is not clear.
@ -122,18 +122,18 @@ ETerrainType::EETerrainType CGHeroInstance::getNativeTerrain() const
// will always have best penalty without any influence from player-defined stacks order // 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? // TODO: What should we do if all hero stacks are neutral creatures?
ETerrainType::EETerrainType nativeTerrain = ETerrainType::BORDER; Terrain nativeTerrain("BORDER");
for(auto stack : stacks) for(auto stack : stacks)
{ {
ETerrainType::EETerrainType stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar. Terrain stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
if(stackNativeTerrain == ETerrainType::BORDER) if(stackNativeTerrain == Terrain("BORDER"))
continue; continue;
if(nativeTerrain == ETerrainType::BORDER) if(nativeTerrain == Terrain("BORDER"))
nativeTerrain = stackNativeTerrain; nativeTerrain = stackNativeTerrain;
else if(nativeTerrain != stackNativeTerrain) else if(nativeTerrain != stackNativeTerrain)
return ETerrainType::BORDER; return Terrain("BORDER");
} }
return nativeTerrain; return nativeTerrain;
} }
@ -560,23 +560,6 @@ void CGHeroInstance::recreateSecondarySkillsBonuses()
updateSkillBonus(SecondarySkill(skill_info.first), skill_info.second); updateSkillBonus(SecondarySkill(skill_info.first), skill_info.second);
} }
void CGHeroInstance::recreateSpecialtyBonuses(std::vector<HeroSpecial *> & specialtyDeprecated)
{
auto HeroSpecialToSpecialtyBonus = [](HeroSpecial & hs) -> SSpecialtyBonus
{
SSpecialtyBonus sb;
sb.growsWithLevel = hs.growsWithLevel;
sb.bonuses = hs.getBonusList();
return sb;
};
for(HeroSpecial * hs : specialtyDeprecated)
{
for(std::shared_ptr<Bonus> b : SpecialtyBonusToBonuses(HeroSpecialToSpecialtyBonus(*hs), type->ID.getNum()))
addNewBonus(b);
}
}
void CGHeroInstance::updateSkillBonus(SecondarySkill which, int val) void CGHeroInstance::updateSkillBonus(SecondarySkill which, int val)
{ {
removeBonuses(Selector::source(Bonus::SECONDARY_SKILL, which)); removeBonuses(Selector::source(Bonus::SECONDARY_SKILL, which));

View File

@ -1,4 +1,4 @@
/* /*
* CGHeroInstance.h, part of VCMI engine * CGHeroInstance.h, part of VCMI engine
* *
* Authors: listed in file AUTHORS in main folder * Authors: listed in file AUTHORS in main folder
@ -89,15 +89,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & patrolling; h & patrolling;
if(version >= 755) //save format backward compatibility h & initialPos;
{
h & initialPos;
}
else if(!h.saving)
{
patrolling = false;
initialPos = int3();
}
h & patrolRadius; h & patrolRadius;
} }
} patrol; } patrol;
@ -163,7 +155,7 @@ public:
bool needsLastStack()const override; 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 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
ETerrainType::EETerrainType getNativeTerrain() const; Terrain getNativeTerrain() const;
ui32 getLowestCreatureSpeed() const; ui32 getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation' 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 si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
@ -287,7 +279,6 @@ protected:
private: private:
void levelUpAutomatically(CRandomGenerator & rand); void levelUpAutomatically(CRandomGenerator & rand);
void recreateSpecialtyBonuses(std::vector<HeroSpecial*> & specialtyDeprecated);
public: public:
std::string getHeroTypeName() const; std::string getHeroTypeName() const;
@ -316,18 +307,8 @@ public:
h & visitedTown; h & visitedTown;
h & boat; h & boat;
h & type; h & type;
if(version < 781)
{
std::vector<HeroSpecial*> specialtyDeprecated;
h & specialtyDeprecated;
if(!h.saving)
recreateSpecialtyBonuses(specialtyDeprecated);
}
h & commander; h & commander;
h & visitedObjects; h & visitedObjects;
BONUS_TREE_DESERIALIZATION_FIX BONUS_TREE_DESERIALIZATION_FIX
//visitied town pointer will be restored by map serialization method
if(version < 777 && !h.saving)
recreateSecondarySkillsBonuses();
} }
}; };

View File

@ -796,28 +796,6 @@ void CGTownInstance::addTownBonuses()
} }
} }
void CGTownInstance::fixBonusingDuplicates() //For versions 794-800
{
std::map<BuildingID::EBuildingID, int> bids;
for(auto i = 0; i != bonusingBuildings.size(); i++)
{
auto bid = bonusingBuildings[i]->getBuildingType();
if(!bids.count(bid))
bids.insert({ bid, 0 });
else
bids[bid]++;
}
for(auto & pair : bids)
{
if(!pair.second)
continue;
for(auto i = 0; i < pair.second; i++)
deleteTownBonus(pair.first);
}
}
void CGTownInstance::deleteTownBonus(BuildingID::EBuildingID bid) void CGTownInstance::deleteTownBonus(BuildingID::EBuildingID bid)
{ {
size_t i = 0; size_t i = 0;
@ -875,90 +853,6 @@ void CGTownInstance::initObj(CRandomGenerator & rand) ///initialize town structu
updateAppearance(); updateAppearance();
} }
void CGTownInstance::updateBonusingBuildings() //update to version 792
{
if(this->town->faction != nullptr)
{
//firstly, update subtype for the Bonusing objects, which are already stored in the bonusing list
for(auto building : bonusingBuildings) //no garrison bonuses here, only week and visiting bonuses
{
switch(this->town->faction->index)
{
case ETownType::CASTLE:
building->setBuildingSubtype(BuildingSubID::STABLES);
break;
case ETownType::DUNGEON:
if(building->getBuildingType() == BuildingID::SPECIAL_2)
building->setBuildingSubtype(BuildingSubID::MANA_VORTEX);
else if(building->getBuildingType() == BuildingID::SPECIAL_4)
building->setBuildingSubtype(BuildingSubID::EXPERIENCE_VISITING_BONUS);
break;
case ETownType::TOWER:
building->setBuildingSubtype(BuildingSubID::KNOWLEDGE_VISITING_BONUS);
break;
case ETownType::STRONGHOLD:
building->setBuildingSubtype(BuildingSubID::ATTACK_VISITING_BONUS);
break;
case ETownType::INFERNO:
building->setBuildingSubtype(BuildingSubID::SPELL_POWER_VISITING_BONUS);
break;
case ETownType::FORTRESS:
building->setBuildingSubtype(BuildingSubID::DEFENSE_VISITING_BONUS);
break;
}
}
}
//secondly, supplement bonusing buildings list and active bonuses; subtypes for these objects are already set in update792
for(auto & kvp : town->buildings)
{
auto & building = kvp.second;
if(building->subId == BuildingSubID::PORTAL_OF_SUMMONING)
{
if(!hasBuiltInOldWay(ETownType::DUNGEON, BuildingID::PORTAL_OF_SUMMON))
creatures.resize(GameConstants::CREATURES_PER_TOWN + 1);
continue;
}
if(!building->IsVisitingBonus() && !building->IsWeekBonus()) //it's not bonusing => nothing to handle
continue;
if(getBonusingBuilding(building->subId) != nullptr) //it's already added => already handled
continue;
///'hasBuilt' checking for bonuses is in the onHeroVisit handler
if(building->IsWeekBonus())
tryAddOnePerWeekBonus(building->subId);
if(building->IsVisitingBonus())
tryAddVisitingBonus(building->subId);
}
recreateBuildingsBonuses(); ///Clear all bonuses and recreate
}
void CGTownInstance::updateTown794()
{
for(auto builtBuilding : builtBuildings)
{
auto building = town->buildings.at(builtBuilding);
for(auto overriddenBid : building->overrideBids)
overriddenBuildings.insert(overriddenBid);
}
for(auto & kvp : town->buildings)
{
auto & building = kvp.second;
//The building acts as a visiting bonus and it has not been overridden.
if(building->IsVisitingBonus() && overriddenBuildings.find(kvp.first) == overriddenBuildings.end())
tryAddVisitingBonus(building->subId);
}
recreateBuildingsBonuses();
}
bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const bool CGTownInstance::hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const
{ {
return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid)); return (this->town->faction != nullptr && this->town->faction->index == type && hasBuilt(bid));

View File

@ -130,9 +130,7 @@ public:
{ {
h & bID; h & bID;
h & indexOnTV; h & indexOnTV;
h & bType;
if(version >= 792)
h & bType;
} }
protected: protected:
@ -267,16 +265,7 @@ public:
return false; return false;
}); });
if(!h.saving && version < 793) h & overriddenBuildings;
updateBonusingBuildings();
if(version >= 794)
h & overriddenBuildings;
else if(!h.saving)
updateTown794();
if(!h.saving && (version >= 794 && version < 801))
fixBonusingDuplicates();
if(!h.saving) if(!h.saving)
this->setNodeType(CBonusSystemNode::TOWN); this->setNodeType(CBonusSystemNode::TOWN);
@ -367,7 +356,6 @@ private:
void setOwner(const PlayerColor owner) const; void setOwner(const PlayerColor owner) const;
void onTownCaptured(const PlayerColor winner) const; void onTownCaptured(const PlayerColor winner) const;
int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& dwellings) const; int getDwellingBonus(const std::vector<CreatureID>& creatureIds, const std::vector<ConstTransitivePtr<CGDwelling> >& dwellings) const;
void updateBonusingBuildings();
bool hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const; bool hasBuiltInOldWay(ETownType::ETownType type, BuildingID bid) const;
bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const; bool townEnvisagesBuilding(BuildingSubID::EBuildingSubID bid) const;
bool isBonusingBuildingAdded(BuildingID::EBuildingID bid) const; bool isBonusingBuildingAdded(BuildingID::EBuildingID bid) const;
@ -375,6 +363,4 @@ private:
void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID); void tryAddVisitingBonus(BuildingSubID::EBuildingSubID subID);
void initOverriddenBids(); void initOverriddenBids();
void addTownBonuses(); void addTownBonuses();
void updateTown794(); //populate overriddenBuildings and vanila bonuses for old saves
void fixBonusingDuplicates(); //For versions 794-800.
}; };

View File

@ -1,4 +1,4 @@
/* /*
* CObjectClassesHandler.cpp, part of VCMI engine * CObjectClassesHandler.cpp, part of VCMI engine
* *
* Authors: listed in file AUTHORS in main folder * Authors: listed in file AUTHORS in main folder
@ -195,7 +195,7 @@ void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, cons
else else
handler->init(entry); handler->init(entry);
if (handler->getTemplates().empty()) //if (handler->getTemplates().empty())
{ {
auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id)); auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id));
for (auto & templ : boost::make_iterator_range(range.first, range.second)) for (auto & templ : boost::make_iterator_range(range.first, range.second))
@ -569,14 +569,14 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const
return templates; return templates;
} }
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
{ {
std::vector<ObjectTemplate> templates = getTemplates(); std::vector<ObjectTemplate> templates = getTemplates();
std::vector<ObjectTemplate> filtered; std::vector<ObjectTemplate> filtered;
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj)
{ {
return obj.canBePlacedAt(ETerrainType(terrainType)); return obj.canBePlacedAt(terrainType);
}); });
// H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here // H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here
// Perhaps we should re-define faulty templates and remove this workaround (already done for resources) // Perhaps we should re-define faulty templates and remove this workaround (already done for resources)
@ -586,7 +586,7 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) c
return filtered; return filtered;
} }
boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
{ {
std::vector<ObjectTemplate> ret = getTemplates(terrainType); std::vector<ObjectTemplate> ret = getTemplates(terrainType);
for (auto & tmpl : ret) for (auto & tmpl : ret)

View File

@ -178,11 +178,11 @@ public:
/// returns all templates matching parameters /// returns all templates matching parameters
std::vector<ObjectTemplate> getTemplates() const; std::vector<ObjectTemplate> getTemplates() const;
std::vector<ObjectTemplate> getTemplates(si32 terrainType) const; std::vector<ObjectTemplate> getTemplates(const Terrain & terrainType) const;
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) /// 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) /// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
boost::optional<ObjectTemplate> getOverride(si32 terrainType, const CGObjectInstance * object) const; boost::optional<ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
const RandomMapInfo & getRMGInfo(); const RandomMapInfo & getRMGInfo();
@ -210,19 +210,10 @@ public:
h & templates; h & templates;
h & rmgInfo; h & rmgInfo;
h & objectName; h & objectName;
if(version >= 759) h & typeName;
{ h & subTypeName;
h & typeName; h & sounds;
h & subTypeName; h & aiValue;
}
if(version >= 778)
{
h & sounds;
}
if(version >= 789)
{
h & aiValue;
}
} }
}; };
@ -253,19 +244,10 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
h & handlerName; h & handlerName;
h & base; h & base;
h & subObjects; h & subObjects;
if(version >= 759) h & identifier;
{ h & subIds;
h & identifier; h & sounds;
h & subIds; h & groupDefaultAiValue;
}
if(version >= 778)
{
h & sounds;
}
if(version >= 789)
{
h & groupDefaultAiValue;
}
} }
}; };

View File

@ -419,7 +419,7 @@ int3 IBoatGenerator::bestLocation() const
{ {
if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
{ {
if(tile->terType == ETerrainType::WATER && (!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; return o->pos + offset;
} }
} }

View File

@ -213,13 +213,9 @@ public:
///Entry point of binary (de-)serialization ///Entry point of binary (de-)serialization
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
if(version >= 759) h & instanceName;
{ h & typeName;
h & instanceName; h & subTypeName;
h & typeName;
h & subTypeName;
}
h & pos; h & pos;
h & ID; h & ID;
h & subID; h & subID;

View File

@ -87,14 +87,7 @@ public:
h & isCustomFirst; h & isCustomFirst;
h & isCustomNext; h & isCustomNext;
h & isCustomComplete; h & isCustomComplete;
if(version >= 757) h & completedOption;
{
h & completedOption;
}
else if(!h.saving)
{
completedOption = 1;
}
} }
void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName); void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName);

View File

@ -269,11 +269,6 @@ public:
h & onVisited; h & onVisited;
h & onEmpty; h & onEmpty;
h & visitMode; h & visitMode;
if(version < 778)
{
ui16 soundID = 0;
h & soundID;
}
h & selectMode; h & selectMode;
h & selectedReward; h & selectedReward;
} }

View File

@ -19,6 +19,7 @@
#include "CObjectHandler.h" #include "CObjectHandler.h"
#include "../CModHandler.h" #include "../CModHandler.h"
#include "../JsonNode.h" #include "../JsonNode.h"
#include "../Terrain.h"
#include "CRewardableConstructor.h" #include "CRewardableConstructor.h"
@ -143,7 +144,17 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
for (size_t i=0; i<9; i++) for (size_t i=0; i<9; i++)
{ {
if (terrStr[8-i] == '1') if (terrStr[8-i] == '1')
allowedTerrains.insert(ETerrainType((si32)i)); allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain("water")))
{
for(auto & terrain : Terrain::Manager::terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain);
}
} }
id = Obj(boost::lexical_cast<int>(strings[5])); id = Obj(boost::lexical_cast<int>(strings[5]));
@ -205,7 +216,17 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
for (size_t i=0; i<9; i++) for (size_t i=0; i<9; i++)
{ {
if (((terrMask >> i) & 1 ) != 0) if (((terrMask >> i) & 1 ) != 0)
allowedTerrains.insert(ETerrainType((si32)i)); allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
}
//assuming that object can be placed on other land terrains
if(allowedTerrains.size() >= 8 && !allowedTerrains.count(Terrain("water")))
{
for(auto & terrain : Terrain::Manager::terrains())
{
if(terrain.isLand() && terrain.isPassable())
allowedTerrains.insert(terrain);
}
} }
id = Obj(reader.readUInt32()); id = Obj(reader.readUInt32());
@ -247,15 +268,16 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
if(withTerrain && !node["allowedTerrains"].isNull()) if(withTerrain && !node["allowedTerrains"].isNull())
{ {
for (auto & entry : node["allowedTerrains"].Vector()) for (auto & entry : node["allowedTerrains"].Vector())
allowedTerrains.insert(ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES, entry.String()))); allowedTerrains.insert(entry.String());
} }
else else
{ {
for (size_t i=0; i< GameConstants::TERRAIN_TYPES; i++) for(auto & i : Terrain::Manager::terrains())
allowedTerrains.insert(ETerrainType((si32)i)); {
if(!i.isPassable() || i.isWater())
allowedTerrains.erase(ETerrainType::ROCK); continue;
allowedTerrains.erase(ETerrainType::WATER); allowedTerrains.insert(i);
}
} }
if(withTerrain && allowedTerrains.empty()) if(withTerrain && allowedTerrains.empty())
@ -329,14 +351,14 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
if(withTerrain) if(withTerrain)
{ {
//assumed that ROCK and WATER terrains are not included //assumed that ROCK and WATER terrains are not included
if(allowedTerrains.size() < (GameConstants::TERRAIN_TYPES - 2)) if(allowedTerrains.size() < (Terrain::Manager::terrains().size() - 2))
{ {
JsonVector & data = node["allowedTerrains"].Vector(); JsonVector & data = node["allowedTerrains"].Vector();
for(auto type : allowedTerrains) for(auto type : allowedTerrains)
{ {
JsonNode value(JsonNode::JsonType::DATA_STRING); JsonNode value(JsonNode::JsonType::DATA_STRING);
value.String() = GameConstants::TERRAIN_NAMES[type.num]; value.String() = type;
data.push_back(value); data.push_back(value);
} }
} }
@ -511,7 +533,7 @@ bool ObjectTemplate::isVisitableFromTop() const
//return isVisitableFrom (0, 1); //return isVisitableFrom (0, 1);
} }
bool ObjectTemplate::canBePlacedAt(ETerrainType terrain) const bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
{ {
return allowedTerrains.count(terrain) != 0; return allowedTerrains.count(terrain) != 0;
} }

View File

@ -15,6 +15,7 @@ class CBinaryReader;
class CLegacyConfigParser; class CLegacyConfigParser;
class JsonNode; class JsonNode;
class int3; class int3;
class Terrain;
class DLL_LINKAGE ObjectTemplate class DLL_LINKAGE ObjectTemplate
{ {
@ -30,7 +31,7 @@ class DLL_LINKAGE ObjectTemplate
/// directions from which object can be entered, format same as for moveDir in CGHeroInstance(but 0 - 7) /// directions from which object can be entered, format same as for moveDir in CGHeroInstance(but 0 - 7)
ui8 visitDir; ui8 visitDir;
/// list of terrains on which this object can be placed /// list of terrains on which this object can be placed
std::set<ETerrainType> allowedTerrains; std::set<Terrain> allowedTerrains;
void afterLoadFixup(); void afterLoadFixup();
@ -70,7 +71,7 @@ public:
bool isVisitableFromTop() const; bool isVisitableFromTop() const;
// Checks if object can be placed on specific terrain // Checks if object can be placed on specific terrain
bool canBePlacedAt(ETerrainType terrain) const; bool canBePlacedAt(Terrain terrain) const;
ObjectTemplate(); ObjectTemplate();
//custom copy constructor is required //custom copy constructor is required
@ -96,10 +97,7 @@ public:
h & subid; h & subid;
h & printPriority; h & printPriority;
h & visitDir; h & visitDir;
if(version >= 770) h & editorAnimationFile;
{
h & editorAnimationFile;
}
} }
}; };

View File

@ -422,17 +422,6 @@ std::vector<CGHeroInstance *> CCampaignScenario::getLostCrossoverHeroes()
return lostCrossoverHeroes; return lostCrossoverHeroes;
} }
std::vector<JsonNode> CCampaignScenario::update787(std::vector<CGHeroInstance *> & heroes)
{
static_assert(MINIMAL_SERIALIZATION_VERSION < 787, "No longer needed CCampaignScenario::update787");
std::vector<JsonNode> heroesNew;
for(auto hero : heroes)
{
heroesNew.push_back(CCampaignState::crossoverSerialize(hero));
}
return heroesNew;
}
void CCampaignState::setCurrentMapAsConquered(const std::vector<CGHeroInstance *> & heroes) void CCampaignState::setCurrentMapAsConquered(const std::vector<CGHeroInstance *> & heroes)
{ {
camp->scenarios[*currentMap].crossoverHeroes.clear(); camp->scenarios[*currentMap].crossoverHeroes.clear();

View File

@ -146,8 +146,7 @@ public:
// FIXME: due to usage of JsonNode I can't make these methods const // FIXME: due to usage of JsonNode I can't make these methods const
const CGHeroInstance * strongestHero(PlayerColor owner); const CGHeroInstance * strongestHero(PlayerColor owner);
std::vector<CGHeroInstance *> getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it std::vector<CGHeroInstance *> getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it
std::vector<JsonNode> update787(std::vector<CGHeroInstance *> & heroes);
CCampaignScenario(); CCampaignScenario();
template <typename Handler> void serialize(Handler &h, const int formatVersion) template <typename Handler> void serialize(Handler &h, const int formatVersion)
@ -163,19 +162,8 @@ public:
h & prolog; h & prolog;
h & epilog; h & epilog;
h & travelOptions; h & travelOptions;
if(formatVersion < 787) h & crossoverHeroes;
{ h & placedCrossoverHeroes;
std::vector<CGHeroInstance *> crossoverHeroesOld, placedCrossoverHeroesOld;
h & crossoverHeroesOld;
h & placedCrossoverHeroesOld;
crossoverHeroes = update787(crossoverHeroesOld);
placedCrossoverHeroes = update787(placedCrossoverHeroesOld);
}
else
{
h & crossoverHeroes;
h & placedCrossoverHeroes;
}
h & keepHeroes; h & keepHeroes;
} }
}; };

View File

@ -148,7 +148,7 @@ static bool ruleIsAny(const std::string & rule)
#endif #endif
///CDrawRoadsOperation ///CDrawRoadsOperation
CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen): CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen):
CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen) CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen)
{ {
@ -225,7 +225,7 @@ void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const
bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const
{ {
return tile.roadType != ERoadType::NO_ROAD; //TODO: this method should be virtual for river support return tile.roadType != ROAD_NAMES[0]; //TODO: this method should be virtual for river support
} }
void CDrawRoadsOperation::updateTiles(std::set<int3> & invalidated) void CDrawRoadsOperation::updateTiles(std::set<int3> & invalidated)
@ -263,7 +263,7 @@ bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const
{ {
//TODO: this method should be virtual for river support //TODO: this method should be virtual for river support
return map->getTile(pos).roadType != ERoadType::NO_ROAD; return map->getTile(pos).roadType != ROAD_NAMES[0];
} }

View File

@ -18,7 +18,7 @@ struct TerrainTile;
class CDrawRoadsOperation : public CMapOperation class CDrawRoadsOperation : public CMapOperation
{ {
public: public:
CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen); CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, const std::string & roadType, CRandomGenerator * gen);
void execute() override; void execute() override;
void undo() override; void undo() override;
void redo() override; void redo() override;
@ -53,6 +53,6 @@ private:
bool tileHasSomething(const int3 & pos) const; bool tileHasSomething(const int3 & pos) const;
CTerrainSelection terrainSel; CTerrainSelection terrainSel;
ERoadType::ERoadType roadType; std::string roadType;
CRandomGenerator * gen; CRandomGenerator * gen;
}; };

View File

@ -123,8 +123,8 @@ CCastleEvent::CCastleEvent() : town(nullptr)
} }
TerrainTile::TerrainTile() : terType(ETerrainType::BORDER), terView(0), riverType(ERiverType::NO_RIVER), TerrainTile::TerrainTile() : terType("BORDER"), terView(0), riverType(RIVER_NAMES[0]),
riverDir(0), roadType(ERoadType::NO_ROAD), roadDir(0), extTileFlags(0), visitable(false), riverDir(0), roadType(ROAD_NAMES[0]), roadDir(0), extTileFlags(0), visitable(false),
blocked(false) blocked(false)
{ {
@ -132,13 +132,13 @@ TerrainTile::TerrainTile() : terType(ETerrainType::BORDER), terView(0), riverTyp
bool TerrainTile::entrableTerrain(const TerrainTile * from) const bool TerrainTile::entrableTerrain(const TerrainTile * from) const
{ {
return entrableTerrain(from ? from->terType != ETerrainType::WATER : true, from ? from->terType == ETerrainType::WATER : true); return entrableTerrain(from ? from->terType.isLand() : true, from ? from->terType.isWater() : true);
} }
bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const bool TerrainTile::entrableTerrain(bool allowLand, bool allowSea) const
{ {
return terType != ETerrainType::ROCK return terType.isPassable()
&& ((allowSea && terType == ETerrainType::WATER) || (allowLand && terType != ETerrainType::WATER)); && ((allowSea && terType.isWater()) || (allowLand && terType.isLand()));
} }
bool TerrainTile::isClear(const TerrainTile * from) const bool TerrainTile::isClear(const TerrainTile * from) const
@ -164,7 +164,7 @@ CGObjectInstance * TerrainTile::topVisitableObj(bool excludeTop) const
EDiggingStatus TerrainTile::getDiggingStatus(const bool excludeTop) const EDiggingStatus TerrainTile::getDiggingStatus(const bool excludeTop) const
{ {
if(terType == ETerrainType::WATER || terType == ETerrainType::ROCK) if(terType.isWater() || !terType.isPassable())
return EDiggingStatus::WRONG_TERRAIN; return EDiggingStatus::WRONG_TERRAIN;
int allowedBlocked = excludeTop ? 1 : 0; int allowedBlocked = excludeTop ? 1 : 0;
@ -181,7 +181,7 @@ bool TerrainTile::hasFavorableWinds() const
bool TerrainTile::isWater() const bool TerrainTile::isWater() const
{ {
return terType == ETerrainType::WATER; return terType.isWater();
} }
void CMapHeader::setupEvents() void CMapHeader::setupEvents()

View File

@ -110,11 +110,7 @@ struct DLL_LINKAGE PlayerInfo
h & posOfMainTown; h & posOfMainTown;
h & team; h & team;
h & generateHero; h & generateHero;
h & mainHeroInstance;
if(version >= 770)
{
h & mainHeroInstance;
}
} }
}; };
@ -164,16 +160,9 @@ struct DLL_LINKAGE EventCondition
h & objectType; h & objectType;
h & position; h & position;
h & condition; h & condition;
//(!!!) should be `version >= 759` here, but do not try to "fix" it h & objectSubtype;
if(version > 759) h & objectInstanceName;
{ h & metaType;
h & objectSubtype;
h & objectInstanceName;
}
if(version >= 770)
{
h & metaType;
}
} }
}; };
@ -495,9 +484,6 @@ public:
h & CGTownInstance::merchantArtifacts; h & CGTownInstance::merchantArtifacts;
h & CGTownInstance::universitySkills; h & CGTownInstance::universitySkills;
if(formatVersion >= 759) h & instanceNames;
{
h & instanceNames;
}
} }
}; };

View File

@ -80,11 +80,11 @@ struct DLL_LINKAGE TerrainTile
EDiggingStatus getDiggingStatus(const bool excludeTop = true) const; EDiggingStatus getDiggingStatus(const bool excludeTop = true) const;
bool hasFavorableWinds() const; bool hasFavorableWinds() const;
ETerrainType terType; Terrain terType;
ui8 terView; ui8 terView;
ERiverType::ERiverType riverType; std::string riverType;
ui8 riverDir; ui8 riverDir;
ERoadType::ERoadType roadType; std::string roadType;
ui8 roadDir; ui8 roadDir;
/// first two bits - how to rotate terrain graphic (next two - river graphic, next two - road); /// 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 /// 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favorable Winds effect

View File

@ -243,13 +243,13 @@ void CMapEditManager::clearTerrain(CRandomGenerator * gen)
execute(make_unique<CClearTerrainOperation>(map, gen ? gen : &(this->gen))); execute(make_unique<CClearTerrainOperation>(map, gen ? gen : &(this->gen)));
} }
void CMapEditManager::drawTerrain(ETerrainType terType, CRandomGenerator * gen) void CMapEditManager::drawTerrain(Terrain terType, CRandomGenerator * gen)
{ {
execute(make_unique<CDrawTerrainOperation>(map, terrainSel, terType, gen ? gen : &(this->gen))); execute(make_unique<CDrawTerrainOperation>(map, terrainSel, terType, gen ? gen : &(this->gen)));
terrainSel.clearSelection(); terrainSel.clearSelection();
} }
void CMapEditManager::drawRoad(ERoadType::ERoadType roadType, CRandomGenerator* gen) void CMapEditManager::drawRoad(const std::string & roadType, CRandomGenerator* gen)
{ {
execute(make_unique<CDrawRoadsOperation>(map, terrainSel, roadType, gen ? gen : &(this->gen))); execute(make_unique<CDrawRoadsOperation>(map, terrainSel, roadType, gen ? gen : &(this->gen)));
terrainSel.clearSelection(); terrainSel.clearSelection();
@ -534,7 +534,7 @@ void CTerrainViewPatternConfig::flipPattern(TerrainViewPattern & pattern, int fl
} }
CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen) CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, Terrain terType, CRandomGenerator * gen)
: CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen) : CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen)
{ {
@ -760,21 +760,17 @@ void CDrawTerrainOperation::updateTerrainViews()
} }
} }
ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(ETerrainType terType) const ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(Terrain terType) const
{ {
switch(terType) if(terType == Terrain("dirt"))
{
case ETerrainType::DIRT:
return ETerrainGroup::DIRT; return ETerrainGroup::DIRT;
case ETerrainType::SAND: if(terType == Terrain("sand"))
return ETerrainGroup::SAND; return ETerrainGroup::SAND;
case ETerrainType::WATER: if(terType.isWater())
return ETerrainGroup::WATER; return ETerrainGroup::WATER;
case ETerrainType::ROCK: if(!terType.isPassable())
return ETerrainGroup::ROCK; return ETerrainGroup::ROCK;
default: return ETerrainGroup::NORMAL;
return ETerrainGroup::NORMAL;
}
} }
CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const std::vector<TerrainViewPattern> * pattern, int recDepth) const CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const std::vector<TerrainViewPattern> * pattern, int recDepth) const
@ -811,7 +807,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
int cy = pos.y + (i / 3) - 1; int cy = pos.y + (i / 3) - 1;
int3 currentPos(cx, cy, pos.z); int3 currentPos(cx, cy, pos.z);
bool isAlien = false; bool isAlien = false;
ETerrainType terType; Terrain terType;
if(!map->isInTheMap(currentPos)) if(!map->isInTheMap(currentPos))
{ {
// position is not in the map, so take the ter type from the neighbor tile // position is not in the map, so take the ter type from the neighbor tile
@ -949,17 +945,11 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
} }
} }
bool CDrawTerrainOperation::isSandType(ETerrainType terType) const bool CDrawTerrainOperation::isSandType(Terrain terType) const
{ {
switch(terType) if(terType.isWater() || terType == Terrain("sand") || !terType.isPassable())
{
case ETerrainType::WATER:
case ETerrainType::SAND:
case ETerrainType::ROCK:
return true; return true;
default: return false;
return false;
}
} }
void CDrawTerrainOperation::invalidateTerrainViews(const int3 & centerPos) void CDrawTerrainOperation::invalidateTerrainViews(const int3 & centerPos)
@ -986,7 +976,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
auto valid = validateTerrainView(pos, ptrConfig->getTerrainTypePatternById("n1")).result; auto valid = validateTerrainView(pos, ptrConfig->getTerrainTypePatternById("n1")).result;
// Special validity check for rock & water // Special validity check for rock & water
if(valid && (terType == ETerrainType::WATER || terType == ETerrainType::ROCK)) if(valid && (terType.isWater() || !terType.isPassable()))
{ {
static const std::string patternIds[] = { "s1", "s2" }; static const std::string patternIds[] = { "s1", "s2" };
for(auto & patternId : patternIds) for(auto & patternId : patternIds)
@ -996,7 +986,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
} }
} }
// Additional validity check for non rock OR water // Additional validity check for non rock OR water
else if(!valid && (terType != ETerrainType::WATER && terType != ETerrainType::ROCK)) else if(!valid && (terType.isLand() && terType.isPassable()))
{ {
static const std::string patternIds[] = { "n2", "n3" }; static const std::string patternIds[] = { "n2", "n3" };
for(auto & patternId : patternIds) for(auto & patternId : patternIds)
@ -1040,7 +1030,7 @@ void CTerrainViewPatternUtils::printDebuggingInfoAboutTile(const CMap * map, int
{ {
auto debugTile = map->getTile(debugPos); auto debugTile = map->getTile(debugPos);
std::string terType = debugTile.terType.toString().substr(0, 6); std::string terType = static_cast<std::string>(debugTile.terType).substr(0, 6);
line += terType; line += terType;
line.insert(line.end(), PADDED_LENGTH - terType.size(), ' '); line.insert(line.end(), PADDED_LENGTH - terType.size(), ' ');
} }
@ -1059,12 +1049,12 @@ CClearTerrainOperation::CClearTerrainOperation(CMap * map, CRandomGenerator * ge
{ {
CTerrainSelection terrainSel(map); CTerrainSelection terrainSel(map);
terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height)); terrainSel.selectRange(MapRect(int3(0, 0, 0), map->width, map->height));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainType::WATER, gen)); addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain("water"), gen));
if(map->twoLevel) if(map->twoLevel)
{ {
terrainSel.clearSelection(); terrainSel.clearSelection();
terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height)); terrainSel.selectRange(MapRect(int3(0, 0, 1), map->width, map->height));
addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, ETerrainType::ROCK, gen)); addOperation(make_unique<CDrawTerrainOperation>(map, terrainSel, Terrain("rock"), gen));
} }
} }

View File

@ -13,6 +13,7 @@
#include "../CRandomGenerator.h" #include "../CRandomGenerator.h"
#include "../int3.h" #include "../int3.h"
#include "../GameConstants.h" #include "../GameConstants.h"
#include "Terrain.h"
class CGObjectInstance; class CGObjectInstance;
class CTerrainViewPatternConfig; class CTerrainViewPatternConfig;
@ -168,10 +169,10 @@ public:
void clearTerrain(CRandomGenerator * gen = nullptr); void clearTerrain(CRandomGenerator * gen = nullptr);
/// Draws terrain at the current terrain selection. The selection will be cleared automatically. /// Draws terrain at the current terrain selection. The selection will be cleared automatically.
void drawTerrain(ETerrainType terType, CRandomGenerator * gen = nullptr); void drawTerrain(Terrain terType, CRandomGenerator * gen = nullptr);
/// Draws roads at the current terrain selection. The selection will be cleared automatically. /// Draws roads at the current terrain selection. The selection will be cleared automatically.
void drawRoad(ERoadType::ERoadType roadType, CRandomGenerator * gen = nullptr); void drawRoad(const std::string & roadType, CRandomGenerator * gen = nullptr);
void insertObject(CGObjectInstance * obj); void insertObject(CGObjectInstance * obj);
@ -353,7 +354,7 @@ private:
class CDrawTerrainOperation : public CMapOperation class CDrawTerrainOperation : public CMapOperation
{ {
public: public:
CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen); CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, Terrain terType, CRandomGenerator * gen);
void execute() override; void execute() override;
void undo() override; void undo() override;
@ -384,16 +385,16 @@ private:
InvalidTiles getInvalidTiles(const int3 & centerPos) const; InvalidTiles getInvalidTiles(const int3 & centerPos) const;
void updateTerrainViews(); void updateTerrainViews();
ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const; ETerrainGroup::ETerrainGroup getTerrainGroup(Terrain terType) const;
/// Validates the terrain view of the given position and with the given pattern. The first method wraps the /// Validates the terrain view of the given position and with the given pattern. The first method wraps the
/// second method to validate the terrain view with the given pattern in all four flip directions(horizontal, vertical). /// second method to validate the terrain view with the given pattern in all four flip directions(horizontal, vertical).
ValidationResult validateTerrainView(const int3 & pos, const std::vector<TerrainViewPattern> * pattern, int recDepth = 0) const; ValidationResult validateTerrainView(const int3 & pos, const std::vector<TerrainViewPattern> * pattern, int recDepth = 0) const;
ValidationResult validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth = 0) const; ValidationResult validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth = 0) const;
/// Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock /// Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock
bool isSandType(ETerrainType terType) const; bool isSandType(Terrain terType) const;
CTerrainSelection terrainSel; CTerrainSelection terrainSel;
ETerrainType terType; Terrain terType;
CRandomGenerator * gen; CRandomGenerator * gen;
std::set<int3> invalidatedTerViews; std::set<int3> invalidatedTerViews;
}; };

View File

@ -935,14 +935,14 @@ void CMapLoaderH3M::readTerrain()
for(int z = 0; z < map->height; z++) for(int z = 0; z < map->height; z++)
{ {
auto & tile = map->getTile(int3(z, c, a)); auto & tile = map->getTile(int3(z, c, a));
tile.terType = ETerrainType(reader.readUInt8()); tile.terType = Terrain::createTerrainTypeH3M(reader.readUInt8());
tile.terView = reader.readUInt8(); tile.terView = reader.readUInt8();
tile.riverType = static_cast<ERiverType::ERiverType>(reader.readUInt8()); tile.riverType = RIVER_NAMES[reader.readUInt8()];
tile.riverDir = reader.readUInt8(); tile.riverDir = reader.readUInt8();
tile.roadType = static_cast<ERoadType::ERoadType>(reader.readUInt8()); tile.roadType = ROAD_NAMES[reader.readUInt8()];
tile.roadDir = reader.readUInt8(); tile.roadDir = reader.readUInt8();
tile.extTileFlags = reader.readUInt8(); tile.extTileFlags = reader.readUInt8();
tile.blocked = ((tile.terType == ETerrainType::ROCK || tile.terType == ETerrainType::BORDER ) ? true : false); //underground tiles are always blocked tile.blocked = ((!tile.terType.isPassable() || tile.terType == Terrain("BORDER") ) ? true : false); //underground tiles are always blocked
tile.visitable = 0; tile.visitable = 0;
} }
} }

View File

@ -323,20 +323,6 @@ namespace TriggeredEventsDetail
namespace TerrainDetail namespace TerrainDetail
{ {
static const std::array<std::string, 10> terrainCodes =
{
"dt", "sa", "gr", "sn", "sw", "rg", "sb", "lv", "wt", "rc"
};
static const std::array<std::string, 4> roadCodes =
{
"", "pd", "pg", "pc"
};
static const std::array<std::string, 5> riverCodes =
{
"", "rw", "ri", "rm", "rl"
};
static const std::array<char, 4> flipCodes = static const std::array<char, 4> flipCodes =
{ {
'_', '-', '|', '+' '_', '-', '|', '+'
@ -959,13 +945,7 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
using namespace TerrainDetail; using namespace TerrainDetail;
{//terrain type {//terrain type
const std::string typeCode = src.substr(0, 2); const std::string typeCode = src.substr(0, 2);
tile.terType = Terrain::createTerrainByCode(typeCode);
int rawType = vstd::find_pos(terrainCodes, typeCode);
if(rawType < 0)
throw std::runtime_error("Invalid terrain type code in "+src);
tile.terType = ETerrainType(rawType);
} }
int startPos = 2; //0+typeCode fixed length int startPos = 2; //0+typeCode fixed length
{//terrain view {//terrain view
@ -992,20 +972,18 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
{//road type {//road type
const std::string typeCode = src.substr(startPos, 2); const std::string typeCode = src.substr(startPos, 2);
startPos+=2; startPos+=2;
int rawType = vstd::find_pos(roadCodes, typeCode); if(vstd::find_pos(ROAD_NAMES, typeCode) < 0)
if(rawType < 0)
{ {
rawType = vstd::find_pos(riverCodes, typeCode); if(vstd::find_pos(RIVER_NAMES, typeCode) < 0)
if(rawType < 0)
throw std::runtime_error("Invalid river type in "+src); throw std::runtime_error("Invalid river type in "+src);
else else
{ {
tile.riverType = ERiverType::ERiverType(rawType); tile.riverType = typeCode;
hasRoad = false; hasRoad = false;
} }
} }
else else
tile.roadType = ERoadType::ERoadType(rawType); tile.roadType = typeCode;
} }
if(hasRoad) if(hasRoad)
{//road dir {//road dir
@ -1033,10 +1011,9 @@ void CMapLoaderJson::readTerrainTile(const std::string & src, TerrainTile & tile
{//river type {//river type
const std::string typeCode = src.substr(startPos, 2); const std::string typeCode = src.substr(startPos, 2);
startPos+=2; startPos+=2;
int rawType = vstd::find_pos(riverCodes, typeCode); if(vstd::find_pos(RIVER_NAMES, typeCode) < 0)
if(rawType < 0)
throw std::runtime_error("Invalid river type in "+src); throw std::runtime_error("Invalid river type in "+src);
tile.riverType = ERiverType::ERiverType(rawType); tile.riverType = typeCode;
} }
{//river dir {//river dir
int pos = startPos; int pos = startPos;
@ -1298,13 +1275,13 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile)
out.setf(std::ios::dec, std::ios::basefield); out.setf(std::ios::dec, std::ios::basefield);
out.unsetf(std::ios::showbase); out.unsetf(std::ios::showbase);
out << terrainCodes.at(int(tile.terType)) << (int)tile.terView << flipCodes[tile.extTileFlags % 4]; out << Terrain::Manager::getInfo(tile.terType).typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
if(tile.roadType != ERoadType::NO_ROAD) if(tile.roadType != ROAD_NAMES[0])
out << roadCodes.at(int(tile.roadType)) << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4]; out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
if(tile.riverType != ERiverType::NO_RIVER) if(tile.riverType != RIVER_NAMES[0])
out << riverCodes.at(int(tile.riverType)) << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4]; out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
return out.str(); return out.str();
} }

View File

@ -69,17 +69,6 @@ CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed) :
void CMapGenerator::loadConfig() void CMapGenerator::loadConfig()
{ {
static std::map<std::string, ETerrainType> terrainMap
{
{"dirt", ETerrainType::DIRT},
{"sand", ETerrainType::SAND},
{"grass", ETerrainType::GRASS},
{"snow", ETerrainType::SNOW},
{"swamp", ETerrainType::SWAMP},
{"subterranean", ETerrainType::SUBTERRANEAN},
{"lava", ETerrainType::LAVA},
{"rough", ETerrainType::ROUGH}
};
static const std::map<std::string, Res::ERes> resMap static const std::map<std::string, Res::ERes> resMap
{ {
{"wood", Res::ERes::WOOD}, {"wood", Res::ERes::WOOD},
@ -90,23 +79,17 @@ void CMapGenerator::loadConfig()
{"sulfur", Res::ERes::SULFUR}, {"sulfur", Res::ERes::SULFUR},
{"gold", Res::ERes::GOLD}, {"gold", Res::ERes::GOLD},
}; };
static std::map<std::string, ERoadType::ERoadType> roadTypeMap
{
{"dirt_road", ERoadType::DIRT_ROAD},
{"gravel_road", ERoadType::GRAVEL_ROAD},
{"cobblestone_road", ERoadType::COBBLESTONE_ROAD}
};
static const ResourceID path("config/randomMap.json"); static const ResourceID path("config/randomMap.json");
JsonNode randomMapJson(path); JsonNode randomMapJson(path);
for(auto& s : randomMapJson["terrain"]["undergroundAllow"].Vector()) for(auto& s : randomMapJson["terrain"]["undergroundAllow"].Vector())
{ {
if(!s.isNull()) if(!s.isNull())
config.terrainUndergroundAllowed.push_back(terrainMap[s.String()]); config.terrainUndergroundAllowed.emplace_back(s.String());
} }
for(auto& s : randomMapJson["terrain"]["groundProhibit"].Vector()) for(auto& s : randomMapJson["terrain"]["groundProhibit"].Vector())
{ {
if(!s.isNull()) if(!s.isNull())
config.terrainGroundProhibit.push_back(terrainMap[s.String()]); config.terrainGroundProhibit.emplace_back(s.String());
} }
config.shipyardGuard = randomMapJson["waterZone"]["shipyard"]["value"].Integer(); config.shipyardGuard = randomMapJson["waterZone"]["shipyard"]["value"].Integer();
for(auto & treasure : randomMapJson["waterZone"]["treasure"].Vector()) for(auto & treasure : randomMapJson["waterZone"]["treasure"].Vector())
@ -119,7 +102,7 @@ void CMapGenerator::loadConfig()
} }
config.mineExtraResources = randomMapJson["mines"]["extraResourcesLimit"].Integer(); config.mineExtraResources = randomMapJson["mines"]["extraResourcesLimit"].Integer();
config.minGuardStrength = randomMapJson["minGuardStrength"].Integer(); config.minGuardStrength = randomMapJson["minGuardStrength"].Integer();
config.defaultRoadType = roadTypeMap[randomMapJson["defaultRoadType"].String()]; config.defaultRoadType = randomMapJson["defaultRoadType"].String();
config.treasureValueLimit = randomMapJson["treasureValueLimit"].Integer(); config.treasureValueLimit = randomMapJson["treasureValueLimit"].Integer();
for(auto & i : randomMapJson["prisons"]["experience"].Vector()) for(auto & i : randomMapJson["prisons"]["experience"].Vector())
config.prisonExperience.push_back(i.Integer()); config.prisonExperience.push_back(i.Integer());
@ -357,7 +340,7 @@ void CMapGenerator::genZones()
{ {
getEditManager()->clearTerrain(&rand); getEditManager()->clearTerrain(&rand);
getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight())); getEditManager()->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
getEditManager()->drawTerrain(ETerrainType::GRASS, &rand); getEditManager()->drawTerrain(Terrain("grass"), &rand);
auto tmpl = mapGenOptions.getMapTemplate(); auto tmpl = mapGenOptions.getMapTemplate();
zones.clear(); zones.clear();
@ -530,14 +513,14 @@ void CMapGenerator::fillZones()
void CMapGenerator::createObstaclesCommon1() void CMapGenerator::createObstaclesCommon1()
{ {
if (map->twoLevel) //underground if(map->twoLevel) //underground
{ {
//negative approach - create rock tiles first, then make sure all accessible tiles have no rock //negative approach - create rock tiles first, then make sure all accessible tiles have no rock
std::vector<int3> rockTiles; std::vector<int3> rockTiles;
for (int x = 0; x < map->width; x++) for(int x = 0; x < map->width; x++)
{ {
for (int y = 0; y < map->height; y++) for(int y = 0; y < map->height; y++)
{ {
int3 tile(x, y, 1); int3 tile(x, y, 1);
if (shouldBeBlocked(tile)) if (shouldBeBlocked(tile))
@ -547,21 +530,29 @@ void CMapGenerator::createObstaclesCommon1()
} }
} }
getEditManager()->getTerrainSelection().setSelection(rockTiles); getEditManager()->getTerrainSelection().setSelection(rockTiles);
getEditManager()->drawTerrain(ETerrainType::ROCK, &rand);
//collect all rock terrain types
std::vector<Terrain> rockTerrains;
for(auto & terrain : Terrain::Manager::terrains())
if(!terrain.isPassable())
rockTerrains.push_back(terrain);
auto rockTerrain = *RandomGeneratorUtil::nextItem(rockTerrains, rand);
getEditManager()->drawTerrain(rockTerrain, &rand);
} }
} }
void CMapGenerator::createObstaclesCommon2() void CMapGenerator::createObstaclesCommon2()
{ {
if (map->twoLevel) if(map->twoLevel)
{ {
//finally mark rock tiles as occupied, spawn no obstacles there //finally mark rock tiles as occupied, spawn no obstacles there
for (int x = 0; x < map->width; x++) for(int x = 0; x < map->width; x++)
{ {
for (int y = 0; y < map->height; y++) for(int y = 0; y < map->height; y++)
{ {
int3 tile(x, y, 1); int3 tile(x, y, 1);
if (map->getTile(tile).terType == ETerrainType::ROCK) if(!map->getTile(tile).terType.isPassable())
{ {
setOccupied(tile, ETileType::USED); setOccupied(tile, ETileType::USED);
} }
@ -904,7 +895,7 @@ void CMapGenerator::setOccupied(const int3 &tile, ETileType::ETileType state)
tiles[tile.x][tile.y][tile.z].setOccupied(state); tiles[tile.x][tile.y][tile.z].setOccupied(state);
} }
void CMapGenerator::setRoad(const int3& tile, ERoadType::ERoadType roadType) void CMapGenerator::setRoad(const int3& tile, const std::string & roadType)
{ {
checkIsOnMap(tile); checkIsOnMap(tile);

View File

@ -26,8 +26,6 @@ class JsonNode;
class CMapGenerator; class CMapGenerator;
class CTileInfo; class CTileInfo;
//#define _BETA
typedef std::vector<JsonNode> JsonVector; typedef std::vector<JsonNode> JsonVector;
class rmgException : public std::exception class rmgException : public std::exception
@ -54,14 +52,14 @@ class DLL_LINKAGE CMapGenerator
public: public:
struct Config struct Config
{ {
std::vector<ETerrainType> terrainUndergroundAllowed; std::vector<Terrain> terrainUndergroundAllowed;
std::vector<ETerrainType> terrainGroundProhibit; std::vector<Terrain> terrainGroundProhibit;
std::vector<CTreasureInfo> waterTreasure; std::vector<CTreasureInfo> waterTreasure;
int shipyardGuard; int shipyardGuard;
int mineExtraResources; int mineExtraResources;
std::map<Res::ERes, int> mineValues; std::map<Res::ERes, int> mineValues;
int minGuardStrength; int minGuardStrength;
ERoadType::ERoadType defaultRoadType; std::string defaultRoadType;
int treasureValueLimit; int treasureValueLimit;
std::vector<int> prisonExperience, prisonValues; std::vector<int> prisonExperience, prisonValues;
std::vector<int> scrollValues; std::vector<int> scrollValues;
@ -101,7 +99,7 @@ public:
bool isRoad(const int3 &tile) const; bool isRoad(const int3 &tile) const;
void setOccupied(const int3 &tile, ETileType::ETileType state); void setOccupied(const int3 &tile, ETileType::ETileType state);
void setRoad(const int3 &tile, ERoadType::ERoadType roadType); void setRoad(const int3 &tile, const std::string & roadType);
CTileInfo getTile(const int3 & tile) const; CTileInfo getTile(const int3 & tile) const;
bool isAllowedSpell(SpellID sid) const; bool isAllowedSpell(SpellID sid) const;

View File

@ -16,6 +16,7 @@
#include "../mapping/CMap.h" #include "../mapping/CMap.h"
#include "../VCMI_Lib.h" #include "../VCMI_Lib.h"
#include "../CTownHandler.h" #include "../CTownHandler.h"
#include "../Terrain.h"
#include "../serializer/JsonSerializeFormat.h" #include "../serializer/JsonSerializeFormat.h"
#include "../StringConstants.h" #include "../StringConstants.h"
@ -66,12 +67,12 @@ class TerrainEncoder
public: public:
static si32 decode(const std::string & identifier) static si32 decode(const std::string & identifier)
{ {
return vstd::find_pos(GameConstants::TERRAIN_NAMES, identifier); return vstd::find_pos(Terrain::Manager::terrains(), identifier);
} }
static std::string encode(const si32 index) static std::string encode(const si32 index)
{ {
return (index >=0 && index < GameConstants::TERRAIN_TYPES) ? GameConstants::TERRAIN_NAMES[index] : "<INVALID TERRAIN>"; return (index >=0 && index < Terrain::Manager::terrains().size()) ? static_cast<std::string>(Terrain::Manager::terrains()[index]) : "<INVALID TERRAIN>";
} }
}; };
@ -89,18 +90,6 @@ public:
} }
}; };
const std::set<ETerrainType> ZoneOptions::DEFAULT_TERRAIN_TYPES =
{
ETerrainType::DIRT,
ETerrainType::SAND,
ETerrainType::GRASS,
ETerrainType::SNOW,
ETerrainType::SWAMP,
ETerrainType::ROUGH,
ETerrainType::SUBTERRANEAN,
ETerrainType::LAVA
};
const TRmgTemplateZoneId ZoneOptions::NO_ZONE = -1; const TRmgTemplateZoneId ZoneOptions::NO_ZONE = -1;
ZoneOptions::CTownInfo::CTownInfo() ZoneOptions::CTownInfo::CTownInfo()
@ -149,7 +138,6 @@ ZoneOptions::ZoneOptions()
playerTowns(), playerTowns(),
neutralTowns(), neutralTowns(),
matchTerrainToTown(true), matchTerrainToTown(true),
terrainTypes(DEFAULT_TERRAIN_TYPES),
townsAreSameType(false), townsAreSameType(false),
townTypes(), townTypes(),
monsterTypes(), monsterTypes(),
@ -161,7 +149,9 @@ ZoneOptions::ZoneOptions()
terrainTypeLikeZone(NO_ZONE), terrainTypeLikeZone(NO_ZONE),
treasureLikeZone(NO_ZONE) treasureLikeZone(NO_ZONE)
{ {
for(auto & terr : Terrain::Manager::terrains())
if(terr.isLand() && terr.isPassable())
terrainTypes.insert(terr);
} }
ZoneOptions & ZoneOptions::operator=(const ZoneOptions & other) ZoneOptions & ZoneOptions::operator=(const ZoneOptions & other)
@ -224,15 +214,15 @@ boost::optional<int> ZoneOptions::getOwner() const
return owner; return owner;
} }
const std::set<ETerrainType> & ZoneOptions::getTerrainTypes() const const std::set<Terrain> & ZoneOptions::getTerrainTypes() const
{ {
return terrainTypes; return terrainTypes;
} }
void ZoneOptions::setTerrainTypes(const std::set<ETerrainType> & value) void ZoneOptions::setTerrainTypes(const std::set<Terrain> & value)
{ {
assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() && //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()); // value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
terrainTypes = value; terrainTypes = value;
} }
@ -339,7 +329,31 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
#undef SERIALIZE_ZONE_LINK #undef SERIALIZE_ZONE_LINK
if(terrainTypeLikeZone == NO_ZONE) if(terrainTypeLikeZone == NO_ZONE)
handler.serializeIdArray<ETerrainType, TerrainEncoder>("terrainTypes", terrainTypes, DEFAULT_TERRAIN_TYPES); {
JsonNode node;
if(handler.saving)
{
node.setType(JsonNode::JsonType::DATA_VECTOR);
for(auto & ttype : terrainTypes)
{
JsonNode n;
n.String() = ttype;
node.Vector().push_back(n);
}
}
handler.serializeRaw("terrainTypes", node, boost::none);
if(!handler.saving)
{
if(!node.Vector().empty())
{
terrainTypes.clear();
for(auto ttype : node.Vector())
{
terrainTypes.emplace(ttype.String());
}
}
}
}
handler.serializeBool("townsAreSameType", townsAreSameType, false); handler.serializeBool("townsAreSameType", townsAreSameType, false);
handler.serializeIdArray<TFaction, FactionID>("allowedMonsters", monsterTypes, VLC->townh->getAllowedFactions(false)); handler.serializeIdArray<TFaction, FactionID>("allowedMonsters", monsterTypes, VLC->townh->getAllowedFactions(false));

View File

@ -13,9 +13,11 @@
#include "../int3.h" #include "../int3.h"
#include "../GameConstants.h" #include "../GameConstants.h"
#include "../ResourceSet.h" #include "../ResourceSet.h"
#include "../Terrain.h"
#include "CMapGenOptions.h" #include "CMapGenOptions.h"
class JsonSerializeFormat; class JsonSerializeFormat;
class Terrain;
namespace ETemplateZoneType namespace ETemplateZoneType
{ {
@ -65,7 +67,6 @@ private:
class DLL_LINKAGE ZoneOptions class DLL_LINKAGE ZoneOptions
{ {
public: public:
static const std::set<ETerrainType> DEFAULT_TERRAIN_TYPES;
static const TRmgTemplateZoneId NO_ZONE; static const TRmgTemplateZoneId NO_ZONE;
class DLL_LINKAGE CTownInfo class DLL_LINKAGE CTownInfo
@ -101,8 +102,8 @@ public:
void setSize(int value); void setSize(int value);
boost::optional<int> getOwner() const; boost::optional<int> getOwner() const;
const std::set<ETerrainType> & getTerrainTypes() const; const std::set<Terrain> & getTerrainTypes() const;
void setTerrainTypes(const std::set<ETerrainType> & value); void setTerrainTypes(const std::set<Terrain> & value);
std::set<TFaction> getDefaultTownTypes() const; std::set<TFaction> getDefaultTownTypes() const;
const std::set<TFaction> & getTownTypes() const; const std::set<TFaction> & getTownTypes() const;
@ -134,7 +135,7 @@ protected:
CTownInfo playerTowns; CTownInfo playerTowns;
CTownInfo neutralTowns; CTownInfo neutralTowns;
bool matchTerrainToTown; bool matchTerrainToTown;
std::set<ETerrainType> terrainTypes; std::set<Terrain> terrainTypes;
bool townsAreSameType; bool townsAreSameType;
std::set<TFaction> townTypes; std::set<TFaction> townTypes;

View File

@ -36,7 +36,7 @@ void CRmgTemplateZone::addRoadNode(const int3& node)
roadNodes.insert(node); roadNodes.insert(node);
} }
CTileInfo::CTileInfo():nearestObjectDistance(float(INT_MAX)), terrain(ETerrainType::WRONG),roadType(ERoadType::NO_ROAD) CTileInfo::CTileInfo():nearestObjectDistance(float(INT_MAX)), terrain()
{ {
occupied = ETileType::POSSIBLE; //all tiles are initially possible to place objects or passages occupied = ETileType::POSSIBLE; //all tiles are initially possible to place objects or passages
} }
@ -69,7 +69,7 @@ bool CTileInfo::isFree() const
bool CTileInfo::isRoad() const bool CTileInfo::isRoad() const
{ {
return roadType != ERoadType::NO_ROAD; return roadType != ROAD_NAMES[0];
} }
bool CTileInfo::isUsed() const bool CTileInfo::isUsed() const
@ -86,17 +86,17 @@ ETileType::ETileType CTileInfo::getTileType() const
return occupied; return occupied;
} }
ETerrainType CTileInfo::getTerrainType() const Terrain CTileInfo::getTerrainType() const
{ {
return terrain; return terrain;
} }
void CTileInfo::setTerrainType(ETerrainType value) void CTileInfo::setTerrainType(Terrain value)
{ {
terrain = value; terrain = value;
} }
void CTileInfo::setRoadType(ERoadType::ERoadType value) void CTileInfo::setRoadType(const std::string & value)
{ {
roadType = value; roadType = value;
// setOccupied(ETileType::FREE); // setOccupied(ETileType::FREE);
@ -106,7 +106,7 @@ void CTileInfo::setRoadType(ERoadType::ERoadType value)
CRmgTemplateZone::CRmgTemplateZone(CMapGenerator * Gen) CRmgTemplateZone::CRmgTemplateZone(CMapGenerator * Gen)
: ZoneOptions(), : ZoneOptions(),
townType(ETownType::NEUTRAL), townType(ETownType::NEUTRAL),
terrainType (ETerrainType::GRASS), terrainType (Terrain("grass")),
minGuardedValue(0), minGuardedValue(0),
questArtZone(), questArtZone(),
gen(Gen) gen(Gen)
@ -989,7 +989,7 @@ bool CRmgTemplateZone::createRoad(const int3& src, const int3& dst)
std::map<int3, int3> cameFrom; // The map of navigated nodes. std::map<int3, int3> cameFrom; // The map of navigated nodes.
std::map<int3, float> distances; std::map<int3, float> distances;
gen->setRoad (src, ERoadType::NO_ROAD); //just in case zone guard already has road under it. Road under nodes will be added at very end gen->setRoad (src, ROAD_NAMES[0]); //just in case zone guard already has road under it. Road under nodes will be added at very end
cameFrom[src] = int3(-1, -1, -1); //first node points to finish condition cameFrom[src] = int3(-1, -1, -1); //first node points to finish condition
pq.push(std::make_pair(src, 0.f)); pq.push(std::make_pair(src, 0.f));
@ -1012,8 +1012,8 @@ bool CRmgTemplateZone::createRoad(const int3& src, const int3& dst)
while (cameFrom[backTracking].valid()) while (cameFrom[backTracking].valid())
{ {
// add node to path // add node to path
roads.insert (backTracking); roads.insert(backTracking);
gen->setRoad (backTracking, ERoadType::COBBLESTONE_ROAD); gen->setRoad(backTracking, gen->getConfig().defaultRoadType);
//logGlobal->trace("Setting road at tile %s", backTracking); //logGlobal->trace("Setting road at tile %s", backTracking);
// do the same for the predecessor // do the same for the predecessor
backTracking = cameFrom[backTracking]; backTracking = cameFrom[backTracking];
@ -1250,6 +1250,17 @@ void CRmgTemplateZone::addToConnectLater(const int3& src)
tilesToConnectLater.insert(src); tilesToConnectLater.insert(src);
} }
int CRmgTemplateZone::chooseRandomAppearance(si32 ObjID) const
{
auto factories = VLC->objtypeh->knownSubObjects(ObjID);
vstd::erase_if(factories, [this, ObjID](si32 f)
{
return VLC->objtypeh->getHandlerFor(ObjID, f)->getTemplates(terrainType).empty();
});
return *RandomGeneratorUtil::nextItem(factories, gen->rand);
}
bool CRmgTemplateZone::addMonster(int3 &pos, si32 strength, bool clearSurroundingTiles, bool zoneGuard) bool CRmgTemplateZone::addMonster(int3 &pos, si32 strength, bool clearSurroundingTiles, bool zoneGuard)
{ {
//precalculate actual (randomized) monster strength based on this post //precalculate actual (randomized) monster strength based on this post
@ -1731,33 +1742,51 @@ void CRmgTemplateZone::initTerrainType ()
{ {
if (type==ETemplateZoneType::WATER) if (type==ETemplateZoneType::WATER)
{ {
terrainType = ETerrainType::WATER; //collect all water terrain types
std::vector<Terrain> waterTerrains;
for(auto & terrain : Terrain::Manager::terrains())
if(terrain.isWater())
waterTerrains.push_back(terrain);
terrainType = *RandomGeneratorUtil::nextItem(waterTerrains, gen->rand);
} }
else else
{ {
if (matchTerrainToTown && townType != ETownType::NEUTRAL) if (matchTerrainToTown && townType != ETownType::NEUTRAL)
{
terrainType = (*VLC->townh)[townType]->nativeTerrain; terrainType = (*VLC->townh)[townType]->nativeTerrain;
}
else else
{
terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand); terrainType = *RandomGeneratorUtil::nextItem(terrainTypes, gen->rand);
}
//TODO: allow new types of terrain? //TODO: allow new types of terrain?
{ {
if(isUnderground()) if(isUnderground())
{ {
if(!vstd::contains(gen->getConfig().terrainUndergroundAllowed, terrainType)) if(!vstd::contains(gen->getConfig().terrainUndergroundAllowed, terrainType))
terrainType = ETerrainType::SUBTERRANEAN; {
//collect all underground terrain types
std::vector<Terrain> undegroundTerrains;
for(auto & terrain : Terrain::Manager::terrains())
if(terrain.isUnderground())
undegroundTerrains.push_back(terrain);
terrainType = *RandomGeneratorUtil::nextItem(undegroundTerrains, gen->rand);
}
} }
else else
{ {
if(vstd::contains(gen->getConfig().terrainGroundProhibit, terrainType)) if(vstd::contains(gen->getConfig().terrainGroundProhibit, terrainType) || terrainType.isUnderground())
terrainType = ETerrainType::DIRT; terrainType = Terrain("dirt");
} }
} }
} }
paintZoneTerrain (terrainType); paintZoneTerrain (terrainType);
} }
void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType) void CRmgTemplateZone::paintZoneTerrain (Terrain terrainType)
{ {
std::vector<int3> tiles(tileinfo.begin(), tileinfo.end()); std::vector<int3> tiles(tileinfo.begin(), tileinfo.end());
gen->getEditManager()->getTerrainSelection().setSelection(tiles); gen->getEditManager()->getTerrainSelection().setSelection(tiles);
@ -1837,6 +1866,9 @@ bool CRmgTemplateZone::createRequiredObjects()
for(const auto &object : requiredObjects) for(const auto &object : requiredObjects)
{ {
auto obj = object.first; auto obj = object.first;
if (!obj->appearance.canBePlacedAt(terrainType))
continue;
int3 pos; int3 pos;
while (true) while (true)
{ {
@ -1845,6 +1877,7 @@ bool CRmgTemplateZone::createRequiredObjects()
logGlobal->error("Failed to fill zone %d due to lack of space", id); logGlobal->error("Failed to fill zone %d due to lack of space", id);
return false; return false;
} }
if (tryToPlaceObjectAndConnectToPath(obj, pos) == EObjectPlacingResult::SUCCESS) if (tryToPlaceObjectAndConnectToPath(obj, pos) == EObjectPlacingResult::SUCCESS)
{ {
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones //paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
@ -1858,6 +1891,9 @@ bool CRmgTemplateZone::createRequiredObjects()
for (const auto &obj : closeObjects) for (const auto &obj : closeObjects)
{ {
setTemplateForObject(obj.first); setTemplateForObject(obj.first);
if (!obj.first->appearance.canBePlacedAt(terrainType))
continue;
auto tilesBlockedByObject = obj.first->getBlockedOffsets(); auto tilesBlockedByObject = obj.first->getBlockedOffsets();
bool finished = false; bool finished = false;
@ -2069,8 +2105,8 @@ int3 CRmgTemplateZone::createShipyard(const std::set<int3> & lake, si32 guardStr
bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength) bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength)
{ {
auto subObjects = VLC->objtypeh->knownSubObjects(Obj::SHIPYARD); int subtype = chooseRandomAppearance(Obj::SHIPYARD);
auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, *RandomGeneratorUtil::nextItem(subObjects, gen->rand))->create(ObjectTemplate()); auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create(ObjectTemplate());
shipyard->tempOwner = PlayerColor::NEUTRAL; shipyard->tempOwner = PlayerColor::NEUTRAL;
setTemplateForObject(shipyard); setTemplateForObject(shipyard);
@ -2569,7 +2605,8 @@ void CRmgTemplateZone::checkAndPlaceObject(CGObjectInstance* object, const int3
if (object->appearance.id == Obj::NO_OBJ) if (object->appearance.id == Obj::NO_OBJ)
{ {
auto terrainType = gen->map->getTile(pos).terType; auto terrainType = gen->map->getTile(pos).terType;
auto templates = VLC->objtypeh->getHandlerFor(object->ID, object->subID)->getTemplates(terrainType); auto h = VLC->objtypeh->getHandlerFor(object->ID, object->subID);
auto templates = h->getTemplates(terrainType);
if (templates.empty()) if (templates.empty())
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % object->ID % object->subID % pos.toString() % terrainType)); throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") % object->ID % object->subID % pos.toString() % terrainType));
@ -3239,7 +3276,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
if (!creaturesAmount) if (!creaturesAmount)
continue; continue;
int randomAppearance = *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::SEER_HUT), gen->rand); int randomAppearance = chooseRandomAppearance(Obj::SEER_HUT);
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
{ {
@ -3270,7 +3307,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
static int seerLevels = std::min(gen->getConfig().questValues.size(), gen->getConfig().questRewardValues.size()); static int seerLevels = std::min(gen->getConfig().questValues.size(), gen->getConfig().questRewardValues.size());
for(int i = 0; i < seerLevels; i++) //seems that code for exp and gold reward is similiar for(int i = 0; i < seerLevels; i++) //seems that code for exp and gold reward is similiar
{ {
int randomAppearance = *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::SEER_HUT), gen->rand); int randomAppearance = chooseRandomAppearance(Obj::SEER_HUT);
oi.setTemplate(Obj::SEER_HUT, randomAppearance, terrainType); oi.setTemplate(Obj::SEER_HUT, randomAppearance, terrainType);
oi.value = gen->getConfig().questValues[i]; oi.value = gen->getConfig().questValues[i];
@ -3332,7 +3369,7 @@ ObjectInfo::ObjectInfo()
} }
void ObjectInfo::setTemplate (si32 type, si32 subtype, ETerrainType terrainType) void ObjectInfo::setTemplate (si32 type, si32 subtype, Terrain terrainType)
{ {
auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype); auto templHandler = VLC->objtypeh->getHandlerFor(type, subtype);
if(!templHandler) if(!templHandler)

View File

@ -17,6 +17,7 @@
#include "CRmgTemplate.h" #include "CRmgTemplate.h"
#include "../mapObjects/ObjectTemplate.h" #include "../mapObjects/ObjectTemplate.h"
#include <boost/heap/priority_queue.hpp> //A* #include <boost/heap/priority_queue.hpp> //A*
#include "Terrain.h"
class CMapGenerator; class CMapGenerator;
class CTileInfo; class CTileInfo;
@ -48,16 +49,16 @@ public:
bool isUsed() const; bool isUsed() const;
bool isRoad() const; bool isRoad() const;
void setOccupied(ETileType::ETileType value); void setOccupied(ETileType::ETileType value);
ETerrainType getTerrainType() const; Terrain getTerrainType() const;
ETileType::ETileType getTileType() const; ETileType::ETileType getTileType() const;
void setTerrainType(ETerrainType value); void setTerrainType(Terrain value);
void setRoadType(ERoadType::ERoadType value); void setRoadType(const std::string & value);
private: private:
float nearestObjectDistance; float nearestObjectDistance;
ETileType::ETileType occupied; ETileType::ETileType occupied;
ETerrainType terrain; Terrain terrain;
ERoadType::ERoadType roadType; std::string roadType;
}; };
struct DLL_LINKAGE ObjectInfo struct DLL_LINKAGE ObjectInfo
@ -69,7 +70,7 @@ struct DLL_LINKAGE ObjectInfo
//ui32 maxPerMap; //unused //ui32 maxPerMap; //unused
std::function<CGObjectInstance *()> generateObject; std::function<CGObjectInstance *()> generateObject;
void setTemplate (si32 type, si32 subtype, ETerrainType terrain); void setTemplate (si32 type, si32 subtype, Terrain terrain);
ObjectInfo(); ObjectInfo();
@ -120,7 +121,7 @@ public:
bool fill (); bool fill ();
bool placeMines (); bool placeMines ();
void initTownType (); void initTownType ();
void paintZoneTerrain (ETerrainType terrainType); void paintZoneTerrain (Terrain terrainType);
void randomizeTownType(bool matchUndergroundType = false); //helper function void randomizeTownType(bool matchUndergroundType = false); //helper function
void initTerrainType (); void initTerrainType ();
void createBorder(); void createBorder();
@ -192,7 +193,7 @@ private:
//template info //template info
si32 townType; si32 townType;
ETerrainType terrainType; Terrain terrainType;
std::weak_ptr<CRmgTemplateZone> questArtZone; //artifacts required for Seer Huts will be placed here - or not if null std::weak_ptr<CRmgTemplateZone> questArtZone; //artifacts required for Seer Huts will be placed here - or not if null
std::vector<ObjectInfo> possibleObjects; std::vector<ObjectInfo> possibleObjects;
@ -230,6 +231,7 @@ private:
bool canObstacleBePlacedHere(ObjectTemplate &temp, int3 &pos); bool canObstacleBePlacedHere(ObjectTemplate &temp, int3 &pos);
void setTemplateForObject(CGObjectInstance* obj); void setTemplateForObject(CGObjectInstance* obj);
void checkAndPlaceObject(CGObjectInstance* object, const int3 &pos); void checkAndPlaceObject(CGObjectInstance* object, const int3 &pos);
int chooseRandomAppearance(si32 ObjID) const;
bool isGuardNeededForTreasure(int value); bool isGuardNeededForTreasure(int value);
}; };

View File

@ -184,28 +184,26 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
zonesToPlace.push_back(zone); zonesToPlace.push_back(zone);
else else
{ {
switch ((*VLC->townh)[faction]->nativeTerrain) auto & tt = (*VLC->townh)[faction]->nativeTerrain;
if(tt == Terrain("dirt"))
{ {
case ETerrainType::GRASS:
case ETerrainType::SWAMP:
case ETerrainType::SNOW:
case ETerrainType::SAND:
case ETerrainType::ROUGH:
//surface
zonesOnLevel[0]++;
levels[zone.first] = 0;
break;
case ETerrainType::LAVA:
case ETerrainType::SUBTERRANEAN:
//underground
zonesOnLevel[1]++;
levels[zone.first] = 1;
break;
case ETerrainType::DIRT:
default:
//any / random //any / random
zonesToPlace.push_back(zone); zonesToPlace.push_back(zone);
break; }
else
{
if(tt.isUnderground())
{
//underground
zonesOnLevel[1]++;
levels[zone.first] = 1;
}
else
{
//surface
zonesOnLevel[0]++;
levels[zone.first] = 0;
}
} }
} }
} }
@ -564,7 +562,7 @@ void CZonePlacer::assignZones()
//make sure that terrain inside zone is not a rock //make sure that terrain inside zone is not a rock
//FIXME: reorder actions? //FIXME: reorder actions?
zone.second->paintZoneTerrain (ETerrainType::SUBTERRANEAN); zone.second->paintZoneTerrain (Terrain("subterra"));
} }
} }
logGlobal->info("Finished zone colouring"); logGlobal->info("Finished zone colouring");

View File

@ -12,8 +12,8 @@
#include "../ConstTransitivePtr.h" #include "../ConstTransitivePtr.h"
#include "../GameConstants.h" #include "../GameConstants.h"
const ui32 SERIALIZATION_VERSION = 801; const ui32 SERIALIZATION_VERSION = 802;
const ui32 MINIMAL_SERIALIZATION_VERSION = 753; const ui32 MINIMAL_SERIALIZATION_VERSION = 802;
const std::string SAVEGAME_MAGIC = "VCMISVG"; const std::string SAVEGAME_MAGIC = "VCMISVG";
class CHero; class CHero;

View File

@ -1018,54 +1018,3 @@ std::vector<bool> CSpellHandler::getDefaultAllowed() const
return allowedSpells; return allowedSpells;
} }
void CSpellHandler::update780()
{
static_assert(MINIMAL_SERIALIZATION_VERSION < 780, "No longer needed CSpellHandler::update780");
auto spellsContent = (*VLC->modh->content)["spells"];
const ContentTypeHandler::ModInfo & coreData = spellsContent.modData.at("core");
const JsonNode & coreSpells = coreData.modData;
const int levelsCount = GameConstants::SPELL_SCHOOL_LEVELS;
for(CSpell * spell : objects)
{
auto identifier = spell->identifier;
size_t colonPos = identifier.find(':');
if(colonPos != std::string::npos)
continue;
const JsonNode & actualConfig = coreSpells[spell->identifier];
if(actualConfig.getType() != JsonNode::JsonType::DATA_STRUCT)
{
logGlobal->error("Spell not found %s", spell->identifier);
continue;
}
if(actualConfig["targetCondition"].getType() == JsonNode::JsonType::DATA_STRUCT && !actualConfig["targetCondition"].Struct().empty())
{
spell->targetCondition = actualConfig["targetCondition"];
}
for(int levelIndex = 0; levelIndex < levelsCount; levelIndex++)
{
const JsonNode & levelNode = actualConfig["levels"][SpellConfig::LEVEL_NAMES[levelIndex]];
logGlobal->debug(levelNode.toJson());
CSpell::LevelInfo & levelObject = spell->levels[levelIndex];
if(levelNode["battleEffects"].getType() == JsonNode::JsonType::DATA_STRUCT && !levelNode["battleEffects"].Struct().empty())
{
levelObject.battleEffects = levelNode["battleEffects"];
logGlobal->trace("Updated special effects for level %d of spell %s", levelIndex, spell->identifier);
}
}
}
}

View File

@ -83,14 +83,7 @@ public:
{ {
h & resourceName; h & resourceName;
h & verticalPosition; h & verticalPosition;
if(version >= 754) h & pause;
{
h & pause;
}
else if(!h.saving)
{
pause = 0;
}
} }
}; };
@ -120,10 +113,7 @@ public:
h & projectile; h & projectile;
h & hit; h & hit;
h & cast; h & cast;
if(version >= 762) h & affect;
{
h & affect;
}
} }
std::string selectProjectile(const double angle) const; std::string selectProjectile(const double angle) const;
@ -158,32 +148,11 @@ public:
h & AIValue; h & AIValue;
h & smartTarget; h & smartTarget;
h & range; h & range;
h & effects;
if(version >= 773) h & cumulativeEffects;
{
h & effects;
h & cumulativeEffects;
}
else
{
//all old effects treated as not cumulative, special cases handled by CSpell::serialize
std::vector<Bonus> old;
h & old;
if(!h.saving)
{
effects.clear();
cumulativeEffects.clear();
for(const Bonus & oldBonus : old)
effects.push_back(std::make_shared<Bonus>(oldBonus));
}
}
h & clearTarget; h & clearTarget;
h & clearAffected; h & clearAffected;
h & battleEffects;
if(version >= 780)
h & battleEffects;
} }
}; };
@ -316,27 +285,7 @@ public:
h & damage; h & damage;
h & offensive; h & offensive;
h & targetType; h & targetType;
h & targetCondition;
if(version >= 780)
{
h & targetCondition;
}
else
{
BTVector immunities;
BTVector absoluteImmunities;
BTVector limiters;
BTVector absoluteLimiters;
h & immunities;
h & limiters;
h & absoluteImmunities;
h & absoluteLimiters;
if(!h.saving)
targetCondition = convertTargetCondition(immunities, absoluteImmunities, limiters, absoluteLimiters);
}
h & iconImmune; h & iconImmune;
h & defaultProbability; h & defaultProbability;
h & special; h & special;
@ -348,16 +297,6 @@ public:
h & levels; h & levels;
h & school; h & school;
h & animationInfo; h & animationInfo;
//backward compatibility
//can not be added to level structure as level structure does not know spell id
if(!h.saving && version < 773)
{
if(id == SpellID::DISRUPTING_RAY || id == SpellID::ACID_BREATH_DEFENSE)
for(auto & level : levels)
std::swap(level.effects, level.cumulativeEffects);
}
} }
friend class CSpellHandler; friend class CSpellHandler;
friend class Graphics; friend class Graphics;
@ -442,11 +381,6 @@ public:
template <typename Handler> void serialize(Handler & h, const int version) template <typename Handler> void serialize(Handler & h, const int version)
{ {
h & objects; h & objects;
if(!h.saving && version < 780)
{
update780();
}
if(!h.saving) if(!h.saving)
{ {
afterLoadFinalization(); afterLoadFinalization();
@ -456,6 +390,4 @@ public:
protected: protected:
const std::vector<std::string> & getTypeNames() const override; const std::vector<std::string> & getTypeNames() const override;
CSpell * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index) override; CSpell * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index) override;
private:
void update780();
}; };

View File

@ -84,9 +84,7 @@ int BattleCbProxy::getTerrainType(lua_State * L)
if(!S.tryGet(1, object)) if(!S.tryGet(1, object))
return S.retVoid(); return S.retVoid();
auto ret = object->battleTerrainType(); return LuaStack::quickRetStr(L, object->battleTerrainType());
return LuaStack::quickRetInt(L, static_cast<si32>(ret.num));
} }
int BattleCbProxy::getUnitByPos(lua_State * L) int BattleCbProxy::getUnitByPos(lua_State * L)

View File

@ -1911,7 +1911,7 @@ void CGameHandler::newTurn()
hth.id = h->id; hth.id = h->id;
auto ti = make_unique<TurnInfo>(h, 1); 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 // 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 != ETerrainType::WATER, ti.get()); hth.move = h->maxMovePointsCached(gs->map->getTile(h->getPosition(false)).terType.isLand(), ti.get());
hth.mana = h->getManaNewTurn(); hth.mana = h->getManaNewTurn();
n.heroes.insert(hth); n.heroes.insert(hth);
@ -2215,9 +2215,9 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
battleResult.set(nullptr); battleResult.set(nullptr);
const auto t = getTile(tile); const auto t = getTile(tile);
ETerrainType terrain = t->terType; Terrain terrain = t->terType;
if (gs->map->isCoastalTile(tile)) //coastal tile is always ground if (gs->map->isCoastalTile(tile)) //coastal tile is always ground
terrain = ETerrainType::SAND; terrain = Terrain("sand");
BFieldType terType = gs->battleGetBattlefieldType(tile, getRandomGenerator()); BFieldType terType = gs->battleGetBattlefieldType(tile, getRandomGenerator());
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat) if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
@ -2314,7 +2314,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
const int3 guardPos = gs->guardingCreaturePosition(hmpos); const int3 guardPos = gs->guardingCreaturePosition(hmpos);
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT; const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
const bool disembarking = h->boat && t.terType != ETerrainType::WATER && !t.blocked; const bool disembarking = h->boat && t.terType.isLand() && !t.blocked;
//result structure for start - movement failed, no move points used //result structure for start - movement failed, no move points used
TryMoveHero tmh; TryMoveHero tmh;
@ -2336,11 +2336,11 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
//it's a rock or blocked and not visitable tile //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) //OR hero is on land and dest is water and (there is not present only one object - boat)
if (((t.terType == ETerrainType::ROCK || (t.blocked && !t.visitable && !canFly)) if (((!t.terType.isPassable() || (t.blocked && !t.visitable && !canFly))
&& complain("Cannot move hero, destination tile is blocked!")) && complain("Cannot move hero, destination tile is blocked!"))
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType == ETerrainType::WATER && (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!")) && complain("Cannot move hero, destination tile is on water!"))
|| ((h->boat && t.terType != ETerrainType::WATER && t.blocked) || ((h->boat && t.terType.isLand() && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!")) && complain("Cannot disembark hero, tile is blocked!"))
|| ((distance(h->pos, dst) >= 1.5 && !teleporting) || ((distance(h->pos, dst) >= 1.5 && !teleporting)
&& complain("Tiles are not neighboring!")) && complain("Tiles are not neighboring!"))

View File

@ -272,21 +272,14 @@ public:
h & QID; h & QID;
h & states; h & states;
h & finishingBattle; h & finishingBattle;
h & getRandomGenerator();
if(version >= 761) JsonNode scriptsState;
{ if(h.saving)
h & getRandomGenerator(); serverScripts->serializeState(h.saving, scriptsState);
} h & scriptsState;
if(!h.saving)
if(version >= 800) serverScripts->serializeState(h.saving, scriptsState);
{
JsonNode scriptsState;
if(h.saving)
serverScripts->serializeState(h.saving, scriptsState);
h & scriptsState;
if(!h.saving)
serverScripts->serializeState(h.saving, scriptsState);
}
} }
void sendMessageToAll(const std::string &message); void sendMessageToAll(const std::string &message);
@ -314,11 +307,6 @@ public:
h & loserHero; h & loserHero;
h & victor; h & victor;
h & loser; h & loser;
if(version < 774 && !h.saving)
{
bool duel;
h & duel;
}
h & remainingBattleQueriesCount; h & remainingBattleQueriesCount;
} }
}; };

View File

@ -193,7 +193,7 @@ public:
const auto t = gameCallback->getTile(tile); const auto t = gameCallback->getTile(tile);
ETerrainType terrain = t->terType; Terrain terrain = t->terType;
BFieldType terType = BFieldType::GRASS_HILLS; BFieldType terType = BFieldType::GRASS_HILLS;
//send info about battles //send info about battles

@ -1 +1 @@
Subproject commit e2239ee6043f73722e7aa812a459f54a28552929 Subproject commit 4bab34d2084259cba67f3bfb51217c10d606e175

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