chore(purity)

This commit is contained in:
yairm210 2025-08-17 14:37:47 +03:00
parent 8e5b36984c
commit b006673e1c
5 changed files with 25 additions and 10 deletions

View File

@ -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 "1.1.1" apply(false)
id("io.github.yairm210.purity-plugin") version "1.2.2" apply(false)
}
allprojects {

View File

@ -11,6 +11,7 @@ import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.utils.randomWeighted
import yairm210.purity.annotations.Readonly
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
@ -241,20 +242,26 @@ class Encampment() : IsPartOfGameInfoSerialization {
/** Attempts to spawn a barbarian on [position], returns true if successful and false if unsuccessful. */
private fun spawnUnit(naval: Boolean): Boolean {
updateBarbarianTech()
val unitToSpawn = chooseBarbarianUnit(naval) ?: return false // return false if we didn't find a unit
val spawnedUnit = gameInfo.tileMap.placeUnitNearTile(position, unitToSpawn, gameInfo.getBarbarianCivilization())
return (spawnedUnit != null)
}
private fun chooseBarbarianUnit(naval: Boolean): BaseUnit? {
// if we don't make this into a separate list then the retain() will happen on the Tech keys,
// which effectively removes those techs from the game and causes all sorts of problems
private fun updateBarbarianTech(){
val barbarianCiv = gameInfo.getBarbarianCivilization()
val allResearchedTechs = gameInfo.ruleset.technologies.keys.toMutableList()
for (civ in gameInfo.civilizations.filter { !it.isBarbarian && !it.isDefeated() }) {
allResearchedTechs.retainAll(civ.tech.techsResearched)
}
val barbarianCiv = gameInfo.getBarbarianCivilization()
barbarianCiv.tech.techsResearched = allResearchedTechs.toHashSet()
}
@Readonly
private fun chooseBarbarianUnit(naval: Boolean): BaseUnit? {
// if we don't make this into a separate list then the retain() will happen on the Tech keys,
// which effectively removes those techs from the game and causes all sorts of problems
val barbarianCiv = gameInfo.getBarbarianCivilization()
val unitList = gameInfo.ruleset.units.values
.filter { it.isMilitary &&
!(it.hasUnique(UniqueType.CannotAttack) ||

View File

@ -97,7 +97,7 @@ class CityStats(val city: City) {
//endregion
//region Pure Functions
@Readonly
private fun getStatsFromTradeRoute(): Stats {
val stats = Stats()
val capitalForTradeRoutePurposes = city.civ.getCapital()!!
@ -201,14 +201,14 @@ class CityStats(val city: City) {
}
@Readonly @Suppress("purity") // stats[] *= fails
@Readonly
private fun getStatsFromUniquesBySource(): StatTreeNode {
val sourceToStats = StatTreeNode()
val cityStateStatsMultipliers = city.civ.getMatchingUniques(UniqueType.BonusStatsFromCityStates).toList()
fun addUniqueStats(unique: Unique) {
val stats = unique.stats.clone()
@LocalState val stats = unique.stats.clone()
if (unique.sourceObjectType==UniqueTarget.CityState)
for (multiplierUnique in cityStateStatsMultipliers)
stats[Stat.valueOf(multiplierUnique.params[1])] *= multiplierUnique.params[0].toPercent()

View File

@ -131,7 +131,7 @@ class TileImprovement : RulesetStatsObject() {
}
}.filter { it !in cannotFilters }.toMutableSet()
@LocalState val terrainsCanBeBuiltOnTypes = sequence {
val terrainsCanBeBuiltOnTypes = sequence {
yieldAll(expandedTerrainsCanBeBuiltOn.asSequence()
.mapNotNull { ruleset.terrains[it]?.type })
yieldAll(

View File

@ -2,12 +2,14 @@ package com.unciv.utils
import com.badlogic.gdx.utils.Array
import yairm210.purity.annotations.Pure
import yairm210.purity.annotations.Readonly
import kotlin.random.Random
/** Get one random element of a given List.
*
* The probability for each element is proportional to the value of its corresponding element in the [weights] List.
*/
@Readonly
fun <T> List<T>.randomWeighted(weights: List<Float>, random: Random = Random): T {
if (this.isEmpty()) throw NoSuchElementException("Empty list.")
if (this.size != weights.size) throw UnsupportedOperationException("Weights size does not match this list size.")
@ -28,6 +30,7 @@ fun <T> List<T>.randomWeighted(weights: List<Float>, random: Random = Random): T
*
* The probability for each element is proportional to the result of [getWeight] (evaluated only once).
*/
@Readonly
fun <T> List<T>.randomWeighted(random: Random = Random, getWeight: (T) -> Float): T =
randomWeighted(map(getWeight), random)
@ -35,6 +38,7 @@ fun <T> List<T>.randomWeighted(random: Random = Random, getWeight: (T) -> Float)
*
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
*/
@Readonly
fun <T> ArrayList<T>.withItem(item: T): ArrayList<T> {
val newArrayList = ArrayList(this)
newArrayList.add(item)
@ -45,6 +49,7 @@ fun <T> ArrayList<T>.withItem(item: T): ArrayList<T> {
*
* Solves concurrent modification problems - everyone who had a reference to the previous hashSet can keep using it because it hasn't changed
*/
@Readonly
fun <T> HashSet<T>.withItem(item: T): HashSet<T> {
val newHashSet = HashSet(this)
newHashSet.add(item)
@ -55,6 +60,7 @@ fun <T> HashSet<T>.withItem(item: T): HashSet<T> {
*
* Solves concurrent modification problems - everyone who had a reference to the previous arrayList can keep using it because it hasn't changed
*/
@Readonly
fun <T> ArrayList<T>.withoutItem(item: T): ArrayList<T> {
val newArrayList = ArrayList(this)
newArrayList.remove(item)
@ -65,6 +71,7 @@ fun <T> ArrayList<T>.withoutItem(item: T): ArrayList<T> {
*
* Solves concurrent modification problems - everyone who had a reference to the previous hashSet can keep using it because it hasn't changed
*/
@Readonly
fun <T> HashSet<T>.withoutItem(item: T): HashSet<T> {
val newHashSet = HashSet(this)
newHashSet.remove(item)
@ -105,6 +112,7 @@ fun <KT, ET> HashMap<KT, HashSet<ET>>.addToMapOfSets(key: KT, element: ET) =
getOrPut(key) { hashSetOf() }.add(element)
/** Simplifies testing whether in a sparse map of sets the [element] exists for [key]. */
@Readonly
fun <KT, ET> HashMap<KT, HashSet<ET>>.contains(key: KT, element: ET) =
get(key)?.contains(element) == true