Fix disbanding units a civ cannot afford (#9073)

* Fix disbanding units a civ cannot afford

* Avoid performance impact of CityState Afraid evaluation where possible
This commit is contained in:
SomeTroglodyte 2023-03-30 09:22:52 +02:00 committed by GitHub
parent c5d0de8144
commit 3d56c1ba5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 105 additions and 42 deletions

View File

@ -258,7 +258,7 @@ object NextTurnAutomation {
if (popupAlert.type == AlertType.DeclarationOfFriendship) { if (popupAlert.type == AlertType.DeclarationOfFriendship) {
val requestingCiv = civInfo.gameInfo.getCivilization(popupAlert.value) val requestingCiv = civInfo.gameInfo.getCivilization(popupAlert.value)
val diploManager = civInfo.getDiplomacyManager(requestingCiv) val diploManager = civInfo.getDiplomacyManager(requestingCiv)
if (diploManager.relationshipLevel() > RelationshipLevel.Neutral if (diploManager.isRelationshipLevelGT(RelationshipLevel.Neutral)
&& !diploManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.Denunciation)) { && !diploManager.otherCivDiplomacy().hasFlag(DiplomacyFlags.Denunciation)) {
diploManager.signDeclarationOfFriendship() diploManager.signDeclarationOfFriendship()
requestingCiv.addNotification("We have signed a Declaration of Friendship with [${civInfo.civName}]!", NotificationCategory.Diplomacy, NotificationIcon.Diplomacy, civInfo.civName) requestingCiv.addNotification("We have signed a Declaration of Friendship with [${civInfo.civName}]!", NotificationCategory.Diplomacy, NotificationIcon.Diplomacy, civInfo.civName)
@ -377,23 +377,21 @@ object NextTurnAutomation {
} }
private fun protectCityStates(civInfo: Civilization) { private fun protectCityStates(civInfo: Civilization) {
for (state in civInfo.getKnownCivs().filter{!it.isDefeated() && it.isCityState()}) { for (state in civInfo.getKnownCivs().filter { !it.isDefeated() && it.isCityState() }) {
val diplomacyManager = state.getDiplomacyManager(civInfo.civName) val diplomacyManager = state.getDiplomacyManager(civInfo.civName)
if(diplomacyManager.relationshipLevel() >= RelationshipLevel.Friend val isAtLeastFriend = diplomacyManager.isRelationshipLevelGE(RelationshipLevel.Friend)
&& state.cityStateFunctions.otherCivCanPledgeProtection(civInfo)) if (isAtLeastFriend && state.cityStateFunctions.otherCivCanPledgeProtection(civInfo)) {
{
state.cityStateFunctions.addProtectorCiv(civInfo) state.cityStateFunctions.addProtectorCiv(civInfo)
} else if (diplomacyManager.relationshipLevel() < RelationshipLevel.Friend } else if (!isAtLeastFriend && state.cityStateFunctions.otherCivCanWithdrawProtection(civInfo)) {
&& state.cityStateFunctions.otherCivCanWithdrawProtection(civInfo)) {
state.cityStateFunctions.removeProtectorCiv(civInfo) state.cityStateFunctions.removeProtectorCiv(civInfo)
} }
} }
} }
private fun bullyCityStates(civInfo: Civilization) { private fun bullyCityStates(civInfo: Civilization) {
for (state in civInfo.getKnownCivs().filter{!it.isDefeated() && it.isCityState()}) { for (state in civInfo.getKnownCivs().filter { !it.isDefeated() && it.isCityState() }) {
val diplomacyManager = state.getDiplomacyManager(civInfo.civName) val diplomacyManager = state.getDiplomacyManager(civInfo.civName)
if(diplomacyManager.relationshipLevel() < RelationshipLevel.Friend if (diplomacyManager.isRelationshipLevelLT(RelationshipLevel.Friend)
&& diplomacyManager.diplomaticStatus == DiplomaticStatus.Peace && diplomacyManager.diplomaticStatus == DiplomaticStatus.Peace
&& valueCityStateAlliance(civInfo, state) <= 0 && valueCityStateAlliance(civInfo, state) <= 0
&& state.cityStateFunctions.getTributeWillingness(civInfo) >= 0) { && state.cityStateFunctions.getTributeWillingness(civInfo) >= 0) {
@ -652,8 +650,8 @@ object NextTurnAutomation {
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange) && !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclinedLuxExchange)
}) { }) {
val relationshipLevel = civInfo.getDiplomacyManager(otherCiv).relationshipLevel() val isEnemy = civInfo.getDiplomacyManager(otherCiv).isRelationshipLevelLE(RelationshipLevel.Enemy)
if (relationshipLevel <= RelationshipLevel.Enemy || otherCiv.tradeRequests.any { it.requestingCiv == civInfo.civName }) if (isEnemy || otherCiv.tradeRequests.any { it.requestingCiv == civInfo.civName })
continue continue
val trades = potentialLuxuryTrades(civInfo, otherCiv) val trades = potentialLuxuryTrades(civInfo, otherCiv)
@ -670,7 +668,7 @@ object NextTurnAutomation {
.asSequence() .asSequence()
.filter { .filter {
it.isMajorCiv() && !it.isAtWarWith(civInfo) it.isMajorCiv() && !it.isAtWarWith(civInfo)
&& it.getDiplomacyManager(civInfo).relationshipLevel() > RelationshipLevel.Neutral && it.getDiplomacyManager(civInfo).isRelationshipLevelGT(RelationshipLevel.Neutral)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship) && !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.DeclarationOfFriendship)
&& !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunciation) && !civInfo.getDiplomacyManager(it).hasFlag(DiplomacyFlags.Denunciation)
} }
@ -804,7 +802,7 @@ object NextTurnAutomation {
if (diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship)) if (diplomacyManager.hasFlag(DiplomacyFlags.DeclarationOfFriendship))
modifierMap["Declaration of Friendship"] = -10 modifierMap["Declaration of Friendship"] = -10
val relationshipModifier = when (diplomacyManager.relationshipLevel()) { val relationshipModifier = when (diplomacyManager.relationshipIgnoreAfraid()) {
RelationshipLevel.Unforgivable -> 10 RelationshipLevel.Unforgivable -> 10
RelationshipLevel.Enemy -> 5 RelationshipLevel.Enemy -> 5
RelationshipLevel.Ally -> -5 // this is so that ally + DoF is not too unbalanced - RelationshipLevel.Ally -> -5 // this is so that ally + DoF is not too unbalanced -

View File

@ -298,7 +298,7 @@ class CityStateFunctions(val civInfo: Civilization) {
return (!civInfo.isDefeated() return (!civInfo.isDefeated()
&& civInfo.isCityState() && civInfo.isCityState()
&& civInfo.cities.any() && civInfo.cities.any()
&& civInfo.getDiplomacyManager(otherCiv).relationshipLevel() == RelationshipLevel.Ally && civInfo.getDiplomacyManager(otherCiv).isRelationshipLevelEQ(RelationshipLevel.Ally)
&& !otherCiv.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.MarriageCooldown) && !otherCiv.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.MarriageCooldown)
&& otherCiv.getMatchingUniques(UniqueType.CityStateCanBeBoughtForGold).any() && otherCiv.getMatchingUniques(UniqueType.CityStateCanBeBoughtForGold).any()
&& otherCiv.gold >= getDiplomaticMarriageCost()) && otherCiv.gold >= getDiplomaticMarriageCost())
@ -464,7 +464,7 @@ class CityStateFunctions(val civInfo: Civilization) {
if (diplomacy.hasFlag(DiplomacyFlags.AngerFreeIntrusion)) continue // They recently helped us if (diplomacy.hasFlag(DiplomacyFlags.AngerFreeIntrusion)) continue // They recently helped us
val unitsInBorder = otherCiv.units.getCivUnits().count { !it.isCivilian() && it.getTile().getOwner() == civInfo } val unitsInBorder = otherCiv.units.getCivUnits().count { !it.isCivilian() && it.getTile().getOwner() == civInfo }
if (unitsInBorder > 0 && diplomacy.relationshipLevel() < RelationshipLevel.Friend) { if (unitsInBorder > 0 && diplomacy.isRelationshipLevelLT(RelationshipLevel.Friend)) {
diplomacy.addInfluence(-10f) diplomacy.addInfluence(-10f)
if (!diplomacy.hasFlag(DiplomacyFlags.BorderConflict)) { if (!diplomacy.hasFlag(DiplomacyFlags.BorderConflict)) {
otherCiv.popupAlerts.add(PopupAlert(AlertType.BorderConflict, civInfo.civName)) otherCiv.popupAlerts.add(PopupAlert(AlertType.BorderConflict, civInfo.civName))

View File

@ -22,13 +22,18 @@ import kotlin.math.min
enum class RelationshipLevel(val color: Color) { enum class RelationshipLevel(val color: Color) {
// War is tested separately for the Diplomacy Screen. Colored RED. // War is tested separately for the Diplomacy Screen. Colored RED.
Unforgivable(Color.FIREBRICK), Unforgivable(Color.FIREBRICK),
Afraid(Color(0x5300ffff)), // HSV(260,100,100)
Enemy(Color.YELLOW), Enemy(Color.YELLOW),
Afraid(Color(0x5300ffff)), // HSV(260,100,100)
Competitor(Color(0x1f998fff)), // HSV(175,80,60) Competitor(Color(0x1f998fff)), // HSV(175,80,60)
Neutral(Color(0x1bb371ff)), // HSV(154,85,70) Neutral(Color(0x1bb371ff)), // HSV(154,85,70)
Favorable(Color(0x14cc3cff)), // HSV(133,90,80) Favorable(Color(0x14cc3cff)), // HSV(133,90,80)
Friend(Color(0x2ce60bff)), // HSV(111,95,90) Friend(Color(0x2ce60bff)), // HSV(111,95,90)
Ally(Color.CHARTREUSE) // HSV(90,100,100) Ally(Color.CHARTREUSE) // HSV(90,100,100)
;
operator fun plus(delta: Int): RelationshipLevel {
val newOrdinal = (ordinal + delta).coerceIn(0, values().size - 1)
return values()[newOrdinal]
}
} }
enum class DiplomacyFlags { enum class DiplomacyFlags {
@ -168,7 +173,69 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
return modifierSum return modifierSum
} }
/** Related to [relationshipLevel], this compares with a specific outcome.
*
* It is cheap unless you ask such that Neutral / Afraid on a CityState need to be distinguished and influence is currently in 0 until 30.
* Thus it can be far cheaper than first retrieving [relationshipLevel] and then comparing.
*
* Readability shortcuts: [isRelationshipLevelEQ], [isRelationshipLevelGE], [isRelationshipLevelGT], [isRelationshipLevelLE], [isRelationshipLevelLT]
*
* @param comparesAs same as [RelationshipLevel.compareTo]
* @return `true` if [relationshipLevel] ().compareTo([level]) == [comparesAs] - or: when [comparesAs] > 0 only if [relationshipLevel] > [level] and so on.
*/
private fun compareRelationshipLevel(level: RelationshipLevel, comparesAs: Int): Boolean {
if (!civInfo.isCityState())
return relationshipLevel().compareTo(level) == comparesAs
return when(level) {
RelationshipLevel.Afraid -> when {
comparesAs < 0 -> getInfluence() < 0
comparesAs > 0 -> getInfluence() >= 30 || relationshipLevel() > level
else -> getInfluence().let { it >= 0 && it < 30 } && relationshipLevel() == level
}
RelationshipLevel.Neutral -> when {
comparesAs < 0 -> getInfluence() < 0 || relationshipLevel() < level
comparesAs > 0 -> getInfluence() >= 30
else -> getInfluence().let { it >= 0 && it < 30 } && relationshipLevel() == level
}
else ->
// Outside the potentially expensive questions, do it the easy way
relationshipLevel().compareTo(level) == comparesAs
}
}
/** @see compareRelationshipLevel */
fun isRelationshipLevelEQ(level: RelationshipLevel) =
compareRelationshipLevel(level, 0)
/** @see compareRelationshipLevel */
fun isRelationshipLevelLT(level: RelationshipLevel) =
compareRelationshipLevel(level, -1)
/** @see compareRelationshipLevel */
fun isRelationshipLevelGT(level: RelationshipLevel) =
compareRelationshipLevel(level, 1)
/** @see compareRelationshipLevel */
fun isRelationshipLevelLE(level: RelationshipLevel) =
if (level == RelationshipLevel.Ally) true
else compareRelationshipLevel(level + 1, -1)
/** @see compareRelationshipLevel */
fun isRelationshipLevelGE(level: RelationshipLevel) =
if (level == RelationshipLevel.Unforgivable) true
else compareRelationshipLevel(level + -1, 1)
/** Careful: Cheap unless this is a CityState and influence is in 0 until 30,
* where the distinction Neutral/Afraid gets expensive.
* @see compareRelationshipLevel
* @see relationshipIgnoreAfraid
*/
fun relationshipLevel(): RelationshipLevel { fun relationshipLevel(): RelationshipLevel {
val level = relationshipIgnoreAfraid()
return when {
level != RelationshipLevel.Neutral || !civInfo.isCityState() -> level
civInfo.cityStateFunctions.getTributeWillingness(otherCiv()) > 0 -> RelationshipLevel.Afraid
else -> RelationshipLevel.Neutral
}
}
/** Same as [relationshipLevel] but omits the distinction Neutral/Afraid, which can be _much_ cheaper */
fun relationshipIgnoreAfraid(): RelationshipLevel {
if (civInfo.isHuman() && otherCiv().isHuman()) if (civInfo.isHuman() && otherCiv().isHuman())
return RelationshipLevel.Neutral // People make their own choices. return RelationshipLevel.Neutral // People make their own choices.
@ -176,9 +243,8 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
return otherCiv().getDiplomacyManager(civInfo).relationshipLevel() return otherCiv().getDiplomacyManager(civInfo).relationshipLevel()
if (civInfo.isCityState()) return when { if (civInfo.isCityState()) return when {
getInfluence() <= -30 || civInfo.isAtWarWith(otherCiv()) -> RelationshipLevel.Unforgivable getInfluence() <= -30 -> RelationshipLevel.Unforgivable // getInfluence tests isAtWarWith
getInfluence() < 0 -> RelationshipLevel.Enemy getInfluence() < 0 -> RelationshipLevel.Enemy
getInfluence() < 30 && civInfo.cityStateFunctions.getTributeWillingness(otherCiv()) > 0 -> RelationshipLevel.Afraid
getInfluence() >= 60 && civInfo.getAllyCiv() == otherCivName -> RelationshipLevel.Ally getInfluence() >= 60 && civInfo.getAllyCiv() == otherCivName -> RelationshipLevel.Ally
getInfluence() >= 30 -> RelationshipLevel.Friend getInfluence() >= 30 -> RelationshipLevel.Friend
else -> RelationshipLevel.Neutral else -> RelationshipLevel.Neutral
@ -209,8 +275,8 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
val dropPerTurn = getCityStateInfluenceDegrade() val dropPerTurn = getCityStateInfluenceDegrade()
return when { return when {
dropPerTurn == 0f -> 0 dropPerTurn == 0f -> 0
relationshipLevel() >= RelationshipLevel.Ally -> ceil((getInfluence() - 60f) / dropPerTurn).toInt() + 1 isRelationshipLevelEQ(RelationshipLevel.Ally) -> ceil((getInfluence() - 60f) / dropPerTurn).toInt() + 1
relationshipLevel() >= RelationshipLevel.Friend -> ceil((getInfluence() - 30f) / dropPerTurn).toInt() + 1 isRelationshipLevelEQ(RelationshipLevel.Friend) -> ceil((getInfluence() - 30f) / dropPerTurn).toInt() + 1
else -> 0 else -> 0
} }
} }
@ -219,13 +285,13 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
@Suppress("unused") //todo Finish original intent (usage in uniques) or remove @Suppress("unused") //todo Finish original intent (usage in uniques) or remove
fun matchesCityStateRelationshipFilter(filter: String): Boolean { fun matchesCityStateRelationshipFilter(filter: String): Boolean {
val relationshipLevel = relationshipLevel() val relationshipLevel = relationshipIgnoreAfraid()
return when (filter) { return when (filter) {
"Allied" -> relationshipLevel == RelationshipLevel.Ally "Allied" -> relationshipLevel == RelationshipLevel.Ally
"Friendly" -> relationshipLevel == RelationshipLevel.Friend "Friendly" -> relationshipLevel == RelationshipLevel.Friend
"Enemy" -> relationshipLevel == RelationshipLevel.Enemy "Enemy" -> relationshipLevel == RelationshipLevel.Enemy
"Unforgiving" -> relationshipLevel == RelationshipLevel.Unforgivable "Unforgiving" -> relationshipLevel == RelationshipLevel.Unforgivable
"Neutral" -> relationshipLevel == RelationshipLevel.Neutral "Neutral" -> isRelationshipLevelEQ(RelationshipLevel.Neutral)
else -> false else -> false
} }
} }
@ -357,7 +423,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
*/ */
fun isConsideredFriendlyTerritory(): Boolean { fun isConsideredFriendlyTerritory(): Boolean {
if (civInfo.isCityState() && if (civInfo.isCityState() &&
(relationshipLevel() >= RelationshipLevel.Friend || otherCiv().hasUnique(UniqueType.CityStateTerritoryAlwaysFriendly))) (isRelationshipLevelGE(RelationshipLevel.Friend) || otherCiv().hasUnique(UniqueType.CityStateTerritoryAlwaysFriendly)))
return true return true
return otherCivDiplomacy().hasOpenBorders // if THEY can enter US then WE are considered friendly territory for THEM return otherCivDiplomacy().hasOpenBorders // if THEY can enter US then WE are considered friendly territory for THEM
@ -435,7 +501,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
} }
private fun nextTurnCityStateInfluence() { private fun nextTurnCityStateInfluence() {
val initialRelationshipLevel = relationshipLevel() val initialRelationshipLevel = relationshipIgnoreAfraid() // Enough since only >= Friend is notified
val restingPoint = getCityStateInfluenceRestingPoint() val restingPoint = getCityStateInfluenceRestingPoint()
// We don't use `getInfluence()` here, as then during war with the ally of this CS, // We don't use `getInfluence()` here, as then during war with the ally of this CS,
@ -458,7 +524,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
else otherCiv().addNotification(text, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy) else otherCiv().addNotification(text, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy)
} }
if (initialRelationshipLevel >= RelationshipLevel.Friend && initialRelationshipLevel != relationshipLevel()) { if (initialRelationshipLevel >= RelationshipLevel.Friend && initialRelationshipLevel != relationshipIgnoreAfraid()) {
val text = "Your relationship with [${civInfo.civName}] degraded" val text = "Your relationship with [${civInfo.civName}] degraded"
if (civCapitalLocation != null) otherCiv().addNotification(text, civCapitalLocation, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy) if (civCapitalLocation != null) otherCiv().addNotification(text, civCapitalLocation, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy)
else otherCiv().addNotification(text, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy) else otherCiv().addNotification(text, NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy)
@ -622,7 +688,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
if (!otherCiv().isCityState()) return if (!otherCiv().isCityState()) return
if (relationshipLevel() < RelationshipLevel.Friend) { if (isRelationshipLevelLT(RelationshipLevel.Friend)) {
if (hasFlag(DiplomacyFlags.ProvideMilitaryUnit)) if (hasFlag(DiplomacyFlags.ProvideMilitaryUnit))
removeFlag(DiplomacyFlags.ProvideMilitaryUnit) removeFlag(DiplomacyFlags.ProvideMilitaryUnit)
return return
@ -630,7 +696,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
val variance = listOf(-1, 0, 1).random() val variance = listOf(-1, 0, 1).random()
val provideMilitaryUnitUniques = civInfo.cityStateFunctions.getCityStateBonuses(otherCiv().cityStateType, relationshipLevel(), UniqueType.CityStateMilitaryUnits) val provideMilitaryUnitUniques = civInfo.cityStateFunctions.getCityStateBonuses(otherCiv().cityStateType, relationshipIgnoreAfraid(), UniqueType.CityStateMilitaryUnits)
.filter { it.conditionalsApply(civInfo) }.toList() .filter { it.conditionalsApply(civInfo) }.toList()
if (provideMilitaryUnitUniques.isEmpty()) removeFlag(DiplomacyFlags.ProvideMilitaryUnit) if (provideMilitaryUnitUniques.isEmpty()) removeFlag(DiplomacyFlags.ProvideMilitaryUnit)
@ -846,7 +912,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
removeModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies) removeModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies)
for (thirdCiv in getCommonKnownCivs() for (thirdCiv in getCommonKnownCivs()
.filter { it.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.DeclarationOfFriendship) }) { .filter { it.getDiplomacyManager(civInfo).hasFlag(DiplomacyFlags.DeclarationOfFriendship) }) {
when (otherCiv().getDiplomacyManager(thirdCiv).relationshipLevel()) { when (otherCiv().getDiplomacyManager(thirdCiv).relationshipIgnoreAfraid()) {
RelationshipLevel.Unforgivable -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -15f) RelationshipLevel.Unforgivable -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -15f)
RelationshipLevel.Enemy -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -5f) RelationshipLevel.Enemy -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurEnemies, -5f)
RelationshipLevel.Friend -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies, 5f) RelationshipLevel.Friend -> addModifier(DiplomaticModifiers.DeclaredFriendshipWithOurAllies, 5f)
@ -869,7 +935,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
getCommonKnownCivs().filter { it.isMajorCiv() }.forEach { thirdCiv -> getCommonKnownCivs().filter { it.isMajorCiv() }.forEach { thirdCiv ->
thirdCiv.addNotification("[${civInfo.civName}] has denounced [$otherCivName]!", thirdCiv.addNotification("[${civInfo.civName}] has denounced [$otherCivName]!",
NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy, otherCivName) NotificationCategory.Diplomacy, civInfo.civName, NotificationIcon.Diplomacy, otherCivName)
val thirdCivRelationshipWithOtherCiv = thirdCiv.getDiplomacyManager(otherCiv()).relationshipLevel() val thirdCivRelationshipWithOtherCiv = thirdCiv.getDiplomacyManager(otherCiv()).relationshipIgnoreAfraid()
val thirdCivDiplomacyManager = thirdCiv.getDiplomacyManager(civInfo) val thirdCivDiplomacyManager = thirdCiv.getDiplomacyManager(civInfo)
when (thirdCivRelationshipWithOtherCiv) { when (thirdCivRelationshipWithOtherCiv) {
RelationshipLevel.Unforgivable -> thirdCivDiplomacyManager.addModifier(DiplomaticModifiers.DenouncedOurEnemies, 15f) RelationshipLevel.Unforgivable -> thirdCivDiplomacyManager.addModifier(DiplomaticModifiers.DenouncedOurEnemies, 15f)

View File

@ -245,15 +245,15 @@ class TurnManager(val civInfo: Civilization) {
// disband units until there are none left OR the gold values are normal // disband units until there are none left OR the gold values are normal
if (!civInfo.isBarbarian() && civInfo.gold <= -200 && nextTurnStats.gold.toInt() < 0) { if (!civInfo.isBarbarian() && civInfo.gold <= -200 && nextTurnStats.gold.toInt() < 0) {
val militaryUnits = civInfo.units.getCivUnits().filter { it.isMilitary() }
do { do {
val militaryUnits = civInfo.units.getCivUnits().filter { it.isMilitary() } // New sequence as disband replaces unitList
val unitToDisband = militaryUnits.minByOrNull { it.baseUnit.cost } val unitToDisband = militaryUnits.minByOrNull { it.baseUnit.cost }
// or .firstOrNull()? // or .firstOrNull()?
?: break ?: break
unitToDisband.disband() unitToDisband.disband()
val unitName = unitToDisband.shortDisplayName() val unitName = unitToDisband.shortDisplayName()
civInfo.addNotification("Cannot provide unit upkeep for $unitName - unit has been disbanded!", NotificationCategory.Units, unitName, NotificationIcon.Death) civInfo.addNotification("Cannot provide unit upkeep for $unitName - unit has been disbanded!", NotificationCategory.Units, unitName, NotificationIcon.Death)
civInfo.updateStatsForNextTurn() // recalculate unit upkeep // No need to recalculate unit upkeep, disband did that in UnitManager.removeUnit
nextTurnStats = civInfo.stats.statsForNextTurn nextTurnStats = civInfo.stats.statsForNextTurn
} while (civInfo.gold <= -200 && nextTurnStats.gold.toInt() < 0) } while (civInfo.gold <= -200 && nextTurnStats.gold.toInt() < 0)
} }

View File

@ -171,9 +171,8 @@ class CivInfoStatsForNextTurn(val civInfo: Civilization) {
//City-States bonuses //City-States bonuses
for (otherCiv in civInfo.getKnownCivs()) { for (otherCiv in civInfo.getKnownCivs()) {
if (!otherCiv.isCityState()) continue if (!otherCiv.isCityState()) continue
if (otherCiv.getDiplomacyManager(civInfo.civName) if (!otherCiv.getDiplomacyManager(civInfo.civName).isRelationshipLevelEQ(RelationshipLevel.Ally))
.relationshipLevel() != RelationshipLevel.Ally continue
) continue
for (unique in civInfo.getMatchingUniques(UniqueType.CityStateStatPercent)) { for (unique in civInfo.getMatchingUniques(UniqueType.CityStateStatPercent)) {
statMap.add( statMap.add(
Constants.cityStates, Constants.cityStates,

View File

@ -70,7 +70,7 @@ class TradeEvaluation {
// If we're making a peace treaty, don't try to up the bargain for people you don't like. // If we're making a peace treaty, don't try to up the bargain for people you don't like.
// Leads to spartan behaviour where you demand more, the more you hate the enemy...unhelpful // Leads to spartan behaviour where you demand more, the more you hate the enemy...unhelpful
if (trade.ourOffers.none { it.name == Constants.peaceTreaty || it.name == Constants.researchAgreement }) { if (trade.ourOffers.none { it.name == Constants.peaceTreaty || it.name == Constants.researchAgreement }) {
val relationshipLevel = evaluator.getDiplomacyManager(tradePartner).relationshipLevel() val relationshipLevel = evaluator.getDiplomacyManager(tradePartner).relationshipIgnoreAfraid()
if (relationshipLevel == RelationshipLevel.Enemy) sumOfOurOffers = (sumOfOurOffers * 1.5).toInt() if (relationshipLevel == RelationshipLevel.Enemy) sumOfOurOffers = (sumOfOurOffers * 1.5).toInt()
else if (relationshipLevel == RelationshipLevel.Unforgivable) sumOfOurOffers *= 2 else if (relationshipLevel == RelationshipLevel.Unforgivable) sumOfOurOffers *= 2
} }
@ -259,7 +259,7 @@ class TradeEvaluation {
} }
TradeType.Agreement -> { TradeType.Agreement -> {
if (offer.name == Constants.openBorders) { if (offer.name == Constants.openBorders) {
return when (civInfo.getDiplomacyManager(tradePartner).relationshipLevel()) { return when (civInfo.getDiplomacyManager(tradePartner).relationshipIgnoreAfraid()) {
RelationshipLevel.Unforgivable -> 10000 RelationshipLevel.Unforgivable -> 10000
RelationshipLevel.Enemy -> 2000 RelationshipLevel.Enemy -> 2000
RelationshipLevel.Competitor -> 500 RelationshipLevel.Competitor -> 500

View File

@ -256,7 +256,7 @@ class DiplomacyScreen(
val allyBonusObjects = viewingCiv.cityStateFunctions.getCityStateBonuses(otherCiv.cityStateType, RelationshipLevel.Ally) val allyBonusObjects = viewingCiv.cityStateFunctions.getCityStateBonuses(otherCiv.cityStateType, RelationshipLevel.Ally)
allyBonusText += allyBonusObjects.joinToString(separator = "\n") { it.text.tr() } allyBonusText += allyBonusObjects.joinToString(separator = "\n") { it.text.tr() }
val relationLevel = otherCivDiplomacyManager.relationshipLevel() val relationLevel = otherCivDiplomacyManager.relationshipIgnoreAfraid()
if (relationLevel >= RelationshipLevel.Friend) { if (relationLevel >= RelationshipLevel.Friend) {
// RelationshipChange = Ally -> Friend or Friend -> Favorable // RelationshipChange = Ally -> Friend or Friend -> Favorable
val turnsToRelationshipChange = otherCivDiplomacyManager.getTurnsToRelationshipChange() val turnsToRelationshipChange = otherCivDiplomacyManager.getTurnsToRelationshipChange()
@ -637,7 +637,7 @@ class DiplomacyScreen(
val diplomacyTable = Table() val diplomacyTable = Table()
diplomacyTable.defaults().pad(10f) diplomacyTable.defaults().pad(10f)
val helloText = if (otherCivDiplomacyManager.relationshipLevel() <= RelationshipLevel.Enemy) val helloText = if (otherCivDiplomacyManager.isRelationshipLevelLE(RelationshipLevel.Enemy))
otherCiv.nation.hateHello otherCiv.nation.hateHello
else otherCiv.nation.neutralHello else otherCiv.nation.neutralHello
val leaderIntroTable = LeaderIntroTable(otherCiv, helloText) val leaderIntroTable = LeaderIntroTable(otherCiv, helloText)

View File

@ -217,7 +217,7 @@ class GlobalPoliticsOverviewTable (
//allied CS //allied CS
for (cityState in gameInfo.getAliveCityStates()) { for (cityState in gameInfo.getAliveCityStates()) {
if (cityState.diplomacy[civ.civName]?.relationshipLevel() == RelationshipLevel.Ally) { if (cityState.diplomacy[civ.civName]?.isRelationshipLevelEQ(RelationshipLevel.Ally) == true) {
val alliedText = "Allied with [${getCivName(cityState)}]".toLabel() val alliedText = "Allied with [${getCivName(cityState)}]".toLabel()
alliedText.color = Color.GREEN alliedText.color = Color.GREEN
politicsTable.add(alliedText).row() politicsTable.add(alliedText).row()

View File

@ -293,13 +293,13 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
val player = worldScreen.viewingCiv val player = worldScreen.viewingCiv
addLeaderName(bullyOrAttacker) addLeaderName(bullyOrAttacker)
val relation = bullyOrAttacker.getDiplomacyManager(player).relationshipLevel() val isAtLeastNeutral = bullyOrAttacker.getDiplomacyManager(player).isRelationshipLevelGE(RelationshipLevel.Neutral)
val text = when { val text = when {
popupAlert.type == AlertType.BulliedProtectedMinor && relation >= RelationshipLevel.Neutral -> // Nice message popupAlert.type == AlertType.BulliedProtectedMinor && isAtLeastNeutral -> // Nice message
"I've been informed that my armies have taken tribute from [${cityState.civName}], a city-state under your protection.\nI assure you, this was quite unintentional, and I hope that this does not serve to drive us apart." "I've been informed that my armies have taken tribute from [${cityState.civName}], a city-state under your protection.\nI assure you, this was quite unintentional, and I hope that this does not serve to drive us apart."
popupAlert.type == AlertType.BulliedProtectedMinor -> // Nasty message popupAlert.type == AlertType.BulliedProtectedMinor -> // Nasty message
"We asked [${cityState.civName}] for a tribute recently and they gave in.\nYou promised to protect them from such things, but we both know you cannot back that up." "We asked [${cityState.civName}] for a tribute recently and they gave in.\nYou promised to protect them from such things, but we both know you cannot back that up."
relation >= RelationshipLevel.Neutral -> // Nice message isAtLeastNeutral -> // Nice message
"It's come to my attention that I may have attacked [${cityState.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." "It's come to my attention that I may have attacked [${cityState.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."
else -> // Nasty message else -> // Nasty message
"I thought you might like to know that I've launched an invasion of one of your little pet states.\nThe lands of [${cityState.civName}] will make a fine addition to my own." "I thought you might like to know that I've launched an invasion of one of your little pet states.\nThe lands of [${cityState.civName}] will make a fine addition to my own."