mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-29 06:51:30 -04:00
Diplomacy Screen Nation relation indicator (#5032)
This commit is contained in:
parent
b0e3aa326b
commit
06c7f049b7
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user