chore(purity): Trade, TradeOffer

This commit is contained in:
yairm210 2025-08-08 10:05:52 +03:00
parent 67c3c7292b
commit fc7fe1f3bd
5 changed files with 32 additions and 28 deletions

View File

@ -685,6 +685,7 @@ class Civilization : IsPartOfGameInfoSerialization {
* Like "Milan" if the nation is a city state, "Caesar of Rome" otherwise, with an added
* " (AI)", " (Human - Hotseat)", or " (Human - Multiplayer)" if the game is multiplayer.
*/
@Readonly
fun getLeaderDisplayName(): String {
val severalHumans = gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
val online = gameInfo.gameParameters.isOnlineMultiplayer

View File

@ -17,6 +17,8 @@ import com.unciv.models.ruleset.unique.UniqueTriggerActivation
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.fillPlaceholders
import com.unciv.ui.components.extensions.toPercent
import yairm210.purity.annotations.Immutable
import yairm210.purity.annotations.Pure
import yairm210.purity.annotations.Readonly
import kotlin.math.ceil
import kotlin.math.max
@ -35,7 +37,7 @@ enum class RelationshipLevel(val color: Color) {
Friend(Color.ROYAL),
Ally(Color.CYAN)
;
@Readonly
@Pure
operator fun plus(delta: Int): RelationshipLevel {
val newOrdinal = (ordinal + delta).coerceIn(0, entries.size - 1)
return entries[newOrdinal]
@ -140,8 +142,8 @@ enum class DiplomaticModifiers(val text: String) {
BelieveSameReligion("We believe in the same religion");
companion object{
private val valuesAsMap = entries.associateBy { it.name }
fun safeValueOf(name: String) = valuesAsMap[name]
@Immutable private val valuesAsMap = entries.associateBy { it.name }
@Pure fun safeValueOf(name: String) = valuesAsMap[name]
}
}
@ -206,6 +208,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
@Readonly fun otherCiv() = civInfo.gameInfo.getCivilization(otherCivName)
@Readonly fun otherCivDiplomacy() = otherCiv().getDiplomacyManager(civInfo)!!
@Readonly
fun turnsToPeaceTreaty(): Int {
for (trade in trades)
for (offer in trade.ourOffers)
@ -321,6 +324,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
}
}
@Readonly
private fun believesSameReligion(): Boolean {
// what is the majorityReligion of civInfo? If it is null, we immediately return false
val civMajorityReligion = civInfo.religionManager.getMajorityReligion() ?: return false
@ -330,6 +334,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
}
/** Returns the number of turns to degrade from Ally or from Friend */
@Readonly
fun getTurnsToRelationshipChange(): Int {
if (otherCiv().isCityState)
return otherCivDiplomacy().getTurnsToRelationshipChange()
@ -346,19 +351,6 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
return 0
}
@Suppress("unused") //todo Finish original intent (usage in uniques) or remove
fun matchesCityStateRelationshipFilter(filter: String): Boolean {
val relationshipLevel = relationshipIgnoreAfraid()
return when (filter) {
"Allied" -> relationshipLevel == RelationshipLevel.Ally
"Friendly" -> relationshipLevel == RelationshipLevel.Friend
"Enemy" -> relationshipLevel == RelationshipLevel.Enemy
"Unforgiving" -> relationshipLevel == RelationshipLevel.Unforgivable
"Neutral" -> isRelationshipLevelEQ(RelationshipLevel.Neutral)
else -> false
}
}
fun addInfluence(amount: Float) {
setInfluence(influence + amount)
}
@ -381,6 +373,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
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.
@Readonly
internal fun getCityStateInfluenceRestingPoint(): Float {
var restingPoint = 0f
@ -399,6 +392,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
return restingPoint
}
@Readonly
internal fun getCityStateInfluenceDegrade(): Float {
if (getInfluence() <= getCityStateInfluenceRestingPoint())
return 0f
@ -428,6 +422,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
}
@Readonly
fun canDeclareWar() = !civInfo.isDefeated() && !otherCiv().isDefeated()
&& turnsToPeaceTreaty() == 0 && diplomaticStatus != DiplomaticStatus.War
@ -435,8 +430,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
DeclareWar.declareWar(this, declareWarReason)
//Used for nuke
fun canAttack() = turnsToPeaceTreaty() == 0
@Readonly fun canAttack() = turnsToPeaceTreaty() == 0
@Readonly
fun goldPerTurn(): Int {
var goldPerTurnForUs = 0
for (trade in trades) {

View File

@ -5,6 +5,7 @@ import com.unciv.logic.IsPartOfGameInfoSerialization
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
import com.unciv.models.ruleset.nation.PersonalityValue
import yairm210.purity.annotations.Readonly
class Trade : IsPartOfGameInfoSerialization {
@ -13,20 +14,22 @@ class Trade : IsPartOfGameInfoSerialization {
fun reverse(): Trade {
val newTrade = Trade()
newTrade.theirOffers+=ourOffers.map { it.copy() }
newTrade.ourOffers+=theirOffers.map { it.copy() }
newTrade.theirOffers += ourOffers.map { it.copy() }
newTrade.ourOffers += theirOffers.map { it.copy() }
return newTrade
}
@Readonly
fun equalTrade(trade: Trade): Boolean {
if(trade.ourOffers.size!=ourOffers.size
|| trade.theirOffers.size!=theirOffers.size) return false
if (trade.ourOffers.size != ourOffers.size
|| trade.theirOffers.size != theirOffers.size
) return false
for(offer in trade.ourOffers)
if(ourOffers.none { it.equals(offer)})
for (offer in trade.ourOffers)
if (ourOffers.none { it.equals(offer) })
return false
for(offer in trade.theirOffers)
if(theirOffers.none { it.equals(offer)})
for (offer in trade.theirOffers)
if (theirOffers.none { it.equals(offer) })
return false
return true
}
@ -45,7 +48,7 @@ class Trade : IsPartOfGameInfoSerialization {
theirOffers.addAll(trade.theirOffers)
}
fun isPeaceTreaty() = ourOffers.any { it.type == TradeOfferType.Treaty && it.name == Constants.peaceTreaty }
@Readonly fun isPeaceTreaty() = ourOffers.any { it.type == TradeOfferType.Treaty && it.name == Constants.peaceTreaty }
}

View File

@ -7,6 +7,7 @@ import com.unciv.logic.trade.TradeOfferType.TradeTypeNumberType
import com.unciv.models.ruleset.Speed
import com.unciv.models.translations.tr
import com.unciv.ui.components.fonts.Fonts
import yairm210.purity.annotations.Readonly
data class TradeOffer(val name: String, val type: TradeOfferType, var amount: Int = 1, var duration: Int) : IsPartOfGameInfoSerialization {
@ -26,14 +27,16 @@ data class TradeOffer(val name: String, val type: TradeOfferType, var amount: In
constructor() : this("", TradeOfferType.Gold, duration = -1) // so that the json deserializer can work
@Suppress("CovariantEquals", "WrongEqualsTypeParameter") // This is an overload, not an override of the built-in equals(Any?)
@Readonly
fun equals(offer: TradeOffer): Boolean {
return offer.name == name
&& offer.type == type
&& offer.amount == amount
}
fun isTradable() = amount > 0
@Readonly fun isTradable() = amount > 0
@Readonly
fun getOfferText(untradable: Int = 0): String {
var offerText = when(type) {
TradeOfferType.WarDeclaration -> "Declare war on [$name]"

View File

@ -23,11 +23,12 @@ import kotlin.math.pow
class Nation : RulesetObject() {
var leaderName = ""
@Readonly
fun getLeaderDisplayName() = if (isCityState || isSpectator) name
else "[$leaderName] of [$name]"
val style = ""
fun getStyleOrCivName() = style.ifEmpty { name }
@Readonly fun getStyleOrCivName() = style.ifEmpty { name }
var cityStateType: String? = null
var preferredVictoryType: String = Constants.neutralVictoryType