mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
chore: Readonly 4
This commit is contained in:
parent
7e1cc64ca7
commit
3ba87902a5
@ -54,6 +54,9 @@ allprojects {
|
||||
"kotlin.apply",
|
||||
"kotlin.takeIf",
|
||||
"kotlin.takeUnless",
|
||||
"kotlin.ranges.coerceIn",
|
||||
"com.unciv.logic.civilization.diplomacy.RelationshipLevel.compareTo",
|
||||
// "kotlin.Enum.compareTo", // so overrides are considered pure as well :think:
|
||||
)
|
||||
wellKnownReadonlyFunctions = setOf(
|
||||
"kotlin.collections.any",
|
||||
@ -62,6 +65,11 @@ allprojects {
|
||||
"kotlin.ranges.coerceAtLeast",
|
||||
// Looks like the Collection.contains is not considered overridden :thunk:
|
||||
"java.util.AbstractCollection.contains",
|
||||
"kotlin.collections.sum",
|
||||
)
|
||||
wellKnownPureClasses = setOf(
|
||||
"kotlin.enums.EnumEntries",
|
||||
"kotlin.Enum",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ import com.unciv.ui.screens.savescreens.Gzip
|
||||
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
|
||||
import com.unciv.utils.DebugUtils
|
||||
import com.unciv.utils.debug
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import java.security.MessageDigest
|
||||
import java.util.UUID
|
||||
|
||||
@ -231,6 +232,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
val civMap by lazy { civilizations.associateBy { it.civName } }
|
||||
/** Get a civ by name
|
||||
* @throws NoSuchElementException if no civ of that name is in the game (alive or dead)! */
|
||||
@Readonly
|
||||
fun getCivilization(civName: String) = civMap[civName]
|
||||
?: civilizations.first { it.civName == civName } // This is for spectators who are added in later, artificially
|
||||
fun getCurrentPlayerCivilization() = currentPlayerCiv
|
||||
@ -241,6 +243,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
||||
fun getDifficulty() = difficultyObject
|
||||
/** Access a cached `GlobalUniques` that combines the [ruleset]'s [globalUniques][Ruleset.globalUniques]
|
||||
* with the Uniques of the chosen [speed] and [difficulty][getDifficulty] */
|
||||
@Readonly @Suppress("purity") // This should be autorecognized!!
|
||||
fun getGlobalUniques() = combinedGlobalUniques
|
||||
|
||||
/** @return Sequence of all cities in game, both major civilizations and city states */
|
||||
|
@ -545,6 +545,7 @@ class City : IsPartOfGameInfoSerialization, INamed {
|
||||
}
|
||||
|
||||
// Uniques coming from this city, but that should be provided globally
|
||||
@Readonly
|
||||
fun getMatchingUniquesWithNonLocalEffects(uniqueType: UniqueType, gameContext: GameContext = state): Sequence<Unique> {
|
||||
val uniques = cityConstructions.builtBuildingUniqueMap.getUniques(uniqueType)
|
||||
// Memory performance showed that this function was very memory intensive, thus we only create the filter if needed
|
||||
|
@ -339,18 +339,23 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
* city-states to contain the barbarians. Therefore, [getKnownCivs] will **not** list the barbarians
|
||||
* for major civs, but **will** do so for city-states after some gameplay.
|
||||
*/
|
||||
@Readonly
|
||||
fun getKnownCivs() = diplomacy.values.asSequence().map { it.otherCiv() }
|
||||
.filter { !it.isDefeated() && !it.isSpectator() }
|
||||
|
||||
fun getKnownCivsWithSpectators() = diplomacy.values.asSequence().map { it.otherCiv() }
|
||||
.filter { !it.isDefeated() }
|
||||
|
||||
@Readonly
|
||||
fun knows(otherCivName: String) = diplomacy.containsKey(otherCivName)
|
||||
@Readonly
|
||||
fun knows(otherCiv: Civilization) = knows(otherCiv.civName)
|
||||
|
||||
fun getCapital(firstCityIfNoCapital: Boolean = true) = cities.firstOrNull { it.isCapital() } ?:
|
||||
if (firstCityIfNoCapital) cities.firstOrNull() else null
|
||||
@Readonly
|
||||
fun isHuman() = playerType == PlayerType.Human
|
||||
@Readonly
|
||||
fun isAI() = playerType == PlayerType.AI
|
||||
fun isAIOrAutoPlaying(): Boolean {
|
||||
if (playerType == PlayerType.AI) return true
|
||||
@ -370,7 +375,9 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
@delegate:Transient
|
||||
val isBarbarian by lazy { nation.isBarbarian }
|
||||
|
||||
@Readonly
|
||||
fun isSpectator() = nation.isSpectator
|
||||
@Readonly
|
||||
fun isAlive(): Boolean = !isDefeated()
|
||||
|
||||
@delegate:Transient
|
||||
@ -524,11 +531,13 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
|
||||
fun hasResource(resourceName: String): Boolean = getResourceAmount(resourceName) > 0
|
||||
|
||||
@Readonly
|
||||
fun hasUnique(uniqueType: UniqueType, gameContext: GameContext = state) =
|
||||
getMatchingUniques(uniqueType, gameContext).any()
|
||||
|
||||
// Does not return local uniques, only global ones.
|
||||
/** Destined to replace getMatchingUniques, gradually, as we fill the enum */
|
||||
@Readonly
|
||||
fun getMatchingUniques(
|
||||
uniqueType: UniqueType,
|
||||
gameContext: GameContext = state
|
||||
@ -653,16 +662,20 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
* If the civ has never controlled an original capital, it stays 'alive' as long as it has units (irrespective of non-original-capitals owned)
|
||||
* Otherwise, it stays 'alive' as long as it has cities (irrespective of settlers owned)
|
||||
*/
|
||||
@Readonly
|
||||
fun isDefeated() = when {
|
||||
isBarbarian || isSpectator() -> false // Barbarians and voyeurs can't lose
|
||||
hasEverOwnedOriginalCapital -> cities.isEmpty()
|
||||
else -> units.getCivUnitsSize() == 0
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getEra(): Era = tech.era
|
||||
|
||||
@Readonly
|
||||
fun getEraNumber(): Int = getEra().eraNumber
|
||||
|
||||
@Readonly
|
||||
fun isAtWarWith(otherCiv: Civilization) = diplomacyFunctions.isAtWarWith(otherCiv)
|
||||
|
||||
fun isAtWar() = diplomacy.values.any { it.diplomaticStatus == DiplomaticStatus.War && !it.otherCiv().isDefeated() }
|
||||
@ -1039,6 +1052,7 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
|
||||
fun getAllyCiv(): Civilization? = if (allyCivName == null) null
|
||||
else gameInfo.getCivilization(allyCivName!!)
|
||||
@Readonly @Suppress("purity") // should be autorecognized!
|
||||
fun getAllyCivName() = allyCivName
|
||||
fun setAllyCiv(newAllyName: String?) { allyCivName = newAllyName }
|
||||
|
||||
|
@ -27,6 +27,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import com.unciv.utils.randomWeighted
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.random.Random
|
||||
@ -408,10 +409,12 @@ class CityStateFunctions(val civInfo: Civilization) {
|
||||
civInfo.destroy(notificationLocation)
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getTributeWillingness(demandingCiv: Civilization, demandingWorker: Boolean = false): Int {
|
||||
return getTributeModifiers(demandingCiv, demandingWorker).values.sum()
|
||||
}
|
||||
|
||||
@Readonly @Suppress("purity")
|
||||
fun getTributeModifiers(demandingCiv: Civilization, demandingWorker: Boolean = false, requireWholeList: Boolean = false): HashMap<String, Int> {
|
||||
val modifiers = LinkedHashMap<String, Int>() // Linked to preserve order when presenting the modifiers table
|
||||
// Can't bully major civs or unsettled CS's
|
||||
@ -789,6 +792,7 @@ class CityStateFunctions(val civInfo: Civilization) {
|
||||
}
|
||||
|
||||
// TODO: Optimize, update whenever status changes, otherwise retain the same list
|
||||
@Readonly
|
||||
fun getUniquesProvidedByCityStates(
|
||||
uniqueType: UniqueType,
|
||||
gameContext: GameContext
|
||||
@ -809,6 +813,7 @@ class CityStateFunctions(val civInfo: Civilization) {
|
||||
}
|
||||
|
||||
|
||||
@Readonly
|
||||
fun getCityStateBonuses(cityStateType: CityStateType, relationshipLevel: RelationshipLevel, uniqueType: UniqueType? = null): Sequence<Unique> {
|
||||
val cityStateUniqueMap = when (relationshipLevel) {
|
||||
RelationshipLevel.Ally -> cityStateType.allyBonusUniqueMap
|
||||
|
@ -11,6 +11,7 @@ import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.max
|
||||
|
||||
class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
@ -74,7 +75,7 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Readonly
|
||||
fun isAtWarWith(otherCiv: Civilization): Boolean {
|
||||
return when {
|
||||
otherCiv == civInfo -> false
|
||||
|
@ -17,6 +17,7 @@ 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.Readonly
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
@ -34,6 +35,7 @@ enum class RelationshipLevel(val color: Color) {
|
||||
Friend(Color.ROYAL),
|
||||
Ally(Color.CYAN)
|
||||
;
|
||||
@Readonly
|
||||
operator fun plus(delta: Int): RelationshipLevel {
|
||||
val newOrdinal = (ordinal + delta).coerceIn(0, entries.size - 1)
|
||||
return entries[newOrdinal]
|
||||
@ -196,7 +198,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
//region pure functions
|
||||
@Readonly
|
||||
fun otherCiv() = civInfo.gameInfo.getCivilization(otherCivName)
|
||||
@Readonly
|
||||
fun otherCivDiplomacy() = otherCiv().getDiplomacyManager(civInfo)!!
|
||||
|
||||
fun turnsToPeaceTreaty(): Int {
|
||||
@ -206,6 +210,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
return 0
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun opinionOfOtherCiv(): Float {
|
||||
var modifierSum = diplomaticModifiers.values.sum()
|
||||
// Angry about attacked CS and destroyed CS do not stack
|
||||
@ -224,6 +229,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
* @param comparesAs same as [RelationshipLevel.compareTo]
|
||||
* @return `true` if [relationshipLevel] ().compareTo([level]) == [comparesAs] - or: when [comparesAs] > 0 only if [relationshipLevel] > [level] and so on.
|
||||
*/
|
||||
@Readonly
|
||||
private fun compareRelationshipLevel(level: RelationshipLevel, comparesAs: Int): Boolean {
|
||||
if (!civInfo.isCityState)
|
||||
return relationshipLevel().compareTo(level).sign == comparesAs
|
||||
@ -259,6 +265,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
if (level == RelationshipLevel.Ally) true
|
||||
else compareRelationshipLevel(level + 1, -1)
|
||||
/** @see compareRelationshipLevel */
|
||||
@Readonly
|
||||
fun isRelationshipLevelGE(level: RelationshipLevel) =
|
||||
if (level == RelationshipLevel.Unforgivable) true
|
||||
else compareRelationshipLevel(level + -1, 1)
|
||||
@ -268,6 +275,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
* @see compareRelationshipLevel
|
||||
* @see relationshipIgnoreAfraid
|
||||
*/
|
||||
@Readonly
|
||||
fun relationshipLevel(): RelationshipLevel {
|
||||
val level = relationshipIgnoreAfraid()
|
||||
return when {
|
||||
@ -278,6 +286,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
/** Same as [relationshipLevel] but omits the distinction Neutral/Afraid, which can be _much_ cheaper */
|
||||
@Readonly
|
||||
fun relationshipIgnoreAfraid(): RelationshipLevel {
|
||||
if (civInfo.isHuman() && otherCiv().isHuman())
|
||||
return RelationshipLevel.Neutral // People make their own choices.
|
||||
@ -365,6 +374,7 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
civInfo.cityStateFunctions.updateAllyCivForCityState()
|
||||
}
|
||||
|
||||
@Readonly
|
||||
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.
|
||||
@ -549,12 +559,14 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
diplomaticModifiers[modifier.name] = amount
|
||||
}
|
||||
|
||||
@Readonly
|
||||
internal fun getModifier(modifier: DiplomaticModifiers): Float {
|
||||
if (!hasModifier(modifier)) return 0f
|
||||
return diplomaticModifiers[modifier.name]!!
|
||||
}
|
||||
|
||||
internal fun removeModifier(modifier: DiplomaticModifiers) = diplomaticModifiers.remove(modifier.name)
|
||||
@Readonly
|
||||
fun hasModifier(modifier: DiplomaticModifiers) = diplomaticModifiers.containsKey(modifier.name)
|
||||
|
||||
fun signDeclarationOfFriendship() {
|
||||
|
@ -13,6 +13,7 @@ import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.ruleset.unique.UniqueTriggerActivation
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
class UnitManager(val civInfo: Civilization) {
|
||||
|
||||
@ -126,6 +127,7 @@ class UnitManager(val civInfo: Civilization) {
|
||||
}
|
||||
return unit
|
||||
}
|
||||
@Readonly
|
||||
fun getCivUnitsSize(): Int = unitList.size
|
||||
fun getCivUnits(): Sequence<MapUnit> = unitList.asSequence()
|
||||
fun getCivGreatPeople(): Sequence<MapUnit> = getCivUnits().filter { mapUnit -> mapUnit.isGreatPerson() }
|
||||
|
@ -650,6 +650,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly @Suppress("purity") // sets cached value
|
||||
fun isAdjacentToRiver(): Boolean {
|
||||
if (!isAdjacentToRiverKnown) {
|
||||
isAdjacentToRiver =
|
||||
|
@ -43,9 +43,11 @@ interface IHasUniques : INamed {
|
||||
* */
|
||||
fun getUniqueTarget(): UniqueTarget
|
||||
|
||||
@Readonly
|
||||
fun getMatchingUniques(uniqueType: UniqueType, state: GameContext = GameContext.EmptyState) =
|
||||
uniqueMap.getMatchingUniques(uniqueType, state)
|
||||
|
||||
@Readonly
|
||||
fun getMatchingUniques(uniqueTag: String, state: GameContext = GameContext.EmptyState) =
|
||||
uniqueMap.getMatchingUniques(uniqueTag, state)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.models.ruleset.unique
|
||||
|
||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
class TemporaryUnique() : IsPartOfGameInfoSerialization {
|
||||
|
||||
@ -32,6 +33,7 @@ fun ArrayList<TemporaryUnique>.endTurn() {
|
||||
removeAll { it.turnsLeft == 0 }
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun ArrayList<TemporaryUnique>.getMatchingUniques(uniqueType: UniqueType, gameContext: GameContext): Sequence<Unique> {
|
||||
return this.asSequence()
|
||||
.map { it.uniqueObject }
|
||||
|
Loading…
x
Reference in New Issue
Block a user