From 9241cd1e62a7988d77cfb27e1eef0a77484b9229 Mon Sep 17 00:00:00 2001 From: Nordsoft91 Date: Wed, 22 Jun 2022 11:41:02 +0300 Subject: [PATCH] New battlegrounds (#758) --- client/Graphics.cpp | 46 ++++---- client/Graphics.h | 2 +- client/battle/CBattleInterface.cpp | 13 ++- config/battles_graphics.json | 54 +++++----- config/obstacles.json | 138 ++++++++++++------------ config/terrains.json | 37 +++++-- lib/CGameState.cpp | 54 +++------- lib/CGameState.h | 2 +- lib/CHeroHandler.cpp | 31 +++--- lib/CHeroHandler.h | 11 +- lib/GameConstants.h | 43 -------- lib/Terrain.cpp | 49 +++++++++ lib/Terrain.h | 40 +++++++ lib/battle/BattleInfo.cpp | 155 +++++++++++---------------- lib/battle/BattleInfo.h | 9 +- lib/battle/BattleProxy.cpp | 2 +- lib/battle/BattleProxy.h | 2 +- lib/battle/CBattleInfoCallback.cpp | 2 +- lib/battle/CBattleInfoEssentials.cpp | 4 +- lib/battle/CBattleInfoEssentials.h | 2 +- lib/battle/IBattleInfoCallback.h | 4 +- lib/battle/IBattleState.h | 3 +- lib/mapping/CMapEditManager.cpp | 102 ++++++------------ lib/mapping/CMapEditManager.h | 24 +---- lib/serializer/CSerializer.h | 4 +- lib/spells/ISpellMechanics.cpp | 2 +- scripting/lua/api/BattleCb.cpp | 2 +- server/CGameHandler.cpp | 4 +- test/erm/ERM_BU.cpp | 4 +- test/game/CGameStateTest.cpp | 2 +- test/map/CMapEditManagerTest.cpp | 3 +- test/mock/BattleFake.cpp | 2 +- test/mock/mock_IBattleInfoCallback.h | 2 +- test/mock/mock_battle_IBattleState.h | 2 +- 34 files changed, 412 insertions(+), 444 deletions(-) diff --git a/client/Graphics.cpp b/client/Graphics.cpp index 93351c81e..fe64be0f9 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -24,6 +24,7 @@ #include "gui/CAnimation.h" #include #include "../lib/CThreadHelper.h" +#include "../lib/CModHandler.h" #include "CGameInfo.h" #include "../lib/VCMI_Lib.h" #include "../CCallback.h" @@ -99,28 +100,35 @@ void Graphics::loadPaletteAndColors() void Graphics::initializeBattleGraphics() { - const JsonNode config(ResourceID("config/battles_graphics.json")); + auto allConfigs = VLC->modh->getActiveMods(); + allConfigs.insert(allConfigs.begin(), "core"); + for(auto & mod : allConfigs) + { + if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/battles_graphics.json"))) + continue; + + const JsonNode config(mod, ResourceID("config/battles_graphics.json")); - // Reserve enough space for the terrains - int idx = static_cast(config["backgrounds"].Vector().size()); - battleBacks.resize(idx+1); // 1 to idx, 0 is unused - - idx = 1; - for(const JsonNode &t : config["backgrounds"].Vector()) { - battleBacks[idx].push_back(t.String()); - idx++; - } - - //initialization of AC->def name mapping - for(const JsonNode &ac : config["ac_mapping"].Vector()) { - int ACid = static_cast(ac["id"].Float()); - std::vector< std::string > toAdd; - - for(const JsonNode &defname : ac["defnames"].Vector()) { - toAdd.push_back(defname.String()); + if(!config["backgrounds"].isNull()) + for(auto & t : config["backgrounds"].Struct()) + { + battleBacks[t.first] = t.second.String(); } - battleACToDef[ACid] = toAdd; + //initialization of AC->def name mapping + if(!config["ac_mapping"].isNull()) + for(const JsonNode &ac : config["ac_mapping"].Vector()) + { + int ACid = static_cast(ac["id"].Float()); + std::vector< std::string > toAdd; + + for(const JsonNode &defname : ac["defnames"].Vector()) + { + toAdd.push_back(defname.String()); + } + + battleACToDef[ACid] = toAdd; + } } } Graphics::Graphics() diff --git a/client/Graphics.h b/client/Graphics.h index 9cc4fd92a..d59ae3fb2 100644 --- a/client/Graphics.h +++ b/client/Graphics.h @@ -87,7 +87,7 @@ public: //towns std::map ERMUtoPicture[GameConstants::F_NUMBER]; //maps building ID to it's picture's name for each town type //for battles - std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type + std::map battleBacks; //maps BattleField to it's picture's name std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names //functions diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index e04f36b7a..f1de912ec 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -200,15 +200,14 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet } else { - auto bfieldType = (int)curInt->cb->battleGetBattlefieldType(); - if (graphics->battleBacks.size() <= bfieldType || bfieldType < 0) - logGlobal->error("%d is not valid battlefield type index!", bfieldType); - else if (graphics->battleBacks[bfieldType].empty()) - logGlobal->error("%d battlefield type does not have any backgrounds!", bfieldType); + auto bfieldType = curInt->cb->battleGetBattlefieldType(); + if(!vstd::contains(graphics->battleBacks, bfieldType)) + { + logGlobal->error("%s is not valid battlefield type!", static_cast(bfieldType)); + } else { - const std::string bgName = *RandomGeneratorUtil::nextItem(graphics->battleBacks[bfieldType], CRandomGenerator::getDefault()); - background = BitmapHandler::loadBitmap(bgName, false); + background = BitmapHandler::loadBitmap(graphics->battleBacks[bfieldType], false); } } diff --git a/config/battles_graphics.json b/config/battles_graphics.json index f07e72ec6..8e37ae7eb 100644 --- a/config/battles_graphics.json +++ b/config/battles_graphics.json @@ -1,32 +1,32 @@ { // backgrounds of terrains battles can be fought on - "backgrounds": [ - "CMBKBCH.BMP", - "CMBKDES.BMP", - "CMBKDRTR.BMP", - "CMBKDRMT.BMP", - "CMBKDRDD.BMP", - "CMBKGRMT.BMP", - "CMBKGRTR.BMP", - "CMBKLAVA.BMP", - "CMBKMAG.BMP", - "CMBKSNMT.BMP", - "CMBKSNTR.BMP", - "CMBKSUB.BMP", - "CMBKSWMP.BMP", - "CMBKFF.BMP", - "CMBKRK.BMP", - "CMBKMC.BMP", - "CMBKLP.BMP", - "CMBKHG.BMP", - "CMBKCF.BMP", - "CMBKEF.BMP", - "CMBKFW.BMP", - "CMBKCUR.BMP", - "CMBKRGH.BMP", - "CMBKBOAT.BMP", - "CMBKDECK.BMP" - ], + "backgrounds": { + "sand_shore": "CMBKBCH.BMP", + "sand_mesas": "CMBKDES.BMP", + "dirt_birches": "CMBKDRTR.BMP", + "dirt_hills": "CMBKDRMT.BMP", + "dirt_pines": "CMBKDRDD.BMP", + "grass_hills": "CMBKGRMT.BMP", + "grass_pines": "CMBKGRTR.BMP", + "lava": "CMBKLAVA.BMP", + "magic_plains": "CMBKMAG.BMP", + "snow_mountains": "CMBKSNMT.BMP", + "snow_trees": "CMBKSNTR.BMP", + "subterranean": "CMBKSUB.BMP", + "swamp_trees": "CMBKSWMP.BMP", + "fiery_fields": "CMBKFF.BMP", + "rocklands": "CMBKRK.BMP", + "magic_clouds": "CMBKMC.BMP", + "lucid_pools": "CMBKLP.BMP", + "holy_ground": "CMBKHG.BMP", + "clover_field": "CMBKCF.BMP", + "evil_fog": "CMBKEF.BMP", + "favorable_winds": "CMBKFW.BMP", + "cursed_ground": "CMBKCUR.BMP", + "rough": "CMBKRGH.BMP", + "ship_to_ship": "CMBKBOAT.BMP", + "ship": "CMBKDECK.BMP" + }, // WoG_Ac_format_to_def_names_mapping "ac_mapping": [ diff --git a/config/obstacles.json b/config/obstacles.json index bee4258e4..22a944f3c 100644 --- a/config/obstacles.json +++ b/config/obstacles.json @@ -25,7 +25,7 @@ { "id" : 1, "allowedTerrain" : ["dirt", "sand", "rough", "subterra"], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 3, "height" : 2, "blockedTiles" : [0, 1, 2], @@ -45,7 +45,7 @@ { "id" : 3, "allowedTerrain" : ["dirt", "rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -55,7 +55,7 @@ { "id" : 4, "allowedTerrain" : ["dirt", "rough", "subterra"], - "specialBattlefields" : [0, 1], + "specialBattlefields" : ["sand_shore", "cursed_ground"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -135,7 +135,7 @@ { "id" : 12, "allowedTerrain" : ["dirt", "rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 3, "blockedTiles" : [0, 1, 2, 3], @@ -145,7 +145,7 @@ { "id" : 13, "allowedTerrain" : ["dirt", "rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 2, "blockedTiles" : [1, 2, -15], @@ -155,7 +155,7 @@ { "id" : 14, "allowedTerrain" : ["dirt", "rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 2, "blockedTiles" : [2, -15, -16], @@ -165,7 +165,7 @@ { "id" : 15, "allowedTerrain" : ["dirt", "rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 3, "blockedTiles" : [1, -16, -33], @@ -215,7 +215,7 @@ { "id" : 20, "allowedTerrain" : ["grass", "swamp"], - "specialBattlefields" : [2], + "specialBattlefields" : ["magic_plains"], "width" : 2, "height" : 2, "blockedTiles" : [0, 1], @@ -235,7 +235,7 @@ { "id" : 22, "allowedTerrain" : ["grass"], - "specialBattlefields" : [2], + "specialBattlefields" : ["magic_plains"], "width" : 6, "height" : 2, "blockedTiles" : [1, 2, 3, 4, -13, -14, -15, -16], @@ -415,7 +415,7 @@ { "id" : 40, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 2, "height" : 2, "blockedTiles" : [0, 1, -16], @@ -425,7 +425,7 @@ { "id" : 41, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 4, "height" : 3, "blockedTiles" : [-14, -15, -16, -32, -33], @@ -435,7 +435,7 @@ { "id" : 42, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 2, "blockedTiles" : [1, 2, -15, -16], @@ -445,7 +445,7 @@ { "id" : 43, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 3, "blockedTiles" : [-16, -32, -33], @@ -455,7 +455,7 @@ { "id" : 44, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 3, "height" : 3, "blockedTiles" : [-15, -16, -32], @@ -575,7 +575,7 @@ { "id" : 56, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 3, "height" : 2, "blockedTiles" : [1, -15, -16], @@ -585,7 +585,7 @@ { "id" : 57, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 3, "height" : 2, "blockedTiles" : [0, 1, 2], @@ -595,7 +595,7 @@ { "id" : 58, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 5, "height" : 2, "blockedTiles" : [1, 2, 3, -14, -15, -16], @@ -605,7 +605,7 @@ { "id" : 59, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 4, "height" : 2, "blockedTiles" : [1, 2, -14, -15], @@ -615,7 +615,7 @@ { "id" : 60, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 2, "height" : 2, "blockedTiles" : [0, 1, -16], @@ -625,7 +625,7 @@ { "id" : 61, "allowedTerrain" : [], - "specialBattlefields" : [3], + "specialBattlefields" : ["holy_ground"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -635,7 +635,7 @@ { "id" : 62, "allowedTerrain" : [], - "specialBattlefields" : [3], + "specialBattlefields" : ["holy_ground"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -645,7 +645,7 @@ { "id" : 63, "allowedTerrain" : [], - "specialBattlefields" : [3], + "specialBattlefields" : ["holy_ground"], "width" : 3, "height" : 3, "blockedTiles" : [1], @@ -655,7 +655,7 @@ { "id" : 64, "allowedTerrain" : [], - "specialBattlefields" : [3], + "specialBattlefields" : ["holy_ground"], "width" : 3, "height" : 2, "blockedTiles" : [0, 1, 2], @@ -665,7 +665,7 @@ { "id" : 65, "allowedTerrain" : [], - "specialBattlefields" : [3], + "specialBattlefields" : ["holy_ground"], "width" : 4, "height" : 3, "blockedTiles" : [0, 1, 2, 3], @@ -675,7 +675,7 @@ { "id" : 66, "allowedTerrain" : [], - "specialBattlefields" : [4], + "specialBattlefields" : ["evil_fog"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -685,7 +685,7 @@ { "id" : 67, "allowedTerrain" : [], - "specialBattlefields" : [4], + "specialBattlefields" : ["evil_fog"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -695,7 +695,7 @@ { "id" : 68, "allowedTerrain" : [], - "specialBattlefields" : [4], + "specialBattlefields" : ["evil_fog"], "width" : 3, "height" : 2, "blockedTiles" : [0, 1, 2], @@ -705,7 +705,7 @@ { "id" : 69, "allowedTerrain" : [], - "specialBattlefields" : [4], + "specialBattlefields" : ["evil_fog"], "width" : 4, "height" : 2, "blockedTiles" : [1, 2], @@ -715,7 +715,7 @@ { "id" : 70, "allowedTerrain" : [], - "specialBattlefields" : [4], + "specialBattlefields" : ["evil_fog"], "width" : 6, "height" : 2, "blockedTiles" : [1, 2, 3, -12, -13], @@ -725,7 +725,7 @@ { "id" : 71, "allowedTerrain" : [], - "specialBattlefields" : [5], + "specialBattlefields" : ["clover_field"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -735,7 +735,7 @@ { "id" : 72, "allowedTerrain" : [], - "specialBattlefields" : [5], + "specialBattlefields" : ["clover_field"], "width" : 3, "height" : 1, "blockedTiles" : [0, 1, 2], @@ -745,7 +745,7 @@ { "id" : 73, "allowedTerrain" : [], - "specialBattlefields" : [5], + "specialBattlefields" : ["clover_field"], "width" : 3, "height" : 2, "blockedTiles" : [1, 2, -15, -16], @@ -755,7 +755,7 @@ { "id" : 74, "allowedTerrain" : [], - "specialBattlefields" : [5], + "specialBattlefields" : ["clover_field"], "width" : 4, "height" : 2, "blockedTiles" : [0, 1, 2, -14, -15, -16], @@ -765,7 +765,7 @@ { "id" : 75, "allowedTerrain" : [], - "specialBattlefields" : [6], + "specialBattlefields" : ["lucid_pools"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -775,7 +775,7 @@ { "id" : 76, "allowedTerrain" : [], - "specialBattlefields" : [6], + "specialBattlefields" : ["lucid_pools"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -785,7 +785,7 @@ { "id" : 77, "allowedTerrain" : [], - "specialBattlefields" : [6], + "specialBattlefields" : ["lucid_pools"], "width" : 3, "height" : 2, "blockedTiles" : [0, -15, -16], @@ -795,7 +795,7 @@ { "id" : 78, "allowedTerrain" : [], - "specialBattlefields" : [6], + "specialBattlefields" : ["lucid_pools"], "width" : 5, "height" : 2, "blockedTiles" : [1, 2, 3, -13, -14, -15, -16], @@ -805,7 +805,7 @@ { "id" : 79, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -815,7 +815,7 @@ { "id" : 80, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -825,7 +825,7 @@ { "id" : 81, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 3, "height" : 2, "blockedTiles" : [0, 1, 2, -15], @@ -835,7 +835,7 @@ { "id" : 82, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 4, "height" : 2, "blockedTiles" : [1, 2, 3, -15, -16], @@ -845,7 +845,7 @@ { "id" : 83, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 3, "height" : 3, "blockedTiles" : [0, 1, 2, 3, -14, -15, -16], @@ -855,7 +855,7 @@ { "id" : 84, "allowedTerrain" : [], - "specialBattlefields" : [8], + "specialBattlefields" : ["rocklands"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -865,7 +865,7 @@ { "id" : 85, "allowedTerrain" : [], - "specialBattlefields" : [8], + "specialBattlefields" : ["rocklands"], "width" : 2, "height" : 1, "blockedTiles" : [0, 1], @@ -875,7 +875,7 @@ { "id" : 86, "allowedTerrain" : [], - "specialBattlefields" : [8], + "specialBattlefields" : ["rocklands"], "width" : 3, "height" : 1, "blockedTiles" : [0, 1, 2], @@ -885,7 +885,7 @@ { "id" : 87, "allowedTerrain" : [], - "specialBattlefields" : [8], + "specialBattlefields" : ["rocklands"], "width" : 4, "height" : 2, "blockedTiles" : [1, 2, 3, -15, -16], @@ -895,7 +895,7 @@ { "id" : 88, "allowedTerrain" : [], - "specialBattlefields" : [9], + "specialBattlefields" : ["magic_clouds"], "width" : 1, "height" : 1, "blockedTiles" : [0], @@ -905,7 +905,7 @@ { "id" : 89, "allowedTerrain" : [], - "specialBattlefields" : [9], + "specialBattlefields" : ["magic_clouds"], "width" : 2, "height" : 2, "blockedTiles" : [1, -16], @@ -915,7 +915,7 @@ { "id" : 90, "allowedTerrain" : [], - "specialBattlefields" : [9], + "specialBattlefields" : ["magic_clouds"], "width" : 4, "height" : 2, "blockedTiles" : [0, 1, -14, -15], @@ -1053,7 +1053,7 @@ { "id" : 14, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 186, "height" : 212, "blockedTiles" : [55, 72, 90, 107, 125, 126, 127, 128, 129, 130, 131, 132], @@ -1062,7 +1062,7 @@ { "id" : 15, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 347, "height" : 174, "blockedTiles" : [41, 59, 76, 94, 111, 129, 143, 144, 145], @@ -1071,7 +1071,7 @@ { "id" : 16, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 294, "height" : 169, "blockedTiles" : [40, 41, 42, 43, 58, 75, 93, 110, 128, 145], @@ -1080,7 +1080,7 @@ { "id" : 17, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 165, "height" : 257, "blockedTiles" : [72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 89, 105], @@ -1089,7 +1089,7 @@ { "id" : 18, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 208, "height" : 268, "blockedTiles" : [72, 73, 74, 75, 76, 77, 78, 79, 80, 90, 91, 92, 93, 94, 95, 96, 97], @@ -1098,7 +1098,7 @@ { "id" : 19, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 252, "height" : 254, "blockedTiles" : [73, 74, 75, 76, 77, 78, 91, 92, 93, 94], @@ -1107,7 +1107,7 @@ { "id" : 20, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 278, "height" : 128, "blockedTiles" : [23, 40, 58, 75, 93, 110, 128, 145, 163], @@ -1116,7 +1116,7 @@ { "id" : 21, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 208, "height" : 268, "blockedTiles" : [72, 73, 74, 75, 76, 77, 78, 79, 80, 90, 91, 92, 93, 94, 95, 96, 97], @@ -1125,7 +1125,7 @@ { "id" : 22, "allowedTerrain" : ["rough"], - "specialBattlefields" : [1], + "specialBattlefields" : ["cursed_ground"], "width" : 168, "height" : 212, "blockedTiles" : [73, 74, 75, 76, 77, 78, 79, 90, 91, 92, 93, 94, 95, 96, 97, 106, 107, 108, 109, 110, 111, 112], @@ -1134,7 +1134,7 @@ { "id" : 23, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 147, "height" : 264, "blockedTiles" : [72, 73, 74, 75, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98], @@ -1143,7 +1143,7 @@ { "id" : 24, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 178, "height" : 262, "blockedTiles" : [71, 72, 73, 74, 75, 76, 77, 78, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98], @@ -1152,7 +1152,7 @@ { "id" : 25, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 173, "height" : 257, "blockedTiles" : [72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 89, 90, 105, 106], @@ -1161,7 +1161,7 @@ { "id" : 26, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 241, "height" : 272, "blockedTiles" : [73, 91, 108, 109, 110, 111, 112, 113], @@ -1170,7 +1170,7 @@ { "id" : 27, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 261, "height" : 129, "blockedTiles" : [27, 28, 43, 44, 60, 61, 76, 77, 93, 94, 109, 110, 126, 127, 142, 143, 159], @@ -1179,7 +1179,7 @@ { "id" : 28, "allowedTerrain" : [], - "specialBattlefields" : [0], + "specialBattlefields" : ["sand_shore"], "width" : 180, "height" : 154, "blockedTiles" : [22, 38, 39, 40, 44, 45, 46, 55, 56, 57, 62, 63, 123, 124, 125, 130, 131, 140, 141, 146, 147, 148], @@ -1188,7 +1188,7 @@ { "id" : 29, "allowedTerrain" : [], - "specialBattlefields" : [5], + "specialBattlefields" : ["clover_field"], "width" : 304, "height" : 264, "blockedTiles" : [76, 77, 92, 93, 94, 95, 109, 110, 111], @@ -1197,7 +1197,7 @@ { "id" : 30, "allowedTerrain" : [], - "specialBattlefields" : [6], + "specialBattlefields" : ["lucid_pools"], "width" : 256, "height" : 257, "blockedTiles" : [76, 77, 78, 92, 93, 94, 107, 108, 109], @@ -1206,7 +1206,7 @@ { "id" : 31, "allowedTerrain" : [], - "specialBattlefields" : [7], + "specialBattlefields" : ["fiery_fields"], "width" : 257, "height" : 255, "blockedTiles" : [76, 77, 91, 92, 93, 94, 95, 108, 109, 110, 111], @@ -1215,7 +1215,7 @@ { "id" : 32, "allowedTerrain" : [], - "specialBattlefields" : [8], + "specialBattlefields" : ["rocklands"], "width" : 277, "height" : 218, "blockedTiles" : [60, 61, 75, 76, 77, 91, 92, 93, 94, 95], @@ -1224,7 +1224,7 @@ { "id" : 33, "allowedTerrain" : [], - "specialBattlefields" : [9], + "specialBattlefields" : ["magic_clouds"], "width" : 300, "height" : 214, "blockedTiles" : [59, 60, 74, 75, 76, 93, 94, 95, 111, 112], diff --git a/config/terrains.json b/config/terrains.json index b6c1b0bf6..c62e2ee36 100644 --- a/config/terrains.json +++ b/config/terrains.json @@ -6,7 +6,9 @@ "minimapBlocked" : [ 57, 40, 8 ], "music" : "Dirt.mp3", "tiles" : "DIRTTL", - "code" : "dt" + "code" : "dt", + "battleFields" : ["dirt_birches", "dirt_hills", "dirt_pines"], + "terrainViewPatterns" : "dirt" }, "sand" : { @@ -15,7 +17,10 @@ "minimapBlocked" : [ 165, 158, 107 ], "music" : "Sand.mp3", "tiles" : "SANDTL", - "code" : "sa" + "code" : "sa", + "battleFields" : ["sand_mesas"], + "transitionRequired" : true, + "terrainViewPatterns" : "sand" }, "grass" : { @@ -24,7 +29,8 @@ "minimapBlocked" : [ 0, 48, 0 ], "music" : "Grass.mp3", "tiles" : "GRASTL", - "code" : "gr" + "code" : "gr", + "battleFields" : ["grass_hills", "grass_pines"] }, "snow" : { @@ -33,7 +39,8 @@ "minimapBlocked" : [ 140, 158, 156 ], "music" : "Snow.mp3", "tiles" : "SNOWTL", - "code" : "sn" + "code" : "sn", + "battleFields" : ["snow_mountains", "snow_trees"] }, "swamp" : { @@ -42,7 +49,8 @@ "minimapBlocked" : [ 33, 89, 66 ], "music" : "Swamp.mp3", "tiles" : "SWMPTL", - "code" : "sw" + "code" : "sw", + "battleFields" : ["swamp_trees"] }, "rough" : { @@ -51,7 +59,8 @@ "minimapBlocked" : [ 99, 81, 33 ], "music" : "Rough.mp3", "tiles" : "ROUGTL", - "code" : "rg" + "code" : "rg", + "battleFields" : ["rough"] }, "subterra" : { @@ -61,7 +70,8 @@ "music" : "Underground.mp3", "tiles" : "SUBBTL", "type" : "SUB", - "code" : "sb" + "code" : "sb", + "battleFields" : ["subterranean"] }, "lava" : { @@ -70,7 +80,8 @@ "minimapBlocked" : [ 41, 40, 41 ], "music" : "Lava.mp3", "tiles" : "LAVATL", - "code" : "lv" + "code" : "lv", + "battleFields" : ["lava"] }, "water" : { @@ -80,7 +91,10 @@ "music" : "Water.mp3", "tiles" : "WATRTL", "type" : "WATER", - "code" : "wt" + "code" : "wt", + "battleFields" : ["ship"], + "transitionRequired" : true, + "terrainViewPatterns" : "water" }, "rock" : { @@ -90,6 +104,9 @@ "music" : "Underground.mp3", // Impossible in H3 "tiles" : "ROCKTL", "type" : "ROCK", - "code" : "rc" + "code" : "rc", + "battleFields" : ["rocklands"], + "transitionRequired" : true, + "terrainViewPatterns" : "rock" } } diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index a70f7a998..abbf72ce8 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1894,17 +1894,17 @@ void CGameState::initVisitingAndGarrisonedHeroes() } } -BFieldType CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & rand) +BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & rand) { if(!tile.valid() && curB) tile = curB->tile; else if(!tile.valid() && !curB) - return BFieldType::NONE; + return BattleField::NONE; const TerrainTile &t = map->getTile(tile); //fight in mine -> subterranean if(dynamic_cast(t.visitableObjects.front())) - return BFieldType::SUBTERRANEAN; + return BattleField("subterranean"); for(auto &obj : map->objects) { @@ -1915,56 +1915,32 @@ BFieldType CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & ra switch(obj->ID) { case Obj::CLOVER_FIELD: - return BFieldType::CLOVER_FIELD; + return BattleField("clover_field"); case Obj::CURSED_GROUND1: case Obj::CURSED_GROUND2: - return BFieldType::CURSED_GROUND; + return BattleField("cursed_ground"); case Obj::EVIL_FOG: - return BFieldType::EVIL_FOG; + return BattleField("evil_fog"); case Obj::FAVORABLE_WINDS: - return BFieldType::FAVORABLE_WINDS; + return BattleField("favorable_winds"); case Obj::FIERY_FIELDS: - return BFieldType::FIERY_FIELDS; + return BattleField("fiery_fields"); case Obj::HOLY_GROUNDS: - return BFieldType::HOLY_GROUND; + return BattleField("holy_ground"); case Obj::LUCID_POOLS: - return BFieldType::LUCID_POOLS; + return BattleField("lucid_pools"); case Obj::MAGIC_CLOUDS: - return BFieldType::MAGIC_CLOUDS; + return BattleField("magic_clouds"); case Obj::MAGIC_PLAINS1: case Obj::MAGIC_PLAINS2: - return BFieldType::MAGIC_PLAINS; + return BattleField("magic_plains"); case Obj::ROCKLANDS: - return BFieldType::ROCKLANDS; + return BattleField("rocklands"); } } if(map->isCoastalTile(tile)) //coastal tile is always ground - return BFieldType::SAND_SHORE; - - if(t.terType == Terrain("dirt")) - return BFieldType(rand.nextInt(3, 5)); - if(t.terType == Terrain("sand")) - return BFieldType::SAND_MESAS; //TODO: coast support - if(t.terType == Terrain("grass")) - return BFieldType(rand.nextInt(6, 7)); - if(t.terType == Terrain("snow")) - return BFieldType(rand.nextInt(10, 11)); - if(t.terType == Terrain("swamp")) - return BFieldType::SWAMP_TREES; - if(t.terType == Terrain("rough")) - return BFieldType::ROUGH; - if(t.terType.isUnderground()) - return BFieldType::SUBTERRANEAN; - if(t.terType == Terrain("lava")) - return BFieldType::LAVA; - if(t.terType.isWater()) - return BFieldType::SHIP; - if(!t.terType.isPassable()) - return BFieldType::ROCKLANDS; + return BattleField("sand_shore"); - //TODO: STUB, support new battlegrounds - return BFieldType::DIRT_HILLS; - - return BFieldType::NONE; + return *RandomGeneratorUtil::nextItem(Terrain::Manager::getInfo(t.terType).battleFields, rand); } UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack) diff --git a/lib/CGameState.h b/lib/CGameState.h index d4fba20c9..84e3077b3 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -179,7 +179,7 @@ public: void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid); void apply(CPack *pack); - BFieldType battleGetBattlefieldType(int3 tile, CRandomGenerator & rand); + BattleField battleGetBattlefieldType(int3 tile, CRandomGenerator & rand); UpgradeInfo getUpgradeInfo(const CStackInstance &stack); PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2); bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 107fe81cd..74093e959 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -177,9 +177,9 @@ std::vector CObstacleInfo::getBlocked(BattleHex hex) const return ret; } -bool CObstacleInfo::isAppropriate(Terrain terrainType, int specialBattlefield) const +bool CObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const { - if(specialBattlefield != -1) + if(!allowedSpecialBfields.empty() && specialBattlefield != BattleField::NONE) return vstd::contains(allowedSpecialBfields, specialBattlefield); return vstd::contains(allowedTerrains, terrainType); @@ -817,28 +817,35 @@ void CHeroHandler::loadExperience() void CHeroHandler::loadObstacles() { - auto loadObstacles = [](const JsonNode &node, bool absolute, std::map &out) + auto loadObstacles = [](const JsonNode & node, bool absolute, std::vector & out) { for(const JsonNode &obs : node.Vector()) { - int ID = static_cast(obs["id"].Float()); - CObstacleInfo & obi = out[ID]; - obi.ID = ID; + out.emplace_back(); + CObstacleInfo & obi = out.back(); obi.defName = obs["defname"].String(); obi.width = static_cast(obs["width"].Float()); obi.height = static_cast(obs["height"].Float()); for(auto & t : obs["allowedTerrain"].Vector()) obi.allowedTerrains.emplace_back(t.String()); - obi.allowedSpecialBfields = obs["specialBattlefields"].convertTo >(); + for(auto & t : obs["specialBattlefields"].Vector()) + obi.allowedSpecialBfields.emplace_back(t.String()); obi.blockedTiles = obs["blockedTiles"].convertTo >(); obi.isAbsoluteObstacle = absolute; } }; - - const JsonNode config(ResourceID("config/obstacles.json")); - loadObstacles(config["obstacles"], false, obstacles); - loadObstacles(config["absoluteObstacles"], true, absoluteObstacles); - //loadObstacles(config["moats"], true, moats); + + auto allConfigs = VLC->modh->getActiveMods(); + allConfigs.insert(allConfigs.begin(), "core"); + for(auto & mod : allConfigs) + { + if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/obstacles.json"))) + continue; + + const JsonNode config(mod, ResourceID("config/obstacles.json")); + loadObstacles(config["obstacles"], false, obstacles); + loadObstacles(config["absoluteObstacles"], true, absoluteObstacles); + } } /// convert h3-style ID (e.g. Gobin Wolf Rider) to vcmi (e.g. goblinWolfRider) diff --git a/lib/CHeroHandler.h b/lib/CHeroHandler.h index 14d2b1b8a..674dabb0a 100644 --- a/lib/CHeroHandler.h +++ b/lib/CHeroHandler.h @@ -27,6 +27,7 @@ class JsonNode; class CRandomGenerator; class JsonSerializeFormat; class Terrain; +class BattleField; struct SSpecialtyInfo { si32 type; @@ -224,10 +225,9 @@ public: struct DLL_LINKAGE CObstacleInfo { - si32 ID; std::string defName; std::vector allowedTerrains; - std::vector allowedSpecialBfields; + std::vector allowedSpecialBfields; ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same si32 width, height; //how much space to the right and up is needed to place obstacle (affects only placement algorithm) @@ -235,11 +235,10 @@ struct DLL_LINKAGE CObstacleInfo std::vector getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex' - bool isAppropriate(Terrain terrainType, int specialBattlefield = -1) const; + bool isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const; template void serialize(Handler &h, const int version) { - h & ID; h & defName; h & allowedTerrains; h & allowedSpecialBfields; @@ -316,8 +315,8 @@ public: }; std::vector ballistics; //info about ballistics ability per level; [0] - none; [1] - basic; [2] - adv; [3] - expert - std::map obstacles; //info about obstacles that may be placed on battlefield - std::map absoluteObstacles; //info about obstacles that may be placed on battlefield + std::vector obstacles; //info about obstacles that may be placed on battlefield + std::vector absoluteObstacles; //info about obstacles that may be placed on battlefield ui32 level(ui64 experience) const; //calculates level corresponding to given experience amount ui64 reqExp(ui32 level) const; //calculates experience required for given level diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 34777ad55..636766ed9 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -844,26 +844,6 @@ namespace SecSkillLevel }; } - -//follows ERM BI (battle image) format -namespace BattlefieldBI -{ - enum BattlefieldBI - { - NONE = -1, - COASTAL, - CURSED_GROUND, - MAGIC_PLAINS, - HOLY_GROUND, - EVIL_FOG, - CLOVER_FIELD, - LUCID_POOLS, - FIERY_FIELDS, - ROCKLANDS, - MAGIC_CLOUDS - }; -} - namespace Date { enum EDateType @@ -940,29 +920,6 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EPathfindingLayer ID_LIKE_OPERATORS(EPathfindingLayer, EPathfindingLayer::EEPathfindingLayer) -class BFieldType -{ -public: - // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines - //8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields - //15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog - //21. "favorable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship - enum EBFieldType {NONE = -1, NONE2, SAND_SHORE, SAND_MESAS, DIRT_BIRCHES, DIRT_HILLS, DIRT_PINES, GRASS_HILLS, - GRASS_PINES, LAVA, MAGIC_PLAINS, SNOW_MOUNTAINS, SNOW_TREES, SUBTERRANEAN, SWAMP_TREES, FIERY_FIELDS, - ROCKLANDS, MAGIC_CLOUDS, LUCID_POOLS, HOLY_GROUND, CLOVER_FIELD, EVIL_FOG, FAVORABLE_WINDS, CURSED_GROUND, - ROUGH, SHIP_TO_SHIP, SHIP - }; - - BFieldType(EBFieldType _num = NONE) : num(_num) - {} - - ID_LIKE_CLASS_COMMON(BFieldType, EBFieldType) - - EBFieldType num; -}; - -ID_LIKE_OPERATORS(BFieldType, BFieldType::EBFieldType) - namespace EPlayerStatus { enum EStatus {WRONG = -1, INGAME, LOSER, WINNER}; diff --git a/lib/Terrain.cpp b/lib/Terrain.cpp index 17f8de861..4a669fc86 100644 --- a/lib/Terrain.cpp +++ b/lib/Terrain.cpp @@ -18,6 +18,8 @@ const Terrain Terrain::ANY("ANY"); +const BattleField BattleField::NONE(""); + Terrain Terrain::createTerrainTypeH3M(int tId) { static std::array terrainsH3M @@ -106,6 +108,25 @@ Terrain::Manager::Manager() assert(info.typeCode.length() == 2); } + if(!terr.second["battleFields"].isNull()) + { + for(auto & t : terr.second["battleFields"].Vector()) + { + info.battleFields.emplace_back(t.String()); + } + } + + info.transitionRequired = false; + if(!terr.second["transitionRequired"].isNull()) + { + info.transitionRequired = terr.second["transitionRequired"].Bool(); + } + + info.terrainViewPatterns = "normal"; + if(!terr.second["terrainViewPatterns"].isNull()) + { + info.terrainViewPatterns = terr.second["terrainViewPatterns"].String(); + } terrainInfo[Terrain(terr.first)] = info; } @@ -202,3 +223,31 @@ bool Terrain::isNative() const { return name.empty(); } +bool Terrain::isTransitionRequired() const +{ + return Terrain::Manager::getInfo(*this).transitionRequired; +} + +bool operator==(const BattleField & l, const BattleField & r) +{ + return l.name == r.name; +} + +bool operator!=(const BattleField & l, const BattleField & r) +{ + return l.name != r.name; +} + +bool operator<(const BattleField & l, const BattleField & r) +{ + return l.name < r.name; +} +BattleField::operator std::string() const +{ + return name; +} + +int BattleField::hash() const +{ + return std::hash{}(name); +} diff --git a/lib/Terrain.h b/lib/Terrain.h index d173f2ab7..5e69fa384 100644 --- a/lib/Terrain.h +++ b/lib/Terrain.h @@ -13,6 +13,41 @@ #include "ConstTransitivePtr.h" #include "JsonNode.h" +class DLL_LINKAGE BattleField +{ +public: + // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines + //8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields + //15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog + //21. "favorable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship + /*enum EBFieldType {NONE = -1, NONE2, SAND_SHORE, SAND_MESAS, DIRT_BIRCHES, DIRT_HILLS, DIRT_PINES, GRASS_HILLS, + GRASS_PINES, LAVA, MAGIC_PLAINS, SNOW_MOUNTAINS, SNOW_TREES, SUBTERRANEAN, SWAMP_TREES, FIERY_FIELDS, + ROCKLANDS, MAGIC_CLOUDS, LUCID_POOLS, HOLY_GROUND, CLOVER_FIELD, EVIL_FOG, FAVORABLE_WINDS, CURSED_GROUND, + ROUGH, SHIP_TO_SHIP, SHIP + };*/ + + BattleField(const std::string & type = "") : name(type) + {} + + static const BattleField NONE; + + DLL_LINKAGE friend bool operator==(const BattleField & l, const BattleField & r); + DLL_LINKAGE friend bool operator!=(const BattleField & l, const BattleField & r); + DLL_LINKAGE friend bool operator<(const BattleField & l, const BattleField & r); + + operator std::string() const; + int hash() const; + + template void serialize(Handler &h, const int version) + { + h & name; + } + +protected: + + std::string name; +}; + class DLL_LINKAGE Terrain { public: @@ -27,14 +62,17 @@ public: }; int moveCost; + bool transitionRequired; std::array minimapBlocked; std::array minimapUnblocked; std::string musicFilename; std::string tilesFilename; std::string terrainText; std::string typeCode; + std::string terrainViewPatterns; int horseSoundId; Type type; + std::vector battleFields; }; class DLL_LINKAGE Manager @@ -77,6 +115,8 @@ public: bool isPassable() const; //ROCK bool isUnderground() const; bool isNative() const; + bool isTransitionRequired() const; + operator std::string() const; diff --git a/lib/battle/BattleInfo.cpp b/lib/battle/BattleInfo.cpp index bc119bde7..2dd2b173c 100644 --- a/lib/battle/BattleInfo.cpp +++ b/lib/battle/BattleInfo.cpp @@ -187,7 +187,7 @@ struct RangeGenerator std::function myRand; }; -BattleInfo * BattleInfo::setupBattle(int3 tile, Terrain terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town) +BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town) { CMP_stack cmpst; auto curB = new BattleInfo(); @@ -239,24 +239,24 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, Terrain terrain, BFieldType batt //randomize obstacles if (town == nullptr && !creatureBank) //do it only when it's not siege and not creature bank { - const int ABSOLUTE_OBSTACLES_COUNT = 34, USUAL_OBSTACLES_COUNT = 91; //shouldn't be changes if we want H3-like obstacle placement + const int ABSOLUTE_OBSTACLES_COUNT = VLC->heroh->absoluteObstacles.size(); + const int USUAL_OBSTACLES_COUNT = VLC->heroh->obstacles.size(); //shouldn't be changes if we want H3-like obstacle placement RandGen r; auto ourRand = [&](){ return r.rand(); }; r.srand(tile); r.rand(1,8); //battle sound ID to play... can't do anything with it here int tilesToBlock = r.rand(5,12); - const int specialBattlefield = battlefieldTypeToBI(battlefieldType); std::vector blockedTiles; auto appropriateAbsoluteObstacle = [&](int id) { - return VLC->heroh->absoluteObstacles[id].isAppropriate(curB->terrainType, specialBattlefield); + return VLC->heroh->absoluteObstacles[id].isAppropriate(curB->terrainType, battlefieldType); }; auto appropriateUsualObstacle = [&](int id) -> bool { - return VLC->heroh->obstacles[id].isAppropriate(curB->terrainType, specialBattlefield); + return VLC->heroh->obstacles[id].isAppropriate(curB->terrainType, battlefieldType); }; if(r.rand(1,100) <= 40) //put cliff-like obstacle @@ -460,71 +460,60 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, Terrain terrain, BFieldType batt //giving terrain overlay premies int bonusSubtype = -1; - switch(battlefieldType) - { - case BFieldType::MAGIC_PLAINS: - { - bonusSubtype = 0; - } - FALLTHROUGH - case BFieldType::FIERY_FIELDS: - { - if(bonusSubtype == -1) bonusSubtype = 1; - } - FALLTHROUGH - case BFieldType::ROCKLANDS: - { - if(bonusSubtype == -1) bonusSubtype = 8; - } - FALLTHROUGH - case BFieldType::MAGIC_CLOUDS: - { - if(bonusSubtype == -1) bonusSubtype = 2; - } - FALLTHROUGH - case BFieldType::LUCID_POOLS: - { - if(bonusSubtype == -1) bonusSubtype = 4; - } - { //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, bonusSubtype)); - break; - } - case BFieldType::HOLY_GROUND: - { - std::string goodArmyDesc = VLC->generaltexth->arraytxt[123]; - goodArmyDesc.erase(goodArmyDesc.size() - 2, 2); //omitting hardcoded +1 in description - std::string evilArmyDesc = VLC->generaltexth->arraytxt[124]; - evilArmyDesc.erase(evilArmyDesc.size() - 2, 2); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType, goodArmyDesc, 0)->addLimiter(good)); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType, evilArmyDesc, 0)->addLimiter(evil)); - break; - } - case BFieldType::CLOVER_FIELD: - { //+2 luck bonus for neutral creatures - std::string desc = VLC->generaltexth->arraytxt[83]; - desc.erase(desc.size() - 2, 2); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::LUCK, Bonus::TERRAIN_OVERLAY, +2, battlefieldType, desc, 0)->addLimiter(neutral)); - break; - } - case BFieldType::EVIL_FOG: - { - std::string goodArmyDesc = VLC->generaltexth->arraytxt[126]; - goodArmyDesc.erase(goodArmyDesc.size() - 2, 2); - std::string evilArmyDesc = VLC->generaltexth->arraytxt[125]; - evilArmyDesc.erase(evilArmyDesc.size() - 2, 2); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType, goodArmyDesc, 0)->addLimiter(good)); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType, evilArmyDesc, 0)->addLimiter(evil)); - break; - } - case BFieldType::CURSED_GROUND: - { - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::NO_MORALE, Bonus::TERRAIN_OVERLAY, 0, battlefieldType, VLC->generaltexth->arraytxt[112], 0)); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::NO_LUCK, Bonus::TERRAIN_OVERLAY, 0, battlefieldType, VLC->generaltexth->arraytxt[81], 0)); - curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::BLOCK_MAGIC_ABOVE, Bonus::TERRAIN_OVERLAY, 1, battlefieldType, 0, Bonus::INDEPENDENT_MIN)); - break; - } + if(battlefieldType == BattleField("magic_plains")) + { + bonusSubtype = 0; + } + if(battlefieldType == BattleField("fiery_fields")) + { + if(bonusSubtype == -1) bonusSubtype = 1; + } + if(battlefieldType == BattleField("rocklands")) + { + if(bonusSubtype == -1) bonusSubtype = 8; + } + if(battlefieldType == BattleField("magic_clouds")) + { + if(bonusSubtype == -1) bonusSubtype = 2; + } + if(battlefieldType == BattleField("lucid_pools")) + { + if(bonusSubtype == -1) bonusSubtype = 4; + } + 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)); + } + else if(battlefieldType == BattleField("holy_ground")) + { + std::string goodArmyDesc = VLC->generaltexth->arraytxt[123]; + goodArmyDesc.erase(goodArmyDesc.size() - 2, 2); //omitting hardcoded +1 in description + std::string evilArmyDesc = VLC->generaltexth->arraytxt[124]; + evilArmyDesc.erase(evilArmyDesc.size() - 2, 2); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType.hash(), goodArmyDesc, 0)->addLimiter(good)); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType.hash(), evilArmyDesc, 0)->addLimiter(evil)); + } + else if(battlefieldType == BattleField("clover_field")) + { //+2 luck bonus for neutral creatures + std::string desc = VLC->generaltexth->arraytxt[83]; + desc.erase(desc.size() - 2, 2); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::LUCK, Bonus::TERRAIN_OVERLAY, +2, battlefieldType.hash(), desc, 0)->addLimiter(neutral)); + } + else if(battlefieldType == BattleField("evil_fog")) + { + std::string goodArmyDesc = VLC->generaltexth->arraytxt[126]; + goodArmyDesc.erase(goodArmyDesc.size() - 2, 2); + std::string evilArmyDesc = VLC->generaltexth->arraytxt[125]; + evilArmyDesc.erase(evilArmyDesc.size() - 2, 2); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType.hash(), goodArmyDesc, 0)->addLimiter(good)); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType.hash(), evilArmyDesc, 0)->addLimiter(evil)); + } + else if(battlefieldType == BattleField("cursed_ground")) + { + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::NO_MORALE, Bonus::TERRAIN_OVERLAY, 0, battlefieldType.hash(), VLC->generaltexth->arraytxt[112], 0)); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::NO_LUCK, Bonus::TERRAIN_OVERLAY, 0, battlefieldType.hash(), VLC->generaltexth->arraytxt[81], 0)); + curB->addNewBonus(std::make_shared(Bonus::ONE_BATTLE, Bonus::BLOCK_MAGIC_ABOVE, Bonus::TERRAIN_OVERLAY, 1, battlefieldType.hash(), 0, Bonus::INDEPENDENT_MIN)); } //overlay premies given @@ -580,30 +569,6 @@ ui8 BattleInfo::whatSide(PlayerColor player) const return -1; } -BattlefieldBI::BattlefieldBI BattleInfo::battlefieldTypeToBI(BFieldType bfieldType) -{ - static const std::map theMap = - { - {BFieldType::CLOVER_FIELD, BattlefieldBI::CLOVER_FIELD}, - {BFieldType::CURSED_GROUND, BattlefieldBI::CURSED_GROUND}, - {BFieldType::EVIL_FOG, BattlefieldBI::EVIL_FOG}, - {BFieldType::FAVORABLE_WINDS, BattlefieldBI::NONE}, - {BFieldType::FIERY_FIELDS, BattlefieldBI::FIERY_FIELDS}, - {BFieldType::HOLY_GROUND, BattlefieldBI::HOLY_GROUND}, - {BFieldType::LUCID_POOLS, BattlefieldBI::LUCID_POOLS}, - {BFieldType::MAGIC_CLOUDS, BattlefieldBI::MAGIC_CLOUDS}, - {BFieldType::MAGIC_PLAINS, BattlefieldBI::MAGIC_PLAINS}, - {BFieldType::ROCKLANDS, BattlefieldBI::ROCKLANDS}, - {BFieldType::SAND_SHORE, BattlefieldBI::COASTAL} - }; - - auto itr = theMap.find(bfieldType); - if(itr != theMap.end()) - return itr->second; - - return BattlefieldBI::NONE; -} - CStack * BattleInfo::getStack(int stackID, bool onlyAlive) { return const_cast(battleGetStackByID(stackID, onlyAlive)); @@ -611,7 +576,7 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive) BattleInfo::BattleInfo() : round(-1), activeStack(-1), town(nullptr), tile(-1,-1,-1), - battlefieldType(BFieldType::NONE), terrainType(), + battlefieldType(BattleField::NONE), terrainType(), tacticsSide(0), tacticDistance(0) { setBattle(this); @@ -640,7 +605,7 @@ battle::Units BattleInfo::getUnitsIf(battle::UnitFilter predicate) const } -BFieldType BattleInfo::getBattlefieldType() const +BattleField BattleInfo::getBattlefieldType() const { return battlefieldType; } diff --git a/lib/battle/BattleInfo.h b/lib/battle/BattleInfo.h index 0fc5a03b9..1d0c128cc 100644 --- a/lib/battle/BattleInfo.h +++ b/lib/battle/BattleInfo.h @@ -19,6 +19,7 @@ class CStack; class CStackInstance; class CStackBasicDescriptor; class Terrain; +class BattleField; class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState { @@ -36,7 +37,7 @@ public: std::vector > obstacles; SiegeInfo si; - BFieldType battlefieldType; //like !!BA:B + BattleField battlefieldType; //like !!BA:B 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 @@ -72,7 +73,7 @@ public: battle::Units getUnitsIf(battle::UnitFilter predicate) const override; - BFieldType getBattlefieldType() const override; + BattleField getBattlefieldType() const override; Terrain getTerrainType() const override; ObstacleCList getAllObstacles() const override; @@ -138,12 +139,10 @@ public: const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player void localInit(); - static BattleInfo * setupBattle(int3 tile, Terrain terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town); + static BattleInfo * setupBattle(const int3 & tile, const Terrain & terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town); ui8 whatSide(PlayerColor player) const; - static BattlefieldBI::BattlefieldBI battlefieldTypeToBI(BFieldType bfieldType); //converts above to ERM BI format - protected: scripting::Pool * getContextPool() const override; }; diff --git a/lib/battle/BattleProxy.cpp b/lib/battle/BattleProxy.cpp index b1d533501..83df1520a 100644 --- a/lib/battle/BattleProxy.cpp +++ b/lib/battle/BattleProxy.cpp @@ -42,7 +42,7 @@ battle::Units BattleProxy::getUnitsIf(battle::UnitFilter predicate) const return subject->battleGetUnitsIf(predicate); } -BFieldType BattleProxy::getBattlefieldType() const +BattleField BattleProxy::getBattlefieldType() const { return subject->battleGetBattlefieldType(); } diff --git a/lib/battle/BattleProxy.h b/lib/battle/BattleProxy.h index 0489d6974..b756dadea 100644 --- a/lib/battle/BattleProxy.h +++ b/lib/battle/BattleProxy.h @@ -29,7 +29,7 @@ public: battle::Units getUnitsIf(battle::UnitFilter predicate) const override; - BFieldType getBattlefieldType() const override; + BattleField getBattlefieldType() const override; Terrain getTerrainType() const override; ObstacleCList getAllObstacles() const override; diff --git a/lib/battle/CBattleInfoCallback.cpp b/lib/battle/CBattleInfoCallback.cpp index 18aee3c73..a2122bcbb 100644 --- a/lib/battle/CBattleInfoCallback.cpp +++ b/lib/battle/CBattleInfoCallback.cpp @@ -1059,7 +1059,7 @@ AccessibilityInfo CBattleInfoCallback::getAccesibility() const //special battlefields with logically unavailable tiles std::vector impassableHexes; - if(battleGetBattlefieldType().num == BFieldType::SHIP_TO_SHIP) + if(battleGetBattlefieldType() == BattleField("ship_to_ship")) { impassableHexes = { diff --git a/lib/battle/CBattleInfoEssentials.cpp b/lib/battle/CBattleInfoEssentials.cpp index f1b1a55f0..9d0370a1f 100644 --- a/lib/battle/CBattleInfoEssentials.cpp +++ b/lib/battle/CBattleInfoEssentials.cpp @@ -20,9 +20,9 @@ Terrain CBattleInfoEssentials::battleTerrainType() const return getBattle()->getTerrainType(); } -BFieldType CBattleInfoEssentials::battleGetBattlefieldType() const +BattleField CBattleInfoEssentials::battleGetBattlefieldType() const { - RETURN_IF_NOT_BATTLE(BFieldType::NONE); + RETURN_IF_NOT_BATTLE(BattleField::NONE); return getBattle()->getBattlefieldType(); } diff --git a/lib/battle/CBattleInfoEssentials.h b/lib/battle/CBattleInfoEssentials.h index 8d489b998..bc354ab78 100644 --- a/lib/battle/CBattleInfoEssentials.h +++ b/lib/battle/CBattleInfoEssentials.h @@ -47,7 +47,7 @@ public: const IBonusBearer * getBattleNode() const; Terrain battleTerrainType() const override; - BFieldType battleGetBattlefieldType() const override; + BattleField battleGetBattlefieldType() const override; int32_t battleGetEnchanterCounter(ui8 side) const; std::vector > battleGetAllObstacles(boost::optional perspective = boost::none) const; //returns all obstacles on the battlefield diff --git a/lib/battle/IBattleInfoCallback.h b/lib/battle/IBattleInfoCallback.h index 999dbc536..ad3d0e6e4 100644 --- a/lib/battle/IBattleInfoCallback.h +++ b/lib/battle/IBattleInfoCallback.h @@ -13,7 +13,7 @@ #include "BattleHex.h" struct CObstacleInstance; -class BFieldType; +class BattleField; class Terrain; namespace battle @@ -35,7 +35,7 @@ public: virtual scripting::Pool * getContextPool() const = 0; virtual Terrain battleTerrainType() const = 0; - virtual BFieldType battleGetBattlefieldType() const = 0; + virtual BattleField battleGetBattlefieldType() const = 0; ///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw virtual boost::optional battleIsFinished() const = 0; diff --git a/lib/battle/IBattleState.h b/lib/battle/IBattleState.h index 2d96be75f..02f21d935 100644 --- a/lib/battle/IBattleState.h +++ b/lib/battle/IBattleState.h @@ -16,6 +16,7 @@ class UnitChanges; struct Bonus; class JsonNode; class JsonSerializeFormat; +class BattleField; namespace vstd { @@ -40,7 +41,7 @@ public: virtual battle::Units getUnitsIf(battle::UnitFilter predicate) const = 0; - virtual BFieldType getBattlefieldType() const = 0; + virtual BattleField getBattlefieldType() const = 0; virtual Terrain getTerrainType() const = 0; virtual ObstacleCList getAllObstacles() const = 0; diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index d23b1100d..e514084c9 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -421,7 +421,6 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() } // Add pattern to the patterns map - const auto & terGroup = getTerrainGroup(mappingPair.first); std::vector terrainViewPatternFlips; terrainViewPatternFlips.push_back(terGroupPattern); @@ -431,7 +430,8 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() flipPattern(terGroupPattern, i); //FIXME: we flip in place - doesn't make much sense now, but used to work terrainViewPatternFlips.push_back(terGroupPattern); } - terrainViewPatterns[terGroup].push_back(terrainViewPatternFlips); + + terrainViewPatterns[mappingPair.first].push_back(terrainViewPatternFlips); } } else if(i == 1) @@ -453,29 +453,17 @@ CTerrainViewPatternConfig::~CTerrainViewPatternConfig() } -ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const std::string & terGroup) const +const std::vector & CTerrainViewPatternConfig::getTerrainViewPatterns(const Terrain & terrain) const { - static const std::map terGroups = - { - {"normal", ETerrainGroup::NORMAL}, - {"dirt", ETerrainGroup::DIRT}, - {"sand", ETerrainGroup::SAND}, - {"water", ETerrainGroup::WATER}, - {"rock", ETerrainGroup::ROCK}, - }; - auto it = terGroups.find(terGroup); - if(it == terGroups.end()) throw std::runtime_error(boost::str(boost::format("Terrain group '%s' does not exist.") % terGroup)); - return it->second; + auto iter = terrainViewPatterns.find(Terrain::Manager::getInfo(terrain).terrainViewPatterns); + if(iter == terrainViewPatterns.end()) + return terrainViewPatterns.at("normal"); + return iter->second; } -const std::vector & CTerrainViewPatternConfig::getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const +boost::optional CTerrainViewPatternConfig::getTerrainViewPatternById(const Terrain & terrain, const std::string & id) const { - return terrainViewPatterns.find(terGroup)->second; -} - -boost::optional CTerrainViewPatternConfig::getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const -{ - const std::vector & groupPatterns = getTerrainViewPatternsForGroup(terGroup); + const std::vector & groupPatterns = getTerrainViewPatterns(terrain); for (const TVPVector & patternFlips : groupPatterns) { const TerrainViewPattern & pattern = patternFlips.front(); @@ -486,9 +474,10 @@ boost::optional CTerrainViewPatternConfig::getTerrai } return boost::optional(); } -boost::optional CTerrainViewPatternConfig::getTerrainViewPatternsById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const + +boost::optional CTerrainViewPatternConfig::getTerrainViewPatternsById(const Terrain & terrain, const std::string & id) const { - const std::vector & groupPatterns = getTerrainViewPatternsForGroup(terGroup); + const std::vector & groupPatterns = getTerrainViewPatterns(terrain); for (const TVPVector & patternFlips : groupPatterns) { const TerrainViewPattern & pattern = patternFlips.front(); @@ -705,7 +694,7 @@ void CDrawTerrainOperation::updateTerrainViews() { for(const auto & pos : invalidatedTerViews) { - const auto & patterns = VLC->terviewh->getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType)); + const auto & patterns = VLC->terviewh->getTerrainViewPatterns(map->getTile(pos).terType); // Detect a pattern which fits best int bestPattern = -1; @@ -760,19 +749,6 @@ void CDrawTerrainOperation::updateTerrainViews() } } -ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(Terrain terType) const -{ - if(terType == Terrain("dirt")) - return ETerrainGroup::DIRT; - if(terType == Terrain("sand")) - return ETerrainGroup::SAND; - if(terType.isWater()) - return ETerrainGroup::WATER; - if(!terType.isPassable()) - return ETerrainGroup::ROCK; - return ETerrainGroup::NORMAL; -} - CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const std::vector * pattern, int recDepth) const { for(int flip = 0; flip < 4; ++flip) @@ -790,7 +766,6 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth) const { auto centerTerType = map->getTile(pos).terType; - auto centerTerGroup = getTerrainGroup(centerTerType); int totalPoints = 0; std::string transitionReplacement; @@ -857,8 +832,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi { if(terType == centerTerType) { - const auto & group = getTerrainGroup(centerTerType); - const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(group, rule.name); + const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(centerTerType, rule.name); if(auto p = patternForRule) { auto rslt = validateTerrainView(currentPos, &(*p), 1); @@ -884,12 +858,30 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi // Validate cell with the ruleset of the pattern bool nativeTestOk, nativeTestStrongOk; nativeTestOk = nativeTestStrongOk = (rule.isNativeStrong() || rule.isNativeRule()) && !isAlien; - if(centerTerGroup == ETerrainGroup::NORMAL) + + if(centerTerType == Terrain("dirt")) + { + nativeTestOk = rule.isNativeRule() && !terType.isTransitionRequired(); + bool sandTestOk = (rule.isSandRule() || rule.isTransition()) + && terType.isTransitionRequired(); + applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk || nativeTestStrongOk); + } + else if(centerTerType == Terrain("sand")) + { + applyValidationRslt(true); + } + else if(centerTerType.isTransitionRequired()) //water, rock and some special terrains require sand transition + { + bool sandTestOk = (rule.isSandRule() || rule.isTransition()) + && isAlien; + applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk); + } + else { bool dirtTestOk = (rule.isDirtRule() || rule.isTransition()) - && isAlien && !isSandType(terType); + && isAlien && !terType.isTransitionRequired(); bool sandTestOk = (rule.isSandRule() || rule.isTransition()) - && isSandType(terType); + && terType.isTransitionRequired(); if (transitionReplacement.empty() && rule.isTransition() && (dirtTestOk || sandTestOk)) @@ -906,23 +898,6 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi applyValidationRslt(rule.isAnyRule() || dirtTestOk || sandTestOk || nativeTestOk); } } - else if(centerTerGroup == ETerrainGroup::DIRT) - { - nativeTestOk = rule.isNativeRule() && !isSandType(terType); - bool sandTestOk = (rule.isSandRule() || rule.isTransition()) - && isSandType(terType); - applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk || nativeTestStrongOk); - } - else if(centerTerGroup == ETerrainGroup::SAND) - { - applyValidationRslt(true); - } - else if(centerTerGroup == ETerrainGroup::WATER || centerTerGroup == ETerrainGroup::ROCK) - { - bool sandTestOk = (rule.isSandRule() || rule.isTransition()) - && isAlien; - applyValidationRslt(rule.isAnyRule() || sandTestOk || nativeTestOk); - } } if(topPoints == -1) @@ -945,13 +920,6 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi } } -bool CDrawTerrainOperation::isSandType(Terrain terType) const -{ - if(terType.isWater() || terType == Terrain("sand") || !terType.isPassable()) - return true; - return false; -} - void CDrawTerrainOperation::invalidateTerrainViews(const int3 & centerPos) { auto rect = extendTileAroundSafely(centerPos); diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index 5e18cf969..2bd42e26d 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -211,18 +211,6 @@ private: std::list > operations; }; -namespace ETerrainGroup -{ - enum ETerrainGroup - { - NORMAL, - DIRT, - SAND, - WATER, - ROCK - }; -} - /// The terrain view pattern describes a specific composition of terrain tiles /// in a 3x3 matrix and notes which terrain view frame numbers can be used. struct DLL_LINKAGE TerrainViewPattern @@ -338,15 +326,14 @@ public: CTerrainViewPatternConfig(); ~CTerrainViewPatternConfig(); - const std::vector & getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; - boost::optional getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; - boost::optional getTerrainViewPatternsById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; + const std::vector & getTerrainViewPatterns(const Terrain & terrain) const; + boost::optional getTerrainViewPatternById(const Terrain & terrain, const std::string & id) const; + boost::optional getTerrainViewPatternsById(const Terrain & terrain, const std::string & id) const; const TVPVector * getTerrainTypePatternById(const std::string & id) const; - ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const; void flipPattern(TerrainViewPattern & pattern, int flip) const; private: - std::map > terrainViewPatterns; + std::map > terrainViewPatterns; std::map terrainTypePatterns; }; @@ -385,13 +372,10 @@ private: InvalidTiles getInvalidTiles(const int3 & centerPos) const; void updateTerrainViews(); - ETerrainGroup::ETerrainGroup getTerrainGroup(Terrain terType) const; /// 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). ValidationResult validateTerrainView(const int3 & pos, const std::vector * 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 - bool isSandType(Terrain terType) const; CTerrainSelection terrainSel; Terrain terType; diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index 15c84f5d8..e07e48d04 100644 --- a/lib/serializer/CSerializer.h +++ b/lib/serializer/CSerializer.h @@ -12,8 +12,8 @@ #include "../ConstTransitivePtr.h" #include "../GameConstants.h" -const ui32 SERIALIZATION_VERSION = 802; -const ui32 MINIMAL_SERIALIZATION_VERSION = 802; +const ui32 SERIALIZATION_VERSION = 803; +const ui32 MINIMAL_SERIALIZATION_VERSION = 803; const std::string SAVEGAME_MAGIC = "VCMISVG"; class CHero; diff --git a/lib/spells/ISpellMechanics.cpp b/lib/spells/ISpellMechanics.cpp index dedfd5dc8..1aa00f649 100644 --- a/lib/spells/ISpellMechanics.cpp +++ b/lib/spells/ISpellMechanics.cpp @@ -520,7 +520,7 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr caster->getCasterName(text); target.add(std::move(text), spells::Problem::NORMAL); } - else if(b && b->source == Bonus::TERRAIN_OVERLAY && b->sid == BFieldType::CURSED_GROUND) + else if(b && b->source == Bonus::TERRAIN_OVERLAY && b->sid == BattleField("cursed_ground").hash()) { text.addTxt(MetaString::GENERAL_TXT, 537); target.add(std::move(text), spells::Problem::NORMAL); diff --git a/scripting/lua/api/BattleCb.cpp b/scripting/lua/api/BattleCb.cpp index 779289014..6f4f2a81a 100644 --- a/scripting/lua/api/BattleCb.cpp +++ b/scripting/lua/api/BattleCb.cpp @@ -73,7 +73,7 @@ int BattleCbProxy::getBattlefieldType(lua_State * L) auto ret = object->battleGetBattlefieldType(); - return LuaStack::quickRetInt(L, static_cast(ret.num)); + return LuaStack::quickRetStr(L, ret); } int BattleCbProxy::getTerrainType(lua_State * L) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 62e992919..71754f0ea 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2219,9 +2219,9 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const if (gs->map->isCoastalTile(tile)) //coastal tile is always ground terrain = Terrain("sand"); - BFieldType terType = gs->battleGetBattlefieldType(tile, getRandomGenerator()); + BattleField terType = gs->battleGetBattlefieldType(tile, getRandomGenerator()); if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat) - terType = BFieldType::SHIP_TO_SHIP; + terType = BattleField("ship_to_ship"); //send info about battles BattleStart bs; diff --git a/test/erm/ERM_BU.cpp b/test/erm/ERM_BU.cpp index 51624b119..87273b2e9 100644 --- a/test/erm/ERM_BU.cpp +++ b/test/erm/ERM_BU.cpp @@ -155,7 +155,7 @@ TEST_F(ERM_BU_G, Get) source << "!?PI;" << std::endl; source << "!!BU:G?v1;" << std::endl; - EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BFieldType::SNOW_TREES)); + EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField("snow_trees"))); loadScript(VLC->scriptHandler->erm, source.str()); @@ -174,7 +174,7 @@ TEST_F(ERM_BU_G, Get2) source << "!?PI;" << std::endl; source << "!!BU:G?v1;" << std::endl; - EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BFieldType::EVIL_FOG)); + EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField("evil_fog"))); loadScript(VLC->scriptHandler->erm, source.str()); runServer(); diff --git a/test/game/CGameStateTest.cpp b/test/game/CGameStateTest.cpp index a31d8eb25..aebb82783 100644 --- a/test/game/CGameStateTest.cpp +++ b/test/game/CGameStateTest.cpp @@ -194,7 +194,7 @@ public: const auto t = gameCallback->getTile(tile); Terrain terrain = t->terType; - BFieldType terType = BFieldType::GRASS_HILLS; + BattleField terType = BattleField("grass_hills"); //send info about battles diff --git a/test/map/CMapEditManagerTest.cpp b/test/map/CMapEditManagerTest.cpp index 8283bccde..f33ff4d9d 100644 --- a/test/map/CMapEditManagerTest.cpp +++ b/test/map/CMapEditManagerTest.cpp @@ -130,10 +130,9 @@ TEST(MapManager, DrawTerrain_View) if(patternParts.size() != 2) throw std::runtime_error("A pattern should consist of two parts, the group and the id. Continue with next pattern."); const auto & groupStr = patternParts[0]; const auto & id = patternParts[1]; - auto terGroup = VLC->terviewh->getTerrainGroup(groupStr); // Get mapping range - const auto & pattern = VLC->terviewh->getTerrainViewPatternById(terGroup, id); + const auto & pattern = VLC->terviewh->getTerrainViewPatternById(groupStr, id); const auto & mapping = (*pattern).mapping; const auto & positionsNode = node["pos"].Vector(); diff --git a/test/mock/BattleFake.cpp b/test/mock/BattleFake.cpp index 1df5e2ece..23ce30f2f 100644 --- a/test/mock/BattleFake.cpp +++ b/test/mock/BattleFake.cpp @@ -92,7 +92,7 @@ void BattleFake::setupEmptyBattlefield() { EXPECT_CALL(*this, getDefendedTown()).WillRepeatedly(Return(nullptr)); EXPECT_CALL(*this, getAllObstacles()).WillRepeatedly(Return(IBattleInfo::ObstacleCList())); - EXPECT_CALL(*this, getBattlefieldType()).WillRepeatedly(Return(BFieldType::NONE2)); + EXPECT_CALL(*this, getBattlefieldType()).WillRepeatedly(Return(BattleField::NONE)); } diff --git a/test/mock/mock_IBattleInfoCallback.h b/test/mock/mock_IBattleInfoCallback.h index ff7904b3c..688243ebd 100644 --- a/test/mock/mock_IBattleInfoCallback.h +++ b/test/mock/mock_IBattleInfoCallback.h @@ -18,7 +18,7 @@ class IBattleInfoCallbackMock : public IBattleInfoCallback public: MOCK_CONST_METHOD0(getContextPool, scripting::Pool *()); MOCK_CONST_METHOD0(battleTerrainType, Terrain()); - MOCK_CONST_METHOD0(battleGetBattlefieldType, BFieldType()); + MOCK_CONST_METHOD0(battleGetBattlefieldType, BattleField()); MOCK_CONST_METHOD0(battleIsFinished, boost::optional()); diff --git a/test/mock/mock_battle_IBattleState.h b/test/mock/mock_battle_IBattleState.h index 3493b703d..12e3837c0 100644 --- a/test/mock/mock_battle_IBattleState.h +++ b/test/mock/mock_battle_IBattleState.h @@ -18,7 +18,7 @@ public: MOCK_CONST_METHOD0(getActiveStackID, int32_t()); MOCK_CONST_METHOD1(getStacksIf, TStacks(TStackFilter)); MOCK_CONST_METHOD1(getUnitsIf, battle::Units(battle::UnitFilter)); - MOCK_CONST_METHOD0(getBattlefieldType, BFieldType()); + MOCK_CONST_METHOD0(getBattlefieldType, BattleField()); MOCK_CONST_METHOD0(getTerrainType, Terrain()); MOCK_CONST_METHOD0(getAllObstacles, IBattleInfo::ObstacleCList()); MOCK_CONST_METHOD0(getDefendedTown, const CGTownInstance *());