diff --git a/android/assets/jsons/Buildings.json b/android/assets/jsons/Buildings.json index 12e9271ab8..6e11ba906d 100644 --- a/android/assets/jsons/Buildings.json +++ b/android/assets/jsons/Buildings.json @@ -280,7 +280,8 @@ name:"Harbor", maintenance:2, hurryCostModifier:25, - uniques:["+1 production from all sea resources worked by the city","Connects trade routes over water"] // todo - trade routes over water! + uniques:["+1 production from all sea resources worked by the city", + "Connects trade routes over water","Can only be built in coastal cities"] requiredTech:"Compass" }, { diff --git a/android/assets/jsons/Tutorials_English.json b/android/assets/jsons/Tutorials_English.json index e92df7bcb5..30e5637fed 100644 --- a/android/assets/jsons/Tutorials_English.json +++ b/android/assets/jsons/Tutorials_English.json @@ -299,7 +299,7 @@ ] ] - Worker:[ + WorkerTrained:[ [ "You have trained a worker!", "Workers are vital to your cities' growth, since only they can onstruct improvements on tiles", diff --git a/android/build.gradle b/android/build.gradle index 3c5cfce703..35cefb07e4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,8 +21,8 @@ android { applicationId "com.unciv.game" minSdkVersion 14 targetSdkVersion 26 - versionCode 152 - versionName "2.9.6" + versionCode 153 + versionName "2.9.7" } buildTypes { release { diff --git a/core/src/com/unciv/UnCivGame.kt b/core/src/com/unciv/UnCivGame.kt index bc977334e4..23dff849f8 100644 --- a/core/src/com/unciv/UnCivGame.kt +++ b/core/src/com/unciv/UnCivGame.kt @@ -17,7 +17,7 @@ class UnCivGame : Game() { * This exists so that when debugging we can see the entire map. * Remember to turn this to false before commit and upload! */ - val viewEntireMapForDebug = true + val viewEntireMapForDebug = false lateinit var worldScreen: WorldScreen diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 6a0b629781..e53c4010a7 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -15,6 +15,7 @@ import kotlin.math.min class CityInfo { @Transient lateinit var civInfo: CivilizationInfo + @Transient var isConnectedToCapital = false var location: Vector2 = Vector2.Zero var name: String = "" var health = 200 @@ -78,6 +79,7 @@ class CityInfo { toReturn.tiles.addAll(tiles) toReturn.workedTiles.addAll(workedTiles) toReturn.isBeingRazed=isBeingRazed + toReturn.isConnectedToCapital = isConnectedToCapital return toReturn } diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index 53b04590af..6f50a04cb3 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -224,32 +224,14 @@ class CityStats { fun isConnectedToCapital(roadType: RoadStatus): Boolean { if (cityInfo.civInfo.cities.count() < 2) return false// first city! + if(roadType==RoadStatus.Road) return cityInfo.isConnectedToCapital // this transient is not applicable to connection via railroad. + val capitalTile = cityInfo.civInfo.getCapital().getCenterTile() - val BFS = - if(roadType==RoadStatus.Road) BFS(capitalTile){it.roadStatus!=RoadStatus.None} - else BFS(capitalTile){it.roadStatus == roadType} + val BFS = BFS(capitalTile){it.roadStatus == roadType} val cityTile = cityInfo.getCenterTile() BFS.stepUntilDestination(cityTile) return BFS.tilesReached.containsKey(cityTile) - -// val tilesReached = HashSet() -// var tilesToCheck: List = listOf(cityInfo.getCenterTile()) -// while (tilesToCheck.isNotEmpty()) { -// val newTiles = tilesToCheck -// .flatMap { it.neighbors }.distinct() -// .filter { -// !tilesReached.contains(it) -// && !tilesToCheck.contains(it) -// && (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None) -// && (roadType !== RoadStatus.Railroad || it.roadStatus === roadType) -// } -// -// if (newTiles.contains(capitalTile)) return true -// tilesReached.addAll(tilesToCheck) -// tilesToCheck = newTiles -// } -// return false } //endregion diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index b6acce1364..0c93699320 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 import com.unciv.logic.GameInfo import com.unciv.logic.city.CityInfo +import com.unciv.logic.map.BFS import com.unciv.logic.map.MapUnit import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo @@ -15,6 +16,8 @@ import com.unciv.models.gamebasics.tile.TileResource import com.unciv.models.stats.Stats import com.unciv.ui.utils.getRandom import com.unciv.ui.utils.tr +import java.util.* +import kotlin.collections.HashMap import kotlin.math.max import kotlin.math.pow import kotlin.math.roundToInt @@ -255,6 +258,7 @@ class CivilizationInfo { cityInfo.civInfo = this // must be before the city's setTransients because it depends on the tilemap, that comes from the civInfo cityInfo.setTransients() } + setCitiesConnectedToCapitalTransients() } fun endTurn() { @@ -296,6 +300,7 @@ class CivilizationInfo { fun startTurn(){ getViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better + setCitiesConnectedToCapitalTransients() for (city in cities) city.cityStats.update() happiness = getHappinessForNextTurn().values.sum().roundToInt() @@ -328,5 +333,62 @@ class CivilizationInfo { newCity.cityConstructions.chooseNextConstruction() } + fun setCitiesConnectedToCapitalTransients(){ + if(cities.isEmpty()) return // eg barbarians + + // We map which cities we've reached, to the mediums they've been reached by - + // this is so we know that if we've seen which cities can be connected by port A, and one + // of those is city B, then we don't need to check the cities that B can connect to by port, + // since we'll get the same cities we got from A, since they're connected to the same sea. + val citiesReachedToMediums = HashMap>() + var citiesToCheck = mutableListOf(getCapital()) + citiesReachedToMediums[getCapital()] = arrayListOf("Start") + while(citiesToCheck.isNotEmpty() && citiesReachedToMediums.size() + for(cityToConnectFrom in citiesToCheck){ + val reachedMediums = citiesReachedToMediums[cityToConnectFrom]!! + + // This is copypasta and can be cleaned up + if(!reachedMediums.contains("Road")){ + val roadBfs = BFS(cityToConnectFrom.getCenterTile()){it.roadStatus!=RoadStatus.None} + roadBfs.stepToEnd() + val reachedCities = cities.filter { roadBfs.tilesReached.containsKey(it.getCenterTile())} + for(reachedCity in reachedCities){ + if(!citiesReachedToMediums.containsKey(reachedCity)){ + newCitiesToCheck.add(reachedCity) + citiesReachedToMediums[reachedCity] = arrayListOf() + } + val cityReachedByMediums = citiesReachedToMediums[reachedCity]!! + if(!cityReachedByMediums.contains("Road")) + cityReachedByMediums.add("Road") + } + citiesReachedToMediums[cityToConnectFrom]!!.add("Road") + } + + if(!reachedMediums.contains("Harbor") + && cityToConnectFrom.cityConstructions.containsBuildingOrEquivalent("Harbor")){ + val seaBfs = BFS(cityToConnectFrom.getCenterTile()){it.isWater() || it.isCityCenter()} + seaBfs.stepToEnd() + val reachedCities = cities.filter { seaBfs.tilesReached.containsKey(it.getCenterTile())} + for(reachedCity in reachedCities){ + if(!citiesReachedToMediums.containsKey(reachedCity)){ + newCitiesToCheck.add(reachedCity) + citiesReachedToMediums[reachedCity] = arrayListOf() + } + val cityReachedByMediums = citiesReachedToMediums[reachedCity]!! + if(!cityReachedByMediums.contains("Harbor")) + cityReachedByMediums.add("Harbor") + } + citiesReachedToMediums[cityToConnectFrom]!!.add("Harbor") + } + } + citiesToCheck = newCitiesToCheck + } + + for(city in cities){ + city.isConnectedToCapital = citiesReachedToMediums.containsKey(city) + } + } + //endregion } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/BFS.kt b/core/src/com/unciv/logic/map/BFS.kt index 926669cdc9..8780108ef5 100644 --- a/core/src/com/unciv/logic/map/BFS.kt +++ b/core/src/com/unciv/logic/map/BFS.kt @@ -12,6 +12,11 @@ class BFS(val startingPoint: TileInfo, val predicate : (TileInfo) -> Boolean){ tilesReached.put(startingPoint,startingPoint) } + fun stepToEnd(){ + while(tilesToCheck.isNotEmpty()) + nextStep() + } + fun stepUntilDestination(destination: TileInfo){ while(!tilesReached.containsKey(destination) && tilesToCheck.isNotEmpty()) nextStep() diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index 6f4480edb1..493f551cdb 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -94,6 +94,7 @@ class WorldScreen : CameraStageBaseScreen() { val cloneCivilization = gameClone.getPlayerCivilization() kotlin.concurrent.thread { civInfo.happiness = gameClone.getPlayerCivilization().getHappinessForNextTurn().values.sum().toInt() + gameInfo.civilizations.forEach { it.setCitiesConnectedToCapitalTransients() } } if(bottomBar.unitTable.selectedUnit!=null){