Resolves #9533 - double movement unique accepts conditionals (#9538)

This commit is contained in:
Yair Morgenstern 2023-06-07 15:49:59 +03:00 committed by GitHub
parent 936b9e34ef
commit fe1b5825bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 18 deletions

View File

@ -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<String, DoubleMovementTerrainTarget>()
val doubleMovementInTerrain = HashMap<String, DoubleMovement>()
@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)

View File

@ -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