diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 6a1c4c9ac9..c6e4628846 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -9,6 +9,7 @@ import com.unciv.logic.map.mapunit.MapUnit import com.unciv.logic.map.tile.Tile import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.INonPerpetualConstruction +import com.unciv.models.ruleset.PerpetualConstruction import com.unciv.models.ruleset.Victory import com.unciv.models.ruleset.nation.PersonalityValue import com.unciv.models.ruleset.tile.ResourceType @@ -48,6 +49,9 @@ object Automation { val yieldStats = stats.clone() val civPersonality = city.civ.getPersonality() val cityStatsObj = city.cityStats + val civInfo = city.civ + val allTechsAreResearched = civInfo.gameInfo.ruleset.technologies.values + .all { civInfo.tech.isResearched(it.name) || !civInfo.tech.canBeResearched(it.name)} if (areWeRankingSpecialist) { // If you have the Food Bonus, count as 1 extra food production (base is 2food) @@ -99,6 +103,21 @@ object Automation { if (city.civ.getHappiness() < 0) yieldStats.happiness *= 2 + } + + if (city.civ.getHappiness() < 0) { + // 75% of excess food is wasted when in negative happiness + yieldStats.food /= 4 + } + + if (allTechsAreResearched) { + // Science is useless at this point + yieldStats.science *= 0 + } + + if (city.cityConstructions.getCurrentConstruction() is PerpetualConstruction) { + // With 4:1 conversion of production to gold, production is overvalued by a factor (12*4)/8 = 6 + yieldStats.production /= 6 } for (stat in Stat.values()) { diff --git a/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt b/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt index b4e903b630..05ae855005 100644 --- a/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt +++ b/core/src/com/unciv/logic/automation/city/ConstructionAutomation.kt @@ -165,6 +165,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) { private fun addMilitaryUnitChoice() { if (!isAtWar && !cityIsOverAverageProduction) return // don't make any military units here. Infrastructure first! + if (civInfo.stats.getUnitSupplyDeficit() > 0) return // we don't want more units if it's already hurting our empire + // todo: add worker disbandment and consumption of great persons if under attack & short on unit supply if (!isAtWar && (civInfo.stats.statsForNextTurn.gold < 0 || militaryUnits > max(7, cities * 5))) return if (civInfo.gold < -50) return @@ -263,6 +265,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) { private fun addBuildingChoices() { for (building in buildings.filterBuildable()) { if (building.isWonder && city.isPuppet) continue + // We shouldn't try to build wonders in undeveloped empires + if (building.isWonder && civInfo.cities.size < 3) continue addChoice(relativeCostEffectiveness, building.name, getValueOfBuilding(building)) } } diff --git a/core/src/com/unciv/logic/automation/unit/CityLocationTileRanker.kt b/core/src/com/unciv/logic/automation/unit/CityLocationTileRanker.kt index 2b00c5ccf1..e353be3927 100644 --- a/core/src/com/unciv/logic/automation/unit/CityLocationTileRanker.kt +++ b/core/src/com/unciv/logic/automation/unit/CityLocationTileRanker.kt @@ -84,11 +84,17 @@ object CityLocationTileRanker { tileValue += getDistanceToCityModifier(newCityTile, nearbyCities, civ) val onCoast = newCityTile.isCoastalTile() + val onHill = newCityTile.isHill() + val isNextToMountain = newCityTile.isAdjacentTo("Mountain") // Only count a luxary resource that we don't have yet as unique once val newUniqueLuxuryResources = HashSet() - if (onCoast) tileValue += 8 - if (newCityTile.isAdjacentToRiver()) tileValue += 10 + if (onCoast) tileValue += 3 + // Hills are free production and defence + if (onHill) tileValue += 7 + // Observatories are good, but current implementation no mod-friendly + if (isNextToMountain) tileValue += 5 + if (newCityTile.isAdjacentToRiver()) tileValue += 14 if (newCityTile.terrainHasUnique(UniqueType.FreshWater)) tileValue += 5 // We want to found the city on an oasis because it can't be improved otherwise if (newCityTile.terrainHasUnique(UniqueType.Unbuildable)) tileValue += 3 @@ -118,25 +124,15 @@ object CityLocationTileRanker { // If it is not higher the settler may get stuck when it ranks the same tile differently // as it moves away from the city and doesn't include it in the calculation // and values it higher than when it moves closer to the city - distanceToCity == 7 -> 5f // Perfect location, there aren't any unused tiles in between - distanceToCity == 6 -> -4f - distanceToCity == 5 -> -8f - distanceToCity == 4 -> -20f + distanceToCity == 7 -> 2f + distanceToCity == 6 -> 4f + distanceToCity == 5 -> 8f // Settling further away sacrifices tempo + distanceToCity == 4 -> 6f distanceToCity == 3 -> -25f distanceToCity < 3 -> -30f // Even if it is a mod that lets us settle closer, lets still not do it else -> 0f } - // Bigger cities will expand more so we want to stay away from them - // Reduces the chance that we don't settle at the begining - distanceToCityModifier *= when { - city.population.population >= 12 -> 2f - city.population.population >= 8 -> 1.5f - city.population.population >= 3 -> 1.2f - else -> 1f - } - // It is worse to settle cities near our own compare to near another civ - // Do not settle near our capital unless really necessary - // Having a strong capital is esential to constructing wonders + // We want a defensive ring around our capital if (city.civ == civ) distanceToCityModifier *= if (city.isCapital()) 2 else 1 modifier += distanceToCityModifier }