diff --git a/core/src/com/unciv/logic/map/mapunit/MapUnitCache.kt b/core/src/com/unciv/logic/map/mapunit/MapUnitCache.kt index b9ffcc585e..a82aa8af06 100644 --- a/core/src/com/unciv/logic/map/mapunit/MapUnitCache.kt +++ b/core/src/com/unciv/logic/map/mapunit/MapUnitCache.kt @@ -3,6 +3,7 @@ package com.unciv.logic.map.mapunit import com.unciv.Constants import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.unique.StateForConditionals +import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueType class MapUnitCache(val mapUnit: MapUnit) { @@ -47,9 +48,10 @@ class MapUnitCache(val mapUnit: MapUnit) { /** Used for getMovementCostBetweenAdjacentTiles only, based on order of testing */ enum class DoubleMovementTerrainTarget { Feature, Base, Hill, Filter } + class DoubleMovement(val terrainTarget: DoubleMovementTerrainTarget, val unique: Unique) /** Mod-friendly cache of double-movement terrains */ @Transient - val doubleMovementInTerrain = HashMap() + val doubleMovementInTerrain = HashMap() @Transient var canEnterIceTiles = false @@ -86,24 +88,25 @@ class MapUnitCache(val mapUnit: MapUnit) { roughTerrainPenalty = mapUnit.hasUnique(UniqueType.RoughTerrainPenalty) doubleMovementInTerrain.clear() - for (unique in mapUnit.getMatchingUniques(UniqueType.DoubleMovementOnTerrain)) { + for (unique in mapUnit.getMatchingUniques(UniqueType.DoubleMovementOnTerrain, stateForConditionals = StateForConditionals.IgnoreConditionals)) { val param = unique.params[0] val terrain = mapUnit.civ.gameInfo.ruleset.terrains[param] - doubleMovementInTerrain[param] = when { - terrain == null -> DoubleMovementTerrainTarget.Filter - terrain.name == Constants.hill -> DoubleMovementTerrainTarget.Hill - terrain.type == TerrainType.TerrainFeature -> DoubleMovementTerrainTarget.Feature - terrain.type.isBaseTerrain -> DoubleMovementTerrainTarget.Base - else -> DoubleMovementTerrainTarget.Filter - } + doubleMovementInTerrain[param] = DoubleMovement(unique = unique, + terrainTarget = when { + terrain == null -> DoubleMovementTerrainTarget.Filter + terrain.name == Constants.hill -> DoubleMovementTerrainTarget.Hill + terrain.type == TerrainType.TerrainFeature -> DoubleMovementTerrainTarget.Feature + terrain.type.isBaseTerrain -> DoubleMovementTerrainTarget.Base + else -> DoubleMovementTerrainTarget.Filter + }) } // Init shortcut flags noTerrainMovementUniques = doubleMovementInTerrain.isEmpty() && !roughTerrainPenalty && !mapUnit.civ.nation.ignoreHillMovementCost noBaseTerrainOrHillDoubleMovementUniques = doubleMovementInTerrain - .none { it.value != DoubleMovementTerrainTarget.Feature } + .none { it.value.terrainTarget != DoubleMovementTerrainTarget.Feature } noFilteredDoubleMovementUniques = doubleMovementInTerrain - .none { it.value == DoubleMovementTerrainTarget.Filter } + .none { it.value.terrainTarget == DoubleMovementTerrainTarget.Filter } costToDisembark = (mapUnit.getMatchingUniques(UniqueType.ReducedDisembarkCost, checkCivInfoUniques = true)) .minOfOrNull { it.params[0].toFloat() } costToEmbark = mapUnit.getMatchingUniques(UniqueType.ReducedEmbarkCost, checkCivInfoUniques = true) diff --git a/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt b/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt index 5bf17eb6aa..9cc589b76b 100644 --- a/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt +++ b/core/src/com/unciv/logic/map/mapunit/UnitMovement.kt @@ -8,6 +8,7 @@ import com.unciv.logic.map.HexMath.getDistance import com.unciv.logic.map.tile.RoadStatus import com.unciv.logic.map.tile.Tile import com.unciv.models.helpers.UnitMovementMemoryType +import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueType class UnitMovement(val unit: MapUnit) { @@ -60,7 +61,8 @@ class UnitMovement(val unit: MapUnit) { // when entering territory of a city state val areConnectedByRoad = from.hasConnection(civInfo) && to.hasConnection(civInfo) - val areConnectedByRiver = from.isAdjacentToRiver() && to.isAdjacentToRiver() && from.isConnectedByRiver(to) + val areConnectedByRiver = + from.isAdjacentToRiver() && to.isAdjacentToRiver() && from.isConnectedByRiver(to) if (areConnectedByRoad && (!areConnectedByRiver || civInfo.tech.roadsConnectAcrossRivers)) return unit.civ.tech.movementSpeedOnRoads + extraCost @@ -73,7 +75,29 @@ class UnitMovement(val unit: MapUnit) { if (unit.cache.noTerrainMovementUniques) return terrainCost + extraCost - if (to.terrainFeatures.any { unit.cache.doubleMovementInTerrain[it] == MapUnitCache.DoubleMovementTerrainTarget.Feature }) + val stateForConditionals = StateForConditionals(unit.civ, unit = unit, tile = to) + fun matchesTerrainTarget( + doubleMovement: MapUnitCache.DoubleMovement, + target: MapUnitCache.DoubleMovementTerrainTarget + ): Boolean { + if (doubleMovement.terrainTarget != target) return false + if (doubleMovement.unique.conditionals.isNotEmpty()) { + if (!doubleMovement.unique.conditionalsApply(stateForConditionals)) return false + } + + return true + } + + fun matchesTerrainTarget( + terrainName: String, + target: MapUnitCache.DoubleMovementTerrainTarget + ): Boolean { + val doubleMovement = unit.cache.doubleMovementInTerrain[terrainName] ?: return false + return matchesTerrainTarget(doubleMovement, target) + } + + + if (to.terrainFeatures.any { matchesTerrainTarget(it, MapUnitCache.DoubleMovementTerrainTarget.Feature) }) return terrainCost * 0.5f + extraCost if (unit.cache.roughTerrainPenalty && to.isRoughTerrain()) @@ -86,17 +110,18 @@ class UnitMovement(val unit: MapUnit) { if (unit.cache.noBaseTerrainOrHillDoubleMovementUniques) return terrainCost + extraCost - if (unit.cache.doubleMovementInTerrain[to.baseTerrain] == MapUnitCache.DoubleMovementTerrainTarget.Base) + if (matchesTerrainTarget(to.baseTerrain, MapUnitCache.DoubleMovementTerrainTarget.Base)) return terrainCost * 0.5f + extraCost - if (unit.cache.doubleMovementInTerrain[Constants.hill] == MapUnitCache.DoubleMovementTerrainTarget.Hill && to.isHill()) + if (matchesTerrainTarget(Constants.hill, MapUnitCache.DoubleMovementTerrainTarget.Hill) + && to.isHill()) return terrainCost * 0.5f + extraCost if (unit.cache.noFilteredDoubleMovementUniques) return terrainCost + extraCost if (unit.cache.doubleMovementInTerrain.any { - it.value == MapUnitCache.DoubleMovementTerrainTarget.Filter && - to.matchesFilter(it.key) - }) + matchesTerrainTarget(it.value, MapUnitCache.DoubleMovementTerrainTarget.Filter) + && to.matchesFilter(it.key) + }) return terrainCost * 0.5f + extraCost return terrainCost + extraCost // no road or other movement cost reduction