Refactor Cannot Move Unique (#8168)

* Add buildCheck flags

* Catch issues in Swap Units

* Move all code to movement code

* Add back in Red Attack Range for Air Units

* Remove useless parameter
Be more specific for Air Attack range highlight
This commit is contained in:
itanasi 2023-01-18 00:25:33 -08:00 committed by GitHub
parent 62c03d9545
commit b84290de1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 22 additions and 5 deletions

View File

@ -428,6 +428,7 @@ object Battle {
private fun postBattleMoveToAttackedTile(attacker: ICombatant, defender: ICombatant, attackedTile: TileInfo) {
if (!attacker.isMelee()) return
if (!defender.isDefeated() && defender.getCivInfo() != attacker.getCivInfo()) return
if (attacker is MapUnitCombatant && attacker.hasUnique(UniqueType.CannotMove)) return
// This is so that if we attack e.g. a barbarian in enemy territory that we can't enter, we won't enter it
if ((attacker as MapUnitCombatant).unit.movement.canMoveTo(attackedTile)) {
@ -1015,6 +1016,7 @@ object Battle {
if (attacker !is MapUnitCombatant) return false // allow simple access to unit property
if (defender !is MapUnitCombatant) return false
if (defender.unit.isEmbarked()) return false
if (defender.hasUnique(UniqueType.CannotMove)) return false
// Promotions have no effect as per what I could find in available documentation
val attackBaseUnit = attacker.unit.baseUnit
val defendBaseUnit = defender.unit.baseUnit

View File

@ -478,7 +478,6 @@ class MapUnit : IsPartOfGameInfoSerialization {
}
fun getMaxMovementForAirUnits(): Int {
if (hasUnique(UniqueType.CannotMove)) return getRange() // also used for marking attack range
return getRange() * 2
}

View File

@ -189,6 +189,7 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
* Returns an empty list if there's no way to get to the destination.
*/
fun getShortestPath(destination: TileInfo, avoidDamagingTerrain: Boolean = false): List<TileInfo> {
if (unit.hasUnique(UniqueType.CannotMove)) return listOf()
// First try and find a path without damaging terrain
if (!avoidDamagingTerrain && unit.civInfo.passThroughImpassableUnlocked && unit.baseUnit.isLandUnit()) {
val damageFreePath = getShortestPath(destination, true)
@ -328,12 +329,14 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
/** This is performance-heavy - use as last resort, only after checking everything else!
* Also note that REACHABLE tiles are not necessarily tiles that the unit CAN ENTER */
fun canReach(destination: TileInfo): Boolean {
if (unit.hasUnique(UniqueType.CannotMove)) return false
if (unit.baseUnit.movesLikeAirUnits() || unit.isPreparingParadrop())
return canReachInCurrentTurn(destination)
return getShortestPath(destination).any()
}
private fun canReachInCurrentTurn(destination: TileInfo): Boolean {
if (unit.hasUnique(UniqueType.CannotMove)) return false
if (unit.baseUnit.movesLikeAirUnits())
return unit.currentTile.aerialDistanceTo(destination) <= unit.getMaxMovementForAirUnits()
if (unit.isPreparingParadrop())
@ -343,6 +346,7 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
fun getReachableTilesInCurrentTurn(): Sequence<TileInfo> {
return when {
unit.hasUnique(UniqueType.CannotMove) -> emptySequence()
unit.baseUnit.movesLikeAirUnits() ->
unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getMaxMovementForAirUnits()))
unit.isPreparingParadrop() ->
@ -372,6 +376,7 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
if (unit.baseUnit.movesLikeAirUnits()) return false
// We can't swap with ourself
if (reachableTile == unit.getTile()) return false
if (unit.hasUnique(UniqueType.CannotMove)) return false
// Check whether the tile contains a unit of the same type as us that we own and that can
// also reach our tile in its current turn.
val otherUnit = (
@ -381,7 +386,9 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
reachableTile.militaryUnit
) ?: return false
val ourPosition = unit.getTile()
if (otherUnit.owner != unit.owner || !otherUnit.movement.canReachInCurrentTurn(ourPosition)) return false
if (otherUnit.owner != unit.owner
|| otherUnit.hasUnique(UniqueType.CannotMove)
|| !otherUnit.movement.canReachInCurrentTurn(ourPosition)) return false
// Check if we could enter their tile if they wouldn't be there
otherUnit.removeFromTile()
val weCanEnterTheirTile = canMoveTo(reachableTile)
@ -623,7 +630,6 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
* DOES NOT designate whether we can reach that tile in the current turn
*/
fun canMoveTo(tile: TileInfo, assumeCanPassThrough: Boolean = false): Boolean {
if (unit.hasUnique(UniqueType.CannotMove)) return false
if (unit.baseUnit.movesLikeAirUnits())
return canAirUnitMoveTo(tile, unit)
@ -642,7 +648,6 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
}
private fun canAirUnitMoveTo(tile: TileInfo, unit: MapUnit): Boolean {
if (unit.hasUnique(UniqueType.CannotMove)) return false
// landing in the city
if (tile.isCityCenter()) {
if (tile.airUnits.filter { !it.isTransported }.size < 6 && tile.getCity()?.civInfo == unit.civInfo)
@ -675,7 +680,6 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
* because optimization on this function results in massive benefits!
*/
fun canPassThrough(tile: TileInfo): Boolean {
if (unit.hasUnique(UniqueType.CannotMove)) return false
if (tile.isImpassible()) {
// special exception - ice tiles are technically impassible, but some units can move through them anyway
// helicopters can pass through impassable tiles like mountains

View File

@ -30,6 +30,7 @@ import com.unciv.models.AttackableTile
import com.unciv.models.UncivSound
import com.unciv.models.helpers.MapArrowType
import com.unciv.models.helpers.MiscArrowTypes
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.UncivStage
import com.unciv.ui.audio.SoundPlayer
import com.unciv.ui.images.ImageGetter
@ -672,6 +673,17 @@ class WorldMapHolder(
}
}
// Add back in the red markers for Air Unit Attack range since they can't move, but can still attack
if (unit.hasUnique(UniqueType.CannotMove) && isAirUnit && !unit.isPreparingAirSweep()) {
val tilesInAttackRange = unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getRange()))
for (tile in tilesInAttackRange) {
for (tileToColor in tileGroups[tile]!!) {
// The tile is within attack range
tileToColor.showHighlight(Color.RED, 0.3f)
}
}
}
// Movement paths
if (unitMovementPaths.containsKey(unit)) {
for (tile in unitMovementPaths[unit]!!) {