Fix crash when a mod allows a citadel >1 tile outside borders (#3923)

* Fix crash when a mod allows a citadel >1 tile outside borders

* Fix crash when a mod allows a citadel outside borders - no cities
This commit is contained in:
SomeTroglodyte 2021-05-13 19:25:16 +02:00 committed by GitHub
parent 4f1798146c
commit d20b3c4e58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 4 deletions

View File

@ -336,7 +336,8 @@ open class TileInfo {
getOwner() != civInfo && !(
improvement.hasUnique("Can be built outside your borders")
// citadel can be built only next to or within own borders
|| improvement.hasUnique("Can be built just outside your borders") && neighbors.any { it.getOwner() == civInfo }
|| improvement.hasUnique("Can be built just outside your borders")
&& neighbors.any { it.getOwner() == civInfo } && !civInfo.cities.isEmpty()
) -> false
improvement.uniqueObjects.any {
it.placeholderText == "Obsolete with []" && civInfo.tech.isResearched(it.params[0])

View File

@ -360,19 +360,26 @@ object UnitActions {
private fun takeOverTilesAround(unit: MapUnit) {
// This method should only be called for a citadel - therefore one of the neighbour tile
// must belong to unit's civ, so minByOrNull will be never `null`. Thiss
// must belong to unit's civ, so minByOrNull in the nearestCity formula should be never `null`.
// That is, unless a mod does not specify the proper unique - then fallbackNearestCity will take over.
fun priority(tile: TileInfo): Int { // helper calculates priority (lower is better): distance plus razing malus
val city = tile.getCity()!! // !! assertion is guaranteed by the outer filter selector.
return city.getCenterTile().aerialDistanceTo(tile) +
(if (city.isBeingRazed) 5 else 0)
}
fun fallbackNearestCity(unit: MapUnit) =
unit.civInfo.cities.minByOrNull {
it.getCenterTile().aerialDistanceTo(unit.currentTile) +
(if (it.isBeingRazed) 5 else 0)
}!!
// In the rare case more than one city owns tiles neighboring the citadel
// this will prioritize the nearest one not being razed
val nearestCity = unit.currentTile.neighbors
var nearestCity = unit.currentTile.neighbors
.filter { it.getOwner() == unit.civInfo }
.minByOrNull { priority(it) }!!.getCity()!!
.minByOrNull { priority(it) }?.getCity()
?: fallbackNearestCity(unit)
// capture all tiles which do not belong to unit's civ and are not enemy cities
// we use getTilesInDistance here, not neighbours to include the current tile as well