From b41d234db6d478a1e1e3e1c79547339ba4626351 Mon Sep 17 00:00:00 2001 From: SimonCeder <63475501+SimonCeder@users.noreply.github.com> Date: Wed, 6 Oct 2021 16:12:13 +0200 Subject: [PATCH] Barbarians capture civilians and take gold from cities (#5410) * ransom cities * capture civilians * fix bug --- .../jsons/translations/template.properties | 2 ++ .../logic/automation/BarbarianAutomation.kt | 16 ++++++++++++- core/src/com/unciv/logic/battle/Battle.kt | 23 ++++++++++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 1a743e6cb8..1fbc3e7e07 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -544,6 +544,7 @@ An enemy [unit] has attacked [cityName] = An enemy [unit] has attacked our [ourUnit] = Enemy city [cityName] has attacked our [ourUnit] = An enemy [unit] has captured [cityName] = +An enemy [unit] has raided [cityName] = An enemy [unit] has captured our [ourUnit] = An enemy [unit] has destroyed our [ourUnit] = Your [ourUnit] has destroyed an enemy [unit] = @@ -599,6 +600,7 @@ We have received [goldAmount] Gold for discovering [naturalWonder] = Your relationship with [cityStateName] is about to degrade = Your relationship with [cityStateName] degraded = A new barbarian encampment has spawned! = +Barbarians raided [cityName] and stole [amount] Gold from your treasury! = Received [goldAmount] Gold for capturing [cityName] = Our proposed trade is no longer relevant! = [defender] could not withdraw from a [attacker] - blocked. = diff --git a/core/src/com/unciv/logic/automation/BarbarianAutomation.kt b/core/src/com/unciv/logic/automation/BarbarianAutomation.kt index cf64e7bae1..0b514f61cb 100644 --- a/core/src/com/unciv/logic/automation/BarbarianAutomation.kt +++ b/core/src/com/unciv/logic/automation/BarbarianAutomation.kt @@ -14,10 +14,24 @@ class BarbarianAutomation(val civInfo: CivilizationInfo) { } private fun automateUnit(unit: MapUnit) { - if (unit.currentTile.improvement == Constants.barbarianEncampment) automateUnitOnEncampment(unit) + if (unit.isCivilian()) automateCapturedCivilian(unit) + else if (unit.currentTile.improvement == Constants.barbarianEncampment) automateUnitOnEncampment(unit) else automateCombatUnit(unit) } + private fun automateCapturedCivilian(unit: MapUnit) { + // 1 - Stay on current encampment + if (unit.currentTile.improvement == Constants.barbarianEncampment) return + + val campTiles = unit.civInfo.gameInfo.barbarians.camps.map { unit.civInfo.gameInfo.tileMap[it.key] } + .sortedBy { unit.currentTile.aerialDistanceTo(it) } + val bestCamp = campTiles.firstOrNull { it.civilianUnit == null && unit.movement.canReach(it)} + if (bestCamp != null) + unit.movement.headTowards(bestCamp) // 2 - Head towards an encampment + else + UnitAutomation.wander(unit) // 3 - Can't find a reachable encampment, wander aimlessly + } + private fun automateUnitOnEncampment(unit: MapUnit) { // 1 - trying to upgrade if (UnitAutomation.tryUpgradeUnit(unit)) return diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 33c5bff1eb..0bd130ff5d 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -82,8 +82,17 @@ object Battle { // This needs to come BEFORE the move-to-tile, because if we haven't conquered it we can't move there =) if (defender.isDefeated() && defender is CityCombatant && attacker is MapUnitCombatant - && attacker.isMelee() && !attacker.unit.hasUnique("Unable to capture cities")) - conquerCity(defender.city, attacker) + && attacker.isMelee() && !attacker.unit.hasUnique("Unable to capture cities")) { + // Barbarians can't capture cities + if (attacker.unit.civInfo.isBarbarian()) { + defender.takeDamage(-1) // Back to 2 HP + val ransom = min(200, defender.city.civInfo.gold) + defender.city.civInfo.addGold(-ransom) + defender.city.civInfo.addNotification("Barbarians raided [${defender.city.name}] and stole [$ransom] Gold from your treasury!", defender.city.location, NotificationIcon.War) + attacker.unit.destroy() // Remove the barbarian + } else + conquerCity(defender.city, attacker) + } // Exploring units surviving an attack should "wake up" if (!defender.isDefeated() && defender is MapUnitCombatant && defender.unit.isExploring()) @@ -270,6 +279,8 @@ object Battle { NotificationIcon.War to " was destroyed while attacking" !defender.isDefeated() -> NotificationIcon.War to " has attacked" + defender.isCity() && attacker.isMelee() && attacker.getCivInfo().isBarbarian() -> + NotificationIcon.War to " has raided" defender.isCity() && attacker.isMelee() -> NotificationIcon.War to " has captured" else -> @@ -468,12 +479,12 @@ object Battle { val capturedUnitTile = capturedUnit.getTile() when { - // Uncapturable units are destroyed (units captured by barbarians also - for now) - defender.unit.hasUnique("Uncapturable") || attacker.getCivInfo().isBarbarian() -> { + // Uncapturable units are destroyed + defender.unit.hasUnique("Uncapturable") -> { capturedUnit.destroy() } - // Captured settlers are converted to workers. - capturedUnit.name == Constants.settler -> { + // Captured settlers are converted to workers unless captured by barbarians (so they can be returned later). + capturedUnit.name == Constants.settler && !attacker.getCivInfo().isBarbarian() -> { capturedUnit.destroy() // This is so that future checks which check if a unit has been captured are caught give the right answer // For example, in postBattleMoveToAttackedTile