From b7a6967fe65dab2cdbaeb2a0ecafe9bafeb18e8e Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Sat, 13 Feb 2021 21:50:47 +0200 Subject: [PATCH] Movement algorithm updated - can no longer see whether you can move to unknown tiles --- .../unciv/logic/map/UnitMovementAlgorithms.kt | 124 +----------------- .../com/unciv/models/metadata/GameSettings.kt | 1 - .../ui/worldscreen/mainmenu/OptionsPopup.kt | 2 - 3 files changed, 4 insertions(+), 123 deletions(-) diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 54c45fbb4b..6237210e83 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -10,7 +10,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { // This function is called ALL THE TIME and should be as time-optimal as possible! fun getMovementCostBetweenAdjacentTiles(from: TileInfo, to: TileInfo, civInfo: CivilizationInfo): Float { - if ((from.isLand != to.isLand) && !unit.civInfo.nation.embarkDisembarkCosts1 && unit.type.isLandUnit()) + if (from.isLand != to.isLand && !unit.civInfo.nation.embarkDisembarkCosts1 && unit.type.isLandUnit()) return 100f // this is embarkment or disembarkment, and will take the entire turn // land units will still spend all movement points to embark even with this unique @@ -58,64 +58,15 @@ class UnitMovementAlgorithms(val unit:MapUnit) { class ParentTileAndTotalDistance(val parentTile: TileInfo, val totalDistance: Float) - fun isUnknownTileWeShouldAssumeToBePassable(tileInfo: TileInfo) = UncivGame.Current.settings.unitMovementIncludesImpassibles - && !unit.civInfo.exploredTiles.contains(tileInfo.position) + fun isUnknownTileWeShouldAssumeToBePassable(tileInfo: TileInfo) = !unit.civInfo.exploredTiles.contains(tileInfo.position) fun getDistanceToTilesWithinTurn(origin: Vector2, unitMovement: Float): PathsToTilesWithinTurn { - if (UncivGame.Current.settings.unitMovementIncludesImpassibles) - return getDistanceToTilesWithinTurnIncludingUnknownImpassibles(origin, unitMovement) - 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, 0f) - var tilesToCheck = listOf(unitTile) - - while (tilesToCheck.isNotEmpty()) { - val updatedTiles = ArrayList() - for (tileToCheck in tilesToCheck) - for (neighbor in tileToCheck.neighbors) { - var totalDistanceToTile: Float - - if (!canPassThrough(neighbor)) - totalDistanceToTile = unitMovement // Can't go here. - // The reason that we don't just "return" is so that when calculating how to reach an enemy, - // You need to assume his tile is reachable, otherwise all movement algs on reaching enemy - // cities and units goes kaput. - - else { - val distanceBetweenTiles = getMovementCostBetweenAdjacentTiles(tileToCheck, neighbor, unit.civInfo) - totalDistanceToTile = distanceToTiles[tileToCheck]!!.totalDistance + distanceBetweenTiles - } - - if (!distanceToTiles.containsKey(neighbor) || distanceToTiles[neighbor]!!.totalDistance > totalDistanceToTile) { // this is the new best path - if (totalDistanceToTile < unitMovement) // We can still keep moving from here! - updatedTiles += neighbor - else - totalDistanceToTile = unitMovement - // In Civ V, you can always travel between adjacent tiles, even if you don't technically - // have enough movement points - it simple depletes what you have - - distanceToTiles[neighbor] = ParentTileAndTotalDistance(tileToCheck, totalDistanceToTile) - } - } - - tilesToCheck = updatedTiles - } - - return distanceToTiles - } - - fun getDistanceToTilesWithinTurnIncludingUnknownImpassibles(origin: Vector2, unitMovement: Float): 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] + val unitTile = if (origin == currentUnitTile.position) currentUnitTile else currentUnitTile.tileMap[origin] distanceToTiles[unitTile] = ParentTileAndTotalDistance(unitTile, 0f) var tilesToCheck = listOf(unitTile) @@ -285,7 +236,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { unit.putInTile(allowedTile) } - fun moveToTileIncludingUnknownImpassibles(destination: TileInfo) { + fun moveToTile(destination: TileInfo) { if (destination == unit.getTile()) return // already here! if (unit.type.isAirUnit()) { // they move differently from all other units @@ -343,73 +294,6 @@ class UnitMovementAlgorithms(val unit:MapUnit) { } - fun moveToTile(destination: TileInfo) { - if(UncivGame.Current.settings.unitMovementIncludesImpassibles) - return moveToTileIncludingUnknownImpassibles(destination) - - if (destination == unit.getTile()) return // already here! - - class CantEnterThisTileException(msg: String) : Exception(msg) - if (!canMoveTo(destination)) - throw CantEnterThisTileException("$unit can't enter $destination") - - if (unit.type.isAirUnit()) { // they move differently from all other units - unit.action = null - unit.removeFromTile() - unit.isTransported = false // it has left the carrier by own means - unit.putInTile(destination) - unit.currentMovement = 0f - return - } - - val distanceToTiles = getDistanceToTiles() - - class YouCantGetThereFromHereException(msg: String) : Exception(msg) - if (!distanceToTiles.containsKey(destination)) - throw YouCantGetThereFromHereException("$unit can't get from ${unit.currentTile.position} to ${destination.position}.") - - if (destination.isCityCenter() && destination.getOwner() != unit.civInfo && !destination.getCity()!!.hasJustBeenConquered) - throw Exception("This is an enemy city, you can't go here!") - - if (!unit.civInfo.gameInfo.gameParameters.godMode) { - unit.currentMovement -= distanceToTiles[destination]!!.totalDistance - if (unit.currentMovement < 0.1) unit.currentMovement = 0f // silly floats which are "almost zero" - } - if (unit.isFortified() || unit.action == Constants.unitActionSetUp || unit.isSleeping()) - unit.action = null // unfortify/setup after moving - - // If this unit is a carrier, keep record of its air payload whereabouts. - val origin = unit.getTile() - unit.removeFromTile() - unit.putInTile(destination) - - // The .toList() here is because we have a sequence that's running on the units in the tile, - // then if we move one of the units we'll get a ConcurrentModificationException, se we save them all to a list - for (payload in origin.getUnits().filter { it.isTransported && unit.canTransport(it) }.toList()) { // bring along the payloads - payload.removeFromTile() - payload.putInTile(destination) - payload.isTransported = true // restore the flag to not leave the payload in the cit - } - - // Unit maintenance changed - if (unit.canGarrison() - && (origin.isCityCenter() || destination.isCityCenter()) - && unit.civInfo.hasUnique("Units in cities cost no Maintenance") - ) unit.civInfo.updateStatsForNextTurn() - - // Move through all intermediate tiles to get ancient ruins, barb encampments - // and to view tiles along the way - // We only activate the moveThroughTile AFTER the putInTile because of a really weird bug - - // If you're going to (or past) a ruin, and you activate the ruin bonus, and A UNIT spawns. - // That unit could now be blocking your entrance to the destination, so the putInTile would fail! =0 - // Instead, we move you to the destination directly, and only afterwards activate the various tiles on the way. - val pathToFinalTile = distanceToTiles.getPathToTile(destination) - for (tile in pathToFinalTile) { - unit.moveThroughTile(tile) - } - - } - /** * Designates whether we can enter the tile - without attacking diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index f10f485e79..20efd0d223 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -12,7 +12,6 @@ class GameSettings { var showTileYields: Boolean = false var checkForDueUnits: Boolean = true var singleTapMove: Boolean = false - var unitMovementIncludesImpassibles: Boolean = false var language: String = "English" var resolution: String = "900x600" // Auto-detecting resolution was a BAD IDEA since it needs to be based on DPI AND resolution. var tutorialsShown = HashSet() diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt index 81c2a7eb65..8d6dda7664 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt @@ -108,8 +108,6 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr addYesNoRow("Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it } addYesNoRow("Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it } - addYesNoRow("Movement assumes unknown tiles to be passable", settings.unitMovementIncludesImpassibles) - { settings.unitMovementIncludesImpassibles = it } addYesNoRow("Auto-assign city production", settings.autoAssignCityProduction, true) { settings.autoAssignCityProduction = it if (it && previousScreen is WorldScreen &&