Redid how finding attackable enemies works
Bottom line: AI now moves ranged units and attacks in the same turn
This commit is contained in:
parent
b596ca9863
commit
bfad59ca9b
7 changed files with 38 additions and 44 deletions
|
@ -16,7 +16,7 @@ class UnCivGame : Game() {
|
|||
* 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
|
||||
val viewEntireMapForDebug = true
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -39,29 +39,23 @@ class UnitAutomation{
|
|||
return tileCombatant.getCivilization()!=civInfo
|
||||
}
|
||||
|
||||
fun getAttackableEnemies(unit: MapUnit): List<TileInfo> {
|
||||
val attackableTiles = unit.civInfo.getViewableTiles()
|
||||
class AttackableTile(val tileToAttackFrom:TileInfo, val tileToAttack:TileInfo)
|
||||
|
||||
fun getAttackableEnemies(unit: MapUnit): ArrayList<AttackableTile> {
|
||||
val tilesWithEnemies = unit.civInfo.getViewableTiles()
|
||||
.filter { containsAttackableEnemy(it,unit.civInfo) }
|
||||
|
||||
if(MapUnitCombatant(unit).isMelee()) {
|
||||
val distanceToTiles = unit.getDistanceToTiles()
|
||||
// If we're conducting a melee attack,
|
||||
// then there needs to be a tile adjacent to the enemy that we can get to,
|
||||
// AND STILL HAVE MOVEMENT POINTS REMAINING,
|
||||
return attackableTiles.filter {
|
||||
it.neighbors.any {
|
||||
unit.getTile()==it || // We're already right nearby
|
||||
unit.canMoveTo(it)
|
||||
&& distanceToTiles.containsKey(it)
|
||||
&& distanceToTiles[it]!! < unit.currentMovement // We can get there
|
||||
}
|
||||
}
|
||||
}
|
||||
val distanceToTiles = unit.getDistanceToTiles()
|
||||
val rangeOfAttack = if(MapUnitCombatant(unit).isMelee()) 1 else unit.getBaseUnit().range
|
||||
|
||||
else { // Range attack, so enemy needs to be in range
|
||||
return attackableTiles.filter { unit.getTile().getTilesInDistance(unit.getBaseUnit().range).contains(it) }
|
||||
val attackableTiles = ArrayList<AttackableTile>()
|
||||
val tilesToAttackFrom = distanceToTiles.filter { it.value!=unit.currentMovement }.map { it.key }
|
||||
.filter { unit.canMoveTo(it) || it==unit.getTile() }
|
||||
for(reachableTile in tilesToAttackFrom){ // tiles we'll still have energy after we reach there
|
||||
attackableTiles += reachableTile.getTilesInDistance(rangeOfAttack).filter { it in tilesWithEnemies }
|
||||
.map { AttackableTile(reachableTile,it) }
|
||||
}
|
||||
|
||||
return attackableTiles
|
||||
}
|
||||
|
||||
fun automateUnitMoves(unit: MapUnit) {
|
||||
|
@ -93,21 +87,20 @@ class UnitAutomation{
|
|||
} // do nothing but heal
|
||||
|
||||
// if there is an attackable unit in the vicinity, attack!
|
||||
val enemyTileToAttack = getAttackableEnemies(unit).firstOrNull()
|
||||
val enemyTileToAttack = getAttackableEnemies(unit)
|
||||
// Only take enemies we can fight without dying
|
||||
.filter { BattleDamage().calculateDamageToAttacker(MapUnitCombatant(unit),
|
||||
Battle().getMapCombatantOfTile(it.tileToAttack)!!) < unit.health }
|
||||
.firstOrNull()
|
||||
|
||||
if (enemyTileToAttack != null) {
|
||||
val enemy = Battle().getMapCombatantOfTile(enemyTileToAttack.tileToAttack)!!
|
||||
unit.moveToTile(enemyTileToAttack.tileToAttackFrom)
|
||||
val setupAction = UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen).firstOrNull{ it.name == "Set up" }
|
||||
if(setupAction!=null) setupAction.action()
|
||||
|
||||
val enemy = Battle().getMapCombatantOfTile(enemyTileToAttack)!!
|
||||
val damageToAttacker = BattleDamage().calculateDamageToAttacker(MapUnitCombatant(unit), enemy)
|
||||
|
||||
if (damageToAttacker < unit.health) { // don't attack if we'll die from the attack
|
||||
if(MapUnitCombatant(unit).isMelee())
|
||||
unit.movementAlgs().headTowards(enemyTileToAttack)
|
||||
if(unit.currentMovement>0) // This can be 0, if the set up action took away what action points we had left...
|
||||
Battle(unit.civInfo.gameInfo).attack(MapUnitCombatant(unit), enemy)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if(unit.getTile().isCityCenter()) return // It's always good to have a unit in the city center, so if you havn't found annyonw aroud to attack, forget it.
|
||||
|
|
|
@ -159,6 +159,7 @@ open class TileInfo {
|
|||
if (improvement != null) SB.appendln(improvement!!.tr())
|
||||
if (improvementInProgress != null) SB.appendln("{$improvementInProgress} in ${this.turnsToImprovement} {turns}".tr())
|
||||
val isViewableToPlayer = UnCivGame.Current.gameInfo.getPlayerCivilization().getViewableTiles().contains(this)
|
||||
|| UnCivGame.Current.viewEntireMapForDebug
|
||||
if (civilianUnit != null && isViewableToPlayer) SB.appendln(civilianUnit!!.name)
|
||||
if(militaryUnit!=null && isViewableToPlayer){
|
||||
var milUnitString = militaryUnit!!.name
|
||||
|
|
|
@ -25,7 +25,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||
|
||||
fun getDistanceToTilesWithinTurn(origin: Vector2, unitMovement: Float): HashMap<TileInfo, Float> {
|
||||
if(unitMovement==0f) return hashMapOf()
|
||||
val distanceToTiles = HashMap<TileInfo, Float>()
|
||||
val distanceToTiles = LinkedHashMap<TileInfo, Float>()
|
||||
val unitTile = tileMap[origin]
|
||||
distanceToTiles[unitTile] = 0f
|
||||
var tilesToCheck = listOf(unitTile)
|
||||
|
|
|
@ -44,7 +44,8 @@ class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) {
|
|||
addPopulationIcon()
|
||||
|
||||
if (tileInfo.tileMap.gameInfo.getPlayerCivilization().exploredTiles.contains(tileInfo.position)
|
||||
|| UnCivGame.Current.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 || UnCivGame.Current.viewEntireMapForDebug) // needs to be before the update so the units will be above the city button
|
||||
|
||||
super.update(isViewable || UnCivGame.Current.viewEntireMapForDebug)
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@ import com.badlogic.gdx.scenes.scene2d.Group
|
|||
import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
|
||||
import com.unciv.UnCivGame
|
||||
import com.unciv.logic.HexMath
|
||||
import com.unciv.logic.automation.UnitAutomation
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.map.TileMap
|
||||
|
@ -33,7 +35,6 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
|
||||
group.addClickListener {
|
||||
worldScreen.displayTutorials("TileClicked")
|
||||
|
||||
selectedTile = tileInfo
|
||||
worldScreen.bottomBar.unitTable.tileSelected(tileInfo)
|
||||
worldScreen.update()
|
||||
|
@ -92,7 +93,7 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
for (WG in tileGroups.values){
|
||||
WG.update(playerViewableTiles.contains(WG.tileInfo))
|
||||
val unitsInTile = WG.tileInfo.getUnits()
|
||||
if(playerViewableTiles.contains(WG.tileInfo)
|
||||
if((playerViewableTiles.contains(WG.tileInfo) || UnCivGame.Current.viewEntireMapForDebug)
|
||||
&& unitsInTile.isNotEmpty() && unitsInTile.first().civInfo!=civInfo)
|
||||
WG.showCircle(Color.RED)
|
||||
} // Display ALL viewable enemies ewith a red circle so that users don't need to go "hunting" for enemy units
|
||||
|
@ -107,16 +108,14 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
|
|||
val unitType = unit.getBaseUnit().unitType
|
||||
val attackableTiles: List<TileInfo> = when{
|
||||
unitType==UnitType.Civilian -> unit.getDistanceToTiles().keys.toList()
|
||||
unit.getBaseUnit().unitType.isMelee() -> unit.getDistanceToTiles().keys.toList()
|
||||
unitType.isRanged() -> unit.getTile().getTilesInDistance(2)
|
||||
else -> throw Exception("UnitType isn't Civilian, Melee or Ranged???")
|
||||
else -> UnitAutomation().getAttackableEnemies(unit).map { it.tileToAttack }
|
||||
}
|
||||
|
||||
|
||||
for (tile in attackableTiles.filter {
|
||||
it.getUnits().isNotEmpty()
|
||||
&& it.getUnits().first().owner != unit.owner
|
||||
&& playerViewableTiles.contains(it)}) {
|
||||
&& (playerViewableTiles.contains(it) || UnCivGame.Current.viewEntireMapForDebug)}) {
|
||||
if(unit.getBaseUnit().unitType== UnitType.Civilian) tileGroups[tile]!!.hideCircle()
|
||||
else tileGroups[tile]!!.showCircle(colorFromRGB(237, 41, 57))
|
||||
}
|
||||
|
|
|
@ -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.scenes.scene2d.ui.TextButton
|
||||
import com.unciv.UnCivGame
|
||||
import com.unciv.logic.automation.UnitAutomation
|
||||
import com.unciv.logic.battle.Battle
|
||||
import com.unciv.logic.battle.BattleDamage
|
||||
|
@ -43,7 +44,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
|||
val defender: ICombatant? = Battle().getMapCombatantOfTile(selectedTile)
|
||||
|
||||
if(defender==null || defender.getCivilization()==worldScreen.civInfo
|
||||
|| !attacker.getCivilization().exploredTiles.contains(selectedTile.position)) {
|
||||
|| !(attacker.getCivilization().exploredTiles.contains(selectedTile.position) || UnCivGame.Current.viewEntireMapForDebug)) {
|
||||
hide()
|
||||
return
|
||||
}
|
||||
|
@ -120,14 +121,13 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
|||
|
||||
attacker.unit.getDistanceToTiles()
|
||||
|
||||
val attackerCanReachDefender = UnitAutomation().getAttackableEnemies(attacker.unit)
|
||||
.contains(defender.getTile())
|
||||
val attackableEnemy = UnitAutomation().getAttackableEnemies(attacker.unit)
|
||||
.firstOrNull{ it.tileToAttack == defender.getTile()}
|
||||
|
||||
if(!attackerCanReachDefender || !attacker.unit.canAttack()) attackButton.disable()
|
||||
if(attackableEnemy==null || !attacker.unit.canAttack()) attackButton.disable()
|
||||
else {
|
||||
attackButton.addClickListener {
|
||||
if(attacker.isMelee())
|
||||
attacker.unit.movementAlgs().headTowards(defender.getTile())
|
||||
attacker.unit.moveToTile(attackableEnemy.tileToAttackFrom)
|
||||
battle.attack(attacker, defender)
|
||||
worldScreen.update()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue