diff --git a/android/Images/TerrainIcons/Lakes.png b/android/Images/TerrainIcons/Lakes.png index afdaacf0..e839d59a 100644 Binary files a/android/Images/TerrainIcons/Lakes.png and b/android/Images/TerrainIcons/Lakes.png differ diff --git a/android/build.gradle b/android/build.gradle index 811959e2..270bc371 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,7 +21,7 @@ android { applicationId "com.unciv.game" minSdkVersion 14 targetSdkVersion 28 - versionCode 181 + versionCode 182 versionName "2.11.0" } diff --git a/core/src/com/unciv/UnCivGame.kt b/core/src/com/unciv/UnCivGame.kt index d42f058e..fb5df00b 100644 --- a/core/src/com/unciv/UnCivGame.kt +++ b/core/src/com/unciv/UnCivGame.kt @@ -21,7 +21,7 @@ class UnCivGame : Game() { val viewEntireMapForDebug = false // For when you need to test something in an advanced game and don't have time to faff around - val superchargedForDebug = true + val superchargedForDebug = false lateinit var worldScreen: WorldScreen diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 9e321227..43ea921b 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -12,6 +12,12 @@ import java.util.* class TechManager { @Transient lateinit var civInfo: CivilizationInfo @Transient var researchedTechnologies=ArrayList() + @Transient private var researchedTechUniques=ArrayList() + + // MapUnit.canPassThrough is the most called function in the game, and having these extremey specific booleans is or way of improving the time cost + @Transient var unitsCanEmbark=false + @Transient var embarkedUnitsCanEnterOcean=false + var freeTechs = 0 var techsResearched = HashSet() @@ -56,7 +62,7 @@ class TechManager { return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) } } - fun getUniques() = researchedTechnologies.flatMap { it.uniques } + fun getUniques() = researchedTechUniques //endregion @@ -103,7 +109,11 @@ class TechManager { techsResearched.add(techName) // this is to avoid concurrent modification problems - researchedTechnologies = researchedTechnologies.withItem(GameBasics.Technologies[techName]!!) + val newTech = GameBasics.Technologies[techName]!! + researchedTechnologies = researchedTechnologies.withItem(newTech) + for(unique in newTech.uniques) + researchedTechUniques = researchedTechUniques.withItem(unique) + updateTransientBooleans() civInfo.addNotification("Research of [$techName] has completed!", null, Color.BLUE) @@ -144,7 +154,13 @@ class TechManager { techsToResearch.remove("Mass Media") researchedTechnologies.addAll(techsResearched.map { GameBasics.Technologies[it]!! }) + researchedTechUniques.addAll(researchedTechnologies.flatMap { it.uniques }) + updateTransientBooleans() } -} + fun updateTransientBooleans(){ + if(researchedTechUniques.contains("Enables embarkation for land units")) unitsCanEmbark=true + if(researchedTechUniques.contains("Enables embarked units to enter ocean tiles")) embarkedUnitsCanEnterOcean=true + } +} \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 8a14656c..c9314475 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -19,6 +19,13 @@ class MapUnit { @Transient lateinit var baseUnit: BaseUnit @Transient internal lateinit var currentTile :TileInfo + // 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 + @Transient var roughTerrainPenalty = false + @Transient var doubleMovementInCoast = false + lateinit var owner: String lateinit var name: String var currentMovement: Float = 0f @@ -81,6 +88,10 @@ class MapUnit { uniques.addAll(baseUnit.uniques) uniques.addAll(promotions.promotions.map { GameBasics.UnitPromotions[it]!!.effect }) tempUniques = uniques + + if("Ignores terrain cost" in uniques) ignoresTerrainCost=true + if("Rough terrain penalty" in uniques) roughTerrainPenalty=true + if("Double movement in coast" in uniques) doubleMovementInCoast=true } fun hasUnique(unique:String): Boolean { @@ -116,23 +127,26 @@ class MapUnit { return "$name - $owner" } + // This is the most called function in the entire game, + // so multiple callees of this function have been optimized, + // because optimization on this function results in massive benefits! fun canPassThrough(tile: TileInfo):Boolean{ val tileOwner = tile.getOwner() + if(tile.getBaseTerrain().impassable) return false - val isOcean = tile.baseTerrain == "Ocean" // profiling showed that 3.5% of all nextTurn time is taken up by string equals in this function =| - if(tile.isWater() && type.isLandUnit()){ - val techUniques = civInfo.tech.getUniques() - if(!techUniques.contains("Enables embarkation for land units")) - return false - if(isOcean && !techUniques.contains("Enables embarked units to enter ocean tiles")) - return false - } if(tile.isLand() && type.isWaterUnit()) return false + + val isOcean = tile.baseTerrain == "Ocean" + if(tile.isWater() && type.isLandUnit()){ + if(!civInfo.tech.unitsCanEmbark) return false + if(isOcean && !civInfo.tech.embarkedUnitsCanEnterOcean) + return false + } + if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles")) return false if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles until Astronomy") && !civInfo.tech.isResearched("Astronomy")) return false - if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles")) return false if(tileOwner!=null && tileOwner.civName!=owner && (tile.isCityCenter() || !civInfo.canEnterTiles(tileOwner))) return false return true diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 85eeea58..8eb3bbd9 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -92,8 +92,19 @@ class TileMap { fun getViewableTiles(position: Vector2, sightDistance: Int): MutableList { val viewableTiles = getTilesInDistance(position, 1).toMutableList() for (i in 1..sightDistance) { // in each layer, - getTilesAtDistance(position, i).filterTo(viewableTiles) // take only tiles which have a visible neighbor, which is lower than the tile - { tile -> tile.neighbors.any{viewableTiles.contains(it) && (it.getHeight() ==0 || it.getHeight() < tile.getHeight())} } + // This is so we don't use tiles in the same distance to "see over", + // that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance + val tilesToAddInDistanceI = ArrayList() + + for (tile in getTilesAtDistance(position, i)) { // for each tile in that layer, + val tileHeight = tile.getHeight() + val containsViewableNeighborThatCanSeeOver = tile.neighbors.any { + val neighborHeight = it.getHeight() + viewableTiles.contains(it) && (neighborHeight == 0 || neighborHeight < tileHeight) + } + if (containsViewableNeighborThatCanSeeOver) tilesToAddInDistanceI.add(tile) + } + viewableTiles.addAll(tilesToAddInDistanceI) } return viewableTiles diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index 68bb6224..97949120 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -19,13 +19,13 @@ class UnitMovementAlgorithms(val unit:MapUnit) { if (unit.civInfo.tech.getUniques().contains("Improves movement speed on roads")) return 1 / 3f else return 1 / 2f } - if (unit.hasUnique("Ignores terrain cost")) return 1f + if (unit.ignoresTerrainCost) return 1f - if (unit.hasUnique("Rough terrain penalty") + if (unit.roughTerrainPenalty && (to.baseTerrain == "Hill" || to.terrainFeature == "Forest" || to.terrainFeature == "Jungle")) return 4f - if(unit.hasUnique("Double movement in coast") && to.baseTerrain=="Coast") + if(unit.doubleMovementInCoast && to.baseTerrain=="Coast") return 1/2f return to.getLastTerrain().movementCost.toFloat() // no road