mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-26 07:39:44 +07:00
Avoid Growth and Food Ranking Improvements (#12356)
* Code changes * Clean up code for clarity and suggestions * More commenting to clarify * Remove redundant -1 * Put back weights into Stats Add in small floating values for tie breaker preferences
This commit is contained in:
@ -21,6 +21,8 @@ import com.unciv.models.ruleset.unit.BaseUnit
|
|||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
object Automation {
|
object Automation {
|
||||||
|
|
||||||
@ -64,33 +66,51 @@ object Automation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val surplusFood = city.cityStats.currentCityStats[Stat.Food]
|
val surplusFood = city.cityStats.currentCityStats[Stat.Food]
|
||||||
|
val starving = surplusFood < 0
|
||||||
// If current Production converts Food into Production, then calculate increased Production Yield
|
// If current Production converts Food into Production, then calculate increased Production Yield
|
||||||
if (cityStatsObj.canConvertFoodToProduction(surplusFood, city.cityConstructions.getCurrentConstruction())) {
|
if (cityStatsObj.canConvertFoodToProduction(surplusFood, city.cityConstructions.getCurrentConstruction())) {
|
||||||
// calculate delta increase of food->prod. This isn't linear
|
// calculate delta increase of food->prod. This isn't linear
|
||||||
yieldStats.production += cityStatsObj.getProductionFromExcessiveFood(surplusFood+yieldStats.food) - cityStatsObj.getProductionFromExcessiveFood(surplusFood)
|
yieldStats.production += cityStatsObj.getProductionFromExcessiveFood(surplusFood+yieldStats.food) - cityStatsObj.getProductionFromExcessiveFood(surplusFood)
|
||||||
yieldStats.food = 0f // all food goes to 0
|
yieldStats.food = 0f // all food goes to 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split Food Yield into feedFood, amount needed to not Starve
|
||||||
|
// and growthFood, any amount above that
|
||||||
|
var feedFood = 0f
|
||||||
|
if (starving)
|
||||||
|
feedFood = min(yieldStats.food, -surplusFood).coerceAtLeast(0f)
|
||||||
|
var growthFood = yieldStats.food - feedFood // how much extra Food we yield
|
||||||
|
// Avoid Growth, only count Food that gets you not-starving, but no more
|
||||||
|
if (city.avoidGrowth) {
|
||||||
|
growthFood = 0f
|
||||||
|
}
|
||||||
|
yieldStats.food = 1f
|
||||||
|
|
||||||
// Apply base weights
|
// Apply base weights
|
||||||
yieldStats.applyRankingWeights()
|
yieldStats.applyRankingWeights()
|
||||||
|
|
||||||
if (surplusFood > 0 && city.avoidGrowth) {
|
val foodBaseWeight = yieldStats.food
|
||||||
yieldStats.food = 0f // don't need more food!
|
|
||||||
} else if (cityAIFocus in CityFocus.zeroFoodFocuses) {
|
// If starving, need Food, so feedFood > 0
|
||||||
|
// scale feedFood by 14(base weight)*8(super important)
|
||||||
|
// By only scaling what we need to reach Not Starving by x8, we can pick a tile that gives
|
||||||
|
// exactly as much Food as we need to Not Starve that also has other good yields instead of
|
||||||
|
// always picking the Highest Food tile until Not Starving
|
||||||
|
yieldStats.food = feedFood * (foodBaseWeight * 8)
|
||||||
|
// growthFood is any additional food not required to meet Starvation
|
||||||
|
if (cityAIFocus in CityFocus.zeroFoodFocuses) {
|
||||||
// Focus on non-food/growth
|
// Focus on non-food/growth
|
||||||
if (surplusFood < 0)
|
// Reduce excess food focus to prevent Happiness spiral
|
||||||
yieldStats.food *= 8 // Starving, need Food, get to 0
|
if (city.civ.getHappiness() < 1)
|
||||||
else if (city.civ.getHappiness() < 1)
|
yieldStats.food += growthFood * (foodBaseWeight / 4)
|
||||||
yieldStats.food /= 4
|
} else {
|
||||||
} else if (!city.avoidGrowth) {
|
|
||||||
// NoFocus or Food/Growth Focus.
|
// NoFocus or Food/Growth Focus.
|
||||||
if (surplusFood < 0)
|
// When Happy, EmperorPenguin has run sims comparing weights
|
||||||
yieldStats.food *= 8 // Starving, need Food, get to 0
|
// 1.5f is preferred,
|
||||||
else if (city.civ.getHappiness() > -1)
|
// but 2 provides more protection against badly configured personalities
|
||||||
yieldStats.food *= 2 //1.5f is preferred, but 2 provides more protection against badly configured personalities
|
// If unhappy, see above
|
||||||
else if (city.civ.getHappiness() < 0) {
|
val growthFoodScaling = if (city.civ.getHappiness() >= 0) foodBaseWeight * 2 else foodBaseWeight / 4
|
||||||
// 75% of excess food is wasted when in negative happiness
|
yieldStats.food += growthFood * growthFoodScaling
|
||||||
yieldStats.food /= 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (city.population.population < 10) {
|
if (city.population.population < 10) {
|
||||||
|
@ -62,7 +62,7 @@ enum class CityFocus(
|
|||||||
KeyboardBinding.None
|
KeyboardBinding.None
|
||||||
|
|
||||||
open fun getStatMultiplier(stat: Stat) = when (this.stat) {
|
open fun getStatMultiplier(stat: Stat) = when (this.stat) {
|
||||||
stat -> 3f
|
stat -> 3.05f // on ties, prefer the Focus
|
||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +147,9 @@ open class Stats(
|
|||||||
* Apply weighting for Production Ranking */
|
* Apply weighting for Production Ranking */
|
||||||
fun applyRankingWeights() {
|
fun applyRankingWeights() {
|
||||||
food *= 14
|
food *= 14
|
||||||
production *= 12
|
production *= 12.01f // tie break Production vs gold
|
||||||
gold *= 6 // 2 gold worth about 1 production
|
gold *= 6 // 2 gold worth about 1 production
|
||||||
science *= 9
|
science *= 9.01f // 4 Science better than 3 Production
|
||||||
culture *= 8
|
culture *= 8
|
||||||
happiness *= 10 // base
|
happiness *= 10 // base
|
||||||
faith *= 7
|
faith *= 7
|
||||||
|
Reference in New Issue
Block a user