mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
chore(purity): Replace extra @LocalState with declaring that the classes are well known local state classes
This commit is contained in:
parent
152acba973
commit
68894cdac5
@ -38,7 +38,7 @@ plugins {
|
||||
// This is *with* gradle 8.2 downloaded according the project specs, no idea what that's about
|
||||
kotlin("multiplatform") version "1.9.24"
|
||||
kotlin("plugin.serialization") version "1.9.24"
|
||||
id("io.github.yairm210.purity-plugin") version "0.0.43" apply(false)
|
||||
id("io.github.yairm210.purity-plugin") version "0.0.45" apply(false)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
@ -49,28 +49,32 @@ allprojects {
|
||||
apply(plugin = "io.github.yairm210.purity-plugin")
|
||||
configure<yairm210.purity.PurityConfiguration>{
|
||||
wellKnownPureFunctions = setOf(
|
||||
"kotlin.assert",
|
||||
"kotlin.lazy",
|
||||
"kotlin.getValue",
|
||||
"kotlin.error",
|
||||
"kotlin.lazy", // moved
|
||||
"kotlin.getValue", // moved
|
||||
"kotlin.error", // moved
|
||||
)
|
||||
wellKnownReadonlyFunctions = setOf(
|
||||
"com.badlogic.gdx.math.Vector2.len",
|
||||
"com.badlogic.gdx.math.Vector2.cpy",
|
||||
"com.badlogic.gdx.math.Vector2.hashCode",
|
||||
"java.lang.reflect.Field.getAnnotation", // not sure if generic enough to be useful globally
|
||||
"java.lang.Class.getField",
|
||||
|
||||
// Looks like the Collection.contains is not considered overridden :thunk:
|
||||
"kotlin.Array.get",
|
||||
"kotlin.collections.mutableSetOf",
|
||||
"kotlin.collections.withIndex", // applicable to sequence as well
|
||||
"kotlin.collections.intersect",
|
||||
"kotlin.collections.maxOfOrNull",
|
||||
"kotlin.collections.minOfOrNull",
|
||||
"kotlin.reflect.KMutableProperty0.get", // also 1 and 2
|
||||
)
|
||||
wellKnownPureClasses = setOf(
|
||||
wellKnownPureClasses = setOf<String>(
|
||||
)
|
||||
wellKnownInternalStateClasses = setOf<String>(
|
||||
// Moved all
|
||||
"kotlin.collections.MutableList",
|
||||
"kotlin.collections.MutableSet",
|
||||
"kotlin.collections.MutableMap",
|
||||
"kotlin.collections.List",
|
||||
"kotlin.collections.Set",
|
||||
"kotlin.collections.Map",
|
||||
"kotlin.collections.ArrayDequeue",
|
||||
|
||||
"com.unciv.models.stats.Stats",
|
||||
"com.unciv.models.Counter",
|
||||
"com.unciv.models.ruleset.tile.ResourceSupplyList",
|
||||
"com.badlogic.gdx.math.Vector2",
|
||||
)
|
||||
warnOnPossibleAnnotations = true
|
||||
}
|
||||
|
@ -42,8 +42,7 @@ object MultiFilter {
|
||||
fun getAllSingleFilters(input: String): Sequence<String> = when {
|
||||
input.hasSurrounding(andPrefix, andSuffix) && input.contains(andSeparator) -> {
|
||||
// Resolve "AND" filters
|
||||
@LocalState
|
||||
val filters = input.removeSurrounding(andPrefix, andSuffix)
|
||||
@LocalState val filters = input.removeSurrounding(andPrefix, andSuffix)
|
||||
.splitToSequence(andSeparator)
|
||||
filters.flatMap { getAllSingleFilters(it) }
|
||||
}
|
||||
|
@ -183,11 +183,13 @@ object Automation {
|
||||
}
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@Readonly
|
||||
fun providesUnneededCarryingSlots(baseUnit: BaseUnit, civInfo: Civilization): Boolean {
|
||||
// Simplified, will not work for crazy mods with more than one carrying filter for a unit
|
||||
val carryUnique = baseUnit.getMatchingUniques(UniqueType.CarryAirUnits).first()
|
||||
val carryFilter = carryUnique.params[1]
|
||||
|
||||
@Readonly
|
||||
fun getCarryAmount(mapUnit: MapUnit): Int {
|
||||
val mapUnitCarryUnique =
|
||||
mapUnit.getMatchingUniques(UniqueType.CarryAirUnits).firstOrNull() ?: return 0
|
||||
@ -338,6 +340,7 @@ object Automation {
|
||||
|
||||
/** Determines whether the AI should be willing to spend strategic resources to build
|
||||
* [construction] for [civInfo], assumes that we are actually able to do so. */
|
||||
@Readonly
|
||||
fun allowSpendingResource(civInfo: Civilization, construction: INonPerpetualConstruction, cityInfo: City? = null): Boolean {
|
||||
// City states do whatever they want
|
||||
if (civInfo.isCityState)
|
||||
@ -418,13 +421,14 @@ object Automation {
|
||||
else -> ThreatLevel.Medium
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun improvementIsRemovable(city: City, tile: Tile): Boolean {
|
||||
val gameContext = GameContext(city.civ, city, tile = tile)
|
||||
return (tile.getTileImprovement()?.hasUnique(UniqueType.AutomatedUnitsWillNotReplace, gameContext) == false && tile.getTileImprovement()?.hasUnique(UniqueType.Irremovable, gameContext) == false)
|
||||
}
|
||||
|
||||
/** Support [UniqueType.CreatesOneImprovement] unique - find best tile for placement automation */
|
||||
@Readonly
|
||||
fun getTileForConstructionImprovement(city: City, improvement: TileImprovement): Tile? {
|
||||
val localUniqueCache = LocalUniqueCache()
|
||||
val civ = city.civ
|
||||
@ -441,6 +445,7 @@ object Automation {
|
||||
}
|
||||
|
||||
// Ranks a tile for any purpose except the expansion algorithm of cities
|
||||
@Readonly
|
||||
internal fun rankTile(tile: Tile?, civInfo: Civilization,
|
||||
localUniqueCache: LocalUniqueCache): Float {
|
||||
if (tile == null) return 0f
|
||||
@ -460,6 +465,7 @@ object Automation {
|
||||
}
|
||||
|
||||
// Ranks a tile for the expansion algorithm of cities
|
||||
@Readonly
|
||||
internal fun rankTileForExpansion(tile: Tile, city: City,
|
||||
localUniqueCache: LocalUniqueCache): Int {
|
||||
// https://github.com/Gedemon/Civ5-DLL/blob/aa29e80751f541ae04858b6d2a2c7dcca454201e/CvGameCoreDLL_Expansion1/CvCity.cpp#L10301
|
||||
@ -513,6 +519,7 @@ object Automation {
|
||||
return score
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun rankStatsValue(stats: Stats, civInfo: Civilization): Float {
|
||||
var rank = 0.0f
|
||||
rank += stats.food * 1.2f //food get more value to keep city growing
|
||||
|
@ -35,7 +35,7 @@ object BattleDamage {
|
||||
|
||||
@Readonly
|
||||
private fun getGeneralModifiers(combatant: ICombatant, enemy: ICombatant, combatAction: CombatAction, tileToAttackFrom: Tile): Counter<String> {
|
||||
@LocalState val modifiers = Counter<String>()
|
||||
val modifiers = Counter<String>()
|
||||
|
||||
val conditionalState = getStateForConditionals(combatAction, combatant, enemy)
|
||||
val civInfo = combatant.getCivInfo()
|
||||
@ -101,7 +101,7 @@ object BattleDamage {
|
||||
private fun getUnitUniqueModifiers(combatant: MapUnitCombatant, enemy: ICombatant, conditionalState: GameContext,
|
||||
tileToAttackFrom: Tile): Counter<String> {
|
||||
val civInfo = combatant.getCivInfo()
|
||||
@LocalState val modifiers = Counter<String>()
|
||||
val modifiers = Counter<String>()
|
||||
|
||||
for (unique in combatant.getMatchingUniques(UniqueType.Strength, conditionalState, true)) {
|
||||
modifiers.add(getModifierStringFromUnique(unique), unique.params[0].toInt())
|
||||
@ -179,7 +179,7 @@ object BattleDamage {
|
||||
|
||||
@Readonly
|
||||
private fun getTerrainAttackModifiers(attacker: MapUnitCombatant, defender: ICombatant, tileToAttackFrom: Tile): Counter<String> {
|
||||
@LocalState val modifiers = Counter<String>()
|
||||
val modifiers = Counter<String>()
|
||||
if (attacker.unit.isEmbarked() && defender.getTile().isLand
|
||||
&& !attacker.unit.hasUnique(UniqueType.AttackAcrossCoast)
|
||||
)
|
||||
@ -219,7 +219,7 @@ object BattleDamage {
|
||||
fun getAirSweepAttackModifiers(
|
||||
attacker: ICombatant
|
||||
): Counter<String> {
|
||||
@LocalState val modifiers = Counter<String>()
|
||||
val modifiers = Counter<String>()
|
||||
|
||||
if (attacker is MapUnitCombatant) {
|
||||
for (unique in attacker.unit.getMatchingUniques(UniqueType.StrengthWhenAirsweep)) {
|
||||
|
@ -39,7 +39,7 @@ object CityResources {
|
||||
|
||||
@Readonly
|
||||
private fun getResourcesGeneratedByCityNotIncludingBuildings(city: City, resourceModifers: Map<String, Float>): ResourceSupplyList {
|
||||
@LocalState val cityResources = ResourceSupplyList()
|
||||
val cityResources = ResourceSupplyList()
|
||||
|
||||
cityResources.add(getResourcesFromTiles(city, resourceModifers))
|
||||
cityResources.add(getResourceFromUniqueImprovedTiles(city, resourceModifers))
|
||||
@ -79,7 +79,7 @@ object CityResources {
|
||||
|
||||
@Readonly
|
||||
private fun getResourcesFromTiles(city: City, resourceModifer: Map<String, Float>): ResourceSupplyList {
|
||||
@LocalState val resourceSupplyList = ResourceSupplyList()
|
||||
val resourceSupplyList = ResourceSupplyList()
|
||||
for (tileInfo in city.getTiles().filter { it.resource != null }) {
|
||||
val resource = tileInfo.tileResource
|
||||
val amount = getTileResourceAmount(city, tileInfo) * resourceModifer[resource.name]!!
|
||||
@ -90,7 +90,7 @@ object CityResources {
|
||||
|
||||
@Readonly
|
||||
private fun getResourceFromUniqueImprovedTiles(city: City, resourceModifer: Map<String, Float>): ResourceSupplyList {
|
||||
@LocalState val resourceSupplyList = ResourceSupplyList()
|
||||
val resourceSupplyList = ResourceSupplyList()
|
||||
for (tileInfo in city.getTiles().filter { it.getUnpillagedImprovement() != null }) {
|
||||
val gameContext = GameContext(city.civ, city, tile = tileInfo)
|
||||
val tileImprovement = tileInfo.getUnpillagedTileImprovement()
|
||||
@ -114,7 +114,7 @@ object CityResources {
|
||||
|
||||
@Readonly
|
||||
private fun getNegativeCityResourcesRequiredByBuildings(city: City): ResourceSupplyList {
|
||||
@LocalState val resourceSupplyList = ResourceSupplyList()
|
||||
val resourceSupplyList = ResourceSupplyList()
|
||||
val freeBuildings = city.civ.civConstructions.getFreeBuildingNames(city)
|
||||
for (building in city.cityConstructions.getBuiltBuildings()) {
|
||||
// Free buildings cost no resources
|
||||
@ -126,7 +126,7 @@ object CityResources {
|
||||
|
||||
@Readonly
|
||||
private fun getCityResourcesFromCiv(city: City, resourceModifers: HashMap<String, Float>): ResourceSupplyList {
|
||||
@LocalState val resourceSupplyList = ResourceSupplyList()
|
||||
val resourceSupplyList = ResourceSupplyList()
|
||||
// This includes the uniques from buildings, from this and all other cities
|
||||
for (unique in city.getMatchingUniques(UniqueType.ProvidesResources, city.state)) { // E.G "Provides [1] [Iron]"
|
||||
val resource = city.getRuleset().tileResources[unique.params[1]]
|
||||
|
@ -5,7 +5,6 @@ import com.unciv.models.Counter
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
/** Manages calculating Great Person Points per City for nextTurn. See public constructor(city) below for details. */
|
||||
@ -134,13 +133,11 @@ class GreatPersonPointsBreakdown private constructor(private val ruleset: Rulese
|
||||
@Readonly
|
||||
fun sum(): Counter<String> {
|
||||
// Accumulate base points as fake "fixed-point"
|
||||
@LocalState
|
||||
val result = Counter<String>()
|
||||
for (entry in basePoints)
|
||||
result.add(entry.counter * fixedPointFactor)
|
||||
|
||||
// Accumulate percentage bonuses additively not multiplicatively
|
||||
@LocalState
|
||||
val bonuses = Counter<String>()
|
||||
for (entry in percentBonuses) {
|
||||
bonuses.add(entry.counter)
|
||||
|
@ -10,7 +10,6 @@ import com.unciv.models.Religion
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
class CityReligionManager : IsPartOfGameInfoSerialization {
|
||||
@ -282,7 +281,7 @@ class CityReligionManager : IsPartOfGameInfoSerialization {
|
||||
/** Doesn't update the pressures, only returns what they are if the update were to happen right now */
|
||||
@Readonly
|
||||
fun getPressuresFromSurroundingCities(): Counter<String> {
|
||||
@LocalState val addedPressure = Counter<String>()
|
||||
val addedPressure = Counter<String>()
|
||||
if (city.isHolyCity()) {
|
||||
addedPressure[religionThisIsTheHolyCityOf!!] = 5 * pressureFromAdjacentCities
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ import com.unciv.ui.components.extensions.toPercent
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
import yairm210.purity.annotations.Cache
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
@ -750,7 +749,6 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
|
||||
@Readonly
|
||||
fun calculateScoreBreakdown(): HashMap<String,Double> {
|
||||
@LocalState
|
||||
val scoreBreakdown = hashMapOf<String,Double>()
|
||||
// 1276 is the number of tiles in a medium sized map. The original uses 4160 for this,
|
||||
// but they have bigger maps
|
||||
|
@ -27,7 +27,6 @@ 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.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
@ -418,7 +417,6 @@ class CityStateFunctions(val civInfo: Civilization) {
|
||||
|
||||
@Readonly
|
||||
fun getTributeModifiers(demandingCiv: Civilization, demandingWorker: Boolean = false, requireWholeList: Boolean = false): HashMap<String, Int> {
|
||||
@LocalState
|
||||
val modifiers = LinkedHashMap<String, Int>() // Linked to preserve order when presenting the modifiers table
|
||||
// Can't bully major civs or unsettled CS's
|
||||
if (!civInfo.isCityState) {
|
||||
|
@ -128,11 +128,9 @@ object HexMath {
|
||||
@Readonly
|
||||
fun hex2WorldCoords(hexCoord: Vector2): Vector2 {
|
||||
// Distance between cells = 2* normal of triangle = 2* (sqrt(3)/2) = sqrt(3)
|
||||
@LocalState
|
||||
val xVector = getVectorByClockHour(10)
|
||||
xVector.scl(sqrt(3.0).toFloat() * hexCoord.x)
|
||||
|
||||
@LocalState
|
||||
val yVector = getVectorByClockHour(2)
|
||||
yVector.scl(sqrt(3.0).toFloat() * hexCoord.y)
|
||||
|
||||
@ -143,10 +141,8 @@ object HexMath {
|
||||
@Readonly
|
||||
fun world2HexCoords(worldCoord: Vector2): Vector2 {
|
||||
// D: diagonal, A: antidiagonal versors
|
||||
@LocalState
|
||||
val D = getVectorByClockHour(10)
|
||||
D.scl(sqrt(3.0).toFloat())
|
||||
@LocalState
|
||||
val A = getVectorByClockHour(2)
|
||||
A.scl(sqrt(3.0).toFloat())
|
||||
val den = D.x * A.y - D.y * A.x
|
||||
@ -219,7 +215,6 @@ object HexMath {
|
||||
|
||||
@Readonly
|
||||
fun getVectorsAtDistance(origin: Vector2, distance: Int, maxDistance: Int, worldWrap: Boolean): List<Vector2> {
|
||||
@LocalState
|
||||
val vectors = mutableListOf<Vector2>()
|
||||
if (distance == 0) {
|
||||
return listOf(origin.cpy())
|
||||
@ -259,7 +254,6 @@ object HexMath {
|
||||
|
||||
@Readonly
|
||||
fun getVectorsInDistance(origin: Vector2, distance: Int, worldWrap: Boolean): List<Vector2> {
|
||||
@LocalState
|
||||
val hexesToReturn = mutableListOf<Vector2>()
|
||||
for (i in 0..distance) {
|
||||
hexesToReturn += getVectorsAtDistance(origin, i, distance, worldWrap)
|
||||
|
@ -405,7 +405,6 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
||||
@Readonly
|
||||
fun getViewableTiles(position: Vector2, sightDistance: Int, forAttack: Boolean = false): List<Tile> {
|
||||
val aUnitHeight = get(position).unitHeight
|
||||
@LocalState
|
||||
val viewableTiles = mutableListOf(ViewableTile(
|
||||
get(position),
|
||||
aUnitHeight,
|
||||
@ -416,7 +415,6 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
||||
for (i in 1..sightDistance+1) { // in each layer,
|
||||
// This is so we don't use tiles in the same distance to "see over",
|
||||
// that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance
|
||||
@LocalState
|
||||
val tilesToAddInDistanceI = ArrayList<ViewableTile>()
|
||||
|
||||
for (cTile in getTilesAtDistance(position, i)) { // for each tile in that layer,
|
||||
|
@ -329,7 +329,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
* StateForConditionals is assumed to regarding this mapUnit*/
|
||||
@Readonly
|
||||
fun getResourceRequirementsPerTurn(): Counter<String> {
|
||||
@LocalState val resourceRequirements = Counter<String>()
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (baseUnit.requiredResource != null) resourceRequirements[baseUnit.requiredResource!!] = 1
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, cache.state))
|
||||
resourceRequirements.add(unique.params[1], unique.params[0].toInt())
|
||||
|
@ -738,7 +738,6 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
||||
|
||||
@Readonly
|
||||
fun getRulesetIncompatibility(ruleset: Ruleset): HashSet<String> {
|
||||
@LocalState
|
||||
val out = HashSet<String>()
|
||||
if (!ruleset.terrains.containsKey(baseTerrain))
|
||||
out.add("Base terrain [$baseTerrain] does not exist in ruleset!")
|
||||
|
@ -11,8 +11,11 @@ import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import java.util.EnumMap
|
||||
|
||||
@Readonly
|
||||
fun List<Pair<String, Stats>>.toStats(): Stats {
|
||||
val stats = Stats()
|
||||
for ((_, statsToAdd) in this)
|
||||
@ -28,6 +31,7 @@ class TileStatFunctions(val tile: Tile) {
|
||||
localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)
|
||||
): Stats = getTileStats(tile.getCity(), observingCiv, localUniqueCache)
|
||||
|
||||
@Readonly @Suppress("purity") // requires "for @LocalState X"
|
||||
fun getTileStats(
|
||||
city: City?, observingCiv: Civilization?,
|
||||
localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)
|
||||
@ -51,21 +55,22 @@ class TileStatFunctions(val tile: Tile) {
|
||||
return statsBreakdown.toStats()
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getTileStatsBreakdown(city: City?, observingCiv: Civilization?,
|
||||
localUniqueCache: LocalUniqueCache = LocalUniqueCache(false)
|
||||
): List<Pair<String, Stats>> {
|
||||
val gameContext = GameContext(civInfo = observingCiv, city = city, tile = tile)
|
||||
val listOfStats = getTerrainStatsBreakdown(gameContext)
|
||||
@LocalState val listOfStats = getTerrainStatsBreakdown(gameContext)
|
||||
|
||||
val otherYieldsIgnored = tile.allTerrains.any { it.hasUnique(UniqueType.NullifyYields, gameContext) }
|
||||
|
||||
val improvement = if (otherYieldsIgnored) null // Treat it as if there is no improvement
|
||||
else tile.getUnpillagedTileImprovement()
|
||||
val improvementStats = improvement?.cloneStats() ?: Stats.ZERO // If improvement==null, will never be added to
|
||||
@LocalState val improvementStats = improvement?.cloneStats() ?: Stats.ZERO // If improvement==null, will never be added to
|
||||
|
||||
val road = if (otherYieldsIgnored) null
|
||||
else tile.getUnpillagedRoadImprovement()
|
||||
val roadStats = road?.cloneStats() ?: Stats.ZERO
|
||||
@LocalState val roadStats = road?.cloneStats() ?: Stats.ZERO
|
||||
|
||||
if (city != null) {
|
||||
val statsFromTilesUniques =
|
||||
@ -135,6 +140,7 @@ class TileStatFunctions(val tile: Tile) {
|
||||
}
|
||||
|
||||
/** Ensures each stat is >= [minimumStats].stat - modifies in place */
|
||||
@Readonly
|
||||
private fun missingFromMinimum(current: Stats, minimumStats: Stats): Stats {
|
||||
// Note: Not `for ((stat, value) in other)` - that would skip zero values
|
||||
val missingStats = Stats()
|
||||
@ -148,6 +154,7 @@ class TileStatFunctions(val tile: Tile) {
|
||||
/** Gets stats of a single Terrain, unifying the Stats class a Terrain inherits and the Stats Unique
|
||||
* @return A Stats reference, must not be mutated
|
||||
*/
|
||||
@Readonly
|
||||
private fun getSingleTerrainStats(terrain: Terrain, gameContext: GameContext): ArrayList<Pair<String, Stats>> {
|
||||
val list = arrayListOf(terrain.name to (terrain as Stats))
|
||||
|
||||
@ -158,8 +165,10 @@ class TileStatFunctions(val tile: Tile) {
|
||||
}
|
||||
|
||||
/** Gets basic stats to start off [getTileStats] or [getTileStartYield], independently mutable result */
|
||||
@Readonly
|
||||
fun getTerrainStatsBreakdown(gameContext: GameContext = GameContext()): ArrayList<Pair<String, Stats>> {
|
||||
var list = ArrayList<Pair<String, Stats>>()
|
||||
// needs to be marked, because it's a var
|
||||
@LocalState var list = ArrayList<Pair<String, Stats>>()
|
||||
|
||||
// allTerrains iterates over base, natural wonder, then features
|
||||
for (terrain in tile.allTerrains) {
|
||||
@ -183,7 +192,8 @@ class TileStatFunctions(val tile: Tile) {
|
||||
}
|
||||
|
||||
// Only gets the tile percentage bonus, not the improvement percentage bonus
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@Suppress("MemberVisibilityCanBePrivate", "purity")
|
||||
@Readonly
|
||||
fun getTilePercentageStats(observingCiv: Civilization?, city: City?, uniqueCache: LocalUniqueCache): EnumMap<TilePercentageCategory, Stats> {
|
||||
val terrainStats = Stats()
|
||||
val gameContext = GameContext(civInfo = observingCiv, city = city, tile = tile)
|
||||
@ -274,6 +284,7 @@ class TileStatFunctions(val tile: Tile) {
|
||||
|
||||
/** Returns the extra stats that we would get if we switched to this improvement
|
||||
* Can be negative if we're switching to a worse improvement */
|
||||
@Readonly
|
||||
fun getStatDiffForImprovement(
|
||||
improvement: TileImprovement,
|
||||
observingCiv: Civilization,
|
||||
@ -285,16 +296,17 @@ class TileStatFunctions(val tile: Tile) {
|
||||
val currentStats = currentTileStats
|
||||
?: getTileStats(city, observingCiv, cityUniqueCache)
|
||||
|
||||
val tileClone = tile.clone(addUnits = false)
|
||||
@LocalState val tileClone = tile.clone(addUnits = false)
|
||||
tileClone.setTerrainTransients()
|
||||
|
||||
tileClone.setImprovement(improvement.name)
|
||||
val futureStats = tileClone.stats.getTileStats(city, observingCiv, cityUniqueCache)
|
||||
@LocalState val futureStats = tileClone.stats.getTileStats(city, observingCiv, cityUniqueCache)
|
||||
|
||||
return futureStats.minus(currentStats)
|
||||
}
|
||||
|
||||
// Also multiplies the stats by the percentage bonus for improvements (but not for tiles)
|
||||
@Readonly
|
||||
private fun getExtraImprovementStats(
|
||||
improvement: TileImprovement,
|
||||
observingCiv: Civilization,
|
||||
|
@ -52,7 +52,6 @@ open class Counter<K>(
|
||||
@Readonly
|
||||
/** Creates a new instance (does not modify) */
|
||||
operator fun times(amount: Int): Counter<K> {
|
||||
@LocalState
|
||||
val newCounter = Counter<K>()
|
||||
for (key in keys) newCounter[key] = this[key] * amount
|
||||
return newCounter
|
||||
|
@ -556,7 +556,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
state ?: GameContext.EmptyState)
|
||||
if (uniques.none() && requiredResource == null) return Counter.ZERO
|
||||
|
||||
@LocalState val resourceRequirements = Counter<String>()
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
|
||||
for (unique in uniques)
|
||||
resourceRequirements.add(unique.params[1], unique.params[0].toInt())
|
||||
|
@ -13,7 +13,6 @@ import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stat.Companion.statsUsableToBuy
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
import com.unciv.ui.components.fonts.Fonts
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.pow
|
||||
@ -133,7 +132,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
|
||||
|
||||
@Readonly
|
||||
override fun getStockpiledResourceRequirements(state: GameContext): Counter<String> {
|
||||
@LocalState val counter = Counter<String>()
|
||||
val counter = Counter<String>()
|
||||
for (unique in getMatchingUniquesNotConflicting(UniqueType.CostsResources, state)){
|
||||
var amount = unique.params[0].toInt()
|
||||
if (unique.isModifiedByGameSpeed()) amount = (amount * state.gameInfo!!.speed.modifier).toInt()
|
||||
|
@ -14,7 +14,6 @@ import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import yairm210.purity.annotations.Cache
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
class TileResource : RulesetStatsObject(), GameResource {
|
||||
@ -61,7 +60,7 @@ class TileResource : RulesetStatsObject(), GameResource {
|
||||
val ruleset = this.ruleset
|
||||
?: throw IllegalStateException("No ruleset on TileResource when initializing improvements")
|
||||
|
||||
@LocalState val allImprovementsLocal = mutableSetOf<String>()
|
||||
val allImprovementsLocal = mutableSetOf<String>()
|
||||
|
||||
if (improvement != null) allImprovementsLocal += improvement!!
|
||||
allImprovementsLocal.addAll(improvedBy)
|
||||
|
@ -11,7 +11,6 @@ import com.unciv.models.translations.getModifiers
|
||||
import com.unciv.models.translations.getPlaceholderParameters
|
||||
import com.unciv.models.translations.getPlaceholderText
|
||||
import com.unciv.models.translations.removeConditionals
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.max
|
||||
|
||||
@ -181,12 +180,12 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
||||
// note this is only done for the replacement, not the deprecated unique, thus parameters of
|
||||
// conditionals on the deprecated unique are ignored
|
||||
|
||||
@LocalState val finalPossibleUniques = ArrayList<String>()
|
||||
val finalPossibleUniques = ArrayList<String>()
|
||||
|
||||
for (possibleUnique in possibleUniques) {
|
||||
var resultingUnique = possibleUnique
|
||||
|
||||
@LocalState val timesParameterWasSeen = Counter<String>()
|
||||
val timesParameterWasSeen = Counter<String>()
|
||||
for (parameter in possibleUnique.replace('<', ' ').getPlaceholderParameters()) {
|
||||
val parameterHasSign = parameter.startsWith('-') || parameter.startsWith('+')
|
||||
val parameterUnsigned = if (parameterHasSign) parameter.drop(1) else parameter
|
||||
|
@ -13,7 +13,6 @@ import com.unciv.models.ruleset.validation.Suppression
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.SubStat
|
||||
import com.unciv.models.translations.TranslationFileWriter
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
@ -714,7 +713,7 @@ enum class UniqueParameterType(
|
||||
}
|
||||
@Readonly
|
||||
private fun scanExistingValues(type: UniqueParameterType, ruleset: Ruleset): Set<String> {
|
||||
@LocalState val result = mutableSetOf<String>()
|
||||
val result = mutableSetOf<String>()
|
||||
for (unique in ruleset.allUniques()) {
|
||||
val parameterMap = unique.type?.parameterTypeMap ?: continue
|
||||
for ((index, param) in unique.params.withIndex()) {
|
||||
|
@ -1489,7 +1489,7 @@ enum class UniqueType(
|
||||
* For 95% of cases, auto-matching is fine. */
|
||||
@Readonly
|
||||
open fun parameterTypeMapInitializer(): ArrayList<List<UniqueParameterType>> {
|
||||
@LocalState val map = ArrayList<List<UniqueParameterType>>()
|
||||
val map = ArrayList<List<UniqueParameterType>>()
|
||||
for (placeholder in text.getPlaceholderParameters()) {
|
||||
val matchingParameterTypes = placeholder
|
||||
.split('/')
|
||||
|
@ -26,7 +26,6 @@ import com.unciv.ui.objectdescriptions.BaseUnitDescriptions
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import com.unciv.utils.yieldIfNotNull
|
||||
import yairm210.purity.annotations.Cache
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.pow
|
||||
|
||||
@ -478,7 +477,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
|
||||
/** Returns resource requirements from both uniques and requiredResource field */
|
||||
override fun getResourceRequirementsPerTurn(state: GameContext?): Counter<String> {
|
||||
@LocalState val resourceRequirements = Counter<String>()
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, state ?: GameContext.EmptyState))
|
||||
resourceRequirements.add(unique.params[1], unique.params[0].toInt())
|
||||
|
@ -349,7 +349,7 @@ class UniqueValidator(val ruleset: Ruleset) {
|
||||
unique: Unique,
|
||||
): List<UniqueComplianceError> {
|
||||
if (unique.type == null) return emptyList()
|
||||
@LocalState val errorList = ArrayList<UniqueComplianceError>()
|
||||
val errorList = ArrayList<UniqueComplianceError>()
|
||||
for ((index, param) in unique.params.withIndex()) {
|
||||
// Trying to catch the error at #11404
|
||||
if (unique.type.parameterTypeMap.size != unique.params.size) {
|
||||
|
@ -125,6 +125,7 @@ open class Stats(
|
||||
|
||||
/** **Non-Mutating function**
|
||||
* @return a new [Stats] instance with the result of multiplying each value of this instance by [number] as a new instance */
|
||||
@Readonly
|
||||
operator fun times(number: Float) = Stats(
|
||||
production * number,
|
||||
food * number,
|
||||
|
@ -483,7 +483,7 @@ fun String.getPlaceholderParameters(): List<String> {
|
||||
|
||||
val stringToParse = this.removeConditionals()
|
||||
|
||||
@LocalState val parameters = ArrayList<String>()
|
||||
val parameters = ArrayList<String>()
|
||||
var depthOfBraces = 0
|
||||
var startOfCurrentParameter = -1
|
||||
stringToParse.indices.forEach { i ->
|
||||
|
@ -9,7 +9,6 @@ import com.unciv.models.translations.removeConditionals
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.fonts.FontRulesetIcons
|
||||
import com.unciv.ui.components.fonts.Fonts
|
||||
import yairm210.purity.annotations.LocalState
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.ceil
|
||||
|
||||
@ -180,7 +179,7 @@ object UnitActionModifiers {
|
||||
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
||||
|
||||
if (actionUnique.hasModifier(UniqueType.UnitActionStatsCost)) {
|
||||
@LocalState val statCost = Stats()
|
||||
val statCost = Stats()
|
||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost))
|
||||
statCost.add(conditional.stats)
|
||||
effects += statCost.toStringOnlyIcons(false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user