diff --git a/core/src/com/unciv/logic/automation/BattleHelper.kt b/core/src/com/unciv/logic/automation/BattleHelper.kt index 1b69aa2ee4..8721d8ad7d 100644 --- a/core/src/com/unciv/logic/automation/BattleHelper.kt +++ b/core/src/com/unciv/logic/automation/BattleHelper.kt @@ -54,15 +54,14 @@ object BattleHelper { sequenceOf(Pair(unit.currentTile, unit.currentMovement)) else unitDistanceToTiles.asSequence() - .map { - val tile = it.key + .map { (tile, distance) -> val movementPointsToExpendAfterMovement = if (unitMustBeSetUp) 1 else 0 val movementPointsToExpendHere = if (unitMustBeSetUp && !unit.isSetUpForSiege()) 1 else 0 val movementPointsToExpendBeforeAttack = - if (it.key == unit.currentTile) movementPointsToExpendHere else movementPointsToExpendAfterMovement + if (tile == unit.currentTile) movementPointsToExpendHere else movementPointsToExpendAfterMovement val movementLeft = - unit.currentMovement - it.value.totalDistance - movementPointsToExpendBeforeAttack + unit.currentMovement - distance.totalDistance - movementPointsToExpendBeforeAttack Pair(tile, movementLeft) } // still got leftover movement points after all that, to attack (0.1 is because of Float nonsense, see MapUnit.moveToTile(...) @@ -116,8 +115,8 @@ object BattleHelper { } fun tryDisembarkUnitToAttackPosition(unit: MapUnit): Boolean { - val unitDistanceToTiles = unit.movement.getDistanceToTiles() if (!unit.baseUnit.isMelee() || !unit.baseUnit.isLandUnit() || !unit.isEmbarked()) return false + val unitDistanceToTiles = unit.movement.getDistanceToTiles() val attackableEnemiesNextTurn = getAttackableEnemies(unit, unitDistanceToTiles) // Only take enemies we can fight without dying diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index bc5b6c6282..39d2cf37fc 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -29,6 +29,8 @@ object Battle { attacker.unit.movement.moveToTile(attackableTile.tileToAttackFrom) /** You might ask: When can this possibly happen? * We always receive an AttackableTile, which means that it was returned from getAttackableTiles! + * And getAttackableTiles should ensure that we return only units that are in the range of movement! + * * The answer is: when crossing a HIDDEN TILE. * When calculating movement distance, we assume that a hidden tile is 1 movement point, * which can lead to EXCEEDINGLY RARE edge cases where you think @@ -36,6 +38,11 @@ object Battle { * but the hidden tile is actually IMPASSIBLE so you stop halfway! */ if (attacker.getTile() != attackableTile.tileToAttackFrom) return + /** Alternatively, maybe we DID reach that tile, but it turned out to be a hill or something, + * so we expended all of our movement points! + */ + if (attacker.unit.currentMovement != attackableTile.movementLeftAfterMovingToAttackTile) + return if (attacker.unit.hasUnique(UniqueType.MustSetUp) && !attacker.unit.isSetUpForSiege()) { attacker.unit.action = UnitActionType.SetUp.value attacker.unit.useMovementPoints(1f)