Diplomacy Screen Nation relation indicator (#5032)

This commit is contained in:
SomeTroglodyte 2021-08-30 19:25:13 +02:00 committed by GitHub
parent b0e3aa326b
commit 06c7f049b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 40 deletions

View File

@ -1,5 +1,6 @@
package com.unciv.logic.civilization.diplomacy package com.unciv.logic.civilization.diplomacy
import com.badlogic.gdx.graphics.Color
import com.unciv.Constants import com.unciv.Constants
import com.unciv.logic.civilization.* import com.unciv.logic.civilization.*
import com.unciv.logic.trade.Trade import com.unciv.logic.trade.Trade
@ -12,15 +13,16 @@ import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
enum class RelationshipLevel{ enum class RelationshipLevel(val color: Color) {
Unforgivable, // War is tested separately for the Diplomacy Screen. Colored RED.
Afraid, Unforgivable(Color.FIREBRICK),
Enemy, Afraid(Color(0x5300ffff)), // HSV(260,100,100)
Competitor, Enemy(Color.YELLOW),
Neutral, Competitor(Color(0x1f998fff)), // HSV(175,80,60)
Favorable, Neutral(Color(0x1bb371ff)), // HSV(154,85,70)
Friend, Favorable(Color(0x14cc3cff)), // HSV(133,90,80)
Ally Friend(Color(0x2ce60bff)), // HSV(111,95,90)
Ally(Color.CHARTREUSE) // HSV(90,100,100)
} }
enum class DiplomacyFlags{ enum class DiplomacyFlags{
@ -72,6 +74,7 @@ class DiplomacyManager() {
const val MINIMUM_INFLUENCE = -60f const val MINIMUM_INFLUENCE = -60f
} }
@Suppress("JoinDeclarationAndAssignment") // incorrect warning - constructor would need to be higher in scope
@Transient @Transient
lateinit var civInfo: CivilizationInfo lateinit var civInfo: CivilizationInfo
@ -93,8 +96,8 @@ class DiplomacyManager() {
* As for why it's String and not DiplomaticModifier see FlagsCountdown comment */ * As for why it's String and not DiplomaticModifier see FlagsCountdown comment */
var diplomaticModifiers = HashMap<String, Float>() var diplomaticModifiers = HashMap<String, Float>()
/** For city-states. Influence is saved in the CITY STATE -> major civ Diplomacy, NOT in the major civ -> cty state diplomacy. /** 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] */ * Won't go below [MINIMUM_INFLUENCE]. Note this declaration leads to Major Civs getting MINIMUM_INFLUENCE serialized, but that is ignored. */
var influence = 0f var influence = 0f
set(value) { set(value) {
field = max(value, MINIMUM_INFLUENCE) field = max(value, MINIMUM_INFLUENCE)
@ -142,13 +145,13 @@ class DiplomacyManager() {
if (civInfo.isPlayerCivilization()) if (civInfo.isPlayerCivilization())
return otherCiv().getDiplomacyManager(civInfo).relationshipLevel() return otherCiv().getDiplomacyManager(civInfo).relationshipLevel()
if (civInfo.isCityState()) { if (civInfo.isCityState()) return when {
if (influence <= -30 || civInfo.isAtWarWith(otherCiv())) return RelationshipLevel.Unforgivable influence <= -30 || civInfo.isAtWarWith(otherCiv()) -> RelationshipLevel.Unforgivable
if (influence < 30 && civInfo.getTributeWillingness(otherCiv()) > 0) return RelationshipLevel.Afraid influence < 30 && civInfo.getTributeWillingness(otherCiv()) > 0 -> RelationshipLevel.Afraid
if (influence < 0) return RelationshipLevel.Enemy influence < 0 -> RelationshipLevel.Enemy
if (influence >= 60 && civInfo.getAllyCiv() == otherCivName) return RelationshipLevel.Ally influence >= 60 && civInfo.getAllyCiv() == otherCivName -> RelationshipLevel.Ally
if (influence >= 30) return RelationshipLevel.Friend influence >= 30 -> RelationshipLevel.Friend
return RelationshipLevel.Neutral else -> RelationshipLevel.Neutral
} }
// not entirely sure what to do between AI civs, because they probably have different views of each other, // not entirely sure what to do between AI civs, because they probably have different views of each other,
@ -182,7 +185,7 @@ class DiplomacyManager() {
} }
return 0 return 0
} }
fun matchesCityStateRelationshipFilter(filter: String): Boolean { fun matchesCityStateRelationshipFilter(filter: String): Boolean {
val relationshipLevel = relationshipLevel() val relationshipLevel = relationshipLevel()
return when (filter) { return when (filter) {
@ -198,14 +201,14 @@ class DiplomacyManager() {
// To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different. // To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different.
fun getCityStateInfluenceRestingPoint(): Float { fun getCityStateInfluenceRestingPoint(): Float {
var restingPoint = 0f var restingPoint = 0f
for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []")) for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []"))
restingPoint += unique.params[0].toInt() restingPoint += unique.params[0].toInt()
for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States following this religion []")) for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States following this religion []"))
if (otherCiv().religionManager.religion?.name == civInfo.getCapital().religion.getMajorityReligionName()) if (otherCiv().religionManager.religion?.name == civInfo.getCapital().religion.getMajorityReligionName())
restingPoint += unique.params[0].toInt() restingPoint += unique.params[0].toInt()
if (diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5 if (diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5
return restingPoint return restingPoint
} }
@ -228,7 +231,7 @@ class DiplomacyManager() {
for (unique in otherCiv().getMatchingUniques("City-State Influence degrades []% slower")) for (unique in otherCiv().getMatchingUniques("City-State Influence degrades []% slower"))
modifier *= 1f - unique.params[0].toFloat() / 100f modifier *= 1f - unique.params[0].toFloat() / 100f
for (civ in civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != otherCiv()}) { for (civ in civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != otherCiv()}) {
for (unique in civ.getMatchingUniques("Influence of all other civilizations with all city-states degrades []% faster")) { for (unique in civ.getMatchingUniques("Influence of all other civilizations with all city-states degrades []% faster")) {
modifier *= 1f + unique.params[0].toFloat() / 100f modifier *= 1f + unique.params[0].toFloat() / 100f
@ -421,7 +424,7 @@ class DiplomacyManager() {
// No need to decrement negative countdown flags: they do not expire // No need to decrement negative countdown flags: they do not expire
if (flagsCountdown[flag]!! > 0) if (flagsCountdown[flag]!! > 0)
flagsCountdown[flag] = flagsCountdown[flag]!! - 1 flagsCountdown[flag] = flagsCountdown[flag]!! - 1
// If we have uniques that make city states grant military units faster when at war with a common enemy, add higher numbers to this flag // If we have uniques that make city states grant military units faster when at war with a common enemy, add higher numbers to this flag
if (flag == DiplomacyFlags.ProvideMilitaryUnit.name && civInfo.isMajorCiv() && otherCiv().isCityState() && if (flag == DiplomacyFlags.ProvideMilitaryUnit.name && civInfo.isMajorCiv() && otherCiv().isCityState() &&
civInfo.gameInfo.civilizations.filter { civInfo.isAtWarWith(it) && otherCiv().isAtWarWith(it) }.any()) { civInfo.gameInfo.civilizations.filter { civInfo.isAtWarWith(it) && otherCiv().isAtWarWith(it) }.any()) {
@ -551,7 +554,7 @@ class DiplomacyManager() {
} }
} }
/** Everything that happens to both sides equally when war is delcared by one side on the other */ /** Everything that happens to both sides equally when war is declared by one side on the other */
private fun onWarDeclared() { private fun onWarDeclared() {
// Cancel all trades. // Cancel all trades.
for (trade in trades) for (trade in trades)
@ -561,7 +564,7 @@ class DiplomacyManager() {
updateHasOpenBorders() updateHasOpenBorders()
diplomaticStatus = DiplomaticStatus.War diplomaticStatus = DiplomaticStatus.War
removeModifier(DiplomaticModifiers.YearsOfPeace) removeModifier(DiplomaticModifiers.YearsOfPeace)
setFlag(DiplomacyFlags.DeclinedPeace, 10)/// AI won't propose peace for 10 turns setFlag(DiplomacyFlags.DeclinedPeace, 10)/// AI won't propose peace for 10 turns
setFlag(DiplomacyFlags.DeclaredWar, 10) // AI won't agree to trade for 10 turns setFlag(DiplomacyFlags.DeclaredWar, 10) // AI won't agree to trade for 10 turns
@ -574,7 +577,7 @@ class DiplomacyManager() {
onWarDeclared() onWarDeclared()
otherCivDiplomacy.onWarDeclared() otherCivDiplomacy.onWarDeclared()
otherCiv.addNotification("[${civInfo.civName}] has declared war on us!", NotificationIcon.War, civInfo.civName) otherCiv.addNotification("[${civInfo.civName}] has declared war on us!", NotificationIcon.War, civInfo.civName)
otherCiv.popupAlerts.add(PopupAlert(AlertType.WarDeclaration, civInfo.civName)) otherCiv.popupAlerts.add(PopupAlert(AlertType.WarDeclaration, civInfo.civName))
@ -652,7 +655,7 @@ class DiplomacyManager() {
// Our ally city states make peace with us // Our ally city states make peace with us
if (thirdCiv.getAllyCiv() == civInfo.civName && thirdCiv.isAtWarWith(otherCiv)) if (thirdCiv.getAllyCiv() == civInfo.civName && thirdCiv.isAtWarWith(otherCiv))
thirdCiv.getDiplomacyManager(otherCiv).makePeace() thirdCiv.getDiplomacyManager(otherCiv).makePeace()
// Other ccity states that are not our ally don't like the fact that we made peace with their enemy // Other city states that are not our ally don't like the fact that we made peace with their enemy
if (thirdCiv.getAllyCiv() != civInfo.civName && thirdCiv.isAtWarWith(otherCiv)) if (thirdCiv.getAllyCiv() != civInfo.civName && thirdCiv.isAtWarWith(otherCiv))
thirdCiv.getDiplomacyManager(civInfo).influence -= 10 thirdCiv.getDiplomacyManager(civInfo).influence -= 10
} }
@ -776,4 +779,4 @@ class DiplomacyManager() {
//endregion //endregion
} }

View File

@ -25,6 +25,7 @@ import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.tilegroups.CityButton import com.unciv.ui.tilegroups.CityButton
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
import java.text.Collator
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.roundToInt import kotlin.math.roundToInt
import com.unciv.ui.utils.AutoScrollPane as ScrollPane import com.unciv.ui.utils.AutoScrollPane as ScrollPane
@ -60,20 +61,34 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
private fun updateLeftSideTable() { private fun updateLeftSideTable() {
leftSideTable.clear() leftSideTable.clear()
for (civ in viewingCiv.gameInfo.civilizations leftSideTable.add().padBottom(60f).row() // room so the close button does not cover the first
val civsToDisplay = viewingCiv.gameInfo.civilizations.asSequence()
.filterNot { .filterNot {
it.isDefeated() || it == viewingCiv || it.isBarbarian() || it.isSpectator() || !viewingCiv.knows( it.isDefeated() || it == viewingCiv || it.isBarbarian() || it.isSpectator() ||
it !viewingCiv.knows(it)
) }
}) { .sortedWith(
compareByDescending<CivilizationInfo>{ it.isMajorCiv() }
.thenBy (Collator.getInstance(), { it.civName.tr() })
)
for (civ in civsToDisplay) {
val civIndicator = ImageGetter.getNationIndicator(civ.nation, 100f) val civIndicator = ImageGetter.getNationIndicator(civ.nation, 100f)
val relationship = ImageGetter.getCircle() val relationLevel = civ.getDiplomacyManager(viewingCiv).relationshipLevel()
if (viewingCiv.isAtWarWith(civ)) relationship.color = Color.RED val relationshipIcon = if (civ.isCityState() && relationLevel == RelationshipLevel.Ally)
else relationship.color = Color.GREEN ImageGetter.getImage("OtherIcons/Star")
relationship.setSize(30f, 30f) .surroundWithCircle(size = 30f, color = relationLevel.color).apply {
civIndicator.addActor(relationship) actor.color = Color.GOLD
}
else
ImageGetter.getCircle().apply {
color = if (viewingCiv.isAtWarWith(civ)) Color.RED else relationLevel.color
setSize(30f, 30f)
}
civIndicator.addActor(relationshipIcon)
if (civ.isCityState() && civ.questManager.haveQuestsFor(viewingCiv)) { if (civ.isCityState() && civ.questManager.haveQuestsFor(viewingCiv)) {
val questIcon = ImageGetter.getImage("OtherIcons/Quest") val questIcon = ImageGetter.getImage("OtherIcons/Quest")
@ -336,6 +351,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
"Gift [$giftAmount] gold (+[$influenceAmount] influence)".toTextButton() "Gift [$giftAmount] gold (+[$influenceAmount] influence)".toTextButton()
giftButton.onClick { giftButton.onClick {
viewingCiv.giveGoldGift(otherCiv, giftAmount) viewingCiv.giveGoldGift(otherCiv, giftAmount)
updateLeftSideTable()
updateRightSide(otherCiv) updateRightSide(otherCiv)
} }
diplomacyTable.add(giftButton).row() diplomacyTable.add(giftButton).row()
@ -557,6 +573,7 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
denounceButton.onClick { denounceButton.onClick {
YesNoPopup("Denounce [${otherCiv.civName}]?", { YesNoPopup("Denounce [${otherCiv.civName}]?", {
diplomacyManager.denounce() diplomacyManager.denounce()
updateLeftSideTable()
setRightSideFlavorText(otherCiv, "We will remember this.", "Very well.") setRightSideFlavorText(otherCiv, "We will remember this.", "Very well.")
}, this).open() }, this).open()
} }
@ -745,4 +762,4 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
rightSideTable.add(diplomacyTable) rightSideTable.add(diplomacyTable)
} }
} }