mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-26 05:14:32 -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.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(
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic
|
||||
|
||||
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.
|
||||
@ -27,6 +28,6 @@ class MissingModsException(
|
||||
val missingMods: Iterable<String>
|
||||
) : UncivShowableException("Missing mods: [${shorten(missingMods)}]") {
|
||||
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.INonPerpetualConstruction
|
||||
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.TileImprovement
|
||||
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.Stats
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
@ -406,6 +406,7 @@ object Automation {
|
||||
return true
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun threatAssessment(assessor: Civilization, assessed: Civilization): ThreatLevel {
|
||||
val powerLevelComparison =
|
||||
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.unique.UniqueType
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.abs
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -40,6 +41,7 @@ object DiplomacyAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly
|
||||
internal fun wantsToSignDeclarationOfFrienship(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val diploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (diploManager.hasFlag(DiplomacyFlags.DeclinedDeclarationOfFriendship)) return false
|
||||
@ -187,6 +189,7 @@ object DiplomacyAutomation {
|
||||
/**
|
||||
* Test if [otherCiv] wants to accept our embassy in their capital
|
||||
*/
|
||||
@Readonly
|
||||
fun wantsToAcceptEmbassy(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val theirDiploManager = otherCiv.getDiplomacyManager(civInfo)!!
|
||||
if (civInfo.getDiplomacyManager(otherCiv)!!.hasFlag(DiplomacyFlags.DeclinedEmbassy)) return false
|
||||
@ -211,6 +214,7 @@ object DiplomacyAutomation {
|
||||
return true // Relationship is Afraid or greater
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun wantsToOpenBorders(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedOpenBorders)) return false
|
||||
@ -278,6 +282,7 @@ object DiplomacyAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun wantsToSignDefensivePact(civInfo: Civilization, otherCiv: Civilization): Boolean {
|
||||
val ourDiploManager = civInfo.getDiplomacyManager(otherCiv)!!
|
||||
if (ourDiploManager.hasFlag(DiplomacyFlags.DeclinedDefensivePact)) return false
|
||||
@ -450,6 +455,7 @@ object DiplomacyAutomation {
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun areWeOfferingTrade(civInfo: Civilization, otherCiv: Civilization, offerName: String): Boolean {
|
||||
return otherCiv.tradeRequests.filter { request -> request.requestingCiv == civInfo.civName }
|
||||
.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.unit.BaseUnit
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
object MotivationToAttackAutomation {
|
||||
|
||||
/** 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. */
|
||||
@Readonly @Suppress("purity")
|
||||
fun hasAtLeastMotivationToAttack(civInfo: Civilization, targetCiv: Civilization, atLeast: Float): Float {
|
||||
val diplomacyManager = civInfo.getDiplomacyManager(targetCiv)!!
|
||||
val personality = civInfo.getPersonality()
|
||||
|
@ -868,6 +868,7 @@ class Civilization : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun hasStatToBuy(stat: Stat, price: Int): Boolean {
|
||||
return when {
|
||||
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
|
||||
fun addNotification(text: String, category: NotificationCategory, vararg notificationIcons: String) =
|
||||
addNotification(text, null, category, *notificationIcons)
|
||||
|
@ -255,16 +255,16 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
}
|
||||
/** @see compareRelationshipLevel */
|
||||
fun isRelationshipLevelEQ(level: RelationshipLevel) =
|
||||
@Readonly fun isRelationshipLevelEQ(level: RelationshipLevel) =
|
||||
compareRelationshipLevel(level, 0)
|
||||
/** @see compareRelationshipLevel */
|
||||
fun isRelationshipLevelLT(level: RelationshipLevel) =
|
||||
@Readonly fun isRelationshipLevelLT(level: RelationshipLevel) =
|
||||
compareRelationshipLevel(level, -1)
|
||||
/** @see compareRelationshipLevel */
|
||||
fun isRelationshipLevelGT(level: RelationshipLevel) =
|
||||
@Readonly fun isRelationshipLevelGT(level: RelationshipLevel) =
|
||||
compareRelationshipLevel(level, 1)
|
||||
/** @see compareRelationshipLevel */
|
||||
fun isRelationshipLevelLE(level: RelationshipLevel) =
|
||||
@Readonly fun isRelationshipLevelLE(level: RelationshipLevel) =
|
||||
if (level == RelationshipLevel.Ally) true
|
||||
else compareRelationshipLevel(level + 1, -1)
|
||||
/** @see compareRelationshipLevel */
|
||||
@ -468,9 +468,9 @@ class DiplomacyManager() : IsPartOfGameInfoSerialization {
|
||||
}
|
||||
|
||||
/** 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].
|
||||
* 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.tile.Tile
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
import yairm210.purity.annotations.Readonly
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Also ends up calculating and caching [getDistanceToClosestEnemyUnit].
|
||||
*/
|
||||
@Readonly @Suppress("purity")
|
||||
fun getTilesWithEnemyUnitsInDistance(tile: Tile, maxDist: Int): MutableList<Tile> {
|
||||
val tileData = distanceToClosestEnemyTiles[tile]
|
||||
|
||||
@ -129,19 +131,15 @@ class ThreatManager(val civInfo: Civilization) {
|
||||
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
|
||||
*/
|
||||
@Readonly
|
||||
fun getEnemyUnitsOnTiles(tilesWithEnemyUnitsInDistance:List<Tile>): List<MapUnit> =
|
||||
tilesWithEnemyUnitsInDistance.flatMap { enemyTile -> enemyTile.getUnits()
|
||||
.filter { it.isMilitary() && civInfo.isAtWarWith(it.civ) } }
|
||||
|
||||
@Readonly
|
||||
fun getDangerousTiles(unit: MapUnit, distance: Int = 3): HashSet<Tile> {
|
||||
val tilesWithEnemyUnits = getTilesWithEnemyUnitsInDistance(unit.getTile(), distance)
|
||||
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.
|
||||
*/
|
||||
@Readonly
|
||||
fun doesTileHaveMilitaryEnemy(tile: Tile): Boolean {
|
||||
if (!tile.isExplored(civInfo)) return false
|
||||
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. */
|
||||
@Readonly
|
||||
fun getNeighboringCitiesOfOtherCivs(): Sequence<Pair<City,City>> = civInfo.cities.flatMap {
|
||||
ourCity -> ourCity.neighboringCities.filter { it.civ != civInfo }.map { Pair(ourCity, it) }
|
||||
}.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() {
|
||||
distanceToClosestEnemyTiles.clear()
|
||||
|
@ -15,6 +15,7 @@ import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.StatMap
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
@ -125,6 +126,7 @@ class CivInfoStatsForNextTurn(val civInfo: Civilization) {
|
||||
return transportationUpkeep
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getUnitSupply(): Int {
|
||||
/* TotalSupply = BaseSupply + NumCities*modifier + Population*modifier
|
||||
* 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
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getBaseUnitSupply(): Int {
|
||||
return civInfo.getDifficulty().unitSupplyBase +
|
||||
civInfo.getMatchingUniques(UniqueType.BaseUnitSupply).sumOf { it.params[0].toInt() }
|
||||
}
|
||||
@Readonly
|
||||
fun getUnitSupplyFromCities(): Int {
|
||||
return civInfo.cities.size *
|
||||
(civInfo.getDifficulty().unitSupplyPerCity
|
||||
+ civInfo.getMatchingUniques(UniqueType.UnitSupplyPerCity).sumOf { it.params[0].toInt() })
|
||||
}
|
||||
@Readonly
|
||||
fun getUnitSupplyFromPop(): Int {
|
||||
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()
|
||||
}
|
||||
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%. */
|
||||
fun getUnitSupplyProductionPenalty(): Float = -min(getUnitSupplyDeficit() * 10f, 70f)
|
||||
@Readonly fun getUnitSupplyProductionPenalty(): Float = -min(getUnitSupplyDeficit() * 10f, 70f)
|
||||
|
||||
fun getStatMapForNextTurn(): StatMap {
|
||||
val statMap = StatMap()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.map
|
||||
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import yairm210.purity.annotations.Readonly
|
||||
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
|
||||
*/
|
||||
@Readonly
|
||||
fun getPathTo(destination: Tile): Sequence<Tile> = sequence {
|
||||
var currentNode = destination
|
||||
while (true) {
|
||||
|
@ -237,6 +237,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
|
||||
@Readonly fun getTile(): Tile = currentTile
|
||||
|
||||
@Readonly
|
||||
fun getClosestCity(): City? = civ.cities.minByOrNull {
|
||||
it.getCenterTile().aerialDistanceTo(currentTile)
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package com.unciv.models.ruleset.nation
|
||||
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.models.ruleset.RulesetObject
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.Stats
|
||||
import yairm210.purity.annotations.Pure
|
||||
import yairm210.purity.annotations.Readonly
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
/**
|
||||
@ -65,6 +66,7 @@ class Personality: RulesetObject() {
|
||||
var preferredVictoryType: String = Constants.neutralVictoryType
|
||||
var isNeutralPersonality: Boolean = false
|
||||
|
||||
@Pure
|
||||
private fun nameToVariable(value: PersonalityValue): KMutableProperty0<Float> {
|
||||
return when(value) {
|
||||
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
|
||||
*/
|
||||
@Readonly
|
||||
fun scaledFocus(value: PersonalityValue): Float {
|
||||
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
|
||||
*/
|
||||
@Readonly
|
||||
fun inverseScaledFocus(value: PersonalityValue): Float {
|
||||
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
|
||||
* @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 {
|
||||
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
|
||||
* @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 {
|
||||
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
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -9,19 +9,24 @@ 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
|
||||
|
||||
object UnitActionModifiers {
|
||||
@Readonly
|
||||
fun canUse(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||
val usagesLeft = usagesLeft(unit, actionUnique)
|
||||
return usagesLeft == null || usagesLeft > 0
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getUsableUnitActionUniques(unit: MapUnit, actionUniqueType: UniqueType) =
|
||||
unit.getMatchingUniques(actionUniqueType)
|
||||
.filter { unique -> !unique.hasModifier(UniqueType.UnitActionExtraLimitedTimes) }
|
||||
.filter { canUse(unit, it) }
|
||||
|
||||
@Readonly
|
||||
private fun getMovementPointsToUse(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): Int {
|
||||
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
||||
return unit.getMaxMovement()
|
||||
@ -34,6 +39,7 @@ object UnitActionModifiers {
|
||||
return if (defaultAllMovement) unit.getMaxMovement() else 1
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun getMovementPointsRequired(actionUnique: Unique): Int {
|
||||
if (actionUnique.hasModifier(UniqueType.UnitActionMovementCostAll))
|
||||
return 1
|
||||
@ -46,6 +52,7 @@ object UnitActionModifiers {
|
||||
* going into the negatives
|
||||
* @return Boolean
|
||||
*/
|
||||
@Readonly
|
||||
private fun canSpendStatsCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStatsCost)) {
|
||||
for ((stat, value) in conditional.stats) {
|
||||
@ -63,6 +70,7 @@ object UnitActionModifiers {
|
||||
return true
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun canSpendStockpileCost(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||
for (conditional in actionUnique.getModifiers(UniqueType.UnitActionStockpileCost)) {
|
||||
val amount = conditional.params[0].toInt()
|
||||
@ -79,6 +87,7 @@ object UnitActionModifiers {
|
||||
* @param actionUnique: Unique that defines the Action
|
||||
* @return Boolean
|
||||
*/
|
||||
@Readonly
|
||||
fun canActivateSideEffects(unit: MapUnit, actionUnique: Unique): Boolean {
|
||||
if (!canUse(unit, actionUnique)) return false
|
||||
if (getMovementPointsRequired(actionUnique) > ceil(unit.currentMovement).toInt()) return false
|
||||
@ -134,12 +143,14 @@ object UnitActionModifiers {
|
||||
}
|
||||
|
||||
/** Returns 'null' if usages are not limited */
|
||||
@Readonly
|
||||
private fun usagesLeft(unit: MapUnit, actionUnique: Unique): Int?{
|
||||
val usagesTotal = getMaxUsages(unit, actionUnique) ?: return null
|
||||
val usagesSoFar = unit.abilityToTimesUsed[actionUnique.text.removeConditionals()] ?: 0
|
||||
return usagesTotal - usagesSoFar
|
||||
}
|
||||
|
||||
@Readonly
|
||||
private fun getMaxUsages(unit: MapUnit, actionUnique: Unique): Int? {
|
||||
val extraTimes = unit.getMatchingUniques(actionUnique.type!!)
|
||||
.filter { it.text.removeConditionals() == actionUnique.text.removeConditionals() }
|
||||
@ -154,12 +165,14 @@ object UnitActionModifiers {
|
||||
return null
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun actionTextWithSideEffects(originalText: String, actionUnique: Unique, unit: MapUnit): String {
|
||||
val sideEffectString = getSideEffectString(unit, actionUnique)
|
||||
if (sideEffectString == "") return originalText
|
||||
else return "{$originalText} $sideEffectString"
|
||||
}
|
||||
|
||||
@Readonly
|
||||
fun getSideEffectString(unit: MapUnit, actionUnique: Unique, defaultAllMovement: Boolean = false): String {
|
||||
val effects = ArrayList<String>()
|
||||
|
||||
@ -167,7 +180,7 @@ object UnitActionModifiers {
|
||||
if (maxUsages!=null) effects += "${usagesLeft(unit, actionUnique)}/$maxUsages"
|
||||
|
||||
if (actionUnique.hasModifier(UniqueType.UnitActionStatsCost)) {
|
||||
val statCost = Stats()
|
||||
@LocalState 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