AI now accompanies settlers with military units

AI now picks promotions for promotable units
This commit is contained in:
Yair Morgenstern 2018-06-20 18:30:40 +03:00
parent 3f87cfa3db
commit 05b37dc660
13 changed files with 70 additions and 34 deletions

View File

@ -12,6 +12,14 @@ class UnCivGame : Game() {
var gameInfo: GameInfo = GameInfo()
lateinit var settings : GameSettings
/**
* This exists so that when debugging we can see the entire map.
* Remember to turn this to false before commit and upload!
*/
val viewEntireMapForDebug = false
lateinit var worldScreen: WorldScreen
override fun create() {

View File

@ -81,14 +81,6 @@ class GameInfo {
civInfo.setTransients()
}
val civNameToCiv = civilizations.associateBy ({ it.civName},{it})
for (tile in tileMap.values) {
if (tile.militaryUnit != null) tile.militaryUnit!!.civInfo = civNameToCiv[tile.militaryUnit!!.owner]!!
if (tile.civilianUnit!= null) tile.civilianUnit!!.civInfo = civNameToCiv[tile.civilianUnit!!.owner]!!
}
for (civInfo in civilizations)
for (cityInfo in civInfo.cities)
cityInfo.cityStats.update()

View File

@ -47,19 +47,25 @@ class Automation {
val civilianUnits = mutableListOf<MapUnit>()
for (unit in civInfo.getCivUnits()) {
if(unit.promotions.canBePromoted()){
val availablePromotions = unit.promotions.getAvailablePromotions()
if(availablePromotions.isNotEmpty())
unit.promotions.addPromotion(availablePromotions.getRandom().name)
}
val unitType = unit.getBaseUnit().unitType
if(unitType.isRanged()) rangedUnits.add(unit)
else if(unitType.isMelee()) meleeUnits.add(unit)
else civilianUnits.add(unit)
}
for (unit in civilianUnits) UnitAutomation().automateUnitMoves(unit) // They move first so that combat units can accompany a settler
for (unit in rangedUnits) UnitAutomation().automateUnitMoves(unit)
for (unit in meleeUnits) UnitAutomation().automateUnitMoves(unit)
for (unit in civilianUnits) UnitAutomation().automateUnitMoves(unit)
// train settler?
if (civInfo.cities.any()
&& civInfo.happiness > 2*civInfo.cities.size +5
&& civInfo.happiness > civInfo.cities.size +5
&& civInfo.getCivUnits().none { it.name == "Settler" }
&& civInfo.cities.none { it.cityConstructions.currentConstruction == "Settler" }) {

View File

@ -76,7 +76,16 @@ class UnitAutomation{
return
}
if(unit.name.startsWith("Great")) return // DON'T MOVE A MUSCLE
if(unit.name.startsWith("Great")) return // I don't know what to do with you yet.
// Accompany settlers
val closeTileWithSettler = unit.getDistanceToTiles().keys.firstOrNull{
it.civilianUnit!=null && it.civilianUnit!!.name=="Settler"}
if(closeTileWithSettler != null && unit.canMoveTo(closeTileWithSettler)){
unit.movementAlgs().headTowards(closeTileWithSettler)
return
}
if (unit.health < 50) {
healUnit(unit)
@ -87,7 +96,7 @@ class UnitAutomation{
val enemyTileToAttack = getAttackableEnemies(unit).firstOrNull()
if (enemyTileToAttack != null) {
val setupAction = UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).firstOrNull{ it.name == "Set up" }
val setupAction = UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen).firstOrNull{ it.name == "Set up" }
if(setupAction!=null) setupAction.action()
val enemy = Battle().getMapCombatantOfTile(enemyTileToAttack)!!
@ -160,6 +169,8 @@ class UnitAutomation{
}
private fun automateSettlerActions(unit: MapUnit) {
if(unit.getTile().militaryUnit==null) return // Don;t move until you're accompanied by a military unit
// find best city location within 5 tiles
val tilesNearCities = unit.civInfo.gameInfo.civilizations.flatMap { it.cities }
.flatMap { it.getCenterTile().getTilesInDistance(2) }

View File

@ -127,6 +127,12 @@ class CivilizationInfo {
policies.civInfo = this
tech.civInfo = this
for (unit in getCivUnits()) {
unit.civInfo=this
unit.setTransients()
}
for (cityInfo in cities) {
cityInfo.setTransients()
cityInfo.civInfo = this
@ -180,7 +186,7 @@ class CivilizationInfo {
}
fun getCivUnits(): List<MapUnit> {
return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.civInfo==this }
return gameInfo.tileMap.values.flatMap { it.getUnits() }.filter { it.owner==civName }
}
fun getViewableTiles(): List<TileInfo> {

View File

@ -21,6 +21,10 @@ class MapUnit {
var attacksThisTurn = 0
var promotions = UnitPromotions()
init{
promotions.unit=this
}
fun getBaseUnit(): Unit = GameBasics.Units[name]!!
fun getMovementString(): String = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + maxMovement
fun getTile(): TileInfo {
@ -190,4 +194,8 @@ class MapUnit {
if(hasUnique("Must set up to ranged attack") && action != "Set Up") return false
return true
}
fun setTransients(){
promotions.unit=this
}
}

View File

@ -67,7 +67,7 @@ class TileMap {
fun setTransients() {
for (tileInfo in values){
tileInfo.tileMap = this
if(tileInfo.unit!=null){
if(tileInfo.unit!=null){ // thi is for the old "unit" field which has been replaced.
tileInfo.unit!!.putInTile(tileInfo)
tileInfo.unit=null
}

View File

@ -1,6 +1,10 @@
package com.unciv.logic.map
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.unit.Promotion
class UnitPromotions{
@Transient lateinit var unit:MapUnit
var XP=0
var promotions = HashSet<String>()
var numberOfPromotions = 0 // The number of times this unit has been promoted - some promotions don't come from being promoted but from other things!
@ -13,4 +17,10 @@ class UnitPromotions{
promotions.add(promotionName)
numberOfPromotions++
}
fun getAvailablePromotions(): List<Promotion> {
return GameBasics.UnitPromotions.values
.filter { unit.getBaseUnit().unitType.toString() in it.unitTypes && it.name !in promotions }
.filter { it.prerequisites.isEmpty() || it.prerequisites.all { p->p in promotions } }
}
}

View File

@ -21,13 +21,13 @@ class PromotionPickerScreen(mapUnit: MapUnit) : PickerScreen() {
dispose()
}
val availablePromotions = VerticalGroup()
availablePromotions.space(10f)
val availablePromotionsGroup = VerticalGroup()
availablePromotionsGroup.space(10f)
val unitType = mapUnit.getBaseUnit().unitType
val promotionsForUnitType = GameBasics.UnitPromotions.values.filter { it.unitTypes.contains(unitType.toString()) }
val unitAvailablePromotions = mapUnit.promotions.getAvailablePromotions()
for (promotion in promotionsForUnitType) {
val isPromotionAvailable = promotion.prerequisites.isEmpty()
|| promotion.prerequisites.any { mapUnit.promotions.promotions.contains(it) }
val isPromotionAvailable = promotion in unitAvailablePromotions
val unitHasPromotion = mapUnit.promotions.promotions.contains(promotion.name)
val promotionButton = Button(skin)
@ -48,8 +48,8 @@ class PromotionPickerScreen(mapUnit: MapUnit) : PickerScreen() {
.joinToString(" OR ")
descriptionLabel.setText(descriptionText)
}
availablePromotions.addActor(promotionButton)
availablePromotionsGroup.addActor(promotionButton)
}
topTable.add(availablePromotions)
topTable.add(availablePromotionsGroup)
}
}

View File

@ -15,13 +15,6 @@ import com.unciv.ui.utils.center
import com.unciv.ui.utils.colorFromRGB
open class TileGroup(var tileInfo: TileInfo) : Group() {
/**
* This exists so that when debugging we can see the entire map.
* Remember to turn this to false before commit and upload!
*/
protected val viewEntireMapForDebug = false
protected val hexagon = ImageGetter.getImage("TerrainIcons/Hexagon.png")
protected var terrainFeatureImage:Image?=null
@ -90,7 +83,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
open fun update(isViewable: Boolean) {
hideCircle()
if (!tileInfo.tileMap.gameInfo.getPlayerCivilization().exploredTiles.contains(tileInfo.position)
&& !viewEntireMapForDebug) {
&& !UnCivGame.Current.viewEntireMapForDebug) {
hexagon.color = Color.BLACK
return
}
@ -109,7 +102,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
updateBorderImages()
fogImage.toFront()
fogImage.isVisible=!isViewable
fogImage.isVisible=!(isViewable || UnCivGame.Current.viewEntireMapForDebug)
}
private fun updateBorderImages() {
@ -256,7 +249,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
currentImage.remove()
}
if (unit != null && (isViewable || viewEntireMapForDebug)) { // Tile is visible
if (unit != null && isViewable) { // Tile is visible
newImage = getUnitImage(unit, unit.civInfo.getCivilization().getColor(), 25f)
addActor(newImage)
newImage.center(this)

View File

@ -44,9 +44,9 @@ class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) {
addPopulationIcon()
if (tileInfo.tileMap.gameInfo.getPlayerCivilization().exploredTiles.contains(tileInfo.position)
|| viewEntireMapForDebug) updateCityButton(city, isViewable) // needs to be before the update so the units will be above the city button
|| UnCivGame.Current.viewEntireMapForDebug) updateCityButton(city, isViewable) // needs to be before the update so the units will be above the city button
super.update(isViewable)
super.update(isViewable || UnCivGame.Current.viewEntireMapForDebug)
yieldGroup.isVisible = !UnCivGame.Current.settings.showResourcesAndImprovements
if(yieldGroup.isVisible)

View File

@ -6,6 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.unciv.UnCivGame
import com.unciv.logic.HexMath
import com.unciv.logic.map.TileInfo
import com.unciv.ui.utils.ImageGetter
@ -74,7 +75,7 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
for(tileInfo in tileMapHolder.tileMap.values) {
val RGB = tileInfo.getBaseTerrain().RGB!!
val hex = tileImages[tileInfo]!!
if (!exploredTiles.contains(tileInfo.position)) hex.color = Color.BLACK
if (!(exploredTiles.contains(tileInfo.position) || UnCivGame.Current.viewEntireMapForDebug)) hex.color = Color.BLACK
else if (tileInfo.isCityCenter()) hex.color = Color.WHITE
else if (tileInfo.getCity() != null) hex.color = tileInfo.getOwner()!!.getCivilization().getColor()
else hex.color = colorFromRGB(RGB[0], RGB[1], RGB[2]).lerp(Color.GRAY, 0.5f) // Todo add to baseterrain as function

View File

@ -3,6 +3,7 @@ package com.unciv.ui.worldscreen.bottombar
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.UnCivGame
import com.unciv.logic.map.TileInfo
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
@ -18,7 +19,7 @@ class TileInfoTable(private val worldScreen: WorldScreen) : Table() {
val civInfo = worldScreen.civInfo
columnDefaults(0).padRight(10f)
if (civInfo.exploredTiles.contains(tile.position)) {
if (civInfo.exploredTiles.contains(tile.position) || UnCivGame.Current.viewEntireMapForDebug) {
add(getStatsTable(tile)).pad(10f)
add(Label(tile.toString(), skin)).colspan(2)
}