diff --git a/config/objects/generic.json b/config/objects/generic.json index 7b5ee3c0c..1f866bcba 100644 --- a/config/objects/generic.json +++ b/config/objects/generic.json @@ -914,7 +914,7 @@ /// Passive objects, terrain overlays "cursedGround" : { "index" : 21, - "handler": "generic", + "handler": "terrain", "base" : { "sounds" : { "ambient" : ["LOOPCURS"] @@ -922,13 +922,14 @@ }, "types" : { "object" : { - "index" : 0 + "index" : 0, + "battleground": "cursed_ground" } } }, - "magicPlains" : { + "magicPlains" : { "index" : 46, - "handler" : "generic", + "handler" : "terrain", "base" : { "sounds" : { "ambient" : ["LOOPMAGI"] @@ -936,18 +937,28 @@ }, "types" : { "object" : { - "index" : 0 + "index" : 0, + "battleground": "magic_plains" } } }, - "swampFoliage" : { "index" :211, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "cloverField" : { "index" :222, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "swampFoliage" : { + "index" :211, + "handler": "terrain", + "types" : { "object" : { "index" : 0} } + }, + "cloverField" : { + "index" :222, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "clover_field" } } + }, "cursedGroundDUPLICATE" : { "index" : 223, - "handler" : "generic", + "handler" : "terrain", "types" : { "object" : { - "index" : 0 + "index" : 0, + "battleground": "cursed_ground" } }, "base" : { @@ -956,15 +967,39 @@ } } }, - "evilFog" : { "index" :224, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "favorableWinds" : { "index" :225, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "fieryFields" : { "index" :226, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "holyGround" : { "index" :227, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "lucidPools" : { "index" :228, "handler": "generic", "types" : { "object" : { "index" : 0} } }, - "magicClouds" : { "index" :229, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "evilFog" : { + "index" :224, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "evil_fog" } } + }, + "favorableWinds" : { + "index" :225, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "favorable_winds" } } + }, + "fieryFields": { + "index" :226, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "fiery_fields" } } + }, + "holyGround" : { + "index" :227, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "holy_ground" } } + }, + "lucidPools" : { + "index" :228, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "lucid_pools" } } + }, + "magicClouds" : { + "index" :229, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "magic_clouds" } } + }, "magicPlainsDUPLICATE" : { "index" : 230, - "handler": "generic", + "handler": "terrain", "base" : { "sounds" : { "ambient" : ["LOOPMAGI"] @@ -972,11 +1007,16 @@ }, "types" : { "object" : { - "index" : 0 + "index" : 0, + "battleground": "magic_plains" } } }, - "rocklands" : { "index" :231, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "rocklands" : { + "index" :231, + "handler": "terrain", + "types" : { "object" : { "index" : 0, "battleground": "rocklands" } } + }, /// Decorations "cactus" : { "index" :116, "handler": "static", "types" : { "object" : { "index" : 0} } }, diff --git a/config/objects/moddables.json b/config/objects/moddables.json index 69ccf20bf..f7e3c1034 100644 --- a/config/objects/moddables.json +++ b/config/objects/moddables.json @@ -237,7 +237,8 @@ }, "sounds" : { "ambient" : ["LOOPLUMB"] - } + }, + "battleground": "subterranean" }, "alchemistLab" : { "index" : 1, @@ -247,7 +248,8 @@ }, "sounds" : { "ambient" : ["LOOPSTAR"] - } + }, + "battleground": "subterranean" }, "orePit" : { "index" : 2, @@ -257,7 +259,8 @@ }, "sounds" : { "ambient" : ["LOOPSULF"] - } + }, + "battleground": "subterranean" }, "sulfurDune" : { "index" : 3, @@ -267,7 +270,8 @@ }, "sounds" : { "ambient" : ["LOOPSULF"] - } + }, + "battleground": "subterranean" }, "crystalCavern" : { "index" : 4, @@ -277,7 +281,8 @@ }, "sounds" : { "ambient" : ["LOOPCRYS"] - } + }, + "battleground": "subterranean" }, "gemPond" : { "index" : 5, @@ -287,7 +292,8 @@ }, "sounds" : { "ambient" : ["LOOPGEMP"] - } + }, + "battleground": "subterranean" }, "goldMine" : { "index" : 6, @@ -297,7 +303,8 @@ }, "sounds" : { "ambient" : ["LOOPMINE"] - } + }, + "battleground": "subterranean" }, "abandoned" : { "index" : 7, @@ -305,7 +312,8 @@ "sounds" : { "ambient" : ["LOOPCAVE"], "visit" : ["MYSTERY"] - } + }, + "battleground": "subterranean" } } }, @@ -319,7 +327,7 @@ } }, "types" : { - "mine" : { "index" : 7 } + "mine" : { "index" : 7, "battleground": "subterranean" } } }, diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index abbf72ce8..83196ce72 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1902,9 +1902,12 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & r return BattleField::NONE; const TerrainTile &t = map->getTile(tile); - //fight in mine -> subterranean - if(dynamic_cast(t.visitableObjects.front())) - return BattleField("subterranean"); + + auto topObject = t.visitableObjects.front(); + if(topObject && topObject->getBattlefield() != BattleField::NONE) + { + return topObject->getBattlefield(); + } for(auto &obj : map->objects) { @@ -1912,29 +1915,10 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & r if( !obj || obj->pos.z != tile.z || !obj->coveringAt(tile.x, tile.y)) continue; - switch(obj->ID) - { - case Obj::CLOVER_FIELD: - return BattleField("clover_field"); - case Obj::CURSED_GROUND1: case Obj::CURSED_GROUND2: - return BattleField("cursed_ground"); - case Obj::EVIL_FOG: - return BattleField("evil_fog"); - case Obj::FAVORABLE_WINDS: - return BattleField("favorable_winds"); - case Obj::FIERY_FIELDS: - return BattleField("fiery_fields"); - case Obj::HOLY_GROUNDS: - return BattleField("holy_ground"); - case Obj::LUCID_POOLS: - return BattleField("lucid_pools"); - case Obj::MAGIC_CLOUDS: - return BattleField("magic_clouds"); - case Obj::MAGIC_PLAINS1: case Obj::MAGIC_PLAINS2: - return BattleField("magic_plains"); - case Obj::ROCKLANDS: - return BattleField("rocklands"); - } + auto customBattlefield = obj->getBattlefield(); + + if(customBattlefield != BattleField::NONE) + return customBattlefield; } if(map->isCoastalTile(tile)) //coastal tile is always ground diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 74093e959..7fae83f7e 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -177,10 +177,10 @@ std::vector CObstacleInfo::getBlocked(BattleHex hex) const return ret; } -bool CObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const +bool CObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & battlefield) const { - if(!allowedSpecialBfields.empty() && specialBattlefield != BattleField::NONE) - return vstd::contains(allowedSpecialBfields, specialBattlefield); + if(battlefield.isSpecial()) + return vstd::contains(allowedSpecialBfields, battlefield); return vstd::contains(allowedTerrains, terrainType); } diff --git a/lib/Terrain.h b/lib/Terrain.h index 5e69fa384..63dac1b6f 100644 --- a/lib/Terrain.h +++ b/lib/Terrain.h @@ -42,6 +42,11 @@ public: { h & name; } + + bool isSpecial() const + { + return name.find('_') >= 0; // hack for special battlefields, move to JSON + } protected: diff --git a/lib/battle/BattleInfo.cpp b/lib/battle/BattleInfo.cpp index 2dd2b173c..1f4587901 100644 --- a/lib/battle/BattleInfo.cpp +++ b/lib/battle/BattleInfo.cpp @@ -467,7 +467,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, } if(battlefieldType == BattleField("fiery_fields")) { - if(bonusSubtype == -1) bonusSubtype = 1; + if(bonusSubtype == -1) bonusSubtype = 2; } if(battlefieldType == BattleField("rocklands")) { @@ -475,13 +475,13 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, } if(battlefieldType == BattleField("magic_clouds")) { - if(bonusSubtype == -1) bonusSubtype = 2; + if(bonusSubtype == -1) bonusSubtype = 1; } if(battlefieldType == BattleField("lucid_pools")) { if(bonusSubtype == -1) bonusSubtype = 4; } - if(bonusSubtype == -1) + if(bonusSubtype != -1) { //common part for cases 9, 14, 15, 16, 17 curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL,Bonus::TERRAIN_OVERLAY, 3, battlefieldType.hash(), bonusSubtype)); } diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index c7944b940..638ad7cea 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -97,6 +97,7 @@ CObjectClassesHandler::CObjectClassesHandler() SET_HANDLER("oncePerHero", CGVisitableOPH); SET_HANDLER("oncePerWeek", CGVisitableOPW); SET_HANDLER("witch", CGWitchHut); + SET_HANDLER("terrain", CGTerrainPatch); #undef SET_HANDLER_CLASS #undef SET_HANDLER @@ -514,6 +515,11 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional>(input["aiValue"].Integer()); + if(input["battleground"].isNull()) + battlefield = BattleField::NONE; + else + battlefield = BattleField(input["battleground"].String()); + initTypeData(input); } @@ -569,6 +575,11 @@ std::vector AObjectTypeHandler::getTemplates() const return templates; } +BattleField AObjectTypeHandler::getBattlefield() const +{ + return battlefield; +} + std::vector AObjectTypeHandler::getTemplates(const Terrain & terrainType) const { std::vector templates = getTemplates(); diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index cc737fc99..c46275261 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -15,6 +15,7 @@ #include "../ConstTransitivePtr.h" #include "../IHandlerBase.h" #include "../JsonNode.h" +#include "Terrain.h" class JsonNode; class CRandomGenerator; @@ -148,6 +149,9 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable SObjectSounds sounds; boost::optional aiValue; + + BattleField battlefield; + protected: void preInitObject(CGObjectInstance * obj) const; virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; @@ -179,6 +183,7 @@ public: /// returns all templates matching parameters std::vector getTemplates() const; std::vector getTemplates(const Terrain & terrainType) const; + BattleField getBattlefield() const; /// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) /// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index 7a0f84d64..9f5d7b1da 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -400,6 +400,11 @@ void CGObjectInstance::serializeJsonOwner(JsonSerializeFormat & handler) tempOwner = PlayerColor(temp); } +BattleField CGObjectInstance::getBattlefield() const +{ + return VLC->objtypeh->getHandlerFor(ID, subID)->getBattlefield(); +} + CGObjectInstanceBySubIdFinder::CGObjectInstanceBySubIdFinder(CGObjectInstance * obj) : obj(obj) { diff --git a/lib/mapObjects/CObjectHandler.h b/lib/mapObjects/CObjectHandler.h index 2897606cc..3db649b4e 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/lib/mapObjects/CObjectHandler.h @@ -159,21 +159,9 @@ public: std::set getBlockedOffsets() const; //returns set of relative positions blocked by this object bool isVisitable() const; //returns true if object is visitable - bool isTile2Terrain() const - { - return ID.num == Obj::CLOVER_FIELD - || ID.num == Obj::CURSED_GROUND1 - || ID.num == Obj::CURSED_GROUND2 - || ID.num == Obj::EVIL_FOG - || ID.num == Obj::FAVORABLE_WINDS - || ID.num == Obj::FIERY_FIELDS - || ID.num == Obj::HOLY_GROUNDS - || ID.num == Obj::LUCID_POOLS - || ID.num == Obj::MAGIC_CLOUDS - || ID.num == Obj::MAGIC_PLAINS1 - || ID.num == Obj::MAGIC_PLAINS2 - || ID.num == Obj::ROCKLANDS; - } + BattleField getBattlefield() const; + + virtual bool isTile2Terrain() const { return false; } boost::optional getAmbientSound() const; boost::optional getVisitSound() const; diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 9ec8d9c52..3a8f405ba 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -2199,4 +2199,4 @@ void CGLighthouse::giveBonusTo(PlayerColor player, bool onInit) const void CGLighthouse::serializeJsonOptions(JsonSerializeFormat& handler) { serializeJsonOwner(handler); -} +} \ No newline at end of file diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index a6ad8567e..e13165fe0 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -529,3 +529,14 @@ public: protected: void serializeJsonOptions(JsonSerializeFormat & handler) override; }; + +class DLL_LINKAGE CGTerrainPatch : public CGObjectInstance +{ +public: + CGTerrainPatch() = default; + + virtual bool isTile2Terrain() const override + { + return true; + } +};