mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-04 07:17:50 +07:00
Conquering a city destroys buildings inside the city (#4995)
* When conquering a city, some buildings are now destroyed * Added missing translation for uniques
This commit is contained in:
@ -18,7 +18,8 @@
|
||||
"culture": 2,
|
||||
"cost": 40,
|
||||
"hurryCostModifier": 40,
|
||||
"maintenance": 1
|
||||
"maintenance": 1,
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
// Column 1
|
||||
{
|
||||
@ -128,7 +129,8 @@
|
||||
"cityStrength": 5,
|
||||
"cityHealth": 50,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredTech": "Masonry"
|
||||
"requiredTech": "Masonry",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Walls of Babylon",
|
||||
@ -138,7 +140,8 @@
|
||||
"cityStrength": 6,
|
||||
"cityHealth": 100,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredTech": "Masonry"
|
||||
"requiredTech": "Masonry",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "The Pyramids",
|
||||
@ -163,7 +166,7 @@
|
||||
"name": "Barracks",
|
||||
"hurryCostModifier": 25,
|
||||
"maintenance": 1,
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]"]
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]", "Destroyed when the city is captured"],
|
||||
"requiredTech": "Bronze Working"
|
||||
},
|
||||
{
|
||||
@ -173,7 +176,7 @@
|
||||
"hurryCostModifier": 25,
|
||||
"maintenance": 1,
|
||||
"uniques": ["-[25]% Culture cost of acquiring tiles [in this city]","-[25]% Gold cost of acquiring tiles [in this city]",
|
||||
"New [Military] units start with [15] Experience [in this city]"],
|
||||
"New [Military] units start with [15] Experience [in this city]", "Destroyed when the city is captured"],
|
||||
"requiredTech": "Bronze Working"
|
||||
},
|
||||
{
|
||||
@ -270,7 +273,7 @@
|
||||
"maintenance": 2,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredTech": "Philosophy",
|
||||
"uniques": ["Hidden when religion is disabled"]
|
||||
"uniques": ["Hidden when religion is disabled", "Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "National College",
|
||||
@ -570,8 +573,8 @@
|
||||
"cityHealth": 25,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredBuilding": "Walls",
|
||||
"requiredTech": "Chivalry"
|
||||
// 4 cityStrength in vanilla, no ExtraCityHitPoints in vanilla
|
||||
"requiredTech": "Chivalry",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Mughal Fort",
|
||||
@ -583,7 +586,7 @@
|
||||
"culture": 2,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredBuilding": "Walls",
|
||||
"uniques": ["[+1 Gold] once [Flight] is discovered"],
|
||||
"uniques": ["[+1 Gold] once [Flight] is discovered", "Destroyed when the city is captured"],
|
||||
"requiredTech": "Chivalry"
|
||||
},
|
||||
{
|
||||
@ -620,7 +623,7 @@
|
||||
"hurryCostModifier": 25,
|
||||
"maintenance": 1,
|
||||
"requiredBuilding": "Barracks",
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]"]
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]", "Destroyed when the city is captured"],
|
||||
"requiredTech": "Steel"
|
||||
},
|
||||
|
||||
@ -643,7 +646,8 @@
|
||||
"hurryCostModifier": 10,
|
||||
"requiredBuilding": "Amphitheater",
|
||||
"maintenance": 2,
|
||||
"requiredTech": "Acoustics"
|
||||
"requiredTech": "Acoustics",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Sistine Chapel",
|
||||
@ -800,7 +804,8 @@
|
||||
"requiredBuilding": "Opera House",
|
||||
"maintenance": 3,
|
||||
"hurryCostModifier": 0,
|
||||
"requiredTech": "Archaeology"
|
||||
"requiredTech": "Archaeology",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "The Louvre",
|
||||
@ -848,7 +853,7 @@
|
||||
"hurryCostModifier": 0,
|
||||
"maintenance": 1,
|
||||
"requiredBuilding": "Armory",
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]"],
|
||||
"uniques": ["New [Military] units start with [15] Experience [in this city]", "Destroyed when the city is captured"],
|
||||
"requiredTech": "Military Science"
|
||||
},
|
||||
{
|
||||
@ -905,7 +910,8 @@
|
||||
"percentStatBonus": {"culture": 33},
|
||||
"requiredBuilding": "Museum",
|
||||
"maintenance": 3,
|
||||
"requiredTech": "Radio"
|
||||
"requiredTech": "Radio",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Eiffel Tower",
|
||||
@ -923,7 +929,8 @@
|
||||
"cityHealth": 25,
|
||||
"hurryCostModifier": 25,
|
||||
"requiredBuilding": "Arsenal",
|
||||
"requiredTech": "Replaceable Parts"
|
||||
"requiredTech": "Replaceable Parts",
|
||||
"uniques": ["Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Statue of Liberty",
|
||||
@ -1134,7 +1141,7 @@
|
||||
"faith": 2,
|
||||
"uniques": ["[+1 Culture, +1 Faith] from [Wine] tiles [in this city]",
|
||||
"[+1 Culture, +1 Faith] from [Incense] tiles [in this city]",
|
||||
"Unbuildable", "Hidden when religion is disabled"]
|
||||
"Unbuildable", "Hidden when religion is disabled", "Destroyed when the city is captured"]
|
||||
},
|
||||
{
|
||||
"name": "Mosque",
|
||||
|
@ -1166,3 +1166,4 @@ in all cities with a garrison =
|
||||
Only available after [] turns =
|
||||
This Unit upgrades for free =
|
||||
[stats] when a city adopts this religion for the first time =
|
||||
Never destroyed when the city is captured =
|
@ -15,15 +15,66 @@ import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
|
||||
/** Helper class for containing 200 lines of "how to move cities between civs" */
|
||||
class CityInfoConquestFunctions(val city: CityInfo){
|
||||
fun annexCity() {
|
||||
city.isPuppet = false
|
||||
city.cityConstructions.inProgressConstructions.clear() // undo all progress of the previous civ on units etc.
|
||||
city.cityStats.update()
|
||||
if (!UncivGame.Current.consoleMode)
|
||||
UncivGame.Current.worldScreen.shouldUpdate = true
|
||||
private val tileBasedRandom = Random(city.getCenterTile().position.toString().hashCode())
|
||||
|
||||
private fun getGoldForCapturingCity(conqueringCiv: CivilizationInfo): Int {
|
||||
val baseGold = 20 + 10 * city.population.population + tileBasedRandom.nextInt(40)
|
||||
val turnModifier = max(0, min(50, city.civInfo.gameInfo.turns - city.turnAcquired)) / 50f
|
||||
val cityModifier = if (city.containsBuildingUnique("Doubles Gold given to enemy if city is captured")) 2f else 1f
|
||||
val conqueringCivModifier = if (conqueringCiv.hasUnique("Receive triple Gold from Barbarian encampments and pillaging Cities")) 3f else 1f
|
||||
|
||||
val goldPlundered = baseGold * turnModifier * cityModifier * conqueringCivModifier
|
||||
return goldPlundered.toInt()
|
||||
}
|
||||
|
||||
private fun destroyBuildingsOnCapture() {
|
||||
city.apply {
|
||||
// Remove all national wonders (must come after the palace relocation because that's a national wonder too!)
|
||||
for (building in cityConstructions.getBuiltBuildings()) {
|
||||
when {
|
||||
building.hasUnique("Never destroyed when the city is captured") -> continue
|
||||
building.hasUnique("Destroyed when the city is captured") ->
|
||||
cityConstructions.removeBuilding(building.name)
|
||||
else -> {
|
||||
if (tileBasedRandom.nextInt(100) < 34) {
|
||||
cityConstructions.removeBuilding(building.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Function for stuff that should happen on any capture, be it puppet, annex or liberate.
|
||||
* Stuff that should happen any time a city is moved between civs, so also when trading,
|
||||
* should go in `this.moveToCiv()`, which this function also calls.
|
||||
*/
|
||||
private fun conquerCity(conqueringCiv: CivilizationInfo, conqueredCiv: CivilizationInfo, receivingCiv: CivilizationInfo) {
|
||||
val goldPlundered = getGoldForCapturingCity(conqueringCiv)
|
||||
city.apply {
|
||||
conqueringCiv.addGold(goldPlundered)
|
||||
conqueringCiv.addNotification("Received [$goldPlundered] Gold for capturing [$name]", getCenterTile().position, NotificationIcon.Gold)
|
||||
|
||||
val reconqueredCityWhileStillInResistance = previousOwner == conqueringCiv.civName && resistanceCounter != 0
|
||||
|
||||
this@CityInfoConquestFunctions.moveToCiv(receivingCiv)
|
||||
|
||||
destroyBuildingsOnCapture()
|
||||
|
||||
Battle.destroyIfDefeated(conqueredCiv, conqueringCiv)
|
||||
|
||||
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||
if (population.population > 1) population.addPopulation(-1 - population.population / 4) // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
||||
reassignPopulation()
|
||||
|
||||
resistanceCounter =
|
||||
if (reconqueredCityWhileStillInResistance || foundingCiv == receivingCiv.civName) 0
|
||||
else population.population // I checked, and even if you puppet there's resistance for conquering
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,29 +83,16 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
// Gain gold for plundering city
|
||||
val goldPlundered = getGoldForCapturingCity(conqueringCiv)
|
||||
city.apply {
|
||||
conqueringCiv.addGold(goldPlundered)
|
||||
conqueringCiv.addNotification("Received [$goldPlundered] Gold for capturing [$name]", getCenterTile().position, NotificationIcon.Gold)
|
||||
|
||||
|
||||
val oldCiv = civInfo
|
||||
val reconqueredCityWhileStillInResistance = previousOwner == conqueringCiv.civName && resistanceCounter != 0
|
||||
|
||||
|
||||
previousOwner = oldCiv.civName
|
||||
// must be before moving the city to the conquering civ,
|
||||
// so the repercussions are properly checked
|
||||
diplomaticRepercussionsForConqueringCity(oldCiv, conqueringCiv)
|
||||
|
||||
moveToCiv(conqueringCiv)
|
||||
Battle.destroyIfDefeated(oldCiv, conqueringCiv)
|
||||
|
||||
if (population.population > 1) population.addPopulation(-1 - population.population / 4) // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
||||
reassignPopulation()
|
||||
|
||||
if (reconqueredCityWhileStillInResistance || foundingCiv == conqueringCiv.civName)
|
||||
resistanceCounter = 0
|
||||
else resistanceCounter = population.population // I checked, and even if you puppet there's resistance for conquering
|
||||
conquerCity(conqueringCiv, oldCiv, conqueringCiv)
|
||||
|
||||
isPuppet = true
|
||||
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||
cityStats.update()
|
||||
// The city could be producing something that puppets shouldn't, like units
|
||||
cityConstructions.currentConstructionIsUserSet = false
|
||||
@ -63,18 +101,14 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getGoldForCapturingCity(conqueringCiv: CivilizationInfo): Int {
|
||||
val baseGold = 20 + 10 * city.population.population + Random().nextInt(40)
|
||||
val turnModifier = max(0, min(50, city.civInfo.gameInfo.turns - city.turnAcquired)) / 50f
|
||||
val cityModifier = if (city.containsBuildingUnique("Doubles Gold given to enemy if city is captured")) 2f else 1f
|
||||
val conqueringCivModifier = if (conqueringCiv.hasUnique("Receive triple Gold from Barbarian encampments and pillaging Cities")) 3f else 1f
|
||||
|
||||
val goldPlundered = baseGold * turnModifier * cityModifier * conqueringCivModifier
|
||||
return goldPlundered.toInt()
|
||||
fun annexCity() {
|
||||
city.isPuppet = false
|
||||
city.cityConstructions.inProgressConstructions.clear() // undo all progress of the previous civ on units etc.
|
||||
city.cityStats.update()
|
||||
if (!UncivGame.Current.consoleMode)
|
||||
UncivGame.Current.worldScreen.shouldUpdate = true
|
||||
}
|
||||
|
||||
|
||||
private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) {
|
||||
val currentPopulation = city.population.population
|
||||
val percentageOfCivPopulationInThatCity = currentPopulation * 100f /
|
||||
@ -100,32 +134,24 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
}
|
||||
|
||||
fun liberateCity(conqueringCiv: CivilizationInfo) {
|
||||
val goldPlundered = getGoldForCapturingCity(conqueringCiv)
|
||||
city.apply {
|
||||
if (foundingCiv == "") { // this should never happen but just in case...
|
||||
puppetCity(conqueringCiv)
|
||||
annexCity()
|
||||
this@CityInfoConquestFunctions.puppetCity(conqueringCiv)
|
||||
this@CityInfoConquestFunctions.annexCity()
|
||||
return
|
||||
}
|
||||
|
||||
conqueringCiv.addGold(goldPlundered)
|
||||
conqueringCiv.addNotification("Received [$goldPlundered] Gold for capturing [$name]", getCenterTile().position, NotificationIcon.Gold)
|
||||
|
||||
val oldCiv = civInfo
|
||||
|
||||
val foundingCiv = civInfo.gameInfo.civilizations.first { it.civName == foundingCiv }
|
||||
if (foundingCiv.isDefeated()) // resurrected civ
|
||||
for (diploManager in foundingCiv.diplomacy.values)
|
||||
if (diploManager.diplomaticStatus == DiplomaticStatus.War)
|
||||
diploManager.makePeace()
|
||||
|
||||
diplomaticRepercussionsForLiberatingCity(conqueringCiv)
|
||||
moveToCiv(foundingCiv)
|
||||
Battle.destroyIfDefeated(oldCiv, conqueringCiv)
|
||||
|
||||
health = getMaxHealth() / 2 // I think that cities recover to half health when conquered?
|
||||
if (population.population > 1) population.addPopulation(-1 - population.population / 4) // so from 2-4 population, remove 1, from 5-8, remove 2, etc.
|
||||
reassignPopulation()
|
||||
val oldCiv = civInfo
|
||||
|
||||
diplomaticRepercussionsForLiberatingCity(conqueringCiv, oldCiv)
|
||||
|
||||
conquerCity(conqueringCiv, oldCiv, foundingCiv)
|
||||
|
||||
if (foundingCiv.cities.size == 1) cityConstructions.addBuilding(capitalCityIndicator()) // Resurrection!
|
||||
isPuppet = false
|
||||
@ -141,12 +167,11 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
}
|
||||
|
||||
|
||||
private fun diplomaticRepercussionsForLiberatingCity(conqueringCiv: CivilizationInfo) {
|
||||
val oldOwningCiv = city.civInfo
|
||||
val foundingCiv = oldOwningCiv.gameInfo.civilizations.first { it.civName == city.foundingCiv }
|
||||
private fun diplomaticRepercussionsForLiberatingCity(conqueringCiv: CivilizationInfo, conqueredCiv: CivilizationInfo) {
|
||||
val foundingCiv = conqueredCiv.gameInfo.civilizations.first { it.civName == city.foundingCiv }
|
||||
val percentageOfCivPopulationInThatCity = city.population.population *
|
||||
100f / (foundingCiv.cities.sumBy { it.population.population } + city.population.population)
|
||||
val respecForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt()
|
||||
val respectForLiberatingOurCity = 10f + percentageOfCivPopulationInThatCity.roundToInt()
|
||||
|
||||
// In order to get "plus points" in Diplomacy, you have to establish diplomatic relations if you haven't yet
|
||||
if (!conqueringCiv.knows(foundingCiv))
|
||||
@ -154,7 +179,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
|
||||
if (foundingCiv.isMajorCiv()) {
|
||||
foundingCiv.getDiplomacyManager(conqueringCiv)
|
||||
.addModifier(DiplomaticModifiers.CapturedOurCities, respecForLiberatingOurCity)
|
||||
.addModifier(DiplomaticModifiers.CapturedOurCities, respectForLiberatingOurCity)
|
||||
} else {
|
||||
//Liberating a city state gives a large amount of influence, and peace
|
||||
foundingCiv.getDiplomacyManager(conqueringCiv).influence = 90f
|
||||
@ -166,8 +191,8 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
}
|
||||
}
|
||||
|
||||
val otherCivsRespecForLiberating = (respecForLiberatingOurCity / 10).roundToInt().toFloat()
|
||||
for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() && it != oldOwningCiv }) {
|
||||
val otherCivsRespecForLiberating = (respectForLiberatingOurCity / 10).roundToInt().toFloat()
|
||||
for (thirdPartyCiv in conqueringCiv.getKnownCivs().filter { it.isMajorCiv() && it != conqueredCiv }) {
|
||||
thirdPartyCiv.getDiplomacyManager(conqueringCiv)
|
||||
.addModifier(DiplomaticModifiers.LiberatedCity, otherCivsRespecForLiberating) // Cool, keep at at! =D
|
||||
}
|
||||
@ -183,6 +208,7 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
if (isOriginalCapital) civInfo.hasEverOwnedOriginalCapital = true
|
||||
hasJustBeenConquered = false
|
||||
turnAcquired = civInfo.gameInfo.turns
|
||||
previousOwner = oldCiv.civName
|
||||
|
||||
// now that the tiles have changed, we need to reassign population
|
||||
for (it in workedTiles.filterNot { tiles.contains(it) }) {
|
||||
@ -199,13 +225,12 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
||||
}
|
||||
}
|
||||
|
||||
for (building in cityConstructions.getBuiltBuildings()) {
|
||||
if (building.isNationalWonder && !building.hasUnique("Never destroyed when the city is captured"))
|
||||
cityConstructions.removeBuilding(building.name)
|
||||
}
|
||||
|
||||
// Remove all national wonders (must come after the palace relocation because that's a national wonder too!)
|
||||
for (building in cityConstructions.getBuiltBuildings().filter { it.isNationalWonder })
|
||||
cityConstructions.removeBuilding(building.name)
|
||||
|
||||
|
||||
// Locate palace for newCiv if this is the only city they have
|
||||
// Place palace for newCiv if this is the only city they have
|
||||
if (newCivInfo.cities.count() == 1) {
|
||||
cityConstructions.addBuilding(capitalCityIndicator)
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
|
||||
fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
|
||||
return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate }
|
||||
}
|
||||
fun hasUnique(uniqueTemplate: String): Boolean {
|
||||
return uniqueObjects.any { it.placeholderText == uniqueTemplate }
|
||||
}
|
||||
|
||||
fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean = false): Boolean {
|
||||
if (stat in listOf(Stat.Production, Stat.Happiness)) return false
|
||||
|
Reference in New Issue
Block a user