diff --git a/android/assets/jsons/Civ V - Vanilla/Units.json b/android/assets/jsons/Civ V - Vanilla/Units.json index 61613c90..ff47fff7 100644 --- a/android/assets/jsons/Civ V - Vanilla/Units.json +++ b/android/assets/jsons/Civ V - Vanilla/Units.json @@ -133,7 +133,7 @@ "movement": 4, "cost": 30, "requiredTech": "Sailing", - "uniques": ["Cannot enter ocean tiles until Astronomy","May create improvements on water resources"], + "uniques": ["Cannot enter ocean tiles until Astronomy", "May create improvements on water resources"], "hurryCostModifier": 20 }, { @@ -175,7 +175,7 @@ "requiredResource": "Horses", "upgradesTo": "Knight", "obsoleteTech": "Chivalry", - "uniques": ["No defensive terrain bonus","Rough terrain penalty"], + "uniques": ["No defensive terrain bonus", "Rough terrain penalty"], "hurryCostModifier": 20, "attackSound": "arrow" }, @@ -191,7 +191,7 @@ "requiredTech": "The Wheel", "upgradesTo": "Knight", "obsoleteTech": "Chivalry", - "uniques": ["No defensive terrain bonus","Rough terrain penalty"], + "uniques": ["No defensive terrain bonus", "Rough terrain penalty"], "hurryCostModifier": 20, "attackSound": "arrow" }, diff --git a/core/src/com/unciv/Constants.kt b/core/src/com/unciv/Constants.kt index 03c629c3..4c11f158 100644 --- a/core/src/com/unciv/Constants.kt +++ b/core/src/com/unciv/Constants.kt @@ -4,6 +4,7 @@ object Constants { const val worker = "Worker" const val workerUnique = "Can build improvements on tiles" const val settler = "Settler" + const val settlerUnique = "Founds a new city" const val greatGeneral = "Great General" const val impassable = "Impassable" diff --git a/core/src/com/unciv/logic/automation/ConstructionAutomation.kt b/core/src/com/unciv/logic/automation/ConstructionAutomation.kt index 2580b17b..72205df8 100644 --- a/core/src/com/unciv/logic/automation/ConstructionAutomation.kt +++ b/core/src/com/unciv/logic/automation/ConstructionAutomation.kt @@ -107,7 +107,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){ else if (isAtWar) modifier *= unitsToCitiesRatio * 2 if (!cityIsOverAverageProduction) modifier /= 5 // higher production cities will deal with this - if (cityInfo.getCenterTile().civilianUnit?.name == Constants.settler + val civilianUnit = cityInfo.getCenterTile().civilianUnit + if (civilianUnit != null && civilianUnit.hasUnique(Constants.settlerUnique) && cityInfo.getCenterTile().getTilesInDistance(5).none { it.militaryUnit?.civInfo == civInfo }) modifier = 5f // there's a settler just sitting here, doing nothing - BAD diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index 9e4a4ff9..f0d9cbfb 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -15,6 +15,7 @@ import com.unciv.models.ruleset.ModOptions import com.unciv.models.ruleset.ModOptionsConstants import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.tech.Technology +import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.translations.tr import kotlin.math.min @@ -480,14 +481,20 @@ object NextTurnAutomation{ if (civInfo.isCityState()) return if (civInfo.isAtWar()) return // don't train settlers when you could be training troops. if (civInfo.victoryType() == VictoryType.Cultural && civInfo.cities.size > 3) return - if (civInfo.cities.any() - && civInfo.getHappiness() > civInfo.cities.size + 5 - && civInfo.getCivUnits().none { it.name == Constants.settler } - && civInfo.cities.none { it.cityConstructions.currentConstructionFromQueue == Constants.settler }) { + if (civInfo.cities.none() || civInfo.getHappiness() <= civInfo.cities.size + 5) return + + val settlerUnits = civInfo.gameInfo.ruleSet.units.values + .filter { it.uniques.contains(Constants.settlerUnique) && it.isBuildable(civInfo) } + if (settlerUnits.isEmpty()) return + if (civInfo.getCivUnits().none { it.hasUnique(Constants.settlerUnique) } + && civInfo.cities.none { + val currentConstruction = it.cityConstructions.getCurrentConstruction() + currentConstruction is BaseUnit && currentConstruction.uniques.contains(Constants.settlerUnique) + }) { val bestCity = civInfo.cities.maxBy { it.cityStats.currentCityStats.production }!! if (bestCity.cityConstructions.builtBuildings.size > 1) // 2 buildings or more, otherwise focus on self first - bestCity.cityConstructions.currentConstructionFromQueue = Constants.settler + bestCity.cityConstructions.currentConstructionFromQueue = settlerUnits.minBy { it.cost }!!.name } } diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 9050cbf5..b3b459f0 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -91,7 +91,7 @@ object UnitAutomation { throw IllegalStateException("Barbarians is not allowed here.") if(unit.type.isCivilian()) { - if (unit.name == Constants.settler) + if (unit.hasUnique(Constants.settlerUnique)) return SpecificUnitAutomation.automateSettlerActions(unit) if (unit.hasUnique(Constants.workerUnique)) @@ -261,7 +261,8 @@ object UnitAutomation { val settlerOrGreatPersonToAccompany = unit.civInfo.getCivUnits() .firstOrNull { val tile = it.currentTile - (it.name == Constants.settler || it.name in GreatPersonManager().statToGreatPersonMapping.values) + it.type==UnitType.Civilian && + (it.hasUnique(Constants.settlerUnique) || unit.name in GreatPersonManager().statToGreatPersonMapping.values) && tile.militaryUnit == null && unit.movement.canMoveTo(tile) && unit.movement.canReach(tile) } if (settlerOrGreatPersonToAccompany == null) return false diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 94aa475e..ac9eab69 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -15,6 +15,7 @@ import com.unciv.ui.utils.withItem import com.unciv.ui.utils.withoutItem import java.util.* import kotlin.collections.ArrayList +import kotlin.math.ceil import kotlin.math.roundToInt /** @@ -194,7 +195,7 @@ class CityConstructions { // Since this is only ever used for UI purposes, I feel fine with having it be a bit inefficient // and recalculating the entire city stats // We don't want to change our current construction queue - what if we have an empty queue, too many changes to check for - - // So we ust clone it and see what would happen f that was our construction + // So we must clone it and see what would happen if that was our construction val cityConstructionsClone = clone() cityConstructionsClone.currentConstructionFromQueue = constructionName cityConstructionsClone.cityInfo = cityInfo @@ -210,7 +211,7 @@ class CityConstructions { var production = cityStatsForConstruction.production.roundToInt() if (constructionName == Constants.settler) production += cityStatsForConstruction.food.toInt() - return Math.ceil((workLeft / production.toDouble())).toInt() + return ceil(workLeft / production.toDouble()).toInt() } //endregion diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index ff701e19..77df60bf 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -219,34 +219,26 @@ class CityInfo { return 0 } - fun isGrowing(): Boolean { - return foodForNextTurn() > 0 && cityConstructions.currentConstructionFromQueue != Constants.settler - } + fun isGrowing() = foodForNextTurn() > 0 - fun isStarving(): Boolean = foodForNextTurn() < 0 + fun isStarving() = foodForNextTurn() < 0 private fun foodForNextTurn() = cityStats.currentCityStats.food.roundToInt() /** Take null to mean infinity. */ fun getNumTurnsToNewPopulation(): Int? { - if (isGrowing()) { - val roundedFoodPerTurn = foodForNextTurn().toFloat() - val remainingFood = population.getFoodToNextPopulation() - population.foodStored - var turnsToGrowth = ceil( remainingFood / roundedFoodPerTurn).toInt() - if (turnsToGrowth < 1) turnsToGrowth = 1 - return turnsToGrowth - } - - return null + if (!isGrowing()) return null + val roundedFoodPerTurn = foodForNextTurn().toFloat() + val remainingFood = population.getFoodToNextPopulation() - population.foodStored + var turnsToGrowth = ceil( remainingFood / roundedFoodPerTurn).toInt() + if (turnsToGrowth < 1) turnsToGrowth = 1 + return turnsToGrowth } /** Take null to mean infinity. */ fun getNumTurnsToStarvation(): Int? { - if (isStarving()) { - return population.foodStored / -foodForNextTurn() + 1 - } - - return null + if (!isStarving()) return null + return population.foodStored / -foodForNextTurn() + 1 } fun containsBuildingUnique(unique:String) = cityConstructions.getBuiltBuildings().any { it.uniques.contains(unique) } diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 734e4b9e..f5ca6809 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -277,7 +277,7 @@ class CivilizationInfo { if (gameInfo.gameParameters.victoryTypes.contains(VictoryType.Scenario)) return cities.isEmpty() && getCivUnits().none() else return cities.isEmpty() // No cities - && (citiesCreated > 0 || !getCivUnits().any { it.name == Constants.settler }) + && (citiesCreated > 0 || !getCivUnits().any { it.hasUnique(Constants.settlerUnique) }) } fun getEra(): String { diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 4770bb37..a30f3990 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -137,8 +137,8 @@ class BaseUnit : INamed, IConstruction { if (uniques.contains("Requires Manhattan Project") && !civInfo.hasUnique("Enables nuclear weapon")) return "Requires Manhattan Project" if (requiredResource!=null && !civInfo.hasResource(requiredResource!!) && !civInfo.gameInfo.gameParameters.godMode) return "Consumes 1 [$requiredResource]" - if (name == Constants.settler && civInfo.isCityState()) return "No settler for city-states" - if (name == Constants.settler && civInfo.isOneCityChallenger()) return "No settler for players in One City Challenge" + if (uniques.contains(Constants.settlerUnique) && civInfo.isCityState()) return "No settler for city-states" + if (uniques.contains(Constants.settlerUnique) && civInfo.isOneCityChallenger()) return "No settler for players in One City Challenge" return "" } diff --git a/core/src/com/unciv/models/translations/TranslationFileWriter.kt b/core/src/com/unciv/models/translations/TranslationFileWriter.kt index d1eb4c29..1c055012 100644 --- a/core/src/com/unciv/models/translations/TranslationFileWriter.kt +++ b/core/src/com/unciv/models/translations/TranslationFileWriter.kt @@ -209,6 +209,7 @@ object TranslationFileWriter { RulesetCache.getBaseRuleset().tileImprovements.containsKey(parameter) -> "tileImprovement" RulesetCache.getBaseRuleset().tileResources.containsKey(parameter) -> "resource" RulesetCache.getBaseRuleset().technologies.containsKey(parameter) -> "tech" + RulesetCache.getBaseRuleset().unitPromotions.containsKey(parameter) -> "promotion" RulesetCache.getBaseRuleset().buildings.containsKey(parameter) || parameter == "Wonders" -> "building"