diff --git a/config/bonuses.json b/config/bonuses.json index 7ae0bade3..cc0f38b38 100644 --- a/config/bonuses.json +++ b/config/bonuses.json @@ -368,6 +368,11 @@ "icon": "zvs/Lib1.res/E_OBST" } }, + + "NO_TERRAIN_PENALTY": + { + "hidden": true + }, "NON_LIVING": { diff --git a/config/creatures/neutral.json b/config/creatures/neutral.json index dc00f9ba0..ff4c68bcc 100644 --- a/config/creatures/neutral.json +++ b/config/creatures/neutral.json @@ -475,6 +475,15 @@ "index": 142, "level": 3, "faction": "neutral", + "abilities": + { + "sandWalker" : + { + "type" : "NO_TERRAIN_PENALTY", + "subtype" : 1, + "propagator" : "HERO" + } + }, "doubleWide" : true, "graphics" : { diff --git a/lib/GameConstants.h b/lib/GameConstants.h index b6e24c7d3..0a1f74945 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -51,6 +51,7 @@ namespace GameConstants const int SPELLS_QUANTITY=70; const int CREATURES_COUNT = 197; + const ui32 BASE_MOVEMENT_COST = 100; //default cost for non-diagonal movement } class CArtifact; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index ff5f32f63..0acec92cd 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -216,7 +216,9 @@ public: BONUS_NAME(SPOILS_OF_WAR) /*val * 10^-6 * gained exp resources of subtype will be given to hero after battle*/\ BONUS_NAME(BLOCK)\ BONUS_NAME(DISGUISED) /* subtype - spell level */\ - BONUS_NAME(VISIONS) /* subtype - spell level */ + BONUS_NAME(VISIONS) /* subtype - spell level */\ + BONUS_NAME(NO_TERRAIN_PENALTY) /* subtype - terrain type */\ + /* end of list */ #define BONUS_SOURCE_LIST \ diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 48b091b45..f5d12adbb 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -58,56 +58,49 @@ static int lowestSpeed(const CGHeroInstance * chi) ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &from) const { - //base move cost - unsigned ret = 100; + unsigned ret = GameConstants::BASE_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 != ERoadType::NO_ROAD && from.roadType != ERoadType::NO_ROAD) { - int road = std::min(dest.roadType,from.roadType); //used road ID + int road = std::min(dest.roadType,from.roadType); //used road ID switch(road) { - case ERoadType::DIRT_ROAD: + case ERoadType::DIRT_ROAD: ret = 75; break; - case ERoadType::GRAVEL_ROAD: + case ERoadType::GRAVEL_ROAD: ret = 65; break; - case ERoadType::COBBLESTONE_ROAD: + case ERoadType::COBBLESTONE_ROAD: ret = 50; break; default: - logGlobal->errorStream() << "Unknown road type: " << road << "... Something wrong!"; + logGlobal->errorStream() << "Unknown road type: " << road << "... Something wrong!"; break; } } - else + else if(!hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType)) { - //FIXME: in H3 presence of Nomad in army will remove terrain penalty for sand. Bonus not implemented in VCMI - // 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. // Current VCMI behaviour will ignore neutrals in calculations so army in VCMI // will always have best penalty without any influence from player-defined stacks order - bool nativeArmy = true; for(auto stack : stacks) { int nativeTerrain = VLC->townh->factions[stack.second->type->faction]->nativeTerrain; - - if (nativeTerrain != -1 && nativeTerrain != from.terType) + if(nativeTerrain != -1 && nativeTerrain != from.terType) { - nativeArmy = false; + ret = VLC->heroh->terrCosts[from.terType]; + ret -= getSecSkillLevel(SecondarySkill::PATHFINDING) * 25; + if(ret < GameConstants::BASE_MOVEMENT_COST) + ret = GameConstants::BASE_MOVEMENT_COST; + break; } } - if (!nativeArmy) - { - ret = VLC->heroh->terrCosts[from.terType]; - ret-=getSecSkillLevel(SecondarySkill::PATHFINDING)*25; - ret = ret < 100 ? 100 : ret; - } - } + } return ret; }