Mods can handle situations where there is no military unit that is available for construction

This commit is contained in:
Yair Morgenstern 2020-09-04 16:11:48 +03:00
parent 95002bc69b
commit 23a57c711f
3 changed files with 21 additions and 23 deletions

View file

@ -20,29 +20,25 @@ object Automation {
private fun rankStatsForCityWork(stats: Stats, city: CityInfo, foodWeight: Float = 1f): Float {
var rank = 0f
if(city.population.population < 5){
if (city.population.population < 5) {
// "small city" - we care more about food and less about global problems like gold science and culture
rank += stats.food * 1.2f * foodWeight
rank += stats.production
rank += stats.science/2
rank += stats.culture/2
rank += stats.science / 2
rank += stats.culture / 2
rank += stats.gold / 5 // it's barely worth anything at this points
}
else{
if (stats.food <= 2 || city.civInfo.getHappiness() > 5) rank += (stats.food * 1.2f * foodWeight) //food get more value to keep city growing
else rank += ((2.4f + (stats.food - 2) / 2) * foodWeight) // 1.2 point for each food up to 2, from there on half a point
} else {
if (stats.food <= 2 || city.civInfo.getHappiness() > 5) rank += stats.food * 1.2f * foodWeight //food get more value to keep city growing
else rank += (2.4f + (stats.food - 2) / 2) * foodWeight // 1.2 point for each food up to 2, from there on half a point
if (city.civInfo.gold < 0 && city.civInfo.statsForNextTurn.gold <= 0) rank += stats.gold // we have a global problem
else rank += stats.gold / 3 // 3 gold is worse than 2 production
rank += stats.production
rank += stats.science
if (city.tiles.size < 12 || city.civInfo.victoryType() == VictoryType.Cultural){
if (city.tiles.size < 12 || city.civInfo.victoryType() == VictoryType.Cultural) {
rank += stats.culture
}
else{
rank += stats.culture / 2
}
} else rank += stats.culture / 2
}
return rank
}
@ -53,19 +49,20 @@ object Automation {
return rank
}
fun trainMilitaryUnit(city: CityInfo) {
val name = chooseMilitaryUnit(city)
city.cityConstructions.currentConstructionFromQueue = name
fun tryTrainMilitaryUnit(city: CityInfo) {
val chosenUnitName = chooseMilitaryUnit(city)
if (chosenUnitName != null)
city.cityConstructions.currentConstructionFromQueue = chosenUnitName
}
fun chooseMilitaryUnit(city: CityInfo) : String {
fun chooseMilitaryUnit(city: CityInfo) : String? {
var militaryUnits = city.cityConstructions.getConstructableUnits().filter { !it.unitType.isCivilian() }
if (militaryUnits.map { it.name }.contains(city.cityConstructions.currentConstructionFromQueue))
return city.cityConstructions.currentConstructionFromQueue
// This is so that the AI doesn't use all its aluminum on units and have none left for spaceship parts
val aluminum = city.civInfo.getCivResourcesByName()["Aluminum"]
if (aluminum!=null && aluminum < 2) // mods may have no aluminum
if (aluminum != null && aluminum < 2) // mods may have no aluminum
militaryUnits.filter { it.requiredResource != "Aluminum" }
val findWaterConnectedCitiesAndEnemies = BFS(city.getCenterTile()) { it.isWater || it.isCityCenter() }
@ -81,8 +78,9 @@ object Automation {
&& militaryUnits.any { it.unitType == UnitType.Ranged }) // this is for city defence so get an archery unit if we can
chosenUnit = militaryUnits.filter { it.unitType == UnitType.Ranged }.maxBy { it.cost }!!
else { // randomize type of unit and take the most expensive of its kind
val chosenUnitType = militaryUnits.map { it.unitType }.distinct().filterNot { it == UnitType.Scout }.toList().random()
chosenUnit = militaryUnits.filter { it.unitType == chosenUnitType }.maxBy { it.cost }!!
val availableTypes = militaryUnits.map { it.unitType }.distinct().filterNot { it == UnitType.Scout }.toList()
if (availableTypes.isEmpty()) return null
chosenUnit = militaryUnits.filter { it.unitType == availableTypes.random() }.maxBy { it.cost }!!
}
return chosenUnit.name
}

View file

@ -96,10 +96,11 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
}
private fun addMilitaryUnitChoice() {
if(!isAtWar && !cityIsOverAverageProduction) return // don't make any military units here. Infrastructure first!
if (!isAtWar && !cityIsOverAverageProduction) return // don't make any military units here. Infrastructure first!
if ((!isAtWar && civInfo.statsForNextTurn.gold > 0 && militaryUnits < cities * 2)
|| (isAtWar && civInfo.gold > -50)) {
val militaryUnit = Automation.chooseMilitaryUnit(cityInfo)
if (militaryUnit == null) return
val unitsToCitiesRatio = cities.toFloat() / (militaryUnits + 1)
// most buildings and civ units contribute the the civ's growth, military units are anti-growth
var modifier = sqrt(unitsToCitiesRatio) / 2
@ -107,7 +108,7 @@ class ConstructionAutomation(val cityConstructions: CityConstructions){
else if (isAtWar) modifier *= unitsToCitiesRatio * 2
if (!cityIsOverAverageProduction) modifier /= 5 // higher production cities will deal with this
val civilianUnit = cityInfo.getCenterTile().civilianUnit
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

View file

@ -11,7 +11,6 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.logic.map.BFS
import com.unciv.logic.map.MapUnit
import com.unciv.logic.trade.*
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
@ -473,7 +472,7 @@ object NextTurnAutomation{
city.cityConstructions.chooseNextConstruction()
if (city.health < city.getMaxHealth())
Automation.trainMilitaryUnit(city) // override previous decision if city is under attack
Automation.tryTrainMilitaryUnit(city) // override previous decision if city is under attack
}
}