mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-26 21:35:14 -04:00
chore(purity): Many autodetected functions and friends 2
This commit is contained in:
parent
c8893723bf
commit
152acba973
@ -66,6 +66,9 @@ allprojects {
|
|||||||
"kotlin.collections.mutableSetOf",
|
"kotlin.collections.mutableSetOf",
|
||||||
"kotlin.collections.withIndex", // applicable to sequence as well
|
"kotlin.collections.withIndex", // applicable to sequence as well
|
||||||
"kotlin.collections.intersect",
|
"kotlin.collections.intersect",
|
||||||
|
"kotlin.collections.maxOfOrNull",
|
||||||
|
"kotlin.collections.minOfOrNull",
|
||||||
|
"kotlin.reflect.KMutableProperty0.get", // also 1 and 2
|
||||||
)
|
)
|
||||||
wellKnownPureClasses = setOf(
|
wellKnownPureClasses = setOf(
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.logic
|
package com.unciv.logic
|
||||||
|
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An [Exception] wrapper marking an Exception as suitable to be shown to the user.
|
* An [Exception] wrapper marking an Exception as suitable to be shown to the user.
|
||||||
@ -27,6 +28,6 @@ class MissingModsException(
|
|||||||
val missingMods: Iterable<String>
|
val missingMods: Iterable<String>
|
||||||
) : UncivShowableException("Missing mods: [${shorten(missingMods)}]") {
|
) : UncivShowableException("Missing mods: [${shorten(missingMods)}]") {
|
||||||
companion object {
|
companion object {
|
||||||
private fun shorten(missingMods: Iterable<String>) = missingMods.joinToString(limit = 5) { it }
|
@Readonly private fun shorten(missingMods: Iterable<String>) = missingMods.joinToString(limit = 5) { it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import com.unciv.logic.map.tile.Tile
|
|||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.ruleset.INonPerpetualConstruction
|
import com.unciv.models.ruleset.INonPerpetualConstruction
|
||||||
import com.unciv.models.ruleset.PerpetualConstruction
|
import com.unciv.models.ruleset.PerpetualConstruction
|
||||||
import com.unciv.models.ruleset.nation.PersonalityValue
|
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
import com.unciv.models.ruleset.tile.TileImprovement
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||||
@ -21,6 +20,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
|
|||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
@ -406,6 +406,7 @@ object Automation {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun threatAssessment(assessor: Civilization, assessed: Civilization): ThreatLevel {
|
fun threatAssessment(assessor: Civilization, assessed: Civilization): ThreatLevel {
|
||||||
val powerLevelComparison =
|
val powerLevelComparison =
|
||||||
assessed.getStatForRanking(RankingType.Force) / assessor.getStatForRanking(RankingType.Force).toFloat()
|
assessed.getStatForRanking(RankingType.Force) / assessor.getStatForRanking(RankingType.Force).toFloat()
|
||||||
|
@ -19,6 +19,7 @@ import com.unciv.logic.trade.TradeOfferType
|
|||||||
import com.unciv.models.ruleset.nation.PersonalityValue
|
import com.unciv.models.ruleset.nation.PersonalityValue
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ object DiplomacyAutomation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
internal fun wantsToSignDeclarationOfFrienship(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
internal fun wantsToSignDeclarationOfFrienship(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||||
val diploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
val diploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||||
if (diploManager.hasFlag(DiplomacyFlags.DeclinedDeclarationOfFriendship)) return false
|
if (diploManager.hasFlag(DiplomacyFlags.DeclinedDeclarationOfFriendship)) return false
|
||||||
@ -187,6 +189,7 @@ object DiplomacyAutomation {
|
|||||||
/**
|
/**
|
||||||
* Test if [otherCiv] wants to accept our embassy in their capital
|
* Test if [otherCiv] wants to accept our embassy in their capital
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun wantsToAcceptEmbassy(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
fun wantsToAcceptEmbassy(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||||
val theirDiploManager = otherCiv.getDiplomacyManager(civInfo)!!
|
val theirDiploManager = otherCiv.getDiplomacyManager(civInfo)!!
|
||||||
if (civInfo.getDiplomacyManager(otherCiv)!!.hasFlag(DiplomacyFlags.DeclinedEmbassy)) return false
|
if (civInfo.getDiplomacyManager(otherCiv)!!.hasFlag(DiplomacyFlags.DeclinedEmbassy)) return false
|
||||||
@ -211,6 +214,7 @@ object DiplomacyAutomation {
|
|||||||
return true // Relationship is Afraid or greater
|
return true // Relationship is Afraid or greater
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun wantsToOpenBorders(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
fun wantsToOpenBorders(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)) return false
|
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)) return false
|
||||||
@ -278,6 +282,7 @@ object DiplomacyAutomation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun wantsToSignDefensivePact(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
fun wantsToSignDefensivePact(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)) return false
|
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)) return false
|
||||||
@ -450,6 +455,7 @@ object DiplomacyAutomation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun areWeOfferingTrade(civInfo: Civilization, otherCiv: Civilization, offerName: String): Boolean {
|
private fun areWeOfferingTrade(civInfo: Civilization, otherCiv: Civilization, offerName: String): Boolean {
|
||||||
return otherCiv.tradeRequests.filter { request -> request.requestingCiv == civInfo.civName }
|
return otherCiv.tradeRequests.filter { request -> request.requestingCiv == civInfo.civName }
|
||||||
.any { trade -> trade.trade.ourOffers.any { offer -> offer.name == offerName }
|
.any { trade -> trade.trade.ourOffers.any { offer -> offer.name == offerName }
|
||||||
|
@ -16,11 +16,13 @@ import com.unciv.models.ruleset.nation.PersonalityValue
|
|||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
object MotivationToAttackAutomation {
|
object MotivationToAttackAutomation {
|
||||||
|
|
||||||
/** Will return the motivation to attack, but might short circuit if the value is guaranteed to
|
/** Will return the motivation to attack, but might short circuit if the value is guaranteed to
|
||||||
* be lower than `atLeast`. So any values below `atLeast` should not be used for comparison. */
|
* be lower than `atLeast`. So any values below `atLeast` should not be used for comparison. */
|
||||||
|
@Readonly @Suppress("purity")
|
||||||
fun hasAtLeastMotivationToAttack(civInfo: Civilization, targetCiv: Civilization, atLeast: Float): Float {
|
fun hasAtLeastMotivationToAttack(civInfo: Civilization, targetCiv: Civilization, atLeast: Float): Float {
|
||||||
val diplomacyManager = civInfo.getDiplomacyManager(targetCiv)!!
|
val diplomacyManager = civInfo.getDiplomacyManager(targetCiv)!!
|
||||||
val personality = civInfo.getPersonality()
|
val personality = civInfo.getPersonality()
|
||||||
|
@ -868,6 +868,7 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasStatToBuy(stat: Stat, price: Int): Boolean {
|
fun hasStatToBuy(stat: Stat, price: Int): Boolean {
|
||||||
return when {
|
return when {
|
||||||
gameInfo.gameParameters.godMode -> true
|
gameInfo.gameParameters.godMode -> true
|
||||||
@ -930,22 +931,6 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getReserve(stat: GameResource): Int {
|
|
||||||
if (stat is TileResource && !stat.isCityWide && stat.isStockpiled)
|
|
||||||
return resourceStockpiles[stat.name]
|
|
||||||
return when (stat) {
|
|
||||||
Stat.Culture -> policies.storedCulture
|
|
||||||
Stat.Science -> {
|
|
||||||
if (tech.currentTechnology() == null) 0
|
|
||||||
else tech.researchOfTech(tech.currentTechnology()!!.name)
|
|
||||||
}
|
|
||||||
Stat.Gold -> gold
|
|
||||||
Stat.Faith -> religionManager.storedFaith
|
|
||||||
SubStat.GoldenAgePoints -> goldenAges.storedHappiness
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// region addNotification
|
// region addNotification
|
||||||
fun addNotification(text: String, category: NotificationCategory, vararg notificationIcons: String) =
|
fun addNotification(text: String, category: NotificationCategory, vararg notificationIcons: String) =
|
||||||
addNotification(text, null, category, *notificationIcons)
|
addNotification(text, null, category, *notificationIcons)
|
||||||
|
@ -255,16 +255,16 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** @see compareRelationshipLevel */
|
/** @see compareRelationshipLevel */
|
||||||
fun isRelationshipLevelEQ(level: RelationshipLevel) =
|
@Readonly fun isRelationshipLevelEQ(level: RelationshipLevel) =
|
||||||
compareRelationshipLevel(level, 0)
|
compareRelationshipLevel(level, 0)
|
||||||
/** @see compareRelationshipLevel */
|
/** @see compareRelationshipLevel */
|
||||||
fun isRelationshipLevelLT(level: RelationshipLevel) =
|
@Readonly fun isRelationshipLevelLT(level: RelationshipLevel) =
|
||||||
compareRelationshipLevel(level, -1)
|
compareRelationshipLevel(level, -1)
|
||||||
/** @see compareRelationshipLevel */
|
/** @see compareRelationshipLevel */
|
||||||
fun isRelationshipLevelGT(level: RelationshipLevel) =
|
@Readonly fun isRelationshipLevelGT(level: RelationshipLevel) =
|
||||||
compareRelationshipLevel(level, 1)
|
compareRelationshipLevel(level, 1)
|
||||||
/** @see compareRelationshipLevel */
|
/** @see compareRelationshipLevel */
|
||||||
fun isRelationshipLevelLE(level: RelationshipLevel) =
|
@Readonly fun isRelationshipLevelLE(level: RelationshipLevel) =
|
||||||
if (level == RelationshipLevel.Ally) true
|
if (level == RelationshipLevel.Ally) true
|
||||||
else compareRelationshipLevel(level + 1, -1)
|
else compareRelationshipLevel(level + 1, -1)
|
||||||
/** @see compareRelationshipLevel */
|
/** @see compareRelationshipLevel */
|
||||||
@ -468,9 +468,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the [civilizations][Civilization] that know about both sides ([civInfo] and [otherCiv]) */
|
/** Returns the [civilizations][Civilization] that know about both sides ([civInfo] and [otherCiv]) */
|
||||||
fun getCommonKnownCivs(): Set<Civilization> = civInfo.getKnownCivs().asIterable().intersect(otherCiv().getKnownCivs().toSet())
|
@Readonly fun getCommonKnownCivs(): Set<Civilization> = civInfo.getKnownCivs().asIterable().intersect(otherCiv().getKnownCivs().toSet())
|
||||||
|
|
||||||
fun getCommonKnownCivsWithSpectators(): Set<Civilization> = civInfo.getKnownCivsWithSpectators().asIterable().intersect(otherCiv().getKnownCivsWithSpectators().toSet())
|
@Readonly fun getCommonKnownCivsWithSpectators(): Set<Civilization> = civInfo.getKnownCivsWithSpectators().asIterable().intersect(otherCiv().getKnownCivsWithSpectators().toSet())
|
||||||
/** Returns true when the [civInfo]'s territory is considered allied for [otherCiv].
|
/** Returns true when the [civInfo]'s territory is considered allied for [otherCiv].
|
||||||
* This includes friendly and allied city-states and the open border treaties.
|
* This includes friendly and allied city-states and the open border treaties.
|
||||||
*/
|
*/
|
||||||
|
@ -5,6 +5,7 @@ import com.unciv.logic.civilization.Civilization
|
|||||||
import com.unciv.logic.map.mapunit.MapUnit
|
import com.unciv.logic.map.mapunit.MapUnit
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles optimised operations related to finding threats or allies in an area.
|
* Handles optimised operations related to finding threats or allies in an area.
|
||||||
@ -83,6 +84,7 @@ class ThreatManager(val civInfo: Civilization) {
|
|||||||
* May be quicker than a manual search because of caching.
|
* May be quicker than a manual search because of caching.
|
||||||
* Also ends up calculating and caching [getDistanceToClosestEnemyUnit].
|
* Also ends up calculating and caching [getDistanceToClosestEnemyUnit].
|
||||||
*/
|
*/
|
||||||
|
@Readonly @Suppress("purity")
|
||||||
fun getTilesWithEnemyUnitsInDistance(tile: Tile, maxDist: Int): MutableList<Tile> {
|
fun getTilesWithEnemyUnitsInDistance(tile: Tile, maxDist: Int): MutableList<Tile> {
|
||||||
val tileData = distanceToClosestEnemyTiles[tile]
|
val tileData = distanceToClosestEnemyTiles[tile]
|
||||||
|
|
||||||
@ -129,19 +131,15 @@ class ThreatManager(val civInfo: Civilization) {
|
|||||||
return tilesWithEnemies
|
return tilesWithEnemies
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all enemy military units within maxDistance of the tile.
|
|
||||||
*/
|
|
||||||
fun getEnemyMilitaryUnitsInDistance(tile: Tile, maxDist: Int): List<MapUnit> =
|
|
||||||
getEnemyUnitsOnTiles(getTilesWithEnemyUnitsInDistance(tile, maxDist))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all enemy military units on tiles
|
* Returns all enemy military units on tiles
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun getEnemyUnitsOnTiles(tilesWithEnemyUnitsInDistance:List<Tile>): List<MapUnit> =
|
fun getEnemyUnitsOnTiles(tilesWithEnemyUnitsInDistance:List<Tile>): List<MapUnit> =
|
||||||
tilesWithEnemyUnitsInDistance.flatMap { enemyTile -> enemyTile.getUnits()
|
tilesWithEnemyUnitsInDistance.flatMap { enemyTile -> enemyTile.getUnits()
|
||||||
.filter { it.isMilitary() && civInfo.isAtWarWith(it.civ) } }
|
.filter { it.isMilitary() && civInfo.isAtWarWith(it.civ) } }
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getDangerousTiles(unit: MapUnit, distance: Int = 3): HashSet<Tile> {
|
fun getDangerousTiles(unit: MapUnit, distance: Int = 3): HashSet<Tile> {
|
||||||
val tilesWithEnemyUnits = getTilesWithEnemyUnitsInDistance(unit.getTile(), distance)
|
val tilesWithEnemyUnits = getTilesWithEnemyUnitsInDistance(unit.getTile(), distance)
|
||||||
val nearbyRangedEnemyUnits = getEnemyUnitsOnTiles(tilesWithEnemyUnits)
|
val nearbyRangedEnemyUnits = getEnemyUnitsOnTiles(tilesWithEnemyUnits)
|
||||||
@ -162,6 +160,7 @@ class ThreatManager(val civInfo: Civilization) {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the tile has a visible enemy, otherwise returns false.
|
* Returns true if the tile has a visible enemy, otherwise returns false.
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun doesTileHaveMilitaryEnemy(tile: Tile): Boolean {
|
fun doesTileHaveMilitaryEnemy(tile: Tile): Boolean {
|
||||||
if (!tile.isExplored(civInfo)) return false
|
if (!tile.isExplored(civInfo)) return false
|
||||||
if (tile.isCityCenter() && tile.getCity()!!.civ.isAtWarWith(civInfo)) return true
|
if (tile.isCityCenter() && tile.getCity()!!.civ.isAtWarWith(civInfo)) return true
|
||||||
@ -174,13 +173,17 @@ class ThreatManager(val civInfo: Civilization) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return a sequence of pairs of cities, the first city is our city and the second city is a nearby city that is not from our civ. */
|
/** @return a sequence of pairs of cities, the first city is our city and the second city is a nearby city that is not from our civ. */
|
||||||
|
@Readonly
|
||||||
fun getNeighboringCitiesOfOtherCivs(): Sequence<Pair<City,City>> = civInfo.cities.flatMap {
|
fun getNeighboringCitiesOfOtherCivs(): Sequence<Pair<City,City>> = civInfo.cities.flatMap {
|
||||||
ourCity -> ourCity.neighboringCities.filter { it.civ != civInfo }.map { Pair(ourCity, it) }
|
ourCity -> ourCity.neighboringCities.filter { it.civ != civInfo }.map { Pair(ourCity, it) }
|
||||||
}.asSequence()
|
}.asSequence()
|
||||||
|
|
||||||
fun getNeighboringCivilizations(): Set<Civilization> = civInfo.cities.flatMap { it.neighboringCities }.filter { it.civ != civInfo && civInfo.knows(it.civ) }.map { it.civ }.toSet()
|
@Readonly fun getNeighboringCivilizations(): Set<Civilization> = civInfo.cities
|
||||||
|
.flatMap { it.neighboringCities }
|
||||||
|
.filter { it.civ != civInfo && civInfo.knows(it.civ) }
|
||||||
|
.map { it.civ }.toSet()
|
||||||
|
|
||||||
fun getCombinedForceOfWarringCivs(): Int = civInfo.getCivsAtWarWith().sumOf { it.getStatForRanking(RankingType.Force) }
|
@Readonly fun getCombinedForceOfWarringCivs(): Int = civInfo.getCivsAtWarWith().sumOf { it.getStatForRanking(RankingType.Force) }
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
distanceToClosestEnemyTiles.clear()
|
distanceToClosestEnemyTiles.clear()
|
||||||
|
@ -15,6 +15,7 @@ import com.unciv.models.stats.Stat
|
|||||||
import com.unciv.models.stats.StatMap
|
import com.unciv.models.stats.StatMap
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.components.extensions.toPercent
|
import com.unciv.ui.components.extensions.toPercent
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -125,6 +126,7 @@ class CivInfoStatsForNextTurn(val civInfo: Civilization) {
|
|||||||
return transportationUpkeep
|
return transportationUpkeep
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getUnitSupply(): Int {
|
fun getUnitSupply(): Int {
|
||||||
/* TotalSupply = BaseSupply + NumCities*modifier + Population*modifier
|
/* TotalSupply = BaseSupply + NumCities*modifier + Population*modifier
|
||||||
* In civ5, it seems population modifier is always 0.5, so i hardcoded it down below */
|
* In civ5, it seems population modifier is always 0.5, so i hardcoded it down below */
|
||||||
@ -135,15 +137,18 @@ class CivInfoStatsForNextTurn(val civInfo: Civilization) {
|
|||||||
return supply
|
return supply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getBaseUnitSupply(): Int {
|
fun getBaseUnitSupply(): Int {
|
||||||
return civInfo.getDifficulty().unitSupplyBase +
|
return civInfo.getDifficulty().unitSupplyBase +
|
||||||
civInfo.getMatchingUniques(UniqueType.BaseUnitSupply).sumOf { it.params[0].toInt() }
|
civInfo.getMatchingUniques(UniqueType.BaseUnitSupply).sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
@Readonly
|
||||||
fun getUnitSupplyFromCities(): Int {
|
fun getUnitSupplyFromCities(): Int {
|
||||||
return civInfo.cities.size *
|
return civInfo.cities.size *
|
||||||
(civInfo.getDifficulty().unitSupplyPerCity
|
(civInfo.getDifficulty().unitSupplyPerCity
|
||||||
+ civInfo.getMatchingUniques(UniqueType.UnitSupplyPerCity).sumOf { it.params[0].toInt() })
|
+ civInfo.getMatchingUniques(UniqueType.UnitSupplyPerCity).sumOf { it.params[0].toInt() })
|
||||||
}
|
}
|
||||||
|
@Readonly
|
||||||
fun getUnitSupplyFromPop(): Int {
|
fun getUnitSupplyFromPop(): Int {
|
||||||
var totalSupply = civInfo.cities.sumOf { it.population.population } * civInfo.gameInfo.ruleset.modOptions.constants.unitSupplyPerPopulation
|
var totalSupply = civInfo.cities.sumOf { it.population.population } * civInfo.gameInfo.ruleset.modOptions.constants.unitSupplyPerPopulation
|
||||||
|
|
||||||
@ -155,10 +160,10 @@ class CivInfoStatsForNextTurn(val civInfo: Civilization) {
|
|||||||
}
|
}
|
||||||
return totalSupply.toInt()
|
return totalSupply.toInt()
|
||||||
}
|
}
|
||||||
fun getUnitSupplyDeficit(): Int = max(0,civInfo.units.getCivUnitsSize() - getUnitSupply())
|
@Readonly fun getUnitSupplyDeficit(): Int = max(0,civInfo.units.getCivUnitsSize() - getUnitSupply())
|
||||||
|
|
||||||
/** Per each supply missing, a player gets -10% production. Capped at -70%. */
|
/** Per each supply missing, a player gets -10% production. Capped at -70%. */
|
||||||
fun getUnitSupplyProductionPenalty(): Float = -min(getUnitSupplyDeficit() * 10f, 70f)
|
@Readonly fun getUnitSupplyProductionPenalty(): Float = -min(getUnitSupplyDeficit() * 10f, 70f)
|
||||||
|
|
||||||
fun getStatMapForNextTurn(): StatMap {
|
fun getStatMapForNextTurn(): StatMap {
|
||||||
val statMap = StatMap()
|
val statMap = StatMap()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.logic.map
|
package com.unciv.logic.map
|
||||||
|
|
||||||
import com.unciv.logic.map.tile.Tile
|
import com.unciv.logic.map.tile.Tile
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.collections.ArrayDeque
|
import kotlin.collections.ArrayDeque
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,6 +68,7 @@ class BFS(
|
|||||||
/**
|
/**
|
||||||
* @return a Sequence from the [destination] back to the [startingPoint], including both, or empty if [destination] has not been reached
|
* @return a Sequence from the [destination] back to the [startingPoint], including both, or empty if [destination] has not been reached
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun getPathTo(destination: Tile): Sequence<Tile> = sequence {
|
fun getPathTo(destination: Tile): Sequence<Tile> = sequence {
|
||||||
var currentNode = destination
|
var currentNode = destination
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -237,6 +237,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
@Readonly fun getTile(): Tile = currentTile
|
@Readonly fun getTile(): Tile = currentTile
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getClosestCity(): City? = civ.cities.minByOrNull {
|
fun getClosestCity(): City? = civ.cities.minByOrNull {
|
||||||
it.getCenterTile().aerialDistanceTo(currentTile)
|
it.getCenterTile().aerialDistanceTo(currentTile)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package com.unciv.models.ruleset.nation
|
package com.unciv.models.ruleset.nation
|
||||||
|
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.logic.civilization.Civilization
|
|
||||||
import com.unciv.models.ruleset.RulesetObject
|
import com.unciv.models.ruleset.RulesetObject
|
||||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||||
import com.unciv.models.stats.Stat
|
import com.unciv.models.stats.Stat
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
|
import yairm210.purity.annotations.Pure
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.reflect.KMutableProperty0
|
import kotlin.reflect.KMutableProperty0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +66,7 @@ class Personality: RulesetObject() {
|
|||||||
var preferredVictoryType: String = Constants.neutralVictoryType
|
var preferredVictoryType: String = Constants.neutralVictoryType
|
||||||
var isNeutralPersonality: Boolean = false
|
var isNeutralPersonality: Boolean = false
|
||||||
|
|
||||||
|
@Pure
|
||||||
private fun nameToVariable(value: PersonalityValue): KMutableProperty0<Float> {
|
private fun nameToVariable(value: PersonalityValue): KMutableProperty0<Float> {
|
||||||
return when(value) {
|
return when(value) {
|
||||||
PersonalityValue.Production -> ::production
|
PersonalityValue.Production -> ::production
|
||||||
@ -95,6 +97,7 @@ class Personality: RulesetObject() {
|
|||||||
/**
|
/**
|
||||||
* Scales the value to a more meaningful range, where 10 is 2, and 5 is 1, and 0 is 0
|
* Scales the value to a more meaningful range, where 10 is 2, and 5 is 1, and 0 is 0
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun scaledFocus(value: PersonalityValue): Float {
|
fun scaledFocus(value: PersonalityValue): Float {
|
||||||
return nameToVariable(value).get() / 5
|
return nameToVariable(value).get() / 5
|
||||||
}
|
}
|
||||||
@ -102,6 +105,7 @@ class Personality: RulesetObject() {
|
|||||||
/**
|
/**
|
||||||
* Inverse scales the value to a more meaningful range, where 0 is 2, and 5 is 1 and 10 is 0
|
* Inverse scales the value to a more meaningful range, where 0 is 2, and 5 is 1 and 10 is 0
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun inverseScaledFocus(value: PersonalityValue): Float {
|
fun inverseScaledFocus(value: PersonalityValue): Float {
|
||||||
return (10 - nameToVariable(value).get()) / 5
|
return (10 - nameToVariable(value).get()) / 5
|
||||||
}
|
}
|
||||||
@ -110,6 +114,7 @@ class Personality: RulesetObject() {
|
|||||||
* @param weight a value between 0 and 1 that determines how much the modifier deviates from 1
|
* @param weight a value between 0 and 1 that determines how much the modifier deviates from 1
|
||||||
* @return a modifier between 0 and 2 centered around 1 based off of the personality value and the weight given
|
* @return a modifier between 0 and 2 centered around 1 based off of the personality value and the weight given
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun modifierFocus(value: PersonalityValue, weight: Float): Float {
|
fun modifierFocus(value: PersonalityValue, weight: Float): Float {
|
||||||
return 1f + (scaledFocus(value) - 1) * weight
|
return 1f + (scaledFocus(value) - 1) * weight
|
||||||
}
|
}
|
||||||
@ -119,6 +124,7 @@ class Personality: RulesetObject() {
|
|||||||
* @param weight a value between 0 and 1 that determines how much the modifier deviates from 1
|
* @param weight a value between 0 and 1 that determines how much the modifier deviates from 1
|
||||||
* @return a modifier between 0 and 2 centered around 1 based off of the personality value and the weight given
|
* @return a modifier between 0 and 2 centered around 1 based off of the personality value and the weight given
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun inverseModifierFocus(value: PersonalityValue, weight: Float): Float {
|
fun inverseModifierFocus(value: PersonalityValue, weight: Float): Float {
|
||||||
return 1f - (inverseScaledFocus(value) - 2) * weight
|
return 1f - (inverseScaledFocus(value) - 2) * weight
|
||||||
}
|
}
|
||||||
@ -128,7 +134,7 @@ class Personality: RulesetObject() {
|
|||||||
* @param weight a positive value that determines how much the personality should impact the stats given
|
* @param weight a positive value that determines how much the personality should impact the stats given
|
||||||
*/
|
*/
|
||||||
fun scaleStats(stats: Stats, weight: Float): Stats {
|
fun scaleStats(stats: Stats, weight: Float): Stats {
|
||||||
Stat.values().forEach { stats[it] *= modifierFocus(PersonalityValue[it], weight) }
|
Stat.entries.forEach { stats[it] *= modifierFocus(PersonalityValue[it], weight) }
|
||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,19 +9,24 @@ import com.unciv.models.translations.removeConditionals
|
|||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.components.fonts.FontRulesetIcons
|
import com.unciv.ui.components.fonts.FontRulesetIcons
|
||||||
import com.unciv.ui.components.fonts.Fonts
|
import com.unciv.ui.components.fonts.Fonts
|
||||||
|
import yairm210.purity.annotations.LocalState
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
object UnitActionModifiers {
|
object UnitActionModifiers {
|
||||||
|
@Readonly
|
||||||
fun canUse(unit: MapUnit, actionUnique: Unique): Boolean {
|
fun canUse(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||||
val usagesLeft = usagesLeft(unit, actionUnique)
|
val usagesLeft = usagesLeft(unit, actionUnique)
|
||||||
return usagesLeft == null || usagesLeft > 0
|
return usagesLeft == null || usagesLeft > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getUsableUnitActionUniques(unit: MapUnit, actionUniqueType: UniqueType) =
|
fun getUsableUnitActionUniques(unit: MapUnit, actionUniqueType: UniqueType) =
|
||||||
unit.getMatchingUniques(actionUniqueType)
|
unit.getMatchingUniques(actionUniqueType)
|
||||||
.filter { unique -> !unique.hasModifier(UniqueType.UnitActionExtraLimitedTimes) }
|
.filter { unique -> !unique.hasModifier(UniqueType.UnitActionExtraLimitedTimes) }
|
||||||
.filter { canUse(unit, it) }
|
.filter { canUse(unit, it) }
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun getMovementPointsToUse(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): Int {
|
private fun getMovementPointsToUse(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): Int {
|
||||||
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
||||||
return unit.getMaxMovement()
|
return unit.getMaxMovement()
|
||||||
@ -34,6 +39,7 @@ object UnitActionModifiers {
|
|||||||
return if (defaultAllMovement) unit.getMaxMovement() else 1
|
return if (defaultAllMovement) unit.getMaxMovement() else 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun getMovementPointsRequired(actionUnique: Unique): Int {
|
private fun getMovementPointsRequired(actionUnique: Unique): Int {
|
||||||
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
||||||
return 1
|
return 1
|
||||||
@ -46,6 +52,7 @@ object UnitActionModifiers {
|
|||||||
* going into the negatives
|
* going into the negatives
|
||||||
* @return Boolean
|
* @return Boolean
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
private fun canSpendStatsCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
private fun canSpendStatsCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost)) {
|
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost)) {
|
||||||
for ((stat, value) in conditional.stats) {
|
for ((stat, value) in conditional.stats) {
|
||||||
@ -63,6 +70,7 @@ object UnitActionModifiers {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun canSpendStockpileCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
private fun canSpendStockpileCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStockpileCost)) {
|
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStockpileCost)) {
|
||||||
val amount = conditional.params[0].toInt()
|
val amount = conditional.params[0].toInt()
|
||||||
@ -79,6 +87,7 @@ object UnitActionModifiers {
|
|||||||
* @param actionUnique: Unique that defines the Action
|
* @param actionUnique: Unique that defines the Action
|
||||||
* @return Boolean
|
* @return Boolean
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun canActivateSideEffects(unit: MapUnit, actionUnique: Unique): Boolean {
|
fun canActivateSideEffects(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||||
if (!canUse(unit, actionUnique)) return false
|
if (!canUse(unit, actionUnique)) return false
|
||||||
if (getMovementPointsRequired(actionUnique) > ceil(unit.currentMovement).toInt()) return false
|
if (getMovementPointsRequired(actionUnique) > ceil(unit.currentMovement).toInt()) return false
|
||||||
@ -134,12 +143,14 @@ object UnitActionModifiers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns 'null' if usages are not limited */
|
/** Returns 'null' if usages are not limited */
|
||||||
|
@Readonly
|
||||||
private fun usagesLeft(unit: MapUnit, actionUnique: Unique): Int?{
|
private fun usagesLeft(unit: MapUnit, actionUnique: Unique): Int?{
|
||||||
val usagesTotal = getMaxUsages(unit, actionUnique) ?: return null
|
val usagesTotal = getMaxUsages(unit, actionUnique) ?: return null
|
||||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.text.removeConditionals()] ?: 0
|
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.text.removeConditionals()] ?: 0
|
||||||
return usagesTotal - usagesSoFar
|
return usagesTotal - usagesSoFar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
|
private fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
|
||||||
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
|
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
|
||||||
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
|
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
|
||||||
@ -154,12 +165,14 @@ object UnitActionModifiers {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun actionTextWithSideEffects(originalText: String, actionUnique: Unique, unit: MapUnit): String {
|
fun actionTextWithSideEffects(originalText: String, actionUnique: Unique, unit: MapUnit): String {
|
||||||
val sideEffectString = getSideEffectString(unit, actionUnique)
|
val sideEffectString = getSideEffectString(unit, actionUnique)
|
||||||
if (sideEffectString == "") return originalText
|
if (sideEffectString == "") return originalText
|
||||||
else return "{$originalText} $sideEffectString"
|
else return "{$originalText} $sideEffectString"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getSideEffectString(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): String {
|
fun getSideEffectString(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): String {
|
||||||
val effects = ArrayList<String>()
|
val effects = ArrayList<String>()
|
||||||
|
|
||||||
@ -167,7 +180,7 @@ object UnitActionModifiers {
|
|||||||
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
||||||
|
|
||||||
if (actionUnique.hasModifier(UniqueType.UnitActionStatsCost)) {
|
if (actionUnique.hasModifier(UniqueType.UnitActionStatsCost)) {
|
||||||
val statCost = Stats()
|
@LocalState val statCost = Stats()
|
||||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost))
|
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost))
|
||||||
statCost.add(conditional.stats)
|
statCost.add(conditional.stats)
|
||||||
effects += statCost.toStringOnlyIcons(false)
|
effects += statCost.toStringOnlyIcons(false)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user