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) "Upgrade to [unitType] ([goldCost] gold)":{ // EG Upgrade to Cannon (140 gold)
Italian:"Aggiorna a [unitType] ([goldCost] oro)" Italian:"Aggiorna a [unitType] ([goldCost] oro)"
Russian:"Обновите до [unitType] (золото [goldCost])" Russian:"Обновите до [unitType] (золото [goldCost])"
French:"Mise à niveau vers [unitType] (goldCost) gold)" French:"Mise à niveau vers [unitType] ([goldCost] or)"
Romanian:"Treceți la [unitType] (aurul [goldCost])" Romanian:"Treceți la [unitType] (aurul [goldCost])"
} }
@ -247,7 +247,7 @@
"Food":{ "Food":{
Italian:"Cibo" Italian:"Cibo"
Russian:ДА" Russian:дa"
French:"Nourriture" French:"Nourriture"
Romanian:"Hrană" Romanian:"Hrană"
German:"Speise" German:"Speise"
@ -266,7 +266,8 @@
// Menu table // Menu table
"Civilopedia":{} "Civilopedia":{
}
"Start new game":{ "Start new game":{
Italian:"Nuova partita" Italian:"Nuova partita"
@ -1345,6 +1346,7 @@
German:"Gleis" German:"Gleis"
Dutch:"Spoorweg" Dutch:"Spoorweg"
} }
/*
"Remove":{ // as in "Remove Forest/Jungle/Marsh" "Remove":{ // as in "Remove Forest/Jungle/Marsh"
Italian:"Rimuovi" Italian:"Rimuovi"
Russian:"Удалить" Russian:"Удалить"
@ -1353,6 +1355,14 @@
German:"Entfernen:" // verb behind object again German:"Entfernen:" // verb behind object again
Dutch:"Verwijderen" // verb behind object Dutch:"Verwijderen" // verb behind object
} }
*/
"Remove Forest":{
}
"Remove Jungle":{
}
"Remove Marsh":{
}
"Academy":{ "Academy":{
Italian:"Accademia" Italian:"Accademia"
Russian:"Академия" Russian:"Академия"
@ -1939,6 +1949,12 @@
Dutch:"Toekomst Technologie" 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?":{ "Who knows what the future holds?":{
Italian:"Chi sa cosa riserva il futuro?" Italian:"Chi sa cosa riserva il futuro?"
Russian:"Кто знает, что ждет в будущем?" Russian:"Кто знает, что ждет в будущем?"
@ -1969,56 +1985,56 @@
// Tech Eras // Tech Eras
// In case of foreign languages it becomes gender sensitive words // 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 //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 Italian:"Antichità" //one word translation
Russian:"Древняя" Russian:"Древняя"
French:"Ancien" French:"Ancien"
Romanian:"Antica" Romanian:"Antica"
Dutch:"Oude" Dutch:"Oude"
} }
"Classical":{ "Classical era":{
Italian:"Classica" Italian:"Classica"
Russian:"Классическая" Russian:"Классическая"
French:"Classique" French:"Classique"
Romanian:"Clasica" Romanian:"Clasica"
Dutch:"Klasieke" Dutch:"Klasieke"
} }
"Medieval":{ "Medieval era":{
Italian:"Medioevo" //one word translation Italian:"Medioevo" //one word translation
Russian:"Средневековье" //one word translation Russian:"Средневековье" //one word translation
French:"Médiéval" French:"Médiéval"
Romanian:"Medievala" Romanian:"Medievala"
Dutch:"Middeleeuwse" Dutch:"Middeleeuwse"
} }
"Renaissance":{ "Renaissance era":{
Italian:"Rinascimento" //one word translation Italian:"Rinascimento" //one word translation
Russian:"Ренессанс" //one word translation Russian:"Ренессанс" //one word translation
French:"Renaissance" //one word translation French:"Renaissance" //one word translation
Romanian:"Renaşterei" Romanian:"Renaşterei"
Dutch:"Renaissance" Dutch:"Renaissance"
} }
"Industrial":{ "Industrial era":{
Italian:"Industriale" Italian:"Industriale"
Russian:"Современная" Russian:"Современная"
French:"Industriel" French:"Industriel"
Romanian:"Industriala" Romanian:"Industriala"
Dutch:"Industrieele" Dutch:"Industrieele"
} }
"Modern":{ "Modern era":{
Italian:"Moderna" Italian:"Moderna"
Russian:"Современное" Russian:"Современное"
French:"Moderne" French:"Moderne"
Romanian:"Moderna" Romanian:"Moderna"
Dutch:"Moderne" Dutch:"Moderne"
} }
"Information":{ "Information era":{
Italian:"Informatica" //[newEra] +translation Italian:"Informatica" //[newEra] +translation
Russian:"Информатическая" //translation+ [newEra] Russian:"Информатическая" //translation+ [newEra]
French:"Information" French:"Information"
Romanian:"Informației" Romanian:"Informației"
Dutch:"Informatie" Dutch:"Informatie"
} }
"Future":{ "Future era":{
Italian:"Futura" Italian:"Futura"
Russian:"Будущее" //all one word translation Russian:"Будущее" //all one word translation
French:"Avenir" French:"Avenir"
@ -3224,4 +3240,24 @@
Romanian:"Mare Inginer" 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. * This exists so that when debugging we can see the entire map.
* Remember to turn this to false before commit and upload! * Remember to turn this to false before commit and upload!
*/ */
val viewEntireMapForDebug = true val viewEntireMapForDebug = false
lateinit var worldScreen: WorldScreen 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.Battle
import com.unciv.logic.battle.BattleDamage import com.unciv.logic.battle.BattleDamage
import com.unciv.logic.battle.MapUnitCombatant import com.unciv.logic.battle.MapUnitCombatant
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.DiplomaticStatus
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.GameBasics
@ -110,34 +112,11 @@ class UnitAutomation{
} // do nothing but heal } // do nothing but heal
// if there is an attackable unit in the vicinity, attack! // if there is an attackable unit in the vicinity, attack!
val enemyTileToAttack = getAttackableEnemies(unit) if (tryAttackNearbyEnemy(unit)) return
// Only take enemies we can fight without dying
.filter { BattleDamage().calculateDamageToAttacker(MapUnitCombatant(unit),
Battle().getMapCombatantOfTile(it.tileToAttack)!!) < unit.health }
.firstOrNull()
if (enemyTileToAttack != null) { if (tryGarrisoningUnit(unit)) return
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(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) { if (unit.health < 80) {
healUnit(unit) healUnit(unit)
@ -145,11 +124,7 @@ class UnitAutomation{
} // do nothing but heal until 80 health } // do nothing but heal until 80 health
// else, if there is a reachable spot from which we can attack this turn // find the closest enemy unit that we know of within 5 spaces and advance towards it
// (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 closestEnemy = unit.getTile().getTilesInDistance(5) val closestEnemy = unit.getTile().getTilesInDistance(5)
.firstOrNull { containsAttackableEnemy(it,unit.civInfo) && unit.movementAlgs().canReach(it) } .firstOrNull { containsAttackableEnemy(it,unit.civInfo) && unit.movementAlgs().canReach(it) }
@ -178,12 +153,81 @@ class UnitAutomation{
} }
} }
// else, go to a random space // else, go to a random space
randomWalk(unit) randomWalk(unit)
// if both failed, then... there aren't any reachable tiles. Which is possible. // 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) { private fun randomWalk(unit: MapUnit) {
val reachableTiles = unit.getDistanceToTiles() val reachableTiles = unit.getDistanceToTiles()
.filter { unit.canMoveTo(it.key) } .filter { unit.canMoveTo(it.key) }

View File

@ -12,7 +12,8 @@ class WorkerAutomation(val unit: MapUnit) {
fun automateWorkerAction() { fun automateWorkerAction() {
val enemyUnitsInWalkingDistance = unit.getDistanceToTiles().keys 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. if(enemyUnitsInWalkingDistance.isNotEmpty()) return // Don't you dare move.

View File

@ -298,7 +298,7 @@ class CivilizationInfo {
return diplomacy[otherCiv.civName]!!.diplomaticStatus == DiplomaticStatus.War 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 { fun canEnterTiles(otherCiv: CivilizationInfo): Boolean {
if(otherCiv==this) return true 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 (roadStatus !== RoadStatus.None && !isCityCenter()) SB.appendln(roadStatus.toString().tr())
if (improvement != null) SB.appendln(improvement!!.tr()) if (improvement != null) SB.appendln(improvement!!.tr())
if (improvementInProgress != null && isViewableToPlayer) SB.appendln("{$improvementInProgress} in ${this.turnsToImprovement} {turns}".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){ if(militaryUnit!=null && isViewableToPlayer){
var milUnitString = militaryUnit!!.name var milUnitString = militaryUnit!!.name.tr()
if(militaryUnit!!.health<100) milUnitString += "(" + militaryUnit!!.health + ")" if(militaryUnit!!.health<100) milUnitString += "(" + militaryUnit!!.health + ")"
SB.appendln(milUnitString) 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) } 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() val replacedUnits = enabledUnits.map { it.replaces }.filterNotNull()
enabledUnits = enabledUnits.filter { it.name !in replacedUnits} 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 enabledBuildings = GameBasics.Buildings.values.filter { it.requiredTech==name }
val regularBuildings = enabledBuildings.filter { !it.isWonder } val regularBuildings = enabledBuildings.filter { !it.isWonder }
if(regularBuildings.isNotEmpty()) 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 } 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 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()) if(revealedResource!=null) SB.appendln("Reveals [$revealedResource] on the map".tr())
val tileImprovements = GameBasics.TileImprovements.values.filter { it.techRequired==name } 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() return SB.toString().trim().tr()
} }

View File

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

View File

@ -44,7 +44,7 @@ class WorldScreenTopBar(val screen: WorldScreen) : Table() {
pack() pack()
addActor(getMenuButton()) // needs to be after 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.addClickListener { UnCivGame.Current.screen = EmpireOverviewScreen() }
button.center(this) button.center(this)
button.x = screen.stage.width-button.width-10 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 if(selectedUnit!=null) { // set texts - this is valid even when it's the same unit, because movement points and health change
val unit = selectedUnit!! val unit = selectedUnit!!
var nameLabelText = unit.name var nameLabelText = unit.name.tr()
if(unit.health<100) nameLabelText+=" ("+unit.health+")" if(unit.health<100) nameLabelText+=" ("+unit.health+")"
unitNameLabel.setText(nameLabelText) unitNameLabel.setText(nameLabelText)