diff --git a/android/build.gradle b/android/build.gradle index d65688c6e6..30dd783423 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,8 +21,8 @@ android { applicationId "com.unciv.game" minSdkVersion 14 targetSdkVersion 26 - versionCode 165 - versionName "2.10.4" + versionCode 166 + versionName "2.10.5" } buildTypes { release { diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index e81b4cd66f..0137cf38cb 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -173,7 +173,7 @@ class Battle(val gameInfo:GameInfo) { capturedUnit.civInfo.addNotification("An enemy ["+attacker.getName()+"] has captured our ["+defender.getName()+"]", defender.getTile().position, Color.RED) - capturedUnit.civInfo.units.remove(capturedUnit) + capturedUnit.civInfo.removeUnit(capturedUnit) capturedUnit.assignOwner(attacker.getCivilization()) } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 6802317440..8560760a99 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -17,6 +17,7 @@ import com.unciv.models.stats.Stats import com.unciv.ui.utils.getRandom import com.unciv.ui.utils.tr import java.util.* +import kotlin.collections.ArrayList import kotlin.collections.HashMap import kotlin.math.max import kotlin.math.pow @@ -25,7 +26,12 @@ import kotlin.math.roundToInt class CivilizationInfo { @Transient lateinit var gameInfo: GameInfo - @Transient var units=ArrayList() + /** + * never add or remove from here directly, could cause comodification problems. + * Instead, create a copy list with the change, and replace this list. + * The other solution, casting toList() every "get", has a performance cost + */ + @Transient private var units=ArrayList() @Transient var viewableTiles = HashSet() var gold = 0 @@ -200,8 +206,18 @@ class CivilizationInfo { fun getBuildingUniques(): List = cities.flatMap { it.getBuildingUniques()}.distinct() - fun getCivUnits(): List { - return units.toList() // to avoid comodification problems (ie concurrency again...) + fun getCivUnits(): List = units + + fun addUnit(mapUnit: MapUnit){ + val newList = ArrayList(units) + newList.add(mapUnit) + units=newList + } + + fun removeUnit(mapUnit: MapUnit){ + val newList = ArrayList(units) + newList.remove(mapUnit) + units=newList } @@ -241,6 +257,7 @@ class CivilizationInfo { fun isDefeated()= cities.isEmpty() && !getCivUnits().any{it.name=="Settler"} fun getEra(): TechEra { val maxEraOfTech = tech.researchedTechnologies + .asSequence() .map { it.era() } .max() if(maxEraOfTech!=null) return maxEraOfTech @@ -265,6 +282,7 @@ class CivilizationInfo { policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !it.endsWith("Complete") } tech.civInfo = this + tech.setTransients() diplomacy.values.forEach { it.civInfo=this} diff --git a/core/src/com/unciv/logic/civilization/PolicyManager.kt b/core/src/com/unciv/logic/civilization/PolicyManager.kt index bff73a66d0..b45df7cdb3 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -33,9 +33,10 @@ class PolicyManager { fun isAdopted(policyName: String): Boolean = adoptedPolicies.contains(policyName) fun isAdoptable(policy: Policy): Boolean { - return (!policy.name.endsWith("Complete") - && getAdoptedPolicies().containsAll(policy.requires!!) - && policy.getBranch().era <= civInfo.getEra()) + if (policy.name.endsWith("Complete")) return false + if (!getAdoptedPolicies().containsAll(policy.requires!!)) return false + if (policy.getBranch().era > civInfo.getEra()) return false + return true } fun canAdoptPolicy(): Boolean = freePolicies > 0 || storedCulture >= getCultureNeededForNextPolicy() diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 93d4ab5a07..3a5910a5b0 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -113,19 +113,20 @@ class MapUnit { fun canPassThrough(tile: TileInfo):Boolean{ val tileOwner = tile.getOwner() + 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(tile.baseTerrain == "Ocean" && !techUniques.contains("Enables embarked units to enter ocean tiles")) + if(isOcean && !techUniques.contains("Enables embarked units to enter ocean tiles")) return false } if(tile.isLand() && type.isWaterUnit()) return false - if(tile.baseTerrain=="Ocean" && baseUnit.uniques.contains("Cannot enter ocean tiles until Astronomy") + if(isOcean && baseUnit.uniques.contains("Cannot enter ocean tiles until Astronomy") && !civInfo.tech.isResearched("Astronomy")) return false - if(tile.baseTerrain=="Ocean" && baseUnit.uniques.contains("Cannot enter ocean tiles")) 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 @@ -299,7 +300,7 @@ class MapUnit { fun destroy(){ removeFromTile() - civInfo.units.remove(this) + civInfo.removeUnit(this) } fun removeFromTile(){ @@ -360,7 +361,7 @@ class MapUnit { fun assignOwner(civInfo:CivilizationInfo){ owner=civInfo.civName this.civInfo=civInfo - civInfo.units.add(this) + civInfo.addUnit(this) } //endregion } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/RandomMapGenerator.kt b/core/src/com/unciv/logic/map/RandomMapGenerator.kt index 89fd6bd651..7777b77129 100644 --- a/core/src/com/unciv/logic/map/RandomMapGenerator.kt +++ b/core/src/com/unciv/logic/map/RandomMapGenerator.kt @@ -21,8 +21,10 @@ class PerlinNoiseRandomMapGenerator:SeedRandomMapGenerator(){ divideIntoAreas(6, 0f, map) val mapToReturn = HashMap() - for(tile in map) + for(tile in map) { + tile.value.setTransients() mapToReturn[tile.key.toString()] = tile.value + } setWaterTiles(mapToReturn) for(tile in mapToReturn.values) randomizeTile(tile) diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 610ed4db39..5fa2473e24 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -82,7 +82,7 @@ class TileMap { unit.putInTile(unitToPlaceTile) unit.currentMovement = unit.getMaxMovement().toFloat() } - else civInfo.units.remove(unit) // since we added it to the civ units in the previous assignOwner + else civInfo.removeUnit(unit) // since we added it to the civ units in the previous assignOwner return unit } diff --git a/core/src/com/unciv/models/gamebasics/Building.kt b/core/src/com/unciv/models/gamebasics/Building.kt index 56289a5124..15d740c768 100644 --- a/core/src/com/unciv/models/gamebasics/Building.kt +++ b/core/src/com/unciv/models/gamebasics/Building.kt @@ -111,12 +111,13 @@ class Building : NamedStats(), IConstruction{ return stringBuilder.toString().trim() } + val cultureBuildings = hashSetOf("Monument", "Temple", "Monastery") fun getStats(adoptedPolicies: HashSet): Stats { val stats = this.clone() - if (adoptedPolicies.contains("Organized Religion") && hashSetOf("Monument", "Temple", "Monastery").contains(name)) + if (adoptedPolicies.contains("Organized Religion") && cultureBuildings.contains(name)) stats.happiness += 1 - if (adoptedPolicies.contains("Free Religion") && hashSetOf("Monument", "Temple", "Monastery").contains(name)) + if (adoptedPolicies.contains("Free Religion") && cultureBuildings.contains(name)) stats.culture += 1f if (adoptedPolicies.contains("Entrepreneurship") && hashSetOf("Mint", "Market", "Bank", "Stock Market").contains(name)) diff --git a/core/src/com/unciv/models/gamebasics/Policy.kt b/core/src/com/unciv/models/gamebasics/Policy.kt index 92c722db6c..51ee7a326c 100644 --- a/core/src/com/unciv/models/gamebasics/Policy.kt +++ b/core/src/com/unciv/models/gamebasics/Policy.kt @@ -13,5 +13,9 @@ open class Policy : INamed { fun getBranch():PolicyBranch{ return GameBasics.PolicyBranches[branch]!! } + + override fun toString(): String { + return name + } } diff --git a/core/src/com/unciv/ui/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/EmpireOverviewScreen.kt index 726e2d30e3..7117517251 100644 --- a/core/src/com/unciv/ui/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/EmpireOverviewScreen.kt @@ -110,6 +110,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){ val happinessTable = Table(skin) happinessTable.defaults().pad(5f) happinessTable.add(Label("Happiness".tr(), skin).setFontSize(24)).colspan(2).row() + happinessTable.addSeparator() for (entry in civInfo.getHappinessForNextTurn()) { happinessTable.add(entry.key.tr()) happinessTable.add(entry.value.toString()).row() @@ -124,6 +125,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){ val goldTable = Table(skin) goldTable.defaults().pad(5f) goldTable.add(Label("Gold".tr(), skin).setFontSize(24)).colspan(2).row() + goldTable.addSeparator() var total=0f for (entry in civInfo.getStatMapForNextTurn()) { if(entry.value.gold==0f) continue diff --git a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt index 8a4c44fd43..80df7c4705 100644 --- a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt @@ -39,7 +39,7 @@ class PolicyPickerScreen(internal val civInfo: CivilizationInfo) : PickerScreen( topTable.row().pad(30f) for (branch in GameBasics.PolicyBranches.values) { - if (branch.name == "Commerce") topTable.row() + if (branch.name == "Commerce") topTable.addSeparator() val branchGroup = Table() branchGroup.row().pad(20f) branchGroup.add(getPolicyButton(branch, false)).row()