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? // can the unit be placed safely there?
.filter { canMoveTo(it) } .filter { canMoveTo(it) }
// out of those where it can be placed, can it reach them in any meaningful way? // 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. // 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() val origin = unit.getTile()
if (allowedTile == null)
allowedTile = unit.civInfo.cities.flatMap { it.getTiles() }
.sortedBy { it.aerialDistanceTo(origin) }.firstOrNull{ canMoveTo(it) }
if (allowedTile != null) { if (allowedTile != null) {
unit.removeFromTile() // we "teleport" them away unit.removeFromTile() // we "teleport" them away
unit.putInTile(allowedTile) unit.putInTile(allowedTile)
@ -740,7 +737,7 @@ class UnitMovementAlgorithms(val unit: MapUnit) {
private fun getPathBetweenTiles(from: TileInfo, to: TileInfo): MutableSet<TileInfo> { private fun getPathBetweenTiles(from: TileInfo, to: TileInfo): MutableSet<TileInfo> {
val tmp = unit.canEnterForeignTerrain val tmp = unit.canEnterForeignTerrain
unit.canEnterForeignTerrain = true // the trick to ignore tiles owners unit.canEnterForeignTerrain = true // the trick to ignore tiles owners
val bfs = BFS(from) { canMoveTo(it) } val bfs = BFS(from) { canPassThrough(it) }
bfs.stepUntilDestination(to) bfs.stepUntilDestination(to)
unit.canEnterForeignTerrain = tmp unit.canEnterForeignTerrain = tmp
return bfs.getReachedTiles() return bfs.getReachedTiles()

View File

@ -353,6 +353,33 @@ class UnitMovementAlgorithmsTests {
Assert.assertTrue("Unit must be teleported to new location", unit.currentTile == newTiles.last()) 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 @Test
fun `can teleport air unit`() { fun `can teleport air unit`() {
// this is needed for unit.putInTile(), unit.moveThroughTile() to avoid using Uncivgame.Current.viewEntireMapForDebug // 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.position.set(0f, 0f)
tile.setTransients() tile.setTransients()
createOpponentCivAndCity() createOpponentCivAndCity()
val newTiles = generateTileCopies(6) val newTiles = generateTileCopies(7)
// create obstacle // create obstacle
newTiles[4].baseTerrain = "Grand Mesa" newTiles[3].baseTerrain = "Grand Mesa"
newTiles[4].setTransients() newTiles[3].setTransients()
// create our city // create our city
CityInfo().apply { CityInfo().apply {
this.civInfo = this@UnitMovementAlgorithmsTests.civInfo this.civInfo = this@UnitMovementAlgorithmsTests.civInfo
location = newTiles.last().position.cpy() location = newTiles.last().position.cpy()
tiles.add(location) tiles.add(location)
tiles.add(newTiles[5].position)
tileMap = tile.tileMap tileMap = tile.tileMap
civInfo.cities = listOf(this) civInfo.cities = listOf(this)
newTiles[5].setOwningCity(this)
newTiles.last().setOwningCity(this) newTiles.last().setOwningCity(this)
} }
@ -398,7 +427,7 @@ class UnitMovementAlgorithmsTests {
unit.movement.teleportToClosestMoveableTile() 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 @Test
@ -412,8 +441,8 @@ class UnitMovementAlgorithmsTests {
createOpponentCivAndCity() createOpponentCivAndCity()
val newTiles = generateTileCopies(3) val newTiles = generateTileCopies(3)
// create obstacle // create obstacle
newTiles[0].baseTerrain = Constants.grassland newTiles[1].baseTerrain = Constants.grassland
newTiles[0].setTransients() newTiles[1].setTransients()
setupMilitaryUnitInTheCurrentTile("Melee Water") setupMilitaryUnitInTheCurrentTile("Melee Water")