mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Fix and cache CannotMove unique (#9596)
This commit is contained in:
parent
ea505e3e97
commit
7f626083ee
@ -485,7 +485,7 @@ object Battle {
|
||||
private fun postBattleMoveToAttackedTile(attacker: ICombatant, defender: ICombatant, attackedTile: Tile) {
|
||||
if (!attacker.isMelee()) return
|
||||
if (!defender.isDefeated() && defender.getCivInfo() != attacker.getCivInfo()) return
|
||||
if (attacker is MapUnitCombatant && attacker.hasUnique(UniqueType.CannotMove)) return
|
||||
if (attacker is MapUnitCombatant && attacker.unit.cache.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)) {
|
||||
@ -1107,7 +1107,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
|
||||
if (defender.unit.cache.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
|
||||
|
@ -6,43 +6,40 @@ import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
|
||||
class MapUnitCache(val mapUnit: MapUnit) {
|
||||
// Note: Single use in MapUnit and it's @Transient there, so no need for that here
|
||||
class MapUnitCache(private val mapUnit: MapUnit) {
|
||||
// These are for performance improvements to getMovementCostBetweenAdjacentTiles,
|
||||
// a major component of getDistanceToTilesWithinTurn,
|
||||
// which in turn is a component of getShortestPath and canReach
|
||||
@Transient
|
||||
var ignoresTerrainCost = false
|
||||
private set
|
||||
|
||||
@Transient
|
||||
var ignoresZoneOfControl = false
|
||||
private set
|
||||
|
||||
@Transient
|
||||
var allTilesCosts1 = false
|
||||
private set
|
||||
|
||||
@Transient
|
||||
var canPassThroughImpassableTiles = false
|
||||
private set
|
||||
|
||||
@Transient
|
||||
var roughTerrainPenalty = false
|
||||
private set
|
||||
|
||||
/** `true` if movement 0 _or_ has CannotMove unique */
|
||||
var cannotMove = false
|
||||
private set
|
||||
|
||||
/** If set causes an early exit in getMovementCostBetweenAdjacentTiles
|
||||
* - means no double movement uniques, roughTerrainPenalty or ignoreHillMovementCost */
|
||||
@Transient
|
||||
var noTerrainMovementUniques = false
|
||||
private set
|
||||
|
||||
/** If set causes a second early exit in getMovementCostBetweenAdjacentTiles */
|
||||
@Transient
|
||||
var noBaseTerrainOrHillDoubleMovementUniques = false
|
||||
private set
|
||||
|
||||
/** If set skips tile.matchesFilter tests for double movement in getMovementCostBetweenAdjacentTiles */
|
||||
@Transient
|
||||
var noFilteredDoubleMovementUniques = false
|
||||
private set
|
||||
|
||||
@ -50,33 +47,24 @@ class MapUnitCache(val mapUnit: MapUnit) {
|
||||
enum class DoubleMovementTerrainTarget { Feature, Base, Hill, Filter }
|
||||
class DoubleMovement(val terrainTarget: DoubleMovementTerrainTarget, val unique: Unique)
|
||||
/** Mod-friendly cache of double-movement terrains */
|
||||
@Transient
|
||||
val doubleMovementInTerrain = HashMap<String, DoubleMovement>()
|
||||
|
||||
@Transient
|
||||
var canEnterIceTiles = false
|
||||
|
||||
@Transient
|
||||
var cannotEnterOceanTiles = false
|
||||
|
||||
@Transient
|
||||
var canEnterForeignTerrain: Boolean = false
|
||||
|
||||
@Transient
|
||||
var costToDisembark: Float? = null
|
||||
|
||||
@Transient
|
||||
var costToEmbark: Float? = null
|
||||
|
||||
@Transient
|
||||
var paradropRange = 0
|
||||
|
||||
@Transient
|
||||
var hasUniqueToBuildImprovements = false // not canBuildImprovements to avoid confusion
|
||||
|
||||
@Transient
|
||||
var hasStrengthBonusInRadiusUnique = false
|
||||
@Transient
|
||||
|
||||
var hasCitadelPlacementUnique = false
|
||||
|
||||
fun updateUniques(){
|
||||
@ -86,6 +74,7 @@ class MapUnitCache(val mapUnit: MapUnit) {
|
||||
ignoresTerrainCost = mapUnit.hasUnique(UniqueType.IgnoresTerrainCost)
|
||||
ignoresZoneOfControl = mapUnit.hasUnique(UniqueType.IgnoresZOC)
|
||||
roughTerrainPenalty = mapUnit.hasUnique(UniqueType.RoughTerrainPenalty)
|
||||
cannotMove = mapUnit.hasUnique(UniqueType.CannotMove) || mapUnit.baseUnit.movement == 0
|
||||
|
||||
doubleMovementInTerrain.clear()
|
||||
for (unique in mapUnit.getMatchingUniques(UniqueType.DoubleMovementOnTerrain, stateForConditionals = StateForConditionals.IgnoreConditionals)) {
|
||||
|
@ -34,6 +34,7 @@ class UnitMovement(val unit: MapUnit) {
|
||||
civInfo: Civilization,
|
||||
considerZoneOfControl: Boolean = true
|
||||
): Float {
|
||||
if (unit.cache.cannotMove) return 100f
|
||||
|
||||
if (from.isLand != to.isLand && unit.baseUnit.isLandUnit())
|
||||
return if (from.isWater && to.isLand) unit.cache.costToDisembark ?: 100f
|
||||
@ -187,12 +188,15 @@ class UnitMovement(val unit: MapUnit) {
|
||||
movementCostCache: HashMap<Pair<Tile, Tile>, Float> = HashMap()
|
||||
): PathsToTilesWithinTurn {
|
||||
val distanceToTiles = PathsToTilesWithinTurn()
|
||||
if (unitMovement == 0f) return distanceToTiles
|
||||
|
||||
val currentUnitTile = unit.currentTile
|
||||
// This is for performance, because this is called all the time
|
||||
val unitTile = if (origin == currentUnitTile.position) currentUnitTile else currentUnitTile.tileMap[origin]
|
||||
distanceToTiles[unitTile] = ParentTileAndTotalDistance(unitTile, unitTile, 0f)
|
||||
|
||||
// If I can't move my only option is to stay...
|
||||
if (unitMovement == 0f || unit.cache.cannotMove) return distanceToTiles
|
||||
|
||||
var tilesToCheck = listOf(unitTile)
|
||||
|
||||
while (tilesToCheck.isNotEmpty()) {
|
||||
@ -240,7 +244,8 @@ class UnitMovement(val unit: MapUnit) {
|
||||
* Returns an empty list if there's no way to get to the destination.
|
||||
*/
|
||||
fun getShortestPath(destination: Tile, avoidDamagingTerrain: Boolean = false): List<Tile> {
|
||||
if (unit.hasUnique(UniqueType.CannotMove)) return listOf()
|
||||
if (unit.cache.cannotMove) return listOf()
|
||||
|
||||
// First try and find a path without damaging terrain
|
||||
if (!avoidDamagingTerrain && unit.civ.passThroughImpassableUnlocked && unit.baseUnit.isLandUnit()) {
|
||||
val damageFreePath = getShortestPath(destination, true)
|
||||
@ -392,14 +397,14 @@ class UnitMovement(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: Tile): Boolean {
|
||||
if (unit.hasUnique(UniqueType.CannotMove)) return false
|
||||
if (unit.cache.cannotMove) return destination == unit.getTile()
|
||||
if (unit.baseUnit.movesLikeAirUnits() || unit.isPreparingParadrop())
|
||||
return canReachInCurrentTurn(destination)
|
||||
return getShortestPath(destination).any()
|
||||
}
|
||||
|
||||
private fun canReachInCurrentTurn(destination: Tile): Boolean {
|
||||
if (unit.hasUnique(UniqueType.CannotMove)) return false
|
||||
if (unit.cache.cannotMove) return destination == unit.getTile()
|
||||
if (unit.baseUnit.movesLikeAirUnits())
|
||||
return unit.currentTile.aerialDistanceTo(destination) <= unit.getMaxMovementForAirUnits()
|
||||
if (unit.isPreparingParadrop())
|
||||
@ -409,7 +414,7 @@ class UnitMovement(val unit: MapUnit) {
|
||||
|
||||
fun getReachableTilesInCurrentTurn(): Sequence<Tile> {
|
||||
return when {
|
||||
unit.hasUnique(UniqueType.CannotMove) -> emptySequence()
|
||||
unit.cache.cannotMove -> sequenceOf(unit.getTile())
|
||||
unit.baseUnit.movesLikeAirUnits() ->
|
||||
unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getMaxMovementForAirUnits()))
|
||||
unit.isPreparingParadrop() ->
|
||||
@ -439,7 +444,7 @@ class UnitMovement(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
|
||||
if (unit.cache.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 = (
|
||||
@ -450,7 +455,7 @@ class UnitMovement(val unit: MapUnit) {
|
||||
) ?: return false
|
||||
val ourPosition = unit.getTile()
|
||||
if (otherUnit.owner != unit.owner
|
||||
|| otherUnit.hasUnique(UniqueType.CannotMove)
|
||||
|| otherUnit.cache.cannotMove // redundant, line below would cover it too
|
||||
|| !otherUnit.movement.canReachInCurrentTurn(ourPosition)) return false
|
||||
// Check if we could enter their tile if they wouldn't be there
|
||||
otherUnit.removeFromTile()
|
||||
@ -728,7 +733,7 @@ class UnitMovement(val unit: MapUnit) {
|
||||
|
||||
// Can a paratrooper land at this tile?
|
||||
fun canParadropOn(destination: Tile): Boolean {
|
||||
if (unit.hasUnique(UniqueType.CannotMove)) return false
|
||||
if (unit.cache.cannotMove) return false
|
||||
// Can only move to land tiles within range that are visible and not impassible
|
||||
// Based on some testing done in the base game
|
||||
if (!destination.isLand || destination.isImpassible() || !unit.civ.viewableTiles.contains(destination)) return false
|
||||
|
@ -663,7 +663,7 @@ 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()) {
|
||||
if (unit.cache.cannotMove && isAirUnit && !unit.isPreparingAirSweep()) {
|
||||
val tilesInAttackRange = unit.getTile().getTilesInDistanceRange(IntRange(1, unit.getRange()))
|
||||
for (tile in tilesInAttackRange) {
|
||||
// The tile is within attack range
|
||||
|
Loading…
x
Reference in New Issue
Block a user