diff --git a/android/assets/jsons/Translations.json b/android/assets/jsons/Translations.json index 97cd32cd22..177aa94bb5 100644 --- a/android/assets/jsons/Translations.json +++ b/android/assets/jsons/Translations.json @@ -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... + } diff --git a/core/src/com/unciv/UnCivGame.kt b/core/src/com/unciv/UnCivGame.kt index b4a50a61bf..3f1507c1ec 100644 --- a/core/src/com/unciv/UnCivGame.kt +++ b/core/src/com/unciv/UnCivGame.kt @@ -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 diff --git a/core/src/com/unciv/logic/automation/UnitAutomation.kt b/core/src/com/unciv/logic/automation/UnitAutomation.kt index 55d04234f1..a4871e429e 100644 --- a/core/src/com/unciv/logic/automation/UnitAutomation.kt +++ b/core/src/com/unciv/logic/automation/UnitAutomation.kt @@ -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) } diff --git a/core/src/com/unciv/logic/automation/WorkerAutomation.kt b/core/src/com/unciv/logic/automation/WorkerAutomation.kt index 2e064a6bf2..ddc4e0f78c 100644 --- a/core/src/com/unciv/logic/automation/WorkerAutomation.kt +++ b/core/src/com/unciv/logic/automation/WorkerAutomation.kt @@ -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. diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 383a31824c..306fb2a6b3 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -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 diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 0e97665e28..f256ecfb15 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -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) } diff --git a/core/src/com/unciv/models/gamebasics/tech/Technology.kt b/core/src/com/unciv/models/gamebasics/tech/Technology.kt index f267d5f681..e000a6f1b0 100644 --- a/core/src/com/unciv/models/gamebasics/tech/Technology.kt +++ b/core/src/com/unciv/models/gamebasics/tech/Technology.kt @@ -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() } diff --git a/core/src/com/unciv/ui/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/EmpireOverviewScreen.kt index d97ac7b40e..6963621b69 100644 --- a/core/src/com/unciv/ui/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/EmpireOverviewScreen.kt @@ -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) diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt index 68dd2c2d2d..70b8e06dde 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt @@ -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 diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt index 878a0a5333..9c88a29bb9 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt @@ -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)