mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-26 05:14:32 -04:00
Return Civilians captured by Barbarians to original owner; Capture stacked civilians (#5437)
* return captured civilians * stacked civilian capture bug * works on old saves * diplomacy bonus expires on war declared * vector bug
This commit is contained in:
parent
fd3bfbade4
commit
69e1792fa9
@ -165,6 +165,7 @@ You destroyed City States that were under our protection! =
|
||||
You attacked City States that were under our protection! =
|
||||
You demanded tribute from City States that were under our protection! =
|
||||
You sided with a City State over us =
|
||||
You returned captured units to us =
|
||||
|
||||
Demands =
|
||||
Please don't settle new cities near us. =
|
||||
@ -176,6 +177,9 @@ We asked [civName] for a tribute recently and they gave in.\nYou promised to pro
|
||||
It's come to my attention that I may have attacked [civName], a city-state under your protection.\nWhile it was not my goal to be at odds with your empire, this was deemed a necessary course of action. =
|
||||
I thought you might like to know that I've launched an invasion of one of your little pet states.\nThe lands of [civName] will make a fine addition to my own. =
|
||||
|
||||
Return [unitName] to [civName]? =
|
||||
The [unitName] we liberated originally belonged to [civName]. They will be grateful if we return it to them. =
|
||||
|
||||
Enter the amount of gold =
|
||||
|
||||
# City-States
|
||||
|
@ -347,17 +347,20 @@ object Battle {
|
||||
|
||||
private fun postBattleMoveToAttackedTile(attacker: ICombatant, defender: ICombatant, attackedTile: TileInfo) {
|
||||
if (attacker.isMelee()
|
||||
&& (defender.isDefeated() || defender.getCivInfo() == attacker.getCivInfo())
|
||||
// This is so that if we attack e.g. a barbarian in enemy territory that we can't enter, we won't enter it
|
||||
&& (attacker as MapUnitCombatant).unit.movement.canMoveTo(attackedTile)) {
|
||||
&& (defender.isDefeated() || defender.getCivInfo() == attacker.getCivInfo())) {
|
||||
// we destroyed an enemy military unit and there was a civilian unit in the same tile as well
|
||||
// this has to be checked before canMoveTo, otherwise it will return false
|
||||
if (attackedTile.civilianUnit != null && attackedTile.civilianUnit!!.civInfo != attacker.getCivInfo())
|
||||
captureCivilianUnit(attacker, MapUnitCombatant(attackedTile.civilianUnit!!))
|
||||
// Units that can move after attacking are not affected by zone of control if the
|
||||
// movement is caused by killing a unit. Effectively, this means that attack movements
|
||||
// are exempt from zone of control, since units that cannot move after attacking already
|
||||
// lose all remaining movement points anyway.
|
||||
attacker.unit.movement.moveToTile(attackedTile, considerZoneOfControl = false)
|
||||
|
||||
// This is so that if we attack e.g. a barbarian in enemy territory that we can't enter, we won't enter it
|
||||
if ((attacker as MapUnitCombatant).unit.movement.canMoveTo(attackedTile)) {
|
||||
// Units that can move after attacking are not affected by zone of control if the
|
||||
// movement is caused by killing a unit. Effectively, this means that attack movements
|
||||
// are exempt from zone of control, since units that cannot move after attacking already
|
||||
// lose all remaining movement points anyway.
|
||||
attacker.unit.movement.moveToTile(attackedTile, considerZoneOfControl = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,14 +480,40 @@ object Battle {
|
||||
defender.getTile().position, attacker.getName(), NotificationIcon.War, defender.getName())
|
||||
|
||||
val capturedUnitTile = capturedUnit.getTile()
|
||||
val originalOwner = if (capturedUnit.originalOwner != null)
|
||||
capturedUnit.civInfo.gameInfo.getCivilization(capturedUnit.originalOwner!!)
|
||||
else null
|
||||
|
||||
|
||||
when {
|
||||
// Uncapturable units are destroyed
|
||||
defender.unit.hasUnique("Uncapturable") -> {
|
||||
capturedUnit.destroy()
|
||||
}
|
||||
// City states can never capture settlers at all
|
||||
capturedUnit.hasUnique("Founds a new city") && attacker.getCivInfo().isCityState() -> {
|
||||
capturedUnit.destroy()
|
||||
}
|
||||
// Is it our old unit?
|
||||
attacker.getCivInfo() == originalOwner -> {
|
||||
// Then it is recaptured without converting settlers to workers
|
||||
capturedUnit.capturedBy(attacker.getCivInfo())
|
||||
}
|
||||
// Return captured civilian to its original owner?
|
||||
defender.getCivInfo().isBarbarian()
|
||||
&& originalOwner != null
|
||||
&& !originalOwner.isBarbarian()
|
||||
&& attacker.getCivInfo() != originalOwner
|
||||
&& attacker.getCivInfo().knows(originalOwner)
|
||||
&& originalOwner.isAlive()
|
||||
&& !attacker.getCivInfo().isAtWarWith(originalOwner)
|
||||
&& attacker.getCivInfo().playerType == PlayerType.Human // Only humans get the choice
|
||||
-> {
|
||||
capturedUnit.capturedBy(attacker.getCivInfo())
|
||||
attacker.getCivInfo().popupAlerts.add(PopupAlert(AlertType.RecapturedCivilian, capturedUnitTile.position.toString()))
|
||||
}
|
||||
// Captured settlers are converted to workers unless captured by barbarians (so they can be returned later).
|
||||
capturedUnit.name == Constants.settler && !attacker.getCivInfo().isBarbarian() -> {
|
||||
capturedUnit.hasUnique("Founds a new city") && !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
|
||||
@ -492,14 +521,7 @@ object Battle {
|
||||
attacker.getCivInfo().placeUnitNearTile(capturedUnitTile.position, Constants.worker)
|
||||
}
|
||||
else -> {
|
||||
capturedUnit.civInfo.removeUnit(capturedUnit)
|
||||
capturedUnit.assignOwner(attacker.getCivInfo())
|
||||
capturedUnit.currentMovement = 0f
|
||||
// It's possible that the unit can no longer stand on the tile it was captured on.
|
||||
// For example, because it's embarked and the capturing civ cannot embark units yet.
|
||||
if (!capturedUnit.movement.canPassThrough(capturedUnitTile)) {
|
||||
capturedUnit.movement.teleportToClosestMoveableTile()
|
||||
}
|
||||
capturedUnit.capturedBy(attacker.getCivInfo())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ enum class AlertType {
|
||||
DiplomaticMarriage,
|
||||
BulliedProtectedMinor,
|
||||
AttackedProtectedMinor,
|
||||
RecapturedCivilian,
|
||||
}
|
||||
|
||||
class PopupAlert {
|
||||
|
@ -81,6 +81,7 @@ enum class DiplomaticModifiers {
|
||||
AttackedProtectedMinor,
|
||||
BulliedProtectedMinor,
|
||||
SidedWithProtectedMinor,
|
||||
ReturnedCapturedUnits,
|
||||
}
|
||||
|
||||
class DiplomacyManager() {
|
||||
@ -645,6 +646,7 @@ class DiplomacyManager() {
|
||||
}
|
||||
|
||||
otherCivDiplomacy.setModifier(DiplomaticModifiers.DeclaredWarOnUs, -20f)
|
||||
otherCivDiplomacy.removeModifier(DiplomaticModifiers.ReturnedCapturedUnits)
|
||||
if (otherCiv.isCityState()) {
|
||||
otherCivDiplomacy.setInfluence(-60f)
|
||||
civInfo.changeMinorCivsAttacked(1)
|
||||
|
@ -114,6 +114,9 @@ class MapUnit {
|
||||
/** civName owning the unit */
|
||||
lateinit var owner: String
|
||||
|
||||
/** civName of original owner - relevant for returning captured workers from barbarians */
|
||||
var originalOwner: String? = null
|
||||
|
||||
/**
|
||||
* Name key of the unit, used for serialization
|
||||
*/
|
||||
@ -169,6 +172,7 @@ class MapUnit {
|
||||
toReturn.name = name
|
||||
toReturn.civInfo = civInfo
|
||||
toReturn.owner = owner
|
||||
toReturn.originalOwner = originalOwner
|
||||
toReturn.instanceName = instanceName
|
||||
toReturn.currentMovement = currentMovement
|
||||
toReturn.health = health
|
||||
@ -916,6 +920,17 @@ class MapUnit {
|
||||
civInfo.addUnit(this, updateCivInfo)
|
||||
}
|
||||
|
||||
fun capturedBy(captor: CivilizationInfo) {
|
||||
civInfo.removeUnit(this)
|
||||
assignOwner(captor)
|
||||
currentMovement = 0f
|
||||
// It's possible that the unit can no longer stand on the tile it was captured on.
|
||||
// For example, because it's embarked and the capturing civ cannot embark units yet.
|
||||
if (!movement.canPassThrough(getTile())) {
|
||||
movement.teleportToClosestMoveableTile()
|
||||
}
|
||||
}
|
||||
|
||||
fun canIntercept(attackedTile: TileInfo): Boolean {
|
||||
if (!canIntercept()) return false
|
||||
if (currentTile.aerialDistanceTo(attackedTile) > baseUnit.interceptRange) return false
|
||||
|
@ -410,6 +410,8 @@ class TileMap {
|
||||
|
||||
// both the civ name and actual civ need to be in here in order to calculate the canMoveTo...Darn
|
||||
unit.assignOwner(civInfo, false)
|
||||
// remember our first owner
|
||||
unit.originalOwner = civInfo.civName
|
||||
|
||||
var unitToPlaceTile: TileInfo? = null
|
||||
// try to place at the original point (this is the most probable scenario)
|
||||
|
@ -759,6 +759,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo): CameraStageBaseScreen()
|
||||
AttackedProtectedMinor -> "You attacked City States that were under our protection!"
|
||||
BulliedProtectedMinor -> "You demanded tribute from City States that were under our protection!"
|
||||
SidedWithProtectedMinor -> "You sided with a City State over us"
|
||||
ReturnedCapturedUnits -> "You returned captured units to us"
|
||||
}
|
||||
text = text.tr() + " "
|
||||
if (modifier.value > 0) text += "+"
|
||||
|
@ -1,11 +1,13 @@
|
||||
package com.unciv.ui.worldscreen
|
||||
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.civilization.*
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.models.translations.fillPlaceholders
|
||||
import com.unciv.models.translations.tr
|
||||
@ -321,6 +323,49 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
cityState.removeProtectorCiv(player, forced = true)
|
||||
}).row()
|
||||
}
|
||||
AlertType.RecapturedCivilian -> {
|
||||
val position = Vector2().fromString(popupAlert.value)
|
||||
val tile = worldScreen.gameInfo.tileMap[position]
|
||||
val capturedUnit = tile.civilianUnit!! // This has got to be it
|
||||
val originalOwner = worldScreen.gameInfo.getCivilization(capturedUnit.originalOwner!!)
|
||||
val captor = worldScreen.viewingCiv
|
||||
|
||||
addGoodSizedLabel("Return [${capturedUnit.name}] to [${originalOwner.civName}]?")
|
||||
addSeparator()
|
||||
addGoodSizedLabel("The [${capturedUnit.name}] we liberated originally belonged to [${originalOwner.civName}]. They will be grateful if we return it to them.").row()
|
||||
val responseTable = Table()
|
||||
responseTable.defaults().pad(0f, 30f) // Small buttons, plenty of pad so we don't fat-finger it
|
||||
responseTable.add(getCloseButton("Yes", 'y') {
|
||||
// Return it to original owner
|
||||
val unitName = capturedUnit.baseUnit.name
|
||||
capturedUnit.destroy()
|
||||
val closestCity = originalOwner.cities.minByOrNull { it.getCenterTile().aerialDistanceTo(tile) }
|
||||
if (closestCity != null) {
|
||||
// Attempt to place the unit near their nearest city
|
||||
originalOwner.placeUnitNearTile(closestCity.location, unitName)
|
||||
}
|
||||
|
||||
if (originalOwner.isCityState()) {
|
||||
originalOwner.getDiplomacyManager(captor).addInfluence(45f)
|
||||
} else if (originalOwner.isMajorCiv()) {
|
||||
// No extra bonus from doing it several times
|
||||
originalOwner.getDiplomacyManager(captor).setModifier(DiplomaticModifiers.ReturnedCapturedUnits, 20f)
|
||||
}
|
||||
})
|
||||
responseTable.add(getCloseButton("No", 'n') {
|
||||
// Take it for ourselves
|
||||
// Settlers become workers at this point
|
||||
if (capturedUnit.hasUnique("Founds a new city")) {
|
||||
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
|
||||
capturedUnit.civInfo = captor
|
||||
captor.placeUnitNearTile(tile.position, Constants.worker)
|
||||
} else
|
||||
capturedUnit.capturedBy(captor)
|
||||
}).row()
|
||||
add(responseTable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user