All improvement placing units are automated in the same way - this allows for the AI to control modded units that place other improvements!

This commit is contained in:
Yair Morgenstern 2020-07-28 19:26:02 +03:00
parent 9d2cc90ccd
commit 5fbfa637f2
4 changed files with 45 additions and 35 deletions

View file

@ -1290,32 +1290,32 @@
{ {
"name": "Great Artist", "name": "Great Artist",
"unitType": "Civilian", "unitType": "Civilian",
"uniques": ["Can start an 8-turn golden age","Can build improvement: Landmark", "Unbuildable"], "uniques": ["Can start an 8-turn golden age","Can construct [Landmark]", "Unbuildable"],
"movement": 2 "movement": 2
}, },
{ {
"name": "Great Scientist", "name": "Great Scientist",
"unitType": "Civilian", "unitType": "Civilian",
"uniques": ["Can hurry technology research","Can build improvement: Academy", "Unbuildable"], "uniques": ["Can hurry technology research","Can construct [Academy]", "Unbuildable"],
"movement": 2 "movement": 2
}, },
{ {
"name": "Great Merchant", "name": "Great Merchant",
"unitType": "Civilian", "unitType": "Civilian",
"uniques": ["Can undertake a trade mission with City-State, giving a large sum of gold and [30] Influence", "uniques": ["Can undertake a trade mission with City-State, giving a large sum of gold and [30] Influence",
"Can build improvement: Customs house", "Unbuildable"], "Can construct [Customs house]", "Unbuildable"],
"movement": 2 "movement": 2
}, },
{ {
"name": "Great Engineer", "name": "Great Engineer",
"unitType": "Civilian", "unitType": "Civilian",
"uniques": ["Can speed up construction of a wonder","Can build improvement: Manufactory", "Unbuildable"], "uniques": ["Can speed up construction of a wonder","Can construct [Manufactory]", "Unbuildable"],
"movement": 2 "movement": 2
}, },
{ {
"name": "Great General", "name": "Great General",
"unitType": "Civilian", "unitType": "Civilian",
"uniques": ["Can start an 8-turn golden age","Bonus for units in 2 tile radius 15%", "Can build improvement: Citadel", "Unbuildable"], "uniques": ["Can start an 8-turn golden age","Bonus for units in 2 tile radius 15%", "Can construct [Citadel]", "Unbuildable"],
"movement": 2 "movement": 2
}, },
{ {

View file

@ -10,6 +10,8 @@ import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.tile.TileResource
import com.unciv.models.stats.Stats import com.unciv.models.stats.Stats
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.UnitActions
object SpecificUnitAutomation { object SpecificUnitAutomation {
@ -79,18 +81,18 @@ object SpecificUnitAutomation {
if (owner != null) if (owner != null)
distance - WorkerAutomation(unit).getPriority(it, owner) distance - WorkerAutomation(unit).getPriority(it, owner)
else distance } else distance }
.firstOrNull{ unit.movement.canReach(it) } // canReach is perfrmance-heavy and always a last resort .firstOrNull{ unit.movement.canReach(it) } // canReach is performance-heavy and always a last resort
// if there is a good tile to steal - go there // if there is a good tile to steal - go there
if (tileToSteal != null) { if (tileToSteal != null) {
unit.movement.headTowards(tileToSteal) unit.movement.headTowards(tileToSteal)
if (unit.currentMovement > 0 && unit.currentTile == tileToSteal) if (unit.currentMovement > 0 && unit.currentTile == tileToSteal)
UnitActions.getBuildImprovementAction(unit)?.action?.invoke() UnitActions.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
return return
} }
// try to build a citadel // try to build a citadel for defensive purposes
if (WorkerAutomation(unit).evaluateFortPlacement(unit.currentTile, unit.civInfo, true)) { if (WorkerAutomation(unit).evaluateFortPlacement(unit.currentTile, unit.civInfo, true)) {
UnitActions.getBuildImprovementAction(unit)?.action?.invoke() UnitActions.getImprovementConstructionActions(unit,unit.currentTile).firstOrNull()?.action?.invoke()
return return
} }
@ -110,7 +112,7 @@ object SpecificUnitAutomation {
if (tileForCitadel != null) { if (tileForCitadel != null) {
unit.movement.headTowards(tileForCitadel) unit.movement.headTowards(tileForCitadel)
if (unit.currentMovement > 0 && unit.currentTile == tileForCitadel) if (unit.currentMovement > 0 && unit.currentTile == tileForCitadel)
UnitActions.getBuildImprovementAction(unit)?.action?.invoke() UnitActions.getImprovementConstructionActions(unit,unit.currentTile).firstOrNull()?.action?.invoke()
} else } else
unit.movement.headTowards(cityToGarrison) unit.movement.headTowards(cityToGarrison)
return return
@ -190,10 +192,13 @@ object SpecificUnitAutomation {
foundCityAction.action.invoke() foundCityAction.action.invoke()
} }
fun automateGreatPerson(unit: MapUnit) { fun automateImprovementPlacer(unit: MapUnit) {
if (unit.getTile().militaryUnit == null) return // Don't move until you're accompanied by a military unit if (unit.getTile().militaryUnit == null) return // Don't move until you're accompanied by a military unit
val relatedStat = GreatPersonManager().statToGreatPersonMapping.entries.first { it.value == unit.name }.key val improvementName = unit.getUniques().first { it.equalsPlaceholderText("Can construct []") }
.getPlaceholderParameters()[0]
val improvement = unit.civInfo.gameInfo.ruleSet.tileImprovements[improvementName]!!
val relatedStat = improvement.toHashMap().maxBy { it.value }!!.key
val citiesByStatBoost = unit.civInfo.cities.sortedByDescending { val citiesByStatBoost = unit.civInfo.cities.sortedByDescending {
val stats = Stats() val stats = Stats()
@ -221,7 +226,7 @@ object SpecificUnitAutomation {
unit.movement.headTowards(chosenTile) unit.movement.headTowards(chosenTile)
if (unit.currentTile == chosenTile) if (unit.currentTile == chosenTile)
UnitActions.getBuildImprovementAction(unit)?.action?.invoke() UnitActions.getImprovementConstructionActions(unit, unit.currentTile).firstOrNull()?.action?.invoke()
return return
} }
} }

View file

@ -4,12 +4,12 @@ import com.badlogic.gdx.graphics.Color
import com.unciv.Constants import com.unciv.Constants
import com.unciv.logic.battle.* import com.unciv.logic.battle.*
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.GreatPersonManager import com.unciv.logic.civilization.GreatPersonManager
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.models.ruleset.unit.UnitType import com.unciv.models.ruleset.unit.UnitType
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.ui.worldscreen.unit.UnitActions import com.unciv.ui.worldscreen.unit.UnitActions
object UnitAutomation { object UnitAutomation {
@ -90,6 +90,7 @@ object UnitAutomation {
if (unit.civInfo.isBarbarian()) if (unit.civInfo.isBarbarian())
throw IllegalStateException("Barbarians is not allowed here.") throw IllegalStateException("Barbarians is not allowed here.")
if(unit.type==UnitType.Civilian) {
if (unit.name == Constants.settler) if (unit.name == Constants.settler)
return SpecificUnitAutomation.automateSettlerActions(unit) return SpecificUnitAutomation.automateSettlerActions(unit)
@ -102,6 +103,12 @@ object UnitAutomation {
if (unit.name == Constants.greatGeneral || unit.baseUnit.replaces == Constants.greatGeneral) if (unit.name == Constants.greatGeneral || unit.baseUnit.replaces == Constants.greatGeneral)
return SpecificUnitAutomation.automateGreatGeneral(unit) return SpecificUnitAutomation.automateGreatGeneral(unit)
if (unit.getUniques().any { it.equalsPlaceholderText("Can construct []") })
return SpecificUnitAutomation.automateImprovementPlacer(unit) // includes great people plus moddable units
return // The AI doesn't know how to handle unknown civilian units
}
if (unit.type == UnitType.Fighter) if (unit.type == UnitType.Fighter)
return SpecificUnitAutomation.automateFighter(unit) return SpecificUnitAutomation.automateFighter(unit)
@ -112,10 +119,6 @@ object UnitAutomation {
return SpecificUnitAutomation.automateMissile(unit) return SpecificUnitAutomation.automateMissile(unit)
if (unit.name.startsWith("Great")
&& unit.name in GreatPersonManager().statToGreatPersonMapping.values)// So "Great War Infantry" isn't caught here
return SpecificUnitAutomation.automateGreatPerson(unit)
if (tryGoToRuinAndEncampment(unit)) { if (tryGoToRuinAndEncampment(unit)) {
if (unit.currentMovement == 0f) return if (unit.currentMovement == 0f) return
} }

View file

@ -15,6 +15,8 @@ import com.unciv.models.UncivSound
import com.unciv.models.UnitAction import com.unciv.models.UnitAction
import com.unciv.models.UnitActionType import com.unciv.models.UnitActionType
import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.Building
import com.unciv.models.translations.equalsPlaceholderText
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.ImprovementPickerScreen import com.unciv.ui.pickerscreens.ImprovementPickerScreen
import com.unciv.ui.pickerscreens.PromotionPickerScreen import com.unciv.ui.pickerscreens.PromotionPickerScreen
@ -67,11 +69,13 @@ object UnitActions {
addConstructRoadsAction(unit, tile, actionList) addConstructRoadsAction(unit, tile, actionList)
addCreateWaterImprovements(unit, actionList) addCreateWaterImprovements(unit, actionList)
addGreatPersonActions(unit, actionList, tile) addGreatPersonActions(unit, actionList, tile)
actionList += getImprovementConstructionActions(unit, tile)
addDisbandAction(actionList, unit, worldScreen) addDisbandAction(actionList, unit, worldScreen)
return actionList return actionList
} }
private fun addDisbandAction(actionList: ArrayList<UnitAction>, unit: MapUnit, worldScreen: WorldScreen) { private fun addDisbandAction(actionList: ArrayList<UnitAction>, unit: MapUnit, worldScreen: WorldScreen) {
actionList += UnitAction( actionList += UnitAction(
type = UnitActionType.DisbandUnit, type = UnitActionType.DisbandUnit,
@ -347,16 +351,14 @@ object UnitActions {
unit.destroy() unit.destroy()
}.takeIf { canConductTradeMission }) }.takeIf { canConductTradeMission })
} }
val buildImprovementAction = getBuildImprovementAction(unit)
if (buildImprovementAction != null) actionList += buildImprovementAction
} }
fun getBuildImprovementAction(unit: MapUnit): UnitAction? {
val tile = unit.currentTile fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
for (unique in unit.getUniques().filter { it.startsWith("Can build improvement: ") }) { val finalActions = ArrayList<UnitAction>()
val improvementName = unique.replace("Can build improvement: ", "") for (unique in unit.getUniques().filter { it.equalsPlaceholderText("Can construct []") }) {
return UnitAction( val improvementName = unique.getPlaceholderParameters()[0]
finalActions += UnitAction(
type = UnitActionType.Create, type = UnitActionType.Create,
title = "Create [$improvementName]", title = "Create [$improvementName]",
uncivSound = UncivSound.Chimes, uncivSound = UncivSound.Chimes,
@ -384,7 +386,7 @@ object UnitActions {
(improvementName != Constants.citadel || (improvementName != Constants.citadel ||
tile.neighbors.any { it.getOwner() == unit.civInfo })}) tile.neighbors.any { it.getOwner() == unit.civInfo })})
} }
return null return finalActions
} }
private fun takeOverTilesAround(unit: MapUnit) { private fun takeOverTilesAround(unit: MapUnit) {