mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
chore(purity): MapUnit
This commit is contained in:
parent
5fe0517c81
commit
be6216d2fb
@ -56,6 +56,7 @@ allprojects {
|
|||||||
"com.badlogic.gdx.math.Vector2.len",
|
"com.badlogic.gdx.math.Vector2.len",
|
||||||
"com.badlogic.gdx.math.Vector2.cpy",
|
"com.badlogic.gdx.math.Vector2.cpy",
|
||||||
"kotlin.collections.Collection.contains",
|
"kotlin.collections.Collection.contains",
|
||||||
|
"kotlin.collections.dropLastWhile",
|
||||||
)
|
)
|
||||||
wellKnownPureClasses = setOf(
|
wellKnownPureClasses = setOf(
|
||||||
"java.text.NumberFormat"
|
"java.text.NumberFormat"
|
||||||
|
@ -26,6 +26,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
|
|||||||
import com.unciv.models.ruleset.unit.UnitType
|
import com.unciv.models.ruleset.unit.UnitType
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.components.UnitMovementMemoryType
|
import com.unciv.ui.components.UnitMovementMemoryType
|
||||||
|
import yairm210.purity.annotations.LocalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -252,28 +253,30 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return turnsFortified
|
return turnsFortified
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSleeping() = action?.startsWith(UnitActionType.Sleep.value) == true
|
@Readonly fun isSleeping() = action?.startsWith(UnitActionType.Sleep.value) == true
|
||||||
fun isSleepingUntilHealed() = isSleeping() && isActionUntilHealed()
|
@Readonly fun isSleepingUntilHealed() = isSleeping() && isActionUntilHealed()
|
||||||
|
|
||||||
fun isMoving() = action?.startsWith("moveTo") == true
|
@Readonly fun isMoving() = action?.startsWith("moveTo") == true
|
||||||
|
@Readonly
|
||||||
fun getMovementDestination(): Tile {
|
fun getMovementDestination(): Tile {
|
||||||
val destination = action!!.replace("moveTo ", "").split(",").dropLastWhile { it.isEmpty() }
|
val destination = action!!.replace("moveTo ", "").split(",").dropLastWhile { it.isEmpty() }
|
||||||
val destinationVector = Vector2(destination[0].toFloat(), destination[1].toFloat())
|
val destinationVector = Vector2(destination[0].toFloat(), destination[1].toFloat())
|
||||||
return currentTile.tileMap[destinationVector]
|
return currentTile.tileMap[destinationVector]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAutomated() = automated
|
@Readonly fun isAutomated() = automated
|
||||||
|
|
||||||
fun isAutomatingRoadConnection() = action == UnitActionType.ConnectRoad.value
|
@Readonly fun isAutomatingRoadConnection() = action == UnitActionType.ConnectRoad.value
|
||||||
fun isExploring() = action == UnitActionType.Explore.value
|
@Readonly fun isExploring() = action == UnitActionType.Explore.value
|
||||||
fun isPreparingParadrop() = action == UnitActionType.Paradrop.value
|
@Readonly fun isPreparingParadrop() = action == UnitActionType.Paradrop.value
|
||||||
fun isPreparingAirSweep() = action == UnitActionType.AirSweep.value
|
@Readonly fun isPreparingAirSweep() = action == UnitActionType.AirSweep.value
|
||||||
fun isSetUpForSiege() = action == UnitActionType.SetUp.value
|
@Readonly fun isSetUpForSiege() = action == UnitActionType.SetUp.value
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param includeOtherEscortUnit determines whether this method will also check if it's other escort unit is idle if it has one
|
* @param includeOtherEscortUnit determines whether this method will also check if it's other escort unit is idle if it has one
|
||||||
* Leave it as default unless you know what [isIdle] does.
|
* Leave it as default unless you know what [isIdle] does.
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun isIdle(includeOtherEscortUnit: Boolean = true): Boolean {
|
fun isIdle(includeOtherEscortUnit: Boolean = true): Boolean {
|
||||||
if (!hasMovement()) return false
|
if (!hasMovement()) return false
|
||||||
val tile = getTile()
|
val tile = getTile()
|
||||||
@ -285,7 +288,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return !(isFortified() || isExploring() || isSleeping() || isAutomated() || isMoving() || isGuarding())
|
return !(isFortified() || isExploring() || isSleeping() || isAutomated() || isMoving() || isGuarding())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUniques(): Sequence<Unique> = tempUniquesMap.getAllUniques()
|
@Readonly fun getUniques(): Sequence<Unique> = tempUniquesMap.getAllUniques()
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getMatchingUniques(
|
fun getMatchingUniques(
|
||||||
@ -309,6 +312,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return getMatchingUniques(uniqueType, gameContext, checkCivInfoUniques).any()
|
return getMatchingUniques(uniqueType, gameContext, checkCivInfoUniques).any()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getTriggeredUniques(
|
fun getTriggeredUniques(
|
||||||
trigger: UniqueType,
|
trigger: UniqueType,
|
||||||
gameContext: GameContext = cache.state,
|
gameContext: GameContext = cache.state,
|
||||||
@ -320,14 +324,16 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
/** Gets *per turn* resource requirements - does not include immediate costs for stockpiled resources.
|
/** Gets *per turn* resource requirements - does not include immediate costs for stockpiled resources.
|
||||||
* StateForConditionals is assumed to regarding this mapUnit*/
|
* StateForConditionals is assumed to regarding this mapUnit*/
|
||||||
|
@Readonly
|
||||||
fun getResourceRequirementsPerTurn(): Counter<String> {
|
fun getResourceRequirementsPerTurn(): Counter<String> {
|
||||||
val resourceRequirements = Counter<String>()
|
@LocalState val resourceRequirements = Counter<String>()
|
||||||
if (baseUnit.requiredResource != null) resourceRequirements[baseUnit.requiredResource!!] = 1
|
if (baseUnit.requiredResource != null) resourceRequirements[baseUnit.requiredResource!!] = 1
|
||||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, cache.state))
|
for (unique in getMatchingUniques(UniqueType.ConsumesResources, cache.state))
|
||||||
resourceRequirements[unique.params[1]] += unique.params[0].toInt()
|
resourceRequirements.add(unique.params[1], unique.params[0].toInt())
|
||||||
return resourceRequirements
|
return resourceRequirements
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun requiresResource(resource: String): Boolean {
|
fun requiresResource(resource: String): Boolean {
|
||||||
if (getResourceRequirementsPerTurn().contains(resource)) return true
|
if (getResourceRequirementsPerTurn().contains(resource)) return true
|
||||||
for (unique in getMatchingUniques(UniqueType.CostsResources, cache.state)) {
|
for (unique in getMatchingUniques(UniqueType.CostsResources, cache.state)) {
|
||||||
@ -336,8 +342,9 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasMovement() = currentMovement > 0
|
@Readonly fun hasMovement() = currentMovement > 0
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getMaxMovement(ignoreOtherUnit: Boolean = false): Int {
|
fun getMaxMovement(ignoreOtherUnit: Boolean = false): Int {
|
||||||
var movement =
|
var movement =
|
||||||
if (isEmbarked()) 2
|
if (isEmbarked()) 2
|
||||||
@ -364,6 +371,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return movement
|
return movement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasUnitMovedThisTurn(): Boolean {
|
fun hasUnitMovedThisTurn(): Boolean {
|
||||||
val max = getMaxMovement().toFloat()
|
val max = getMaxMovement().toFloat()
|
||||||
return currentMovement < max - max.ulp
|
return currentMovement < max - max.ulp
|
||||||
@ -373,6 +381,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
* Determines this (land or sea) unit's current maximum vision range from unit properties, civ uniques and terrain.
|
* Determines this (land or sea) unit's current maximum vision range from unit properties, civ uniques and terrain.
|
||||||
* @return Maximum distance of tiles this unit may possibly see
|
* @return Maximum distance of tiles this unit may possibly see
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
private fun getVisibilityRange(): Int {
|
private fun getVisibilityRange(): Int {
|
||||||
var visibilityRange = 2
|
var visibilityRange = 2
|
||||||
|
|
||||||
@ -387,17 +396,20 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return visibilityRange
|
return visibilityRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun maxAttacksPerTurn(): Int {
|
fun maxAttacksPerTurn(): Int {
|
||||||
return 1 + getMatchingUniques(UniqueType.AdditionalAttacks, checkCivInfoUniques = true)
|
return 1 + getMatchingUniques(UniqueType.AdditionalAttacks, checkCivInfoUniques = true)
|
||||||
.sumOf { it.params[0].toInt() }
|
.sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canAttack(): Boolean {
|
fun canAttack(): Boolean {
|
||||||
if (!hasMovement()) return false
|
if (!hasMovement()) return false
|
||||||
if (isCivilian()) return false
|
if (isCivilian()) return false
|
||||||
return attacksThisTurn < maxAttacksPerTurn()
|
return attacksThisTurn < maxAttacksPerTurn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getRange(): Int {
|
fun getRange(): Int {
|
||||||
if (baseUnit.isMelee()) return 1
|
if (baseUnit.isMelee()) return 1
|
||||||
var range = baseUnit.range
|
var range = baseUnit.range
|
||||||
@ -406,9 +418,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return range
|
return range
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMaxMovementForAirUnits(): Int {
|
@Readonly fun getMaxMovementForAirUnits(): Int = getRange() * 2
|
||||||
return getRange() * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun isEmbarked(): Boolean {
|
fun isEmbarked(): Boolean {
|
||||||
@ -428,7 +438,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canFortify(ignoreAlreadyFortified: Boolean = false) = when {
|
fun canFortify(ignoreAlreadyFortified: Boolean = false) = when {
|
||||||
baseUnit.isWaterUnit -> false
|
baseUnit.isWaterUnit -> false
|
||||||
isCivilian() -> false
|
isCivilian() -> false
|
||||||
@ -440,10 +450,12 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun adjacentHealingBonus(): Int {
|
private fun adjacentHealingBonus(): Int {
|
||||||
return getMatchingUniques(UniqueType.HealAdjacentUnits).sumOf { it.params[0].toInt() }
|
return getMatchingUniques(UniqueType.HealAdjacentUnits).sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getHealAmountForCurrentTile() = when {
|
fun getHealAmountForCurrentTile() = when {
|
||||||
isEmbarked() -> 0 // embarked units can't heal
|
isEmbarked() -> 0 // embarked units can't heal
|
||||||
health >= 100 -> 0 // No need to heal if at max health
|
health >= 100 -> 0 // No need to heal if at max health
|
||||||
@ -451,9 +463,10 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
else -> rankTileForHealing(getTile())
|
else -> rankTileForHealing(getTile())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canHealInCurrentTile() = getHealAmountForCurrentTile() > 0
|
@Readonly fun canHealInCurrentTile() = getHealAmountForCurrentTile() > 0
|
||||||
|
|
||||||
/** Returns the health points [MapUnit] will receive if healing on [tile] */
|
/** Returns the health points [MapUnit] will receive if healing on [tile] */
|
||||||
|
@Readonly
|
||||||
fun rankTileForHealing(tile: Tile): Int {
|
fun rankTileForHealing(tile: Tile): Int {
|
||||||
val isFriendlyTerritory = tile.isFriendlyTerritory(civ)
|
val isFriendlyTerritory = tile.isFriendlyTerritory(civ)
|
||||||
|
|
||||||
@ -499,20 +512,23 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
@Readonly fun canGarrison() = isMilitary() && baseUnit.isLandUnit
|
@Readonly fun canGarrison() = isMilitary() && baseUnit.isLandUnit
|
||||||
|
|
||||||
@Readonly fun isGreatPerson() = baseUnit.isGreatPerson
|
@Readonly fun isGreatPerson() = baseUnit.isGreatPerson
|
||||||
fun isGreatPersonOfType(type: String) = baseUnit.isGreatPersonOfType(type)
|
@Readonly fun isGreatPersonOfType(type: String) = baseUnit.isGreatPersonOfType(type)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canIntercept(attackedTile: Tile): Boolean {
|
fun canIntercept(attackedTile: Tile): Boolean {
|
||||||
if (!canIntercept()) return false
|
if (!canIntercept()) return false
|
||||||
if (currentTile.aerialDistanceTo(attackedTile) > getInterceptionRange()) return false
|
if (currentTile.aerialDistanceTo(attackedTile) > getInterceptionRange()) return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getInterceptionRange(): Int {
|
fun getInterceptionRange(): Int {
|
||||||
val rangeFromUniques = getMatchingUniques(UniqueType.AirInterceptionRange, checkCivInfoUniques = true)
|
val rangeFromUniques = getMatchingUniques(UniqueType.AirInterceptionRange, checkCivInfoUniques = true)
|
||||||
.sumOf { it.params[0].toInt() }
|
.sumOf { it.params[0].toInt() }
|
||||||
return baseUnit.interceptRange + rangeFromUniques
|
return baseUnit.interceptRange + rangeFromUniques
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canIntercept(): Boolean {
|
fun canIntercept(): Boolean {
|
||||||
if (interceptChance() == 0) return false
|
if (interceptChance() == 0) return false
|
||||||
// Air Units can only Intercept if they didn't move this turn
|
// Air Units can only Intercept if they didn't move this turn
|
||||||
@ -524,15 +540,18 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun interceptChance(): Int {
|
fun interceptChance(): Int {
|
||||||
return getMatchingUniques(UniqueType.ChanceInterceptAirAttacks).sumOf { it.params[0].toInt() }
|
return getMatchingUniques(UniqueType.ChanceInterceptAirAttacks).sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun interceptDamagePercentBonus(): Int {
|
fun interceptDamagePercentBonus(): Int {
|
||||||
return getMatchingUniques(UniqueType.DamageWhenIntercepting)
|
return getMatchingUniques(UniqueType.DamageWhenIntercepting)
|
||||||
.sumOf { it.params[0].toInt() }
|
.sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun receivedInterceptDamageFactor(): Float {
|
fun receivedInterceptDamageFactor(): Float {
|
||||||
var damageFactor = 1f
|
var damageFactor = 1f
|
||||||
for (unique in getMatchingUniques(UniqueType.DamageFromInterceptionReduced))
|
for (unique in getMatchingUniques(UniqueType.DamageFromInterceptionReduced))
|
||||||
@ -540,16 +559,19 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return damageFactor
|
return damageFactor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getDamageFromTerrain(tile: Tile = currentTile): Int {
|
fun getDamageFromTerrain(tile: Tile = currentTile): Int {
|
||||||
return tile.allTerrains.sumOf { it.damagePerTurn }
|
return tile.allTerrains.sumOf { it.damagePerTurn }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isTransportTypeOf(mapUnit: MapUnit): Boolean {
|
fun isTransportTypeOf(mapUnit: MapUnit): Boolean {
|
||||||
// Currently, only missiles and airplanes can be carried
|
// Currently, only missiles and airplanes can be carried
|
||||||
if (!mapUnit.baseUnit.movesLikeAirUnits) return false
|
if (!mapUnit.baseUnit.movesLikeAirUnits) return false
|
||||||
return getMatchingUniques(UniqueType.CarryAirUnits).any { mapUnit.matchesFilter(it.params[1]) }
|
return getMatchingUniques(UniqueType.CarryAirUnits).any { mapUnit.matchesFilter(it.params[1]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun carryCapacity(unit: MapUnit): Int {
|
private fun carryCapacity(unit: MapUnit): Int {
|
||||||
return (getMatchingUniques(UniqueType.CarryAirUnits)
|
return (getMatchingUniques(UniqueType.CarryAirUnits)
|
||||||
+ getMatchingUniques(UniqueType.CarryExtraAirUnits))
|
+ getMatchingUniques(UniqueType.CarryExtraAirUnits))
|
||||||
@ -557,6 +579,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
.sumOf { it.params[0].toInt() }
|
.sumOf { it.params[0].toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canTransport(unit: MapUnit): Boolean {
|
fun canTransport(unit: MapUnit): Boolean {
|
||||||
if (owner != unit.owner) return false
|
if (owner != unit.owner) return false
|
||||||
if (!isTransportTypeOf(unit)) return false
|
if (!isTransportTypeOf(unit)) return false
|
||||||
@ -566,10 +589,12 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a Nuke's blast radius from the BlastRadius unique, defaulting to 2. No check whether the unit actually is a Nuke. */
|
/** Gets a Nuke's blast radius from the BlastRadius unique, defaulting to 2. No check whether the unit actually is a Nuke. */
|
||||||
|
@Readonly
|
||||||
fun getNukeBlastRadius() = getMatchingUniques(UniqueType.BlastRadius)
|
fun getNukeBlastRadius() = getMatchingUniques(UniqueType.BlastRadius)
|
||||||
// Don't check conditionals as these are not supported
|
// Don't check conditionals as these are not supported
|
||||||
.firstOrNull()?.params?.get(0)?.toInt() ?: 2
|
.firstOrNull()?.params?.get(0)?.toInt() ?: 2
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun isAlly(otherCiv: Civilization): Boolean {
|
private fun isAlly(otherCiv: Civilization): Boolean {
|
||||||
return otherCiv == civ
|
return otherCiv == civ
|
||||||
|| (otherCiv.isCityState && otherCiv.getAllyCivName() == civ.civName)
|
|| (otherCiv.isCityState && otherCiv.getAllyCivName() == civ.civName)
|
||||||
@ -577,10 +602,12 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Implements [UniqueParameterType.MapUnitFilter][com.unciv.models.ruleset.unique.UniqueParameterType.MapUnitFilter] */
|
/** Implements [UniqueParameterType.MapUnitFilter][com.unciv.models.ruleset.unique.UniqueParameterType.MapUnitFilter] */
|
||||||
|
@Readonly
|
||||||
fun matchesFilter(filter: String, multiFilter: Boolean = true): Boolean {
|
fun matchesFilter(filter: String, multiFilter: Boolean = true): Boolean {
|
||||||
return if (multiFilter) MultiFilter.multiFilter(filter, ::matchesSingleFilter) else matchesSingleFilter(filter)
|
return if (multiFilter) MultiFilter.multiFilter(filter, ::matchesSingleFilter) else matchesSingleFilter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun matchesSingleFilter(filter: String): Boolean {
|
private fun matchesSingleFilter(filter: String): Boolean {
|
||||||
return when (filter) {
|
return when (filter) {
|
||||||
Constants.wounded, "wounded units" -> health < 100
|
Constants.wounded, "wounded units" -> health < 100
|
||||||
@ -599,6 +626,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canBuildImprovement(improvement: TileImprovement, tile: Tile = currentTile): Boolean {
|
fun canBuildImprovement(improvement: TileImprovement, tile: Tile = currentTile): Boolean {
|
||||||
if (civ.isBarbarian) return false
|
if (civ.isBarbarian) return false
|
||||||
|
|
||||||
@ -617,6 +645,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
.any { improvement.matchesFilter(it.params[0], cache.state) || tile.matchesTerrainFilter(it.params[0], civ) }
|
.any { improvement.matchesFilter(it.params[0], cache.state) || tile.matchesTerrainFilter(it.params[0], civ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getReligionDisplayName(): String? {
|
fun getReligionDisplayName(): String? {
|
||||||
if (religion == null) return null
|
if (religion == null) return null
|
||||||
return civ.gameInfo.religions[religion]!!.getReligionDisplayName()
|
return civ.gameInfo.religions[religion]!!.getReligionDisplayName()
|
||||||
@ -631,6 +660,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return power
|
return power
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getOtherEscortUnit(): MapUnit? {
|
fun getOtherEscortUnit(): MapUnit? {
|
||||||
if (!::currentTile.isInitialized) return null // In some cases we might not have the unit placed on the map yet
|
if (!::currentTile.isInitialized) return null // In some cases we might not have the unit placed on the map yet
|
||||||
if (isCivilian()) return getTile().militaryUnit
|
if (isCivilian()) return getTile().militaryUnit
|
||||||
@ -638,6 +668,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly @Suppress("purity") // Updates escorting state
|
||||||
fun isEscorting(): Boolean {
|
fun isEscorting(): Boolean {
|
||||||
if (escorting) {
|
if (escorting) {
|
||||||
if (getOtherEscortUnit() != null) return true
|
if (getOtherEscortUnit() != null) return true
|
||||||
@ -646,6 +677,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun threatensCiv(civInfo: Civilization): Boolean {
|
fun threatensCiv(civInfo: Civilization): Boolean {
|
||||||
if (getTile().getOwner() == civInfo)
|
if (getTile().getOwner() == civInfo)
|
||||||
return true
|
return true
|
||||||
@ -1051,8 +1083,8 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStatus(name:String): UnitStatus? = statusMap[name]
|
@Readonly fun getStatus(name:String): UnitStatus? = statusMap[name]
|
||||||
fun hasStatus(name:String): Boolean = getStatus(name) != null
|
@Readonly fun hasStatus(name:String): Boolean = getStatus(name) != null
|
||||||
|
|
||||||
fun setStatus(name:String, turns:Int){
|
fun setStatus(name:String, turns:Int){
|
||||||
val existingStatus = getStatus(name)
|
val existingStatus = getStatus(name)
|
||||||
|
@ -261,7 +261,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCity(): City? = owningCity
|
@Readonly fun getCity(): City? = owningCity
|
||||||
|
|
||||||
@Readonly internal fun getNaturalWonder(): Terrain =
|
@Readonly internal fun getNaturalWonder(): Terrain =
|
||||||
if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!")
|
if (naturalWonder == null) throw Exception("No natural wonder exists for this tile!")
|
||||||
@ -281,7 +281,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return exploredBy.contains(player.civName)
|
return exploredBy.contains(player.civName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCityCenter(): Boolean = isCityCenterInternal
|
@Readonly fun isCityCenter(): Boolean = isCityCenterInternal
|
||||||
@Readonly fun isNaturalWonder(): Boolean = naturalWonder != null
|
@Readonly fun isNaturalWonder(): Boolean = naturalWonder != null
|
||||||
@Readonly fun isImpassible() = lastTerrain.impassable
|
@Readonly fun isImpassible() = lastTerrain.impassable
|
||||||
|
|
||||||
|
@ -70,10 +70,12 @@ class Religion() : INamed, IsPartOfGameInfoSerialization {
|
|||||||
updateUniqueMaps()
|
updateUniqueMaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getIconName() =
|
fun getIconName() =
|
||||||
if (isPantheon()) "Pantheon"
|
if (isPantheon()) "Pantheon"
|
||||||
else name
|
else name
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getReligionDisplayName() =
|
fun getReligionDisplayName() =
|
||||||
if (displayName != null) displayName!!
|
if (displayName != null) displayName!!
|
||||||
else name
|
else name
|
||||||
|
@ -22,11 +22,9 @@ class Technology: RulesetObject() {
|
|||||||
var row: Int = 0
|
var row: Int = 0
|
||||||
var quote = ""
|
var quote = ""
|
||||||
|
|
||||||
@Readonly
|
@Readonly fun era(): String = column!!.era
|
||||||
fun era(): String = column!!.era
|
|
||||||
|
|
||||||
@Readonly
|
@Readonly fun isContinuallyResearchable() = hasUnique(UniqueType.ResearchableMultipleTimes)
|
||||||
fun isContinuallyResearchable() = hasUnique(UniqueType.ResearchableMultipleTimes)
|
|
||||||
|
|
||||||
|
|
||||||
/** Get Civilization-specific description for TechPicker or AlertType.TechResearched */
|
/** Get Civilization-specific description for TechPicker or AlertType.TechResearched */
|
||||||
@ -40,6 +38,7 @@ class Technology: RulesetObject() {
|
|||||||
|
|
||||||
override fun era(ruleset: Ruleset) = ruleset.eras[era()]
|
override fun era(ruleset: Ruleset) = ruleset.eras[era()]
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun matchesFilter(filter: String, state: GameContext? = null, multiFilter: Boolean = true): Boolean {
|
fun matchesFilter(filter: String, state: GameContext? = null, multiFilter: Boolean = true): Boolean {
|
||||||
return if (multiFilter) MultiFilter.multiFilter(filter, {
|
return if (multiFilter) MultiFilter.multiFilter(filter, {
|
||||||
matchesSingleFilter(filter) ||
|
matchesSingleFilter(filter) ||
|
||||||
@ -51,6 +50,7 @@ class Technology: RulesetObject() {
|
|||||||
state == null && hasTagUnique(filter)
|
state == null && hasTagUnique(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun matchesSingleFilter(filter: String): Boolean {
|
fun matchesSingleFilter(filter: String): Boolean {
|
||||||
return when (filter) {
|
return when (filter) {
|
||||||
in Constants.all -> true
|
in Constants.all -> true
|
||||||
|
@ -411,9 +411,10 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val cachedMatchesFilterResult = HashMap<String, Boolean>()
|
@LocalState private val cachedMatchesFilterResult = HashMap<String, Boolean>()
|
||||||
|
|
||||||
/** Implements [UniqueParameterType.BaseUnitFilter][com.unciv.models.ruleset.unique.UniqueParameterType.BaseUnitFilter] */
|
/** Implements [UniqueParameterType.BaseUnitFilter][com.unciv.models.ruleset.unique.UniqueParameterType.BaseUnitFilter] */
|
||||||
|
@Readonly
|
||||||
fun matchesFilter(filter: String, state: GameContext? = null, multiFilter: Boolean = true): Boolean {
|
fun matchesFilter(filter: String, state: GameContext? = null, multiFilter: Boolean = true): Boolean {
|
||||||
return if (multiFilter) MultiFilter.multiFilter(filter, {
|
return if (multiFilter) MultiFilter.multiFilter(filter, {
|
||||||
cachedMatchesFilterResult.getOrPut(it) { matchesSingleFilter(it) } ||
|
cachedMatchesFilterResult.getOrPut(it) { matchesSingleFilter(it) } ||
|
||||||
@ -425,7 +426,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
|||||||
state == null && hasTagUnique(filter)
|
state == null && hasTagUnique(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun matchesSingleFilter(filter: String): Boolean {
|
fun matchesSingleFilter(filter: String): Boolean {
|
||||||
// all cases are constants for performance
|
// all cases are constants for performance
|
||||||
return when (filter) {
|
return when (filter) {
|
||||||
@ -464,10 +465,10 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
|||||||
|
|
||||||
/** Determine whether this is a City-founding unit - abstract, **without any game context**.
|
/** Determine whether this is a City-founding unit - abstract, **without any game context**.
|
||||||
* Use other methods for MapUnits or when there is a better StateForConditionals available. */
|
* Use other methods for MapUnits or when there is a better StateForConditionals available. */
|
||||||
fun isCityFounder() = hasUnique(UniqueType.FoundCity, GameContext.IgnoreConditionals)
|
@Readonly fun isCityFounder() = hasUnique(UniqueType.FoundCity, GameContext.IgnoreConditionals)
|
||||||
|
|
||||||
val isGreatPerson by lazy { getMatchingUniques(UniqueType.GreatPerson).any() }
|
val isGreatPerson by lazy { getMatchingUniques(UniqueType.GreatPerson).any() }
|
||||||
fun isGreatPersonOfType(type: String) = getMatchingUniques(UniqueType.GreatPerson).any { it.params[0] == type }
|
@Readonly fun isGreatPersonOfType(type: String) = getMatchingUniques(UniqueType.GreatPerson).any { it.params[0] == type }
|
||||||
|
|
||||||
/** Has a MapUnit implementation that does not ignore conditionals, which should be usually used */
|
/** Has a MapUnit implementation that does not ignore conditionals, which should be usually used */
|
||||||
@Readonly private fun isNuclearWeapon() = hasUnique(UniqueType.NuclearWeapon, GameContext.IgnoreConditionals)
|
@Readonly private fun isNuclearWeapon() = hasUnique(UniqueType.NuclearWeapon, GameContext.IgnoreConditionals)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user