From d20b3c4e584da772c6888cc87b25fee14bd2c134 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Thu, 13 May 2021 19:25:16 +0200 Subject: [PATCH] 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 --- core/src/com/unciv/logic/map/TileInfo.kt | 3 ++- .../com/unciv/ui/worldscreen/unit/UnitActions.kt | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index a7ed12da6b..24482d40b3 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -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]) diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 35ece6ec5b..691f27761e 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -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