Add May not annex cities unique (#9314)

* Add `May not annex cities` unique, following same behaviour as Civ5 Venice. Hopefully this time I won't need to re-install windows.

* Add `May not annex cities` unique, following same behaviour as Civ5 Venice. Hopefully this time I won't need to re-install windows.

* Fix raze button being unavailable in city screen

* Fixed raze button being available in city screen, as per civ5

* Corrected indentation

* mayAnnex instead of canAnnex, hasUnique rather than getMatchingUniques

* AI will follow rules

* Replaced getMatchingUniques with hasUnique, for real this time
This commit is contained in:
Skekdog
2023-05-09 21:02:19 +01:00
committed by GitHub
parent 203477eca1
commit a3ef6fa314
8 changed files with 53 additions and 21 deletions

View File

@ -1411,6 +1411,7 @@ What would you like to do with the city of [cityName]? =
Annex =
Annexed cities become part of your regular empire. =
Their citizens generate 2x the unhappiness, unless you build a courthouse. =
Your civilization may not annex this city. =
Puppet =
Puppeted cities do not increase your tech or policy cost. =
You have no control over the the production of puppeted cities. =
@ -1420,6 +1421,7 @@ Liberate (city returns to [originalOwner]) =
Liberating a city returns it to its original owner, giving you a massive relationship boost with them! =
Raze =
Razing the city annexes it, and starts burning the city to the ground. =
Razing the city puppets it, and starts burning the city to the ground. =
The population will gradually dwindle until the city is destroyed. =
Original capitals and holy cities cannot be razed. =
Destroy =

View File

@ -1016,7 +1016,7 @@ object NextTurnAutomation {
ownMilitaryStrength < sumOfEnemiesMilitaryStrength * 0.66f
for (city in civInfo.cities) {
if (city.isPuppet && city.population.population > 9
&& !city.isInResistance()
&& !city.isInResistance() && !civInfo.hasUnique(UniqueType.MayNotAnnexCities)
) {
city.annexCity()
}
@ -1124,7 +1124,7 @@ object NextTurnAutomation {
if ((city.population.population < 4 || civInfo.isCityState())
&& city.foundingCiv != civInfo.civName && city.canBeDestroyed(justCaptured = true)) {
// raze if attacker is a city state
city.annexCity()
if (!civInfo.hasUnique(UniqueType.MayNotAnnexCities)) { city.annexCity() }
city.isBeingRazed = true
}
}

View File

@ -595,6 +595,7 @@ object Battle {
if (city.isOriginalCapital && city.foundingCiv == attackerCiv.civName) {
// retaking old capital
city.puppetCity(attackerCiv)
//Although in Civ5 Venice is unable to re-annex their capital, that seems a bit silly. No check for May not annex cities here.
city.annexCity()
} else if (attackerCiv.isHuman()) {
// we're not taking our former capital

View File

@ -315,6 +315,13 @@ class CityInfoConquestFunctions(val city: City){
if (civ.gameInfo.isReligionEnabled()) religion.removeUnknownPantheons()
if (newCiv.hasUnique(UniqueType.MayNotAnnexCities)) {
isPuppet = true
cityConstructions.currentConstructionIsUserSet = false
cityConstructions.constructionQueue.clear()
cityConstructions.chooseNextConstruction()
}
tryUpdateRoadStatus()
cityStats.update()

View File

@ -239,6 +239,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
GainInfluenceWithUnitGiftToCityState("Gain [amount] Influence with a [baseUnitFilter] gift to a City-State", UniqueTarget.Global),
FaithCostOfGreatProphetChange("[relativeAmount]% Faith cost of generating Great Prophet equivalents", UniqueTarget.Global),
RestingPointOfCityStatesFollowingReligionChange("Resting point for Influence with City-States following this religion [amount]", UniqueTarget.Global),
MayNotAnnexCities("May not annex cities", UniqueTarget.Nation),
ProvidesGoldWheneverGreatPersonExpended("Provides a sum of gold each time you spend a Great Person", UniqueTarget.Global),
ProvidesStatsWheneverGreatPersonExpended("[stats] whenever a Great Person is expended", UniqueTarget.Global),

View File

@ -259,7 +259,8 @@ class CityScreen(
addWltkIcon("OtherIcons/WLTK 1") { color = Color.FIREBRICK }.padRight(10f)
}
if (city.isPuppet) {
val canAnnex = !city.civ.hasUnique(UniqueType.MayNotAnnexCities)
if (city.isPuppet && canAnnex) {
val annexCityButton = "Annex city".toTextButton()
annexCityButton.labelCell.pad(10f)
annexCityButton.onClick {
@ -272,8 +273,9 @@ class CityScreen(
val razeCityButton = "Raze city".toTextButton()
razeCityButton.labelCell.pad(10f)
razeCityButton.onClick { city.isBeingRazed = true; update() }
if (!canChangeState || !city.canBeDestroyed())
if (!canChangeState || !city.canBeDestroyed() || !canAnnex) {
razeCityButton.disable()
}
razeCityButtonHolder.add(razeCityButton) //.colspan(cityPickerTable.columns)
} else {

View File

@ -14,6 +14,7 @@ import com.unciv.logic.civilization.NotificationCategory
import com.unciv.logic.civilization.PopupAlert
import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.tr
import com.unciv.ui.audio.MusicMood
@ -146,7 +147,8 @@ class AlertPopup(
close()
}
} else {
addAnnexOption {
val mayAnnex = !conqueringCiv.hasUnique(UniqueType.MayNotAnnexCities)
addAnnexOption(mayAnnex = mayAnnex) {
city.puppetCity(conqueringCiv)
city.annexCity()
worldScreen.shouldUpdate = true
@ -154,16 +156,16 @@ class AlertPopup(
}
addSeparator()
addPuppetOption {
addPuppetOption(mayAnnex = mayAnnex) {
city.puppetCity(conqueringCiv)
worldScreen.shouldUpdate = true
close()
}
addSeparator()
addRazeOption(canRaze = { city.canBeDestroyed(justCaptured = true) } ) {
addRazeOption(canRaze = city.canBeDestroyed(justCaptured = true), mayAnnex = mayAnnex) {
city.puppetCity(conqueringCiv)
city.annexCity()
if (mayAnnex) { city.annexCity() }
city.isBeingRazed = true
worldScreen.shouldUpdate = true
close()
@ -239,13 +241,14 @@ class AlertPopup(
close()
}
} else {
addAnnexOption {
val mayAnnex = !marryingCiv.hasUnique(UniqueType.MayNotAnnexCities)
addAnnexOption(mayAnnex) {
city.annexCity()
close()
}
addSeparator()
addPuppetOption {
addPuppetOption(mayAnnex) {
city.isPuppet = true
city.cityStats.update()
worldScreen.shouldUpdate = true
@ -428,16 +431,25 @@ class AlertPopup(
addGoodSizedLabel("Destroying the city instantly razes the city to the ground.").row()
}
private fun addAnnexOption(annexAction: () -> Unit) {
private fun addAnnexOption(mayAnnex: Boolean, annexAction: () -> Unit) {
val button = "Annex".toTextButton()
button.onActivation { annexAction() }
button.keyShortcuts.add('a')
button.apply {
if (!mayAnnex) disable() else {
button.onActivation { annexAction() }
button.keyShortcuts.add('a')
}
}
add(button).row()
addGoodSizedLabel("Annexed cities become part of your regular empire.").row()
addGoodSizedLabel("Their citizens generate 2x the unhappiness, unless you build a courthouse.").row()
if (mayAnnex) {
addGoodSizedLabel("Annexed cities become part of your regular empire.").row()
addGoodSizedLabel("Their citizens generate 2x the unhappiness, unless you build a courthouse.").row()
} else {
addGoodSizedLabel("Your civilization may not annex this city.").row()
}
}
private fun addPuppetOption(puppetAction: () -> Unit) {
private fun addPuppetOption(mayAnnex: Boolean, puppetAction: () -> Unit) {
val button = "Puppet".toTextButton()
button.onActivation { puppetAction() }
button.keyShortcuts.add('p')
@ -445,7 +457,7 @@ class AlertPopup(
addGoodSizedLabel("Puppeted cities do not increase your tech or policy cost.").row()
addGoodSizedLabel("You have no control over the the production of puppeted cities.").row()
addGoodSizedLabel("Puppeted cities also generate 25% less Gold and Science.").row()
addGoodSizedLabel("A puppeted city can be annexed at any time.").row()
if (mayAnnex) addGoodSizedLabel("A puppeted city can be annexed at any time.").row()
}
private fun addLiberateOption(foundingCiv: String, liberateAction: () -> Unit) {
@ -456,18 +468,22 @@ class AlertPopup(
addGoodSizedLabel("Liberating a city returns it to its original owner, giving you a massive relationship boost with them!")
}
private fun addRazeOption(canRaze: () -> Boolean, razeAction: () -> Unit) {
private fun addRazeOption(canRaze: Boolean, mayAnnex: Boolean, razeAction: () -> Unit) {
val button = "Raze".toTextButton()
button.apply {
if (!canRaze()) disable()
if (!canRaze) disable()
else {
onActivation { razeAction() }
keyShortcuts.add('r')
}
}
add(button).row()
if (canRaze()) {
addGoodSizedLabel("Razing the city annexes it, and starts burning the city to the ground.").row()
if (canRaze) {
if (mayAnnex) {
addGoodSizedLabel("Razing the city annexes it, and starts burning the city to the ground.").row()
} else {
addGoodSizedLabel("Razing the city puppets it, and starts burning the city to the ground.").row()
}
addGoodSizedLabel("The population will gradually dwindle until the city is destroyed.").row()
} else {
addGoodSizedLabel("Original capitals and holy cities cannot be razed.").row()

View File

@ -863,6 +863,9 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl
??? example "Will not be chosen for new games"
Applicable to: Nation
??? example "May not annex cities"
Applicable to: Nation
??? example "Starts with [tech]"
Example: "Starts with [Agriculture]"