Disabled CS buttons when at war; CS keep influence when at war with ally (#6813)

* Disabled CS buttons when at war; CS keep influence when at war with ally
This PR does two things:
- When you are at war with a city state, you can no longer give them 
money, demand stuff, etc.
- When at war with the ally of a city state, your influence is frozen, 
and after the end of the conflict set back to its original value.
To implement this last thing, I had to split the getter of `influence` 
off of the underlying field, as otherwise when copying over the old 
value in `.clone()`, we would copy over -60 when at war, instead of the 
original value. Most of the changes in that PR are a result of that.
Also resets the `simulateUntilTurns` variable after completing 
simulations

* Updated comment
This commit is contained in:
Xander Lenstra 2022-05-15 16:56:26 +02:00 committed by GitHub
parent 07562f23ff
commit 66feebae8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 47 deletions

View File

@ -247,6 +247,8 @@ class GameInfo {
}
switchTurn()
}
if (turns == UncivGame.Current.simulateUntilTurnForDebug)
UncivGame.Current.simulateUntilTurnForDebug = 0
currentTurnStartTime = System.currentTimeMillis()
currentPlayer = thisPlayer.civName

View File

@ -244,7 +244,7 @@ object NextTurnAutomation {
private fun tryGainInfluence(civInfo: CivilizationInfo, cityState: CivilizationInfo) {
if (civInfo.gold < 250) return // save up
if (cityState.getDiplomacyManager(civInfo).influence < 20) {
if (cityState.getDiplomacyManager(civInfo).getInfluence() < 20) {
cityState.receiveGoldGift(civInfo, 250)
return
}
@ -267,7 +267,7 @@ object NextTurnAutomation {
for (cityState in civInfo.getKnownCivs()
.filter { it.isCityState() && it.cityStateType == CityStateType.Cultured }) {
val diploManager = cityState.getDiplomacyManager(civInfo)
if (diploManager.influence < 40) { // we want to gain influence with them
if (diploManager.getInfluence() < 40) { // we want to gain influence with them
tryGainInfluence(civInfo, cityState)
return
}
@ -329,7 +329,7 @@ object NextTurnAutomation {
}
if (cityState.getAllyCiv() != null && cityState.getAllyCiv() != civInfo.civName) {
// easier not to compete if a third civ has this locked down
val thirdCivInfluence = cityState.getDiplomacyManager(cityState.getAllyCiv()!!).influence.toInt()
val thirdCivInfluence = cityState.getDiplomacyManager(cityState.getAllyCiv()!!).getInfluence().toInt()
value -= (thirdCivInfluence - 60) / 10
}

View File

@ -177,7 +177,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
}
fun removeProtectorCiv(otherCiv: CivilizationInfo, forced: Boolean = false) {
if(!otherCivCanWithdrawProtection(otherCiv) && !forced)
if(!forced && !otherCivCanWithdrawProtection(otherCiv))
return
val diplomacy = civInfo.getDiplomacyManager(otherCiv)
@ -195,7 +195,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
if (diplomacy.hasFlag(DiplomacyFlags.RecentlyWithdrewProtection))
return false
// Must have at least 0 influence
if (diplomacy.influence < 0)
if (diplomacy.getInfluence() < 0)
return false
// can't be at war
if (civInfo.isAtWarWith(otherCiv))
@ -225,8 +225,8 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
if (!civInfo.isCityState()) return
val maxInfluence = civInfo.diplomacy
.filter { !it.value.otherCiv().isCityState() && !it.value.otherCiv().isDefeated() }
.maxByOrNull { it.value.influence }
if (maxInfluence != null && maxInfluence.value.influence >= 60) {
.maxByOrNull { it.value.getInfluence() }
if (maxInfluence != null && maxInfluence.value.getInfluence() >= 60) {
newAllyName = maxInfluence.key
}
@ -350,7 +350,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
modifiers["Very recently paid tribute"] = -300
else if (recentBullying != null)
modifiers["Recently paid tribute"] = -40
if (civInfo.getDiplomacyManager(demandingCiv).influence < -30)
if (civInfo.getDiplomacyManager(demandingCiv).getInfluence() < -30)
modifiers["Influence below -30"] = -300
// Slight optimization, we don't do the expensive stuff if we have no chance of getting a >= 0 result

View File

@ -598,11 +598,15 @@ class CivilizationInfo {
fun getEraNumber(): Int = getEra().eraNumber
fun isAtWarWith(otherCiv: CivilizationInfo): Boolean {
if (otherCiv == this) return false // never at war with itself
if (otherCiv.isBarbarian() || isBarbarian()) return true
val diplomacyManager = diplomacy[otherCiv.civName]
?: return false // not encountered yet
return diplomacyManager.diplomaticStatus == DiplomaticStatus.War
return when {
otherCiv == this -> false
otherCiv.isBarbarian() || isBarbarian() -> true
else -> {
val diplomacyManager = diplomacy[otherCiv.civName]
?: return false // not encountered yet
return diplomacyManager.diplomaticStatus == DiplomaticStatus.War
}
}
}
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus == DiplomaticStatus.War && !it.otherCiv().isDefeated() }

View File

@ -115,10 +115,10 @@ class DiplomacyManager() {
var diplomaticModifiers = HashMap<String, Float>()
/** For city-states. Influence is saved in the CITY STATE -> major civ Diplomacy, NOT in the major civ -> city state diplomacy.
* Won't go below [MINIMUM_INFLUENCE]. Note this declaration leads to Major Civs getting MINIMUM_INFLUENCE serialized, but that is ignored. */
var influence = 0f
private set
get() = if (civInfo.isAtWarWith(otherCiv())) MINIMUM_INFLUENCE else field
* Access via getInfluence() and setInfluence() unless you know what you're doing.
* Note that not using the setter skips recalculating the ally and bounds checks,
* and skipping the getter bypasses the modified value when at war */
private var influence = 0f
/** Total of each turn Science during Research Agreement */
private var totalOfScienceDuringRA = 0
@ -168,11 +168,11 @@ class DiplomacyManager() {
return otherCiv().getDiplomacyManager(civInfo).relationshipLevel()
if (civInfo.isCityState()) return when {
influence >= 60 && civInfo.getAllyCiv() == otherCivName -> RelationshipLevel.Ally
influence >= 30 -> RelationshipLevel.Friend
influence <= -30 || civInfo.isAtWarWith(otherCiv()) -> RelationshipLevel.Unforgivable
influence < 30 && civInfo.getTributeWillingness(otherCiv()) > 0 -> RelationshipLevel.Afraid
influence < 0 -> RelationshipLevel.Enemy
getInfluence() <= -30 || civInfo.isAtWarWith(otherCiv()) -> RelationshipLevel.Unforgivable
getInfluence() < 0 -> RelationshipLevel.Enemy
getInfluence() < 30 && civInfo.getTributeWillingness(otherCiv()) > 0 -> RelationshipLevel.Afraid
getInfluence() >= 60 && civInfo.getAllyCiv() == otherCivName -> RelationshipLevel.Ally
getInfluence() >= 30 -> RelationshipLevel.Friend
else -> RelationshipLevel.Neutral
}
@ -201,8 +201,8 @@ class DiplomacyManager() {
val dropPerTurn = getCityStateInfluenceDegrade()
return when {
dropPerTurn == 0f -> 0
relationshipLevel() >= RelationshipLevel.Ally -> ceil((influence - 60f) / dropPerTurn).toInt() + 1
relationshipLevel() >= RelationshipLevel.Friend -> ceil((influence - 30f) / dropPerTurn).toInt() + 1
relationshipLevel() >= RelationshipLevel.Ally -> ceil((getInfluence() - 60f) / dropPerTurn).toInt() + 1
relationshipLevel() >= RelationshipLevel.Friend -> ceil((getInfluence() - 30f) / dropPerTurn).toInt() + 1
else -> 0
}
}
@ -230,6 +230,8 @@ class DiplomacyManager() {
influence = max(amount, MINIMUM_INFLUENCE)
civInfo.updateAllyCivForCityState()
}
fun getInfluence() = if (civInfo.isAtWarWith(otherCiv())) MINIMUM_INFLUENCE else influence
// To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different.
private fun getCityStateInfluenceRestingPoint(): Float {
@ -251,7 +253,7 @@ class DiplomacyManager() {
}
private fun getCityStateInfluenceDegrade(): Float {
if (influence < getCityStateInfluenceRestingPoint())
if (getInfluence() < getCityStateInfluenceRestingPoint())
return 0f
val decrement = when {
@ -279,7 +281,7 @@ class DiplomacyManager() {
}
private fun getCityStateInfluenceRecovery(): Float {
if (influence > getCityStateInfluenceRestingPoint())
if (getInfluence() > getCityStateInfluenceRestingPoint())
return 0f
val increment = 1f // sic: personality does not matter here
@ -424,7 +426,7 @@ class DiplomacyManager() {
updateHasOpenBorders()
nextTurnDiplomaticModifiers()
nextTurnFlags()
if (civInfo.isCityState() && !otherCiv().isCityState())
if (civInfo.isCityState() && otherCiv().isMajorCiv())
nextTurnCityStateInfluence()
updateEverBeenFriends()
}
@ -442,14 +444,16 @@ class DiplomacyManager() {
val initialRelationshipLevel = relationshipLevel()
val restingPoint = getCityStateInfluenceRestingPoint()
// We don't use `getInfluence()` here, as then during war with the ally of this CS,
// our influence would be set to -59, overwriting the old value, which we want to keep
// as it should be restored once the war ends (though we keep influence degradation from time during the war)
if (influence > restingPoint) {
val decrement = getCityStateInfluenceDegrade()
influence = max(restingPoint, influence - decrement)
setInfluence(max(restingPoint, influence - decrement))
} else if (influence < restingPoint) {
val increment = getCityStateInfluenceRecovery()
influence = min(restingPoint, influence + increment)
setInfluence(min(restingPoint, influence + increment))
}
civInfo.updateAllyCivForCityState()
if (!civInfo.isDefeated()) { // don't display city state relationship notifications when the city state is currently defeated
val civCapitalLocation = if (civInfo.cities.isNotEmpty()) civInfo.getCapital().location else null
@ -466,7 +470,7 @@ class DiplomacyManager() {
}
// Potentially notify about afraid status
if (influence < 30 // We usually don't want to bully our friends
if (getInfluence() < 30 // We usually don't want to bully our friends
&& !hasFlag(DiplomacyFlags.NotifiedAfraid)
&& civInfo.getTributeWillingness(otherCiv()) > 0
&& otherCiv().isMajorCiv()
@ -650,6 +654,10 @@ class DiplomacyManager() {
trades.clear()
updateHasOpenBorders()
if (civInfo.isCityState() && civInfo.getProtectorCivs().contains(otherCiv())) {
civInfo.removeProtectorCiv(otherCiv(), forced = true)
}
diplomaticStatus = DiplomaticStatus.War
removeModifier(DiplomaticModifiers.YearsOfPeace)
@ -658,7 +666,15 @@ class DiplomacyManager() {
removeFlag(DiplomacyFlags.BorderConflict)
}
fun declareWar() {
/** Declares war with the other civ in this diplomacy manager.
* Handles all war effects and diplomatic changes with other civs and such.
*
* @param indirectCityStateAttack Influence with city states should only be set to -60
* when they are attacked directly, not when their ally is attacked.
* When @indirectCityStateAttack is set to true, we thus don't reset the influence with this city state.
* Should only ever be set to true for calls originating from within this function.
*/
fun declareWar(indirectCityStateAttack: Boolean = false) {
val otherCiv = otherCiv()
val otherCivDiplomacy = otherCivDiplomacy()
@ -675,14 +691,15 @@ class DiplomacyManager() {
otherCivDiplomacy.setModifier(DiplomaticModifiers.DeclaredWarOnUs, -20f)
otherCivDiplomacy.removeModifier(DiplomaticModifiers.ReturnedCapturedUnits)
if (otherCiv.isCityState()) {
otherCivDiplomacy.setInfluence(-60f)
if (!indirectCityStateAttack)
otherCivDiplomacy.setInfluence(-60f)
civInfo.changeMinorCivsAttacked(1)
otherCiv.cityStateFunctions.cityStateAttacked(civInfo)
}
for (thirdCiv in civInfo.getKnownCivs()) {
if (thirdCiv.isAtWarWith(otherCiv)) {
if (thirdCiv.isCityState()) thirdCiv.getDiplomacyManager(civInfo).influence += 10
if (thirdCiv.isCityState()) thirdCiv.getDiplomacyManager(civInfo).addInfluence(10f)
else thirdCiv.getDiplomacyManager(civInfo).addModifier(DiplomaticModifiers.SharedEnemy, 5f)
} else thirdCiv.getDiplomacyManager(civInfo).addModifier(DiplomaticModifiers.WarMongerer, -5f)
}
@ -710,11 +727,11 @@ class DiplomacyManager() {
for (thirdCiv in civInfo.getKnownCivs()) {
if (thirdCiv.isCityState() && thirdCiv.getAllyCiv() == civInfo.civName) {
if (thirdCiv.knows(otherCiv) && !thirdCiv.isAtWarWith(otherCiv))
thirdCiv.getDiplomacyManager(otherCiv).declareWar()
thirdCiv.getDiplomacyManager(otherCiv).declareWar(true)
else if (!thirdCiv.knows(otherCiv)) {
// Our city state ally has not met them yet, so they have to meet first
thirdCiv.makeCivilizationsMeet(otherCiv, warOnContact = true)
thirdCiv.getDiplomacyManager(otherCiv).declareWar()
thirdCiv.getDiplomacyManager(otherCiv).declareWar(true)
}
}
}
@ -725,11 +742,11 @@ class DiplomacyManager() {
for (thirdCiv in otherCiv.getKnownCivs()) {
if (thirdCiv.isCityState() && thirdCiv.getAllyCiv() == otherCiv.civName) {
if (thirdCiv.knows(civInfo) && !thirdCiv.isAtWarWith(civInfo))
thirdCiv.getDiplomacyManager(civInfo).declareWar()
thirdCiv.getDiplomacyManager(civInfo).declareWar(true)
else if (!thirdCiv.knows(civInfo)) {
// Their city state ally has not met us yet, so we have to meet first
thirdCiv.makeCivilizationsMeet(civInfo, warOnContact = true)
thirdCiv.getDiplomacyManager(civInfo).declareWar()
thirdCiv.getDiplomacyManager(civInfo).declareWar(true)
}
}
}

View File

@ -54,7 +54,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
if (city.civInfo.isCityState() && city.civInfo.knows(worldScreen.viewingCiv)) {
val diplomacyManager = city.civInfo.getDiplomacyManager(worldScreen.viewingCiv)
val influenceBar = getInfluenceBar(diplomacyManager.influence, diplomacyManager.relationshipLevel())
val influenceBar = getInfluenceBar(diplomacyManager.getInfluence(), diplomacyManager.relationshipLevel())
add(influenceBar).row()
}

View File

@ -202,7 +202,7 @@ class DiplomacyScreen(
otherCiv.updateAllyCivForCityState()
val ally = otherCiv.getAllyCiv()
if (ally != null) {
val allyInfluence = otherCiv.getDiplomacyManager(ally).influence.toInt()
val allyInfluence = otherCiv.getDiplomacyManager(ally).getInfluence().toInt()
diplomacyTable
.add("Ally: [$ally] with [$allyInfluence] Influence".toLabel())
.row()
@ -214,8 +214,11 @@ class DiplomacyScreen(
diplomacyTable.add(protectorString.toLabel()).row()
}
val atWar = otherCiv.isAtWarWith(viewingCiv)
val nextLevelString = when {
otherCivDiplomacyManager.influence.toInt() < 30 -> "Reach 30 for friendship."
atWar -> ""
otherCivDiplomacyManager.getInfluence().toInt() < 30 -> "Reach 30 for friendship."
ally == viewingCiv.civName -> ""
else -> "Reach highest influence above 60 for alliance."
}
@ -322,7 +325,7 @@ class DiplomacyScreen(
rightSideTable.add(ScrollPane(getGoldGiftTable(otherCiv)))
}
diplomacyTable.add(giveGiftButton).row()
if (isNotPlayersTurn()) giveGiftButton.disable()
if (isNotPlayersTurn() || viewingCiv.isAtWarWith(otherCiv)) giveGiftButton.disable()
val improveTileButton = getImproveTilesButton(otherCiv, otherCivDiplomacyManager)
if (improveTileButton != null) diplomacyTable.add(improveTileButton).row()
@ -357,7 +360,7 @@ class DiplomacyScreen(
rightSideTable.add(ScrollPane(getDemandTributeTable(otherCiv)))
}
diplomacyTable.add(demandTributeButton).row()
if (isNotPlayersTurn()) demandTributeButton.disable()
if (isNotPlayersTurn() || viewingCiv.isAtWarWith(otherCiv)) demandTributeButton.disable()
val diplomacyManager = viewingCiv.getDiplomacyManager(otherCiv)
if (!viewingCiv.gameInfo.ruleSet.modOptions.uniques.contains(ModOptionsConstants.diplomaticRelationshipsCannotChange)) {
@ -440,7 +443,7 @@ class DiplomacyScreen(
}
if (isNotPlayersTurn() || otherCivDiplomacyManager.influence < 60 || !needsImprovements)
if (isNotPlayersTurn() || otherCivDiplomacyManager.getInfluence() < 60 || !needsImprovements)
improveTileButton.disable()
return improveTileButton
}
@ -857,7 +860,7 @@ class DiplomacyScreen(
val relationshipTable = Table()
val opinionOfUs =
if (otherCivDiplomacyManager.civInfo.isCityState()) otherCivDiplomacyManager.influence.toInt()
if (otherCivDiplomacyManager.civInfo.isCityState()) otherCivDiplomacyManager.getInfluence().toInt()
else otherCivDiplomacyManager.opinionOfOtherCiv().toInt()
relationshipTable.add("{Our relationship}: ".toLabel())
@ -875,8 +878,8 @@ class DiplomacyScreen(
if (otherCivDiplomacyManager.civInfo.isCityState())
relationshipTable.add(
CityButton.getInfluenceBar(
otherCivDiplomacyManager.influence,
otherCivDiplomacyManager.relationshipLevel(),
otherCivDiplomacyManager.getInfluence(),
relationshipLevel,
200f, 10f
)
).colspan(2).pad(5f)