mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-13 19:39:34 +07:00
AI worker improvements (#12153)
* 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 * AI changes for humans * Fix puppet focus * Update Automation.kt * Puppet focus * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Automation.kt * Update Stats.kt * Update CityTurnManager.kt * Remove specialist science modifier * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update CivilianUnitAutomation.kt * Update ReligionAutomation.kt * Worker prioritization Workers are valuable in expand cities. * Update ConstructionAutomation.kt Food always important, it's rarely good to skip e.g. granary if we're on 6 pop. * Update ConstructionAutomation.kt Should achieve about the same with less lines of code. * Update Automation.kt * Update ConstructionAutomation.kt * Update Policies.json * Update Policies.json * Update Policies.json * Update ConstructionAutomation.kt * Update Policies.json * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Update ReligionAutomation.kt * Rename Crop Yield to Growth * Update worker usage
This commit is contained in:
parent
e8565b0b6f
commit
1009669126
@ -470,16 +470,16 @@ object Automation {
|
||||
|
||||
fun rankStatsValue(stats: Stats, civInfo: Civilization): Float {
|
||||
var rank = 0.0f
|
||||
rank += if (stats.food <= 2)
|
||||
(stats.food * 1.2f) //food get more value to keep city growing
|
||||
else
|
||||
(2.4f + (stats.food - 2) / 2) // 1.2 point for each food up to 2, from there on half a point
|
||||
rank += stats.food * 1.2f //food get more value to keep city growing
|
||||
|
||||
rank += if (civInfo.gold < 0 && civInfo.stats.statsForNextTurn.gold <= 0)
|
||||
stats.gold
|
||||
stats.gold //build more gold infrastructure if in serious gold problems
|
||||
// This could lead to oscilliatory behaviour however: gold problem -> build trade post -> no gold problem -> replace trade posts -> gold problem
|
||||
else
|
||||
stats.gold / 3 // 3 gold is much worse than 2 production
|
||||
|
||||
stats.gold / 3 // Gold is valued less than is the case for citizen assignment,
|
||||
//otherwise the AI would replace tiles with trade posts upon entering a golden age,
|
||||
//and replace the trade post again when the golden age ends.
|
||||
// We need a way to take golden age gold into account before the GA actually takes place
|
||||
rank += stats.happiness
|
||||
rank += stats.production
|
||||
rank += stats.science
|
||||
|
@ -165,6 +165,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
||||
|
||||
private fun addMilitaryUnitChoice() {
|
||||
if (!isAtWar && !cityIsOverAverageProduction) return // don't make any military units here. Infrastructure first!
|
||||
// There is a risk however, that these cities run out of things to build, and start to construct nothing
|
||||
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
|
||||
@ -244,8 +245,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
||||
}.filterBuildable()
|
||||
if (workerEquivalents.none()) return // for mods with no worker units
|
||||
|
||||
// Dedicate a worker for the first 5 cities, from then on only build another worker for every 2 cities.
|
||||
val numberOfWorkersWeWant = if (cities <= 5) cities else 5 + (cities - 5 / 2)
|
||||
// Dedicate 1.5 workers for the first 5 cities, from then on only build one worker for every city.
|
||||
val numberOfWorkersWeWant = if (cities <= 5) (cities * 1.5f) else 7.5f + ((cities - 5))
|
||||
|
||||
if (workers < numberOfWorkersWeWant) {
|
||||
val modifier = numberOfWorkersWeWant / (workers + 0.4f) // The worse our worker to city ratio is, the more desperate we are
|
||||
@ -266,7 +267,8 @@ class ConstructionAutomation(val cityConstructions: CityConstructions) {
|
||||
val localUniqueCache = LocalUniqueCache()
|
||||
for (building in buildings.filterBuildable()) {
|
||||
if (building.isWonder && city.isPuppet) continue
|
||||
// We shouldn't try to build wonders in undeveloped empires
|
||||
// We shouldn't try to build wonders in undeveloped cities and empires
|
||||
if (building.isWonder && !cityIsOverAverageProduction)
|
||||
if (building.isWonder && civInfo.cities.size < 3) continue
|
||||
addChoice(relativeCostEffectiveness, building.name, getValueOfBuilding(building, localUniqueCache))
|
||||
}
|
||||
|
@ -528,9 +528,6 @@ object NextTurnAutomation {
|
||||
if (civInfo.isCityState) return
|
||||
if (civInfo.isOneCityChallenger()) return
|
||||
if (civInfo.isAtWar()) return // don't train settlers when you could be training troops.
|
||||
if (civInfo.wantsToFocusOn(Victory.Focus.Culture) && civInfo.cities.size > 3 &&
|
||||
civInfo.getPersonality().isNeutralPersonality)
|
||||
return
|
||||
if (civInfo.cities.none()) return
|
||||
if (civInfo.getHappiness() <= civInfo.cities.size) return
|
||||
|
||||
|
@ -102,9 +102,8 @@ object CivilianUnitAutomation {
|
||||
return
|
||||
}
|
||||
|
||||
// Great engineer -> Try to speed up wonder construction if late game
|
||||
if (isLateGame &&
|
||||
(unit.hasUnique(UniqueType.CanSpeedupConstruction)
|
||||
// Great engineer -> Try to speed up wonder construction
|
||||
if ((unit.hasUnique(UniqueType.CanSpeedupConstruction)
|
||||
|| unit.hasUnique(UniqueType.CanSpeedupWonderConstruction))) {
|
||||
val wonderCanBeSpedUpEventually = SpecificUnitAutomation.speedupWonderConstruction(unit)
|
||||
if (wonderCanBeSpedUpEventually)
|
||||
|
@ -18,6 +18,7 @@ import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActions
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsFromUniques
|
||||
@ -74,8 +75,8 @@ class WorkerAutomation(
|
||||
val currentTile = unit.getTile()
|
||||
// Must be called before any getPriority checks to guarantee the local road cache is processed
|
||||
val citiesToConnect = roadBetweenCitiesAutomation.getNearbyCitiesToConnect(unit)
|
||||
// Shortcut, we are working a good tile (like resource) and don't need to check for other tiles to work
|
||||
if (!dangerousTiles.contains(currentTile) && getFullPriority(unit.getTile(), unit, localUniqueCache) >= 10
|
||||
// Shortcut, we are working a suitable tile, and we're better off minimizing worker-turns by finishing everything on this tile
|
||||
if (!dangerousTiles.contains(currentTile) && getFullPriority(unit.getTile(), unit, localUniqueCache) >= 2
|
||||
&& currentTile.improvementInProgress != null) {
|
||||
return
|
||||
}
|
||||
@ -160,7 +161,7 @@ class WorkerAutomation(
|
||||
}
|
||||
|
||||
// Nothing to do, try again to connect cities
|
||||
if (civInfo.stats.statsForNextTurn.gold > 10 && roadBetweenCitiesAutomation.tryConnectingCities(unit, citiesToConnect)) return
|
||||
if (roadBetweenCitiesAutomation.tryConnectingCities(unit, citiesToConnect)) return
|
||||
|
||||
|
||||
debug("WorkerAutomation: %s -> nothing to do", unit.toString())
|
||||
@ -231,24 +232,22 @@ class WorkerAutomation(
|
||||
if (tile.providesYield()) priority += 2
|
||||
if (tile.isPillaged()) priority += 1
|
||||
if (tile.hasFalloutEquivalent()) priority += 1
|
||||
if (tile.terrainFeatures.isNotEmpty() && tile.lastTerrain.hasUnique("Provides a one-time Production bonus to the closest city when cut down")) priority += 1 // removing our forests is good for tempo
|
||||
if (tile.terrainHasUnique(UniqueType.FreshWater)) priority += 1 // we want our farms up when unlocking Civil Service
|
||||
}
|
||||
// give a minor priority to tiles that we could expand onto
|
||||
else if (tile.getOwner() == null && tile.neighbors.any { it.getOwner() == civInfo })
|
||||
priority += 1
|
||||
|
||||
if (priority <= 0 && tile.hasViewableResource(civInfo)) {
|
||||
if (tile.hasViewableResource(civInfo)) {
|
||||
priority += 1
|
||||
// New Resources are great!
|
||||
if (tile.tileResource.resourceType != ResourceType.Bonus
|
||||
&& !civInfo.hasResource(tile.resource!!))
|
||||
priority += 2
|
||||
if (tile.tileResource.resourceType == ResourceType.Luxury) priority += 3
|
||||
//luxuries are more important than other types of resources
|
||||
}
|
||||
if (tile in roadBetweenCitiesAutomation.tilesOfRoadsMap) priority += when {
|
||||
civInfo.stats.statsForNextTurn.gold <= 5 -> 0
|
||||
civInfo.stats.statsForNextTurn.gold <= 10 -> 1
|
||||
civInfo.stats.statsForNextTurn.gold <= 30 -> 2
|
||||
else -> 3
|
||||
}
|
||||
|
||||
if (tile in roadBetweenCitiesAutomation.tilesOfRoadsMap)
|
||||
priority += 3
|
||||
|
||||
tileRankings[tile] = TileImprovementRank(priority)
|
||||
return priority + unitSpecificPriority
|
||||
}
|
||||
@ -357,9 +356,10 @@ class WorkerAutomation(
|
||||
// After gathering all the data, we conduct the hierarchy in one place
|
||||
val improvementString = when {
|
||||
bestBuildableImprovement != null && bestBuildableImprovement.isRoad() -> bestBuildableImprovement.name
|
||||
improvementStringForResource != null -> if (improvementStringForResource==tile.improvement) null else improvementStringForResource
|
||||
// For bonus resources we just want the highest-yield improvement, not necessarily the resource-yielding improvement
|
||||
improvementStringForResource != null && tile.tileResource.resourceType != ResourceType.Bonus -> if (improvementStringForResource==tile.improvement) null else improvementStringForResource
|
||||
// If this is a resource that HAS an improvement that we can see, but this unit can't build it, don't waste your time
|
||||
tile.resource != null && tile.hasViewableResource(civInfo) && tile.tileResource.getImprovements().any() -> return null
|
||||
tile.resource != null && tile.hasViewableResource(civInfo) && tile.tileResource.resourceType != ResourceType.Bonus && tile.tileResource.getImprovements().any() -> return null
|
||||
bestBuildableImprovement == null -> null
|
||||
|
||||
tile.improvement != null &&
|
||||
@ -386,10 +386,7 @@ class WorkerAutomation(
|
||||
if (improvement.isRoad() && roadBetweenCitiesAutomation.bestRoadAvailable.improvement(ruleSet) == improvement
|
||||
&& tile in roadBetweenCitiesAutomation.tilesOfRoadsMap) {
|
||||
val roadPlan = roadBetweenCitiesAutomation.tilesOfRoadsMap[tile]!!
|
||||
var value = roadPlan.priority
|
||||
if (civInfo.stats.statsForNextTurn.gold >= 20)
|
||||
// Higher priority if we are closer to connecting the city
|
||||
value += (5 - roadPlan.numberOfRoadsToBuild).coerceAtLeast(0)
|
||||
val value = (roadPlan.priority - 5) // We want some forest chopping and farm building first if the road doesn't have high priority
|
||||
return value
|
||||
}
|
||||
|
||||
@ -424,6 +421,8 @@ class WorkerAutomation(
|
||||
stats.add(statDiff)
|
||||
// Take into account that the resource might be improved by the *final* improvement
|
||||
isResourceImprovedByNewImprovement = newTile.resource != null && newTile.tileResource.isImprovedBy(wantedFinalImprovement.name)
|
||||
if (tile.terrainFeatures.isNotEmpty() && tile.lastTerrain.hasUnique("Provides a one-time Production bonus to the closest city when cut down"))
|
||||
stats.add(Stat.Production, 0.5f) //We're gaining tempo by chopping the forest, adding an imaginary yield per turn is a way to correct for this
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user