Massive AI combat improvements!

Added translations
This commit is contained in:
Yair Morgenstern
2018-08-06 21:58:30 +03:00
parent a199801c82
commit 02fd349243
10 changed files with 135 additions and 54 deletions

View File

@ -137,7 +137,7 @@
"Upgrade to [unitType] ([goldCost] gold)":{ // EG Upgrade to Cannon (140 gold)
Italian:"Aggiorna a [unitType] ([goldCost] oro)"
Russian:"Обновите до [unitType] (золото [goldCost])"
French:"Mise à niveau vers [unitType] (goldCost) gold)"
French:"Mise à niveau vers [unitType] ([goldCost] or)"
Romanian:"Treceți la [unitType] (aurul [goldCost])"
}
@ -247,7 +247,7 @@
"Food":{
Italian:"Cibo"
Russian:ДА"
Russian:дa"
French:"Nourriture"
Romanian:"Hrană"
German:"Speise"
@ -266,7 +266,8 @@
// Menu table
"Civilopedia":{}
"Civilopedia":{
}
"Start new game":{
Italian:"Nuova partita"
@ -1345,6 +1346,7 @@
German:"Gleis"
Dutch:"Spoorweg"
}
/*
"Remove":{ // as in "Remove Forest/Jungle/Marsh"
Italian:"Rimuovi"
Russian:"Удалить"
@ -1353,6 +1355,14 @@
German:"Entfernen:" // verb behind object again
Dutch:"Verwijderen" // verb behind object
}
*/
"Remove Forest":{
}
"Remove Jungle":{
}
"Remove Marsh":{
}
"Academy":{
Italian:"Accademia"
Russian:"Академия"
@ -1939,6 +1949,12 @@
Dutch:"Toekomst Technologie"
}
"Enables conversion of city production to gold":{}
"Enables conversion of city production to science":{}
"Improves movement speed on roads":{}
"+10% science and production in all cities":{}
"Who knows what the future holds?":{
Italian:"Chi sa cosa riserva il futuro?"
Russian:"Кто знает, что ждет в будущем?"
@ -1969,56 +1985,56 @@
// Tech Eras
// In case of foreign languages it becomes gender sensitive words
//Also in russian "Medieval Era" becomes "Средневековье" or italian for "Renaissance Era" becomes "Rinascimento". So they got a single world to replace 2 english ones
"Ancient":{
"Ancient era":{
Italian:"Antichità" //one word translation
Russian:"Древняя"
French:"Ancien"
Romanian:"Antica"
Dutch:"Oude"
}
"Classical":{
"Classical era":{
Italian:"Classica"
Russian:"Классическая"
French:"Classique"
Romanian:"Clasica"
Dutch:"Klasieke"
}
"Medieval":{
"Medieval era":{
Italian:"Medioevo" //one word translation
Russian:"Средневековье" //one word translation
French:"Médiéval"
Romanian:"Medievala"
Dutch:"Middeleeuwse"
}
"Renaissance":{
"Renaissance era":{
Italian:"Rinascimento" //one word translation
Russian:"Ренессанс" //one word translation
French:"Renaissance" //one word translation
Romanian:"Renaşterei"
Dutch:"Renaissance"
}
"Industrial":{
"Industrial era":{
Italian:"Industriale"
Russian:"Современная"
French:"Industriel"
Romanian:"Industriala"
Dutch:"Industrieele"
}
"Modern":{
"Modern era":{
Italian:"Moderna"
Russian:"Современное"
French:"Moderne"
Romanian:"Moderna"
Dutch:"Moderne"
}
"Information":{
"Information era":{
Italian:"Informatica" //[newEra] +translation
Russian:"Информатическая" //translation+ [newEra]
French:"Information"
Romanian:"Informației"
Dutch:"Informatie"
}
"Future":{
"Future era":{
Italian:"Futura"
Russian:"Будущее" //all one word translation
French:"Avenir"
@ -3224,4 +3240,24 @@
Romanian:"Mare Inginer"
}
"Requires":{}
"Adopt policy":{}
"Unlocked at":{}
"Tradition":{}
"+3 culture in capital and increased rate of border expansion":{}
"Aristocracy":{}
"+15% production when constructing wonders, +1 happiness for every 10 citizens in a city":{}
"Legalism":{}
"Free culture building in your first 4 cities":{}
"Oligarchy":{}
"Units in cities cost no maintainance":{}
"Landed Elite":{}
"+10% food growth and +2 food in capital":{}
"Monarchy":{}
"+1 gold and -1 unhappiness for every 2 citizens in capital":{}
"Tradition Complete":{}
"+15% growth and +2 food in all cities":{}
// And so on for all the policies. I can't be bothered to add them all now...
}

View File

@ -17,7 +17,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 = true
val viewEntireMapForDebug = false
lateinit var worldScreen: WorldScreen

View File

@ -5,7 +5,9 @@ import com.unciv.logic.HexMath
import com.unciv.logic.battle.Battle
import com.unciv.logic.battle.BattleDamage
import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.DiplomaticStatus
import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.GameBasics
@ -110,34 +112,11 @@ class UnitAutomation{
} // do nothing but heal
// if there is an attackable unit in the vicinity, attack!
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 (tryAttackNearbyEnemy(unit)) return
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()
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
}
if (tryGarrisoningUnit(unit)) 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.
val reachableCitiesWithoutUnits = unit.civInfo.cities.filter {
unit.canMoveTo(it.getCenterTile())
&& unit.movementAlgs().canReach(it.getCenterTile()) }
if(reachableCitiesWithoutUnits.isNotEmpty()){
val closestCityWithoutUnit = reachableCitiesWithoutUnits
.minBy { unit.movementAlgs().getShortestPath(it.getCenterTile()).size }!!
unit.movementAlgs().headTowards(closestCityWithoutUnit.getCenterTile())
return
}
if (unit.health < 80) {
healUnit(unit)
@ -145,11 +124,7 @@ class UnitAutomation{
} // 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
// find the closest enemy unit that we know of within 5 spaces and advance towards it
val closestEnemy = unit.getTile().getTilesInDistance(5)
.firstOrNull { containsAttackableEnemy(it,unit.civInfo) && unit.movementAlgs().canReach(it) }
@ -178,12 +153,81 @@ class UnitAutomation{
}
}
// else, go to a random space
randomWalk(unit)
// if both failed, then... there aren't any reachable tiles. Which is possible.
}
private fun tryAttackNearbyEnemy(unit: MapUnit): Boolean {
val attackableEnemies = getAttackableEnemies(unit)
// Only take enemies we can fight without dying
.filter {
BattleDamage().calculateDamageToAttacker(MapUnitCombatant(unit),
Battle().getMapCombatantOfTile(it.tileToAttack)!!) < unit.health
}
val cityTilesToAttack = attackableEnemies.filter { it.tileToAttack.isCityCenter() }
val nonCityTilesToAttack = attackableEnemies.filter { !it.tileToAttack.isCityCenter() }
var enemyTileToAttack: AttackableTile? = null
val capturableCity = cityTilesToAttack.firstOrNull{it.tileToAttack.getCity()!!.health == 1}
val cityWithHealthLeft = cityTilesToAttack.filter { it.tileToAttack.getCity()!!.health != 1 } // don't want ranged units to attack defeated cities
.minBy { it.tileToAttack.getCity()!!.health }
if (unit.getBaseUnit().unitType.isMelee() && capturableCity!=null)
enemyTileToAttack = capturableCity // enter it quickly, top priority!
else if (nonCityTilesToAttack.isNotEmpty()) // second priority, units
enemyTileToAttack = nonCityTilesToAttack.minBy { Battle().getMapCombatantOfTile(it.tileToAttack)!!.getHealth() }
else if (cityWithHealthLeft!=null) enemyTileToAttack = cityWithHealthLeft// third priority, city
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()
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 true
}
return false
}
private fun tryGarrisoningUnit(unit: MapUnit): Boolean {
val reachableCitiesWithoutUnits = unit.civInfo.cities.filter {
val centerTile = it.getCenterTile()
unit.canMoveTo(centerTile)
&& unit.movementAlgs().canReach(centerTile)
}
fun cityThatNeedsDefendingInWartime(city: CityInfo): Boolean {
if (city.health < city.getMaxHealth()) return true // this city is under attack!
for (enemyCivCity in unit.civInfo.diplomacy.values.filter { it.diplomaticStatus == DiplomaticStatus.War }
.map { it.otherCiv() }.flatMap { it.cities })
if (city.getCenterTile().arialDistanceTo(enemyCivCity.getCenterTile()) <= 5) return true// this is an edge city that needs defending
return false
}
if (!unit.civInfo.isAtWar()) {
if (unit.getTile().isCityCenter()) return true // It's always good to have a unit in the city center, so if you haven't found anyone around to attack, forget it.
if (reachableCitiesWithoutUnits.isNotEmpty()) {
}
} else {
if (unit.getTile().isCityCenter() &&
cityThatNeedsDefendingInWartime(unit.getTile().getCity()!!)) return true
val citiesThatCanBeDefended = reachableCitiesWithoutUnits.filter { cityThatNeedsDefendingInWartime(it) }
if (citiesThatCanBeDefended.isNotEmpty()) {
val closestCityWithoutUnit = citiesThatCanBeDefended
.minBy { unit.movementAlgs().getShortestPath(it.getCenterTile()).size }!!
unit.movementAlgs().headTowards(closestCityWithoutUnit.getCenterTile())
return true
}
}
return false
}
private fun randomWalk(unit: MapUnit) {
val reachableTiles = unit.getDistanceToTiles()
.filter { unit.canMoveTo(it.key) }

View File

@ -12,7 +12,8 @@ class WorkerAutomation(val unit: MapUnit) {
fun automateWorkerAction() {
val enemyUnitsInWalkingDistance = unit.getDistanceToTiles().keys
.filter { it.militaryUnit!=null && it.militaryUnit!!.civInfo!=unit.civInfo }
.filter { it.militaryUnit!=null && it.militaryUnit!!.civInfo!=unit.civInfo
&& unit.civInfo.isAtWarWith(it.militaryUnit!!.civInfo) }
if(enemyUnitsInWalkingDistance.isNotEmpty()) return // Don't you dare move.

View File

@ -298,7 +298,7 @@ class CivilizationInfo {
return diplomacy[otherCiv.civName]!!.diplomaticStatus == DiplomaticStatus.War
}
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus==DiplomaticStatus.War }
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus==DiplomaticStatus.War && !it.otherCiv().isDefeated() }
fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
if(otherCiv==this) return true

View File

@ -174,9 +174,9 @@ open class TileInfo {
if (roadStatus !== RoadStatus.None && !isCityCenter()) SB.appendln(roadStatus.toString().tr())
if (improvement != null) SB.appendln(improvement!!.tr())
if (improvementInProgress != null && isViewableToPlayer) SB.appendln("{$improvementInProgress} in ${this.turnsToImprovement} {turns}".tr())
if (civilianUnit != null && isViewableToPlayer) SB.appendln(civilianUnit!!.name)
if (civilianUnit != null && isViewableToPlayer) SB.appendln(civilianUnit!!.name.tr())
if(militaryUnit!=null && isViewableToPlayer){
var milUnitString = militaryUnit!!.name
var milUnitString = militaryUnit!!.name.tr()
if(militaryUnit!!.health<100) milUnitString += "(" + militaryUnit!!.health + ")"
SB.appendln(milUnitString)
}

View File

@ -22,20 +22,20 @@ class Technology : ICivilopedia {
var enabledUnits = GameBasics.Units.values.filter { it.requiredTech==name && (it.uniqueTo==null || it.uniqueTo==UnCivGame.Current.gameInfo.getPlayerCivilization().civName) }
val replacedUnits = enabledUnits.map { it.replaces }.filterNotNull()
enabledUnits = enabledUnits.filter { it.name !in replacedUnits}
if(enabledUnits.isNotEmpty()) SB.appendln("{Units enabled}: "+enabledUnits.map { it.name + " ("+it.getShortDescription()+")" }.joinToString())
if(enabledUnits.isNotEmpty()) SB.appendln("{Units enabled}: "+enabledUnits.map { it.name.tr() + " ("+it.getShortDescription()+")" }.joinToString())
val enabledBuildings = GameBasics.Buildings.values.filter { it.requiredTech==name }
val regularBuildings = enabledBuildings.filter { !it.isWonder }
if(regularBuildings.isNotEmpty())
SB.appendln("{Buildings enabled}: "+regularBuildings.map { "\n * "+it.name + " ("+it.getShortDescription()+")" }.joinToString())
SB.appendln("{Buildings enabled}: "+regularBuildings.map { "\n * "+it.name.tr() + " ("+it.getShortDescription()+")" }.joinToString())
val wonders = enabledBuildings.filter { it.isWonder }
if(wonders.isNotEmpty()) SB.appendln("{Wonders enabled}: "+wonders.map { "\n * "+it.name+ " ("+it.getShortDescription()+")" }.joinToString())
if(wonders.isNotEmpty()) SB.appendln("{Wonders enabled}: "+wonders.map { "\n * "+it.name.tr()+ " ("+it.getShortDescription()+")" }.joinToString())
val revealedResource = GameBasics.TileResources.values.filter { it.revealedBy==name }.map { it.name }.firstOrNull() // can only be one
if(revealedResource!=null) SB.appendln("Reveals [$revealedResource] on the map".tr())
val tileImprovements = GameBasics.TileImprovements.values.filter { it.techRequired==name }
if(tileImprovements.isNotEmpty()) SB.appendln("{Tile improvements enabled}: "+tileImprovements.map { it.name }.joinToString())
if(tileImprovements.isNotEmpty()) SB.appendln("{Tile improvements enabled}: "+tileImprovements.map { it.name.tr() }.joinToString())
return SB.toString().trim().tr()
}

View File

@ -209,7 +209,7 @@ class EmpireOverviewScreen : CameraStageBaseScreen(){
table.row()
for(unit in civInfo.getCivUnits()){
val baseUnit = unit.getBaseUnit()
table.add(unit.name)
table.add(unit.name.tr())
if(baseUnit.strength>0) table.add(baseUnit.strength.toString()) else table.add()
if(baseUnit.rangedStrength>0) table.add(baseUnit.rangedStrength.toString()) else table.add()
table.add(unit.currentMovement.toString()+"/"+unit.maxMovement)

View File

@ -44,7 +44,7 @@ class WorldScreenTopBar(val screen: WorldScreen) : Table() {
pack()
addActor(getMenuButton()) // needs to be after pack
val button = TextButton("Overview",CameraStageBaseScreen.skin)
val button = TextButton("Overview".tr(),CameraStageBaseScreen.skin)
button.addClickListener { UnCivGame.Current.screen = EmpireOverviewScreen() }
button.center(this)
button.x = screen.stage.width-button.width-10

View File

@ -63,7 +63,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
if(selectedUnit!=null) { // set texts - this is valid even when it's the same unit, because movement points and health change
val unit = selectedUnit!!
var nameLabelText = unit.name
var nameLabelText = unit.name.tr()
if(unit.health<100) nameLabelText+=" ("+unit.health+")"
unitNameLabel.setText(nameLabelText)