From 05b37dc660e38af1d9e3ba50ccaa037ad6e825f0 Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Wed, 20 Jun 2018 18:30:40 +0300 Subject: [PATCH] AI now accompanies settlers with military units AI now picks promotions for promotable units --- core/src/com/unciv/UnCivGame.kt | 8 ++++++++ core/src/com/unciv/logic/GameInfo.kt | 8 -------- core/src/com/unciv/logic/automation/Automation.kt | 10 ++++++++-- .../com/unciv/logic/automation/UnitAutomation.kt | 15 +++++++++++++-- .../unciv/logic/civilization/CivilizationInfo.kt | 8 +++++++- core/src/com/unciv/logic/map/MapUnit.kt | 8 ++++++++ core/src/com/unciv/logic/map/TileMap.kt | 2 +- core/src/com/unciv/logic/map/UnitPromotions.kt | 10 ++++++++++ .../ui/pickerscreens/PromotionPickerScreen.kt | 12 ++++++------ core/src/com/unciv/ui/tilegroups/TileGroup.kt | 13 +++---------- .../src/com/unciv/ui/tilegroups/WorldTileGroup.kt | 4 ++-- core/src/com/unciv/ui/worldscreen/Minimap.kt | 3 ++- .../ui/worldscreen/bottombar/TileInfoTable.kt | 3 ++- 13 files changed, 70 insertions(+), 34 deletions(-) diff --git a/core/src/com/unciv/UnCivGame.kt b/core/src/com/unciv/UnCivGame.kt index ed3ebb6593..6fdec59f94 100644 --- a/core/src/com/unciv/UnCivGame.kt +++ b/core/src/com/unciv/UnCivGame.kt @@ -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() { diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 1d5359d248..433c00eb0a 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -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() diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 502ec94f26..fdd7ff7ea3 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -47,19 +47,25 @@ class Automation { val civilianUnits = mutableListOf() 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" }) { diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 582f622e2f..b41df7e3c1 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -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) } diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 4c250cc6ad..6f69ddb09e 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -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 { - 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 { diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 9a92f58ae1..e3f079085f 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -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 + } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 6450ae63a3..f1b870d6e7 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -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 } diff --git a/core/src/com/unciv/logic/map/UnitPromotions.kt b/core/src/com/unciv/logic/map/UnitPromotions.kt index 400cff4f57..445d39a0f9 100644 --- a/core/src/com/unciv/logic/map/UnitPromotions.kt +++ b/core/src/com/unciv/logic/map/UnitPromotions.kt @@ -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() 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 { + 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 } } + } } \ No newline at end of file diff --git a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt index 748eb56868..1691b4ce3d 100644 --- a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt @@ -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) } } \ No newline at end of file diff --git a/core/src/com/unciv/ui/tilegroups/TileGroup.kt b/core/src/com/unciv/ui/tilegroups/TileGroup.kt index ded6e49922..83300ab8df 100644 --- a/core/src/com/unciv/ui/tilegroups/TileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/TileGroup.kt @@ -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) diff --git a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt index a9e15a56b0..31be829313 100644 --- a/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt +++ b/core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt @@ -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) diff --git a/core/src/com/unciv/ui/worldscreen/Minimap.kt b/core/src/com/unciv/ui/worldscreen/Minimap.kt index 0b23d9d75d..1faafd822d 100644 --- a/core/src/com/unciv/ui/worldscreen/Minimap.kt +++ b/core/src/com/unciv/ui/worldscreen/Minimap.kt @@ -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 diff --git a/core/src/com/unciv/ui/worldscreen/bottombar/TileInfoTable.kt b/core/src/com/unciv/ui/worldscreen/bottombar/TileInfoTable.kt index 13a2c35751..f656ece142 100644 --- a/core/src/com/unciv/ui/worldscreen/bottombar/TileInfoTable.kt +++ b/core/src/com/unciv/ui/worldscreen/bottombar/TileInfoTable.kt @@ -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) }