mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-20 04:38:18 +07:00
Massive AI combat improvements!
Added translations
This commit is contained in:
@ -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...
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) }
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
Reference in New Issue
Block a user