Bugfixes to the units' teleportation (#7071)

* Allow to pass other units when teleporting

* Teleport to the closest city tile

* Additional unit tests
This commit is contained in:
Jack Rainy 2022-06-05 23:17:59 +03:00 committed by GitHub
parent 97b2b56956
commit 862f368075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 15 deletions

View File

@ -385,18 +385,15 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
// can the unit be placed safely there?
.filter { canMoveTo(it) }
// out of those where it can be placed, can it reach them in any meaningful way?
.firstOrNull { getPathBetweenTiles(unit.currentTile, it).size > 1 }
.firstOrNull { getPathBetweenTiles(unit.currentTile, it).contains(it) }
}
// No tile within 4 spaces? move him to a city.
if (allowedTile == null) {
for (city in unit.civInfo.cities) {
allowedTile = city.getTiles()
.firstOrNull { canMoveTo(it) }
if (allowedTile != null) break
}
}
val origin = unit.getTile()
if (allowedTile == null)
allowedTile = unit.civInfo.cities.flatMap { it.getTiles() }
.sortedBy { it.aerialDistanceTo(origin) }.firstOrNull{ canMoveTo(it) }
if (allowedTile != null) {
unit.removeFromTile() // we "teleport" them away
unit.putInTile(allowedTile)
@ -740,7 +737,7 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
private fun getPathBetweenTiles(from: TileInfo, to: TileInfo): MutableSet<TileInfo> {
val tmp = unit.canEnterForeignTerrain
unit.canEnterForeignTerrain = true // the trick to ignore tiles owners
val bfs = BFS(from) { canMoveTo(it) }
val bfs = BFS(from) { canPassThrough(it) }
bfs.stepUntilDestination(to)
unit.canEnterForeignTerrain = tmp
return bfs.getReachedTiles()

View File

@ -353,6 +353,33 @@ class UnitMovementAlgorithmsTests {
Assert.assertTrue("Unit must be teleported to new location", unit.currentTile == newTiles.last())
}
@Test
fun `can teleport water unit over other unit`() {
// this is needed for unit.putInTile(), unit.moveThroughTile() to avoid using Uncivgame.Current.viewEntireMapForDebug
civInfo.nation.name = Constants.spectator
tile.baseTerrain = Constants.ocean
tile.position.set(0f, 0f)
tile.setTransients()
createOpponentCivAndCity()
val newTiles = generateTileCopies(3)
// Other unit on the way
val otherUnit = MapUnit()
otherUnit.civInfo = civInfo
otherUnit.owner = civInfo.civName
otherUnit.baseUnit = BaseUnit().apply { unitType = "Melee Water"; strength = 1; ruleset = ruleSet }
otherUnit.currentTile = newTiles[0]
newTiles[0].militaryUnit = otherUnit
otherUnit.name = "Friend Unit"
setupMilitaryUnitInTheCurrentTile("Melee Water")
unit.movement.teleportToClosestMoveableTile()
Assert.assertTrue("Unit must be teleported to new location", unit.currentTile == newTiles.last())
}
@Test
fun `can teleport air unit`() {
// this is needed for unit.putInTile(), unit.moveThroughTile() to avoid using Uncivgame.Current.viewEntireMapForDebug
@ -380,17 +407,19 @@ class UnitMovementAlgorithmsTests {
tile.position.set(0f, 0f)
tile.setTransients()
createOpponentCivAndCity()
val newTiles = generateTileCopies(6)
val newTiles = generateTileCopies(7)
// create obstacle
newTiles[4].baseTerrain = "Grand Mesa"
newTiles[4].setTransients()
newTiles[3].baseTerrain = "Grand Mesa"
newTiles[3].setTransients()
// create our city
CityInfo().apply {
this.civInfo = this@UnitMovementAlgorithmsTests.civInfo
location = newTiles.last().position.cpy()
tiles.add(location)
tiles.add(newTiles[5].position)
tileMap = tile.tileMap
civInfo.cities = listOf(this)
newTiles[5].setOwningCity(this)
newTiles.last().setOwningCity(this)
}
@ -398,7 +427,7 @@ class UnitMovementAlgorithmsTests {
unit.movement.teleportToClosestMoveableTile()
Assert.assertTrue("Unit must be teleported to the city", unit.currentTile == newTiles.last())
Assert.assertTrue("Unit must be teleported to the city", unit.currentTile == newTiles[5])
}
@Test
@ -412,8 +441,8 @@ class UnitMovementAlgorithmsTests {
createOpponentCivAndCity()
val newTiles = generateTileCopies(3)
// create obstacle
newTiles[0].baseTerrain = Constants.grassland
newTiles[0].setTransients()
newTiles[1].baseTerrain = Constants.grassland
newTiles[1].setTransients()
setupMilitaryUnitInTheCurrentTile("Melee Water")