Ranged enemy units don't move towards their targets

Cities under attack now switch to training combat units
This commit is contained in:
Yair Morgenstern
2018-04-23 18:58:19 +03:00
parent 7ff81ac901
commit fe09351db7

View File

@ -3,6 +3,7 @@ package com.unciv.logic
import com.unciv.UnCivGame
import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
@ -12,16 +13,17 @@ import com.unciv.models.gamebasics.TileImprovement
import com.unciv.ui.utils.getRandom
import com.unciv.ui.worldscreen.unit.UnitActions
class Automation{
class Automation {
private fun findTileToWork(currentTile: TileInfo, civInfo: CivilizationInfo): TileInfo {
val selectedTile = currentTile.tileMap.getTilesInDistance(currentTile.position, 4)
.filter { (it.unit==null || it==currentTile )
&& it.improvement==null
&& it.canBuildImprovement(chooseImprovement(it),civInfo) }
.maxBy { getPriority(it,civInfo) }
if(selectedTile!=null && getPriority(selectedTile,civInfo) > 1) return selectedTile
.filter {
(it.unit == null || it == currentTile)
&& it.improvement == null
&& it.canBuildImprovement(chooseImprovement(it), civInfo)
}
.maxBy { getPriority(it, civInfo) }
if (selectedTile != null && getPriority(selectedTile, civInfo) > 1) return selectedTile
else return currentTile
}
@ -35,27 +37,23 @@ class Automation{
}
private fun chooseImprovement(tile: TileInfo): TileImprovement {
return GameBasics.TileImprovements[chooseImprovementString(tile)]!!
}
private fun chooseImprovementString(tile: TileInfo): String? {
when {
tile.improvementInProgress != null -> return tile.improvementInProgress
tile.terrainFeature == "Forest" -> return "Lumber mill"
tile.terrainFeature == "Jungle" -> return "Trading post"
tile.terrainFeature == "Marsh" -> return "Remove Marsh"
tile.resource != null -> return tile.tileResource.improvement
tile.baseTerrain == "Hill" -> return "Mine"
tile.baseTerrain == "Grassland" || tile.baseTerrain == "Desert" || tile.baseTerrain == "Plains" -> return "Farm"
tile.baseTerrain == "Tundra" -> return "Trading post"
else -> return null
val improvementString = when {
tile.improvementInProgress != null -> tile.improvementInProgress
tile.terrainFeature == "Forest" -> "Lumber mill"
tile.terrainFeature == "Jungle" -> "Trading post"
tile.terrainFeature == "Marsh" -> "Remove Marsh"
tile.resource != null -> tile.tileResource.improvement
tile.baseTerrain == "Hill" -> "Mine"
tile.baseTerrain == "Grassland" || tile.baseTerrain == "Desert" || tile.baseTerrain == "Plains" -> "Farm"
tile.baseTerrain == "Tundra" -> "Trading post"
else -> null
}
return GameBasics.TileImprovements[improvementString]!!
}
fun automateWorkerAction(unit: MapUnit) {
var tile = unit.getTile()
val tileToWork = findTileToWork(tile,unit.civInfo)
val tileToWork = findTileToWork(tile, unit.civInfo)
if (tileToWork != tile) {
tile = unit.headTowards(tileToWork.position)
unit.doPreTurnAction(tile)
@ -70,103 +68,114 @@ class Automation{
}
fun automateCivMoves(civInfo: CivilizationInfo) {
if(civInfo.tech.techsToResearch.isEmpty()) {
if (civInfo.tech.techsToResearch.isEmpty()) {
val researchableTechs = GameBasics.Technologies.values.filter { civInfo.tech.canBeResearched(it.name) }
val techToResearch = researchableTechs.minBy { it.cost }
civInfo.tech.techsResearched.add(techToResearch!!.name)
}
for(unit in civInfo.getCivUnits()){
for (city in civInfo.cities) {
if (city.health < city.getMaxHealth()) trainCombatUnit(city)
}
if(unit.name=="Settler") {
UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).first { it.name == "Found city" }.action()
continue
}
if(unit.name=="Worker") {
Automation().automateWorkerAction(unit)
continue
}
fun healUnit(){
// If we're low on health then heal
// todo: go to a more defensible place if there is one
val tilesInDistance = unit.getDistanceToTiles().keys
val unitTile=unit.getTile()
// Go to friendly tile if within distance - better healing!
val friendlyTile = tilesInDistance.firstOrNull { it.getOwner()?.civName ==unit.owner && it.unit==null }
if(unitTile.getOwner()?.civName !=unit.owner && friendlyTile!=null){
unit.moveToTile(friendlyTile)
return
}
// Or at least get out of enemy territory yaknow
val neutralTile = tilesInDistance.firstOrNull { it.getOwner() ==null && it.unit==null }
if(unitTile.getOwner()?.civName !=unit.owner && unitTile.getOwner() !=null && neutralTile!=null){
unit.moveToTile(neutralTile)
return
}
}
if(unit.health < 50) {
healUnit()
continue
} // do nothing but heal
// if there is an attackable unit in the vicinity, attack!
val attackableTiles = civInfo.getViewableTiles()
.filter { it.unit != null && it.unit!!.owner != civInfo.civName && !it.isCityCenter }.toHashSet()
val distanceToTiles = unit.getDistanceToTiles()
val unitTileToAttack = distanceToTiles.keys.firstOrNull{ attackableTiles.contains(it)}
if(unitTileToAttack!=null){
val unitToAttack =unitTileToAttack.unit!!
if(unitToAttack.getBaseUnit().unitType == UnitType.Civilian){ // kill
unitToAttack.civInfo.addNotification("Our "+unitToAttack.name+" was destroyed by an enemy "+unit.name+"!", unitTileToAttack.position)
unitTileToAttack.unit=null
unit.headTowards(unitTileToAttack.position)
continue
}
val damageToAttacker = Battle(civInfo.gameInfo).calculateDamageToAttacker(MapUnitCombatant(unit), MapUnitCombatant(unitToAttack))
if(damageToAttacker < unit.health) { // don't attack if we'll die from the attack
unit.headTowards(unitTileToAttack.position)
Battle(civInfo.gameInfo).attack(MapUnitCombatant(unit), MapUnitCombatant(unitToAttack))
continue
}
}
if(unit.health < 80){
healUnit()
continue
} // do nothing but heal until 80 health
// else, if there is a reachable spot from which we can attack this turn
// (say we're an archer and there's a unit 3 tiles away), go there and attack
// todo
// else, find the closest enemy unit that we know of within 5 spaces and advance towards it
val closestUnit = civInfo.gameInfo.tileMap.getTilesInDistance(unit.getTile().position, 5)
.firstOrNull{ attackableTiles.contains(it) }
if(closestUnit!=null){
unit.headTowards(closestUnit.position)
continue
}
if(unit.health < 100){
healUnit()
continue
}
// else, go to a random space
unit.moveToTile(distanceToTiles.keys.filter { it.unit==null }.toList().getRandom())
for (unit in civInfo.getCivUnits()) {
automateUnitMoves(unit)
}
}
private fun trainCombatUnit(city: CityInfo) {
city.cityConstructions.currentConstruction = "Archer" // when we have more units then we'll see.
}
fun automateUnitMoves(unit: MapUnit) {
if (unit.name == "Settler") {
UnitActions().getUnitActions(unit, UnCivGame.Current.worldScreen!!).first { it.name == "Found city" }.action()
return
}
if (unit.name == "Worker") {
Automation().automateWorkerAction(unit)
return
}
fun healUnit() {
// If we're low on health then heal
// todo: go to a more defensible place if there is one
val tilesInDistance = unit.getDistanceToTiles().keys
val unitTile = unit.getTile()
// Go to friendly tile if within distance - better healing!
val friendlyTile = tilesInDistance.firstOrNull { it.getOwner()?.civName == unit.owner && it.unit == null }
if (unitTile.getOwner()?.civName != unit.owner && friendlyTile != null) {
unit.moveToTile(friendlyTile)
return
}
// Or at least get out of enemy territory yaknow
val neutralTile = tilesInDistance.firstOrNull { it.getOwner() == null && it.unit == null }
if (unitTile.getOwner()?.civName != unit.owner && unitTile.getOwner() != null && neutralTile != null) {
unit.moveToTile(neutralTile)
return
}
}
if (unit.health < 50) {
healUnit()
return
} // do nothing but heal
// if there is an attackable unit in the vicinity, attack!
val attackableTiles = unit.civInfo.getViewableTiles()
.filter { it.unit != null && it.unit!!.owner != unit.civInfo.civName && !it.isCityCenter }.toHashSet()
val distanceToTiles = unit.getDistanceToTiles()
val unitTileToAttack = distanceToTiles.keys.firstOrNull { attackableTiles.contains(it) }
if (unitTileToAttack != null) {
val unitToAttack = unitTileToAttack.unit!!
if (unitToAttack.getBaseUnit().unitType == UnitType.Civilian) { // kill
unitToAttack.civInfo.addNotification("Our " + unitToAttack.name + " was destroyed by an enemy " + unit.name + "!", unitTileToAttack.position)
unitTileToAttack.unit = null
unit.headTowards(unitTileToAttack.position)
return
}
val damageToAttacker = Battle(unit.civInfo.gameInfo).calculateDamageToAttacker(MapUnitCombatant(unit), MapUnitCombatant(unitToAttack))
if (damageToAttacker < unit.health) { // don't attack if we'll die from the attack
if(unit.getBaseUnit().unitType == UnitType.Melee)
unit.headTowards(unitTileToAttack.position)
Battle(unit.civInfo.gameInfo).attack(MapUnitCombatant(unit), MapUnitCombatant(unitToAttack))
return
}
}
if (unit.health < 80) {
healUnit()
return
} // do nothing but heal until 80 health
// else, if there is a reachable spot from which we can attack this turn
// (say we're an archer and there's a unit 3 tiles away), go there and attack
// todo
// else, find the closest enemy unit that we know of within 5 spaces and advance towards it
val closestUnit = unit.civInfo.gameInfo.tileMap.getTilesInDistance(unit.getTile().position, 5)
.firstOrNull { attackableTiles.contains(it) }
if (closestUnit != null) {
unit.headTowards(closestUnit.position)
return
}
if (unit.health < 100) {
healUnit()
return
}
// else, go to a random space
unit.moveToTile(distanceToTiles.keys.filter { it.unit == null }.toList().getRandom())
}
}