Fixed a bug blocking special improvements on removable terrain features (#6865)

This commit is contained in:
Xander Lenstra 2022-05-19 12:04:03 +02:00 committed by GitHub
parent 3d6a01d633
commit 6dabffb5a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -492,24 +492,13 @@ open class TileInfo {
/** Returns true if the [improvement] can be built on this [TileInfo] */ /** Returns true if the [improvement] can be built on this [TileInfo] */
fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean { 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 { return when {
improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName -> false improvement.uniqueTo != null && improvement.uniqueTo != civInfo.civName -> false
@ -531,21 +520,38 @@ open class TileInfo {
improvement.getMatchingUniques(UniqueType.ConsumesResources, stateForConditionals).any { improvement.getMatchingUniques(UniqueType.ConsumesResources, stateForConditionals).any {
civInfo.getCivResourcesByName()[it.params[1]]!! < it.params[0].toInt() civInfo.getCivResourcesByName()[it.params[1]]!! < it.params[0].toInt()
} -> false } -> false
getLastTerrain().unbuildable && !improvement.canBeBuildOnThisUnbuildableTerrain(civInfo, stateForConditionals) -> false else -> canImprovementBeBuiltHere(improvement, hasViewableResource(civInfo), knownFeatureRemovals, stateForConditionals)
else -> canImprovementBeBuiltHere(improvement, hasViewableResource(civInfo), stateForConditionals)
} }
} }
/** Without regards to what CivInfo it is, a lot of the checks are just for the improvement on the tile. /** 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. * Doubles as a check for the map editor.
*/ */
private fun canImprovementBeBuiltHere( private fun canImprovementBeBuiltHere(
improvement: TileImprovement, improvement: TileImprovement,
resourceIsVisible: Boolean = resource != null, resourceIsVisible: Boolean = resource != null,
knownFeatureRemovals: List<TileImprovement>? = null,
stateForConditionals: StateForConditionals = StateForConditionals(tile=this) stateForConditionals: StateForConditionals = StateForConditionals(tile=this)
): Boolean { ): Boolean {
fun TileImprovement.canBeBuildOnThisUnbuildableTerrain(
knownFeatureRemovals: List<TileImprovement>? = 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 { return when {
improvement.name == this.improvement -> false improvement.name == this.improvement -> false
isCityCenter() -> false isCityCenter() -> false
@ -566,6 +572,9 @@ open class TileInfo {
// Can't build if there is already an irremovable improvement here // Can't build if there is already an irremovable improvement here
this.improvement != null && getTileImprovement()!!.hasUnique(UniqueType.Irremovable, stateForConditionals) -> false 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 // Can't build if any terrain specifically prevents building this improvement
getTerrainMatchingUniques(UniqueType.RestrictedBuildableImprovements, stateForConditionals).any { getTerrainMatchingUniques(UniqueType.RestrictedBuildableImprovements, stateForConditionals).any {
unique -> !improvement.matchesFilter(unique.params[0]) unique -> !improvement.matchesFilter(unique.params[0])