From 6dabffb5a9e300e11820a196a2c325e6495742fb Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Thu, 19 May 2022 12:04:03 +0200 Subject: [PATCH] Fixed a bug blocking special improvements on removable terrain features (#6865) --- core/src/com/unciv/logic/map/TileInfo.kt | 53 ++++++++++++++---------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 8348b1b7ff..995cdfe441 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -488,28 +488,17 @@ open class TileInfo { if (terrainFilter == Constants.freshWater && isAdjacentToRiver()) return true return (neighbors + this).any { neighbor -> neighbor.matchesFilter(terrainFilter) } } - + /** Returns true if the [improvement] can be built on this [TileInfo] */ fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean { - - fun TileImprovement.canBeBuildOnThisUnbuildableTerrain(civInfo: CivilizationInfo, stateForConditionals: StateForConditionals): Boolean { - val topTerrain = getLastTerrain() - // We can build if we are specifically allowed to build on this terrain - if (isAllowedOnFeature(topTerrain.name)) return true - - // Otherwise, we can if this improvement removes the top terrain - if (!hasUnique(UniqueType.RemovesFeaturesIfBuilt, stateForConditionals)) return false - val removeAction = ruleset.tileImprovements[Constants.remove + topTerrain.name] ?: return false - // and we have the tech to remove that top terrain - if (removeAction.techRequired != null && !civInfo.tech.isResearched(removeAction.techRequired!!)) return false - // and we can build it on the tile without the top terrain - val clonedTile = this@TileInfo.clone() - clonedTile.removeTerrainFeature(topTerrain.name) - return clonedTile.canBuildImprovement(this, civInfo) - } - - val stateForConditionals = StateForConditionals(civInfo, tile=this) + val stateForConditionals = StateForConditionals(civInfo, tile=this) + val knownFeatureRemovals = ruleset.tileImprovements.values + .filter { rulesetImprovement -> + rulesetImprovement.name.startsWith(Constants.remove) + && RoadStatus.values().none { it.removeAction == rulesetImprovement.name } + && (rulesetImprovement.techRequired == null || civInfo.tech.isResearched(rulesetImprovement.techRequired!!)) + } return when { improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName -> false @@ -531,21 +520,38 @@ open class TileInfo { improvement.getMatchingUniques(UniqueType.ConsumesResources, stateForConditionals).any { civInfo.getCivResourcesByName()[it.params[1]]!! < it.params[0].toInt() } -> false - getLastTerrain().unbuildable && !improvement.canBeBuildOnThisUnbuildableTerrain(civInfo, stateForConditionals) -> false - else -> canImprovementBeBuiltHere(improvement, hasViewableResource(civInfo), stateForConditionals) + else -> canImprovementBeBuiltHere(improvement, hasViewableResource(civInfo), knownFeatureRemovals, stateForConditionals) } } - /** Without regards to what CivInfo it is, a lot of the checks are just for the improvement on the tile. * Doubles as a check for the map editor. */ private fun canImprovementBeBuiltHere( improvement: TileImprovement, resourceIsVisible: Boolean = resource != null, + knownFeatureRemovals: List? = null, stateForConditionals: StateForConditionals = StateForConditionals(tile=this) ): Boolean { + fun TileImprovement.canBeBuildOnThisUnbuildableTerrain( + knownFeatureRemovals: List? = null, + ): Boolean { + val topTerrain = getLastTerrain() + // We can build if we are specifically allowed to build on this terrain + if (isAllowedOnFeature(topTerrain.name)) return true + + // Otherwise, we can if this improvement removes the top terrain + if (!hasUnique(UniqueType.RemovesFeaturesIfBuilt, stateForConditionals)) return false + val removeAction = ruleset.tileImprovements[Constants.remove + topTerrain.name] ?: return false + // and we have the tech to remove that top terrain + if (removeAction.techRequired != null && (knownFeatureRemovals == null || removeAction !in knownFeatureRemovals)) return false + // and we can build it on the tile without the top terrain + val clonedTile = this@TileInfo.clone() + clonedTile.removeTerrainFeature(topTerrain.name) + return clonedTile.canImprovementBeBuiltHere(improvement, resourceIsVisible, knownFeatureRemovals, stateForConditionals) + } + return when { improvement.name == this.improvement -> false isCityCenter() -> false @@ -566,6 +572,9 @@ open class TileInfo { // Can't build if there is already an irremovable improvement here this.improvement != null && getTileImprovement()!!.hasUnique(UniqueType.Irremovable, stateForConditionals) -> false + // Can't build if this terrain is unbuildable, except when we are specifically allowed to + getLastTerrain().unbuildable && !improvement.canBeBuildOnThisUnbuildableTerrain(knownFeatureRemovals) -> false + // Can't build if any terrain specifically prevents building this improvement getTerrainMatchingUniques(UniqueType.RestrictedBuildableImprovements, stateForConditionals).any { unique -> !improvement.matchesFilter(unique.params[0])