AI behaviour changes (#11839)

* AI behaviour changes

* Update Automation.kt

* Update Automation.kt

* Update Automation.kt

* Update Automation.kt

* Update Automation.kt

* Update ConstructionAutomation.kt

* Update Automation.kt

* Reverting some changes

* Changes

* revert changes

* revert changes

* revert changes

* revert changes

* Update CityLocationTileRanker.kt

* Citizen assignment for stat conversion

* Update CityLocationTileRanker.kt

* Reduce AI settling

* Avoid AI building units when in negative Supply

* Update CityLocationTileRanker.kt

* Update CityLocationTileRanker.kt

* Update CityLocationTileRanker.kt

* Update ConstructionAutomation.kt

* Update build.gradle.kts

* Update gradle-wrapper.properties

* Update CityLocationTileRanker.kt

* Update CityLocationTileRanker.kt

* Update ConstructionAutomation.kt

* Update CityLocationTileRanker.kt
This commit is contained in:
EmperorPinguin
2024-06-29 23:18:45 +02:00
committed by GitHub
parent 3a16fcb021
commit e3ca17b3bf
3 changed files with 36 additions and 17 deletions

View File

@ -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()) {

View File

@ -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))
}
}

View File

@ -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<String>()
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
}