mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-24 03:53:12 -04:00
chore: Tile purity
This commit is contained in:
parent
673c33bb01
commit
c1f0b97e2d
@ -240,6 +240,7 @@ class GameInfo : IsPartOfGameInfoSerialization, HasGameInfoSerializationVersion
|
|||||||
/** Get barbarian civ
|
/** Get barbarian civ
|
||||||
* @throws NoSuchElementException in no-barbarians games! */
|
* @throws NoSuchElementException in no-barbarians games! */
|
||||||
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
|
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
|
||||||
|
@Readonly @Suppress("purity") // This should be autorecognized!!
|
||||||
fun getDifficulty() = difficultyObject
|
fun getDifficulty() = difficultyObject
|
||||||
/** Access a cached `GlobalUniques` that combines the [ruleset]'s [globalUniques][Ruleset.globalUniques]
|
/** Access a cached `GlobalUniques` that combines the [ruleset]'s [globalUniques][Ruleset.globalUniques]
|
||||||
* with the Uniques of the chosen [speed] and [difficulty][getDifficulty] */
|
* with the Uniques of the chosen [speed] and [difficulty][getDifficulty] */
|
||||||
|
@ -324,10 +324,8 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
if (!knows(civInfo)) diplomacyFunctions.makeCivilizationsMeet(civInfo)
|
if (!knows(civInfo)) diplomacyFunctions.makeCivilizationsMeet(civInfo)
|
||||||
return getDiplomacyManager(civInfo.civName)!!
|
return getDiplomacyManager(civInfo.civName)!!
|
||||||
}
|
}
|
||||||
@Readonly
|
@Readonly fun getDiplomacyManager(civInfo: Civilization): DiplomacyManager? = getDiplomacyManager(civInfo.civName)
|
||||||
fun getDiplomacyManager(civInfo: Civilization): DiplomacyManager? = getDiplomacyManager(civInfo.civName)
|
@Readonly fun getDiplomacyManager(civName: String): DiplomacyManager? = diplomacy[civName]
|
||||||
@Readonly
|
|
||||||
fun getDiplomacyManager(civName: String): DiplomacyManager? = diplomacy[civName]
|
|
||||||
|
|
||||||
fun getProximity(civInfo: Civilization) = getProximity(civInfo.civName)
|
fun getProximity(civInfo: Civilization) = getProximity(civInfo.civName)
|
||||||
@Suppress("MemberVisibilityCanBePrivate") // same visibility for overloads
|
@Suppress("MemberVisibilityCanBePrivate") // same visibility for overloads
|
||||||
@ -347,17 +345,15 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
fun getKnownCivsWithSpectators() = diplomacy.values.asSequence().map { it.otherCiv() }
|
fun getKnownCivsWithSpectators() = diplomacy.values.asSequence().map { it.otherCiv() }
|
||||||
.filter { !it.isDefeated() }
|
.filter { !it.isDefeated() }
|
||||||
|
|
||||||
@Readonly
|
|
||||||
fun knows(otherCivName: String) = diplomacy.containsKey(otherCivName)
|
@Readonly fun knows(otherCivName: String) = diplomacy.containsKey(otherCivName)
|
||||||
@Readonly
|
@Readonly fun knows(otherCiv: Civilization) = knows(otherCiv.civName)
|
||||||
fun knows(otherCiv: Civilization) = knows(otherCiv.civName)
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getCapital(firstCityIfNoCapital: Boolean = true) = cities.firstOrNull { it.isCapital() } ?:
|
fun getCapital(firstCityIfNoCapital: Boolean = true) = cities.firstOrNull { it.isCapital() } ?:
|
||||||
if (firstCityIfNoCapital) cities.firstOrNull() else null
|
if (firstCityIfNoCapital) cities.firstOrNull() else null
|
||||||
@Readonly
|
|
||||||
fun isHuman() = playerType == PlayerType.Human
|
@Readonly fun isHuman() = playerType == PlayerType.Human
|
||||||
@Readonly
|
@Readonly fun isAI() = playerType == PlayerType.AI
|
||||||
fun isAI() = playerType == PlayerType.AI
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun isAIOrAutoPlaying(): Boolean {
|
fun isAIOrAutoPlaying(): Boolean {
|
||||||
if (playerType == PlayerType.AI) return true
|
if (playerType == PlayerType.AI) return true
|
||||||
@ -365,14 +361,11 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
val worldScreen = UncivGame.Current.worldScreen ?: return false
|
val worldScreen = UncivGame.Current.worldScreen ?: return false
|
||||||
return worldScreen.viewingCiv == this && worldScreen.autoPlay.isAutoPlaying()
|
return worldScreen.viewingCiv == this && worldScreen.autoPlay.isAutoPlaying()
|
||||||
}
|
}
|
||||||
@Readonly
|
|
||||||
fun isOneCityChallenger() = playerType == PlayerType.Human && gameInfo.gameParameters.oneCityChallenge
|
@Readonly fun isOneCityChallenger() = playerType == PlayerType.Human && gameInfo.gameParameters.oneCityChallenge
|
||||||
@Readonly
|
@Readonly fun isCurrentPlayer() = gameInfo.currentPlayerCiv == this
|
||||||
fun isCurrentPlayer() = gameInfo.currentPlayerCiv == this
|
@Readonly fun isMajorCiv() = nation.isMajorCiv
|
||||||
@Readonly
|
@Readonly fun isMinorCiv() = nation.isCityState || nation.isBarbarian
|
||||||
fun isMajorCiv() = nation.isMajorCiv
|
|
||||||
@Readonly
|
|
||||||
fun isMinorCiv() = nation.isCityState || nation.isBarbarian
|
|
||||||
|
|
||||||
@delegate:Transient
|
@delegate:Transient
|
||||||
val isCityState by lazy { nation.isCityState }
|
val isCityState by lazy { nation.isCityState }
|
||||||
@ -380,10 +373,9 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
@delegate:Transient
|
@delegate:Transient
|
||||||
val isBarbarian by lazy { nation.isBarbarian }
|
val isBarbarian by lazy { nation.isBarbarian }
|
||||||
|
|
||||||
@Readonly
|
|
||||||
fun isSpectator() = nation.isSpectator
|
@Readonly fun isSpectator() = nation.isSpectator
|
||||||
@Readonly
|
@Readonly fun isAlive(): Boolean = !isDefeated()
|
||||||
fun isAlive(): Boolean = !isDefeated()
|
|
||||||
|
|
||||||
@delegate:Transient
|
@delegate:Transient
|
||||||
val cityStateType: CityStateType by lazy { gameInfo.ruleset.cityStateTypes[nation.cityStateType!!]!! }
|
val cityStateType: CityStateType by lazy { gameInfo.ruleset.cityStateTypes[nation.cityStateType!!]!! }
|
||||||
@ -407,13 +399,6 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
fun getPreferredVictoryTypeObjects(): List<Victory> {
|
|
||||||
val preferredVictoryTypes = getPreferredVictoryTypes()
|
|
||||||
return if (preferredVictoryTypes.contains(Constants.neutralVictoryType)) emptyList()
|
|
||||||
else preferredVictoryTypes.map { gameInfo.ruleset.victories[it]!! }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getPersonality(): Personality {
|
fun getPersonality(): Personality {
|
||||||
return if (isAIOrAutoPlaying()) gameInfo.ruleset.personalities[nation.personality] ?: Personality.neutralPersonality
|
return if (isAIOrAutoPlaying()) gameInfo.ruleset.personalities[nation.personality] ?: Personality.neutralPersonality
|
||||||
@ -1081,6 +1066,7 @@ class Civilization : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
fun asPreview() = CivilizationInfoPreview(this)
|
fun asPreview() = CivilizationInfoPreview(this)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getLastSeenImprovement(position: Vector2): String? {
|
fun getLastSeenImprovement(position: Vector2): String? {
|
||||||
if (isAI() || isSpectator()) return null
|
if (isAI() || isSpectator()) return null
|
||||||
return lastSeenImprovement[position]
|
return lastSeenImprovement[position]
|
||||||
|
@ -147,6 +147,7 @@ class DiplomacyFunctions(val civInfo: Civilization) {
|
|||||||
* Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through
|
* Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through
|
||||||
* a specific tile.
|
* a specific tile.
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun canPassThroughTiles(otherCiv: Civilization): Boolean {
|
fun canPassThroughTiles(otherCiv: Civilization): Boolean {
|
||||||
if (otherCiv == civInfo) return true
|
if (otherCiv == civInfo) return true
|
||||||
if (otherCiv.isBarbarian) return true
|
if (otherCiv.isBarbarian) return true
|
||||||
|
@ -18,10 +18,11 @@ import com.unciv.models.ruleset.unique.UniqueType
|
|||||||
import com.unciv.models.ruleset.unit.BaseUnit
|
import com.unciv.models.ruleset.unit.BaseUnit
|
||||||
import com.unciv.utils.addToMapOfSets
|
import com.unciv.utils.addToMapOfSets
|
||||||
import com.unciv.utils.contains
|
import com.unciv.utils.contains
|
||||||
|
import yairm210.purity.annotations.LocalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
import java.lang.Integer.max
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/** An Unciv map with all properties as produced by the [map editor][com.unciv.ui.screens.mapeditorscreen.MapEditorScreen]
|
/** An Unciv map with all properties as produced by the [map editor][com.unciv.ui.screens.mapeditorscreen.MapEditorScreen]
|
||||||
* or [MapGenerator][com.unciv.logic.map.mapgenerator.MapGenerator]; or as part of a running [game][GameInfo].
|
* or [MapGenerator][com.unciv.logic.map.mapgenerator.MapGenerator]; or as part of a running [game][GameInfo].
|
||||||
@ -400,8 +401,10 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
|||||||
data class ViewableTile(val tile: Tile, val maxHeightSeenToTile: Int, val isVisible: Boolean, val isAttackable: Boolean)
|
data class ViewableTile(val tile: Tile, val maxHeightSeenToTile: Int, val isVisible: Boolean, val isAttackable: Boolean)
|
||||||
|
|
||||||
/** @return List of tiles visible from location [position] for a unit with sight range [sightDistance] */
|
/** @return List of tiles visible from location [position] for a unit with sight range [sightDistance] */
|
||||||
|
@Readonly
|
||||||
fun getViewableTiles(position: Vector2, sightDistance: Int, forAttack: Boolean = false): List<Tile> {
|
fun getViewableTiles(position: Vector2, sightDistance: Int, forAttack: Boolean = false): List<Tile> {
|
||||||
val aUnitHeight = get(position).unitHeight
|
val aUnitHeight = get(position).unitHeight
|
||||||
|
@LocalState
|
||||||
val viewableTiles = mutableListOf(ViewableTile(
|
val viewableTiles = mutableListOf(ViewableTile(
|
||||||
get(position),
|
get(position),
|
||||||
aUnitHeight,
|
aUnitHeight,
|
||||||
@ -412,6 +415,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
|||||||
for (i in 1..sightDistance+1) { // in each layer,
|
for (i in 1..sightDistance+1) { // in each layer,
|
||||||
// This is so we don't use tiles in the same distance to "see over",
|
// This is so we don't use tiles in the same distance to "see over",
|
||||||
// that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance
|
// that is to say, the "viewableTiles.contains(it) check will return false for neighbors from the same distance
|
||||||
|
@LocalState
|
||||||
val tilesToAddInDistanceI = ArrayList<ViewableTile>()
|
val tilesToAddInDistanceI = ArrayList<ViewableTile>()
|
||||||
|
|
||||||
for (cTile in getTilesAtDistance(position, i)) { // for each tile in that layer,
|
for (cTile in getTilesAtDistance(position, i)) { // for each tile in that layer,
|
||||||
|
@ -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.Readonly
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.ulp
|
import kotlin.math.ulp
|
||||||
@ -230,6 +231,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
fun getMovementString(): String =
|
fun getMovementString(): String =
|
||||||
(DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement()).tr()
|
(DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement()).tr()
|
||||||
|
|
||||||
|
@Readonly @Suppress("purity") // should be autorecognized
|
||||||
fun getTile(): Tile = currentTile
|
fun getTile(): Tile = currentTile
|
||||||
|
|
||||||
fun getClosestCity(): City? = civ.cities.minByOrNull {
|
fun getClosestCity(): City? = civ.cities.minByOrNull {
|
||||||
@ -284,6 +286,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
|
|
||||||
fun getUniques(): Sequence<Unique> = tempUniquesMap.getAllUniques()
|
fun getUniques(): Sequence<Unique> = tempUniquesMap.getAllUniques()
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getMatchingUniques(
|
fun getMatchingUniques(
|
||||||
uniqueType: UniqueType,
|
uniqueType: UniqueType,
|
||||||
gameContext: GameContext = cache.state,
|
gameContext: GameContext = cache.state,
|
||||||
@ -296,6 +299,7 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
yieldAll(civ.getMatchingUniques(uniqueType, gameContext))
|
yieldAll(civ.getMatchingUniques(uniqueType, gameContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasUnique(
|
fun hasUnique(
|
||||||
uniqueType: UniqueType,
|
uniqueType: UniqueType,
|
||||||
gameContext: GameContext = cache.state,
|
gameContext: GameContext = cache.state,
|
||||||
@ -405,12 +409,14 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
|||||||
return getRange() * 2
|
return getRange() * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isEmbarked(): Boolean {
|
fun isEmbarked(): Boolean {
|
||||||
if (!baseUnit.isLandUnit) return false
|
if (!baseUnit.isLandUnit) return false
|
||||||
if (cache.canMoveOnWater) return false
|
if (cache.canMoveOnWater) return false
|
||||||
return currentTile.isWater
|
return currentTile.isWater
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isInvisible(to: Civilization): Boolean {
|
fun isInvisible(to: Civilization): Boolean {
|
||||||
if (hasUnique(UniqueType.Invisible) && !to.isSpectator())
|
if (hasUnique(UniqueType.Invisible) && !to.isSpectator())
|
||||||
return true
|
return true
|
||||||
|
@ -34,6 +34,7 @@ import com.unciv.utils.DebugUtils
|
|||||||
import com.unciv.utils.Log
|
import com.unciv.utils.Log
|
||||||
import com.unciv.utils.withItem
|
import com.unciv.utils.withItem
|
||||||
import com.unciv.utils.withoutItem
|
import com.unciv.utils.withoutItem
|
||||||
|
import yairm210.purity.annotations.LocalState
|
||||||
import yairm210.purity.annotations.Readonly
|
import yairm210.purity.annotations.Readonly
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashSet
|
import kotlin.collections.HashSet
|
||||||
@ -241,9 +242,10 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
|
|
||||||
//region pure functions
|
//region pure functions
|
||||||
|
|
||||||
fun isHill() = baseTerrain == Constants.hill || terrainFeatures.contains(Constants.hill)
|
@Readonly fun isHill() = baseTerrain == Constants.hill || terrainFeatures.contains(Constants.hill)
|
||||||
|
|
||||||
/** Returns military, civilian and air units in tile */
|
/** Returns military, civilian and air units in tile */
|
||||||
|
@Readonly
|
||||||
fun getUnits() = sequence {
|
fun getUnits() = sequence {
|
||||||
if (militaryUnit != null) yield(militaryUnit!!)
|
if (militaryUnit != null) yield(militaryUnit!!)
|
||||||
if (civilianUnit != null) yield(civilianUnit!!)
|
if (civilianUnit != null) yield(civilianUnit!!)
|
||||||
@ -251,6 +253,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** This is for performance reasons of canPassThrough() - faster than getUnits().firstOrNull() */
|
/** This is for performance reasons of canPassThrough() - faster than getUnits().firstOrNull() */
|
||||||
|
@Readonly
|
||||||
fun getFirstUnit(): MapUnit? {
|
fun getFirstUnit(): MapUnit? {
|
||||||
if (militaryUnit != null) return militaryUnit!!
|
if (militaryUnit != null) return militaryUnit!!
|
||||||
if (civilianUnit != null) return civilianUnit!!
|
if (civilianUnit != null) return civilianUnit!!
|
||||||
@ -258,41 +261,39 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Readonly
|
@Readonly @Suppress("purity") // should be autorecognized as readonly
|
||||||
fun getCity(): City? = owningCity
|
fun getCity(): City? = owningCity
|
||||||
|
|
||||||
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!")
|
||||||
else ruleset.terrains[naturalWonder!!]!!
|
else ruleset.terrains[naturalWonder!!]!!
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isVisible(player: Civilization): Boolean {
|
fun isVisible(player: Civilization): Boolean {
|
||||||
if (DebugUtils.VISIBLE_MAP)
|
if (DebugUtils.VISIBLE_MAP)
|
||||||
return true
|
return true
|
||||||
return player.viewableTiles.contains(this)
|
return player.viewableTiles.contains(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isExplored(player: Civilization): Boolean {
|
fun isExplored(player: Civilization): Boolean {
|
||||||
if (DebugUtils.VISIBLE_MAP || player.civName == Constants.spectator)
|
if (DebugUtils.VISIBLE_MAP || player.civName == Constants.spectator)
|
||||||
return true
|
return true
|
||||||
return exploredBy.contains(player.civName)
|
return exploredBy.contains(player.civName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly @Suppress("purity") // should be autorecognized as readonly
|
||||||
fun isCityCenter(): Boolean = isCityCenterInternal
|
fun isCityCenter(): Boolean = isCityCenterInternal
|
||||||
fun isNaturalWonder(): Boolean = naturalWonder != null
|
@Readonly fun isNaturalWonder(): Boolean = naturalWonder != null
|
||||||
fun isImpassible() = lastTerrain.impassable
|
@Readonly fun isImpassible() = lastTerrain.impassable
|
||||||
|
|
||||||
fun hasImprovementInProgress() = improvementQueue.isNotEmpty()
|
@Readonly fun hasImprovementInProgress() = improvementQueue.isNotEmpty()
|
||||||
|
|
||||||
@Readonly
|
@Readonly fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!]
|
||||||
fun getTileImprovement(): TileImprovement? = if (improvement == null) null else ruleset.tileImprovements[improvement!!]
|
@Readonly fun isPillaged(): Boolean = improvementIsPillaged || roadIsPillaged
|
||||||
@Readonly
|
@Readonly fun getUnpillagedTileImprovement(): TileImprovement? = if (getUnpillagedImprovement() == null) null else ruleset.tileImprovements[improvement!!]
|
||||||
fun isPillaged(): Boolean = improvementIsPillaged || roadIsPillaged
|
@Readonly fun getTileImprovementInProgress(): TileImprovement? = improvementQueue.firstOrNull()?.let { ruleset.tileImprovements[it.improvement] }
|
||||||
@Readonly
|
@Readonly fun containsGreatImprovement() = getTileImprovement()?.isGreatImprovement() == true
|
||||||
fun getUnpillagedTileImprovement(): TileImprovement? = if (getUnpillagedImprovement() == null) null else ruleset.tileImprovements[improvement!!]
|
|
||||||
@Readonly
|
|
||||||
fun getTileImprovementInProgress(): TileImprovement? = improvementQueue.firstOrNull()?.let { ruleset.tileImprovements[it.improvement] }
|
|
||||||
@Readonly
|
|
||||||
fun containsGreatImprovement() = getTileImprovement()?.isGreatImprovement() == true
|
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getImprovementToPillage(): TileImprovement? {
|
fun getImprovementToPillage(): TileImprovement? {
|
||||||
@ -319,10 +320,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return ruleset.tileImprovements[roadStatus.name]!!
|
return ruleset.tileImprovements[roadStatus.name]!!
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@Readonly
|
@Readonly fun canPillageTile(): Boolean = canPillageTileImprovement() || canPillageRoad()
|
||||||
fun canPillageTile(): Boolean {
|
|
||||||
return canPillageTileImprovement() || canPillageRoad()
|
|
||||||
}
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun canPillageTileImprovement(): Boolean {
|
fun canPillageTileImprovement(): Boolean {
|
||||||
return improvement != null && !improvementIsPillaged
|
return improvement != null && !improvementIsPillaged
|
||||||
@ -335,12 +333,10 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Unpillagable)
|
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Unpillagable)
|
||||||
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Irremovable)
|
&& !ruleset.tileImprovements[roadStatus.name]!!.hasUnique(UniqueType.Irremovable)
|
||||||
}
|
}
|
||||||
@Readonly
|
@Readonly fun getUnpillagedImprovement(): String? = if (improvementIsPillaged) null else improvement
|
||||||
fun getUnpillagedImprovement(): String? = if (improvementIsPillaged) null else improvement
|
|
||||||
|
|
||||||
/** @return [RoadStatus] on this [Tile], pillaged road counts as [RoadStatus.None] */
|
/** @return [RoadStatus] on this [Tile], pillaged road counts as [RoadStatus.None] */
|
||||||
@Readonly
|
@Readonly fun getUnpillagedRoad(): RoadStatus = if (roadIsPillaged) RoadStatus.None else roadStatus
|
||||||
fun getUnpillagedRoad(): RoadStatus = if (roadIsPillaged) RoadStatus.None else roadStatus
|
|
||||||
|
|
||||||
@Readonly
|
@Readonly
|
||||||
fun getUnpillagedRoadImprovement(): TileImprovement? {
|
fun getUnpillagedRoadImprovement(): TileImprovement? {
|
||||||
@ -354,12 +350,13 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
* @param viewingCiv `null` means civ-agnostic and thus always showing the actual improvement
|
* @param viewingCiv `null` means civ-agnostic and thus always showing the actual improvement
|
||||||
* @return The improvement name, or `null` if no improvement should be shown
|
* @return The improvement name, or `null` if no improvement should be shown
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun getShownImprovement(viewingCiv: Civilization?): String? =
|
fun getShownImprovement(viewingCiv: Civilization?): String? =
|
||||||
if (viewingCiv == null || viewingCiv.playerType == PlayerType.AI || viewingCiv.isSpectator()) improvement
|
if (viewingCiv == null || viewingCiv.playerType == PlayerType.AI || viewingCiv.isSpectator()) improvement
|
||||||
else viewingCiv.getLastSeenImprovement(position)
|
else viewingCiv.getLastSeenImprovement(position)
|
||||||
|
|
||||||
/** Returns true if this tile has fallout or an equivalent terrain feature */
|
/** Returns true if this tile has fallout or an equivalent terrain feature */
|
||||||
fun hasFalloutEquivalent(): Boolean = terrainFeatures.any { ruleset.terrains[it]!!.hasUnique(UniqueType.NullifyYields)}
|
@Readonly fun hasFalloutEquivalent(): Boolean = terrainFeatures.any { ruleset.terrains[it]!!.hasUnique(UniqueType.NullifyYields)}
|
||||||
|
|
||||||
|
|
||||||
fun getRow() = HexMath.getRow(position)
|
fun getRow() = HexMath.getRow(position)
|
||||||
@ -367,9 +364,9 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
|
|
||||||
fun getBaseTerrain(): Terrain = baseTerrainObject
|
fun getBaseTerrain(): Terrain = baseTerrainObject
|
||||||
|
|
||||||
@Readonly
|
@Readonly fun getOwner(): Civilization? = getCity()?.civ
|
||||||
fun getOwner(): Civilization? = getCity()?.civ
|
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getRoadOwner(): Civilization? {
|
fun getRoadOwner(): Civilization? {
|
||||||
return if (roadOwner != "")
|
return if (roadOwner != "")
|
||||||
tileMap.gameInfo.getCivilization(roadOwner)
|
tileMap.gameInfo.getCivilization(roadOwner)
|
||||||
@ -394,19 +391,22 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return civInfo.isAtWarWith(tileOwner)
|
return civInfo.isAtWarWith(tileOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isRoughTerrain() = allTerrains.any { it.isRough() }
|
@Readonly fun isRoughTerrain() = allTerrains.any { it.isRough() }
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
internal var stateThisTile: GameContext = GameContext.EmptyState
|
internal var stateThisTile: GameContext = GameContext.EmptyState
|
||||||
/** Checks whether any of the TERRAINS of this tile has a certain unique */
|
/** Checks whether any of the TERRAINS of this tile has a certain unique */
|
||||||
|
@Readonly
|
||||||
fun terrainHasUnique(uniqueType: UniqueType, state: GameContext = stateThisTile) =
|
fun terrainHasUnique(uniqueType: UniqueType, state: GameContext = stateThisTile) =
|
||||||
cachedTerrainData.uniques.hasMatchingUnique(uniqueType, state)
|
cachedTerrainData.uniques.hasMatchingUnique(uniqueType, state)
|
||||||
/** Get all uniques of this type that any TERRAIN on this tile has */
|
/** Get all uniques of this type that any TERRAIN on this tile has */
|
||||||
|
@Readonly
|
||||||
fun getTerrainMatchingUniques(uniqueType: UniqueType, gameContext: GameContext = stateThisTile ): Sequence<Unique> {
|
fun getTerrainMatchingUniques(uniqueType: UniqueType, gameContext: GameContext = stateThisTile ): Sequence<Unique> {
|
||||||
return cachedTerrainData.uniques.getMatchingUniques(uniqueType, gameContext)
|
return cachedTerrainData.uniques.getMatchingUniques(uniqueType, gameContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get all uniques of this type that any part of this tile has: terrains, improvement, resource */
|
/** Get all uniques of this type that any part of this tile has: terrains, improvement, resource */
|
||||||
|
@Readonly
|
||||||
fun getMatchingUniques(uniqueType: UniqueType, gameContext: GameContext = stateThisTile): Sequence<Unique> {
|
fun getMatchingUniques(uniqueType: UniqueType, gameContext: GameContext = stateThisTile): Sequence<Unique> {
|
||||||
var uniques = getTerrainMatchingUniques(uniqueType, gameContext)
|
var uniques = getTerrainMatchingUniques(uniqueType, gameContext)
|
||||||
if (getUnpillagedImprovement() != null) {
|
if (getUnpillagedImprovement() != null) {
|
||||||
@ -427,6 +427,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return civInfo.cities.firstOrNull { it != owningCity && it.isWorked(this) }
|
return civInfo.cities.firstOrNull { it != owningCity && it.isWorked(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isBlockaded(): Boolean {
|
fun isBlockaded(): Boolean {
|
||||||
val owner = getOwner() ?: return false
|
val owner = getOwner() ?: return false
|
||||||
val unit = militaryUnit
|
val unit = militaryUnit
|
||||||
@ -463,11 +464,13 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
|| terrainHasUnique(UniqueType.TileProvidesYieldWithoutPopulation)
|
|| terrainHasUnique(UniqueType.TileProvidesYieldWithoutPopulation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun isLocked(): Boolean {
|
fun isLocked(): Boolean {
|
||||||
val workingCity = getWorkingCity()
|
val workingCity = getWorkingCity()
|
||||||
return workingCity != null && workingCity.lockedTiles.contains(position)
|
return workingCity != null && workingCity.lockedTiles.contains(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun providesResources(civInfo: Civilization): Boolean {
|
fun providesResources(civInfo: Civilization): Boolean {
|
||||||
if (!hasViewableResource(civInfo)) return false
|
if (!hasViewableResource(civInfo)) return false
|
||||||
if (isCityCenter()) {
|
if (isCityCenter()) {
|
||||||
@ -520,6 +523,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Implements [UniqueParameterType.TerrainFilter][com.unciv.models.ruleset.unique.UniqueParameterType.TerrainFilter] */
|
/** Implements [UniqueParameterType.TerrainFilter][com.unciv.models.ruleset.unique.UniqueParameterType.TerrainFilter] */
|
||||||
|
@Readonly
|
||||||
fun matchesTerrainFilter(filter: String, observingCiv: Civilization?, multiFilter: Boolean = true): Boolean {
|
fun matchesTerrainFilter(filter: String, observingCiv: Civilization?, multiFilter: Boolean = true): Boolean {
|
||||||
return if (multiFilter) MultiFilter.multiFilter(filter, { matchesSingleTerrainFilter(it, observingCiv) })
|
return if (multiFilter) MultiFilter.multiFilter(filter, { matchesSingleTerrainFilter(it, observingCiv) })
|
||||||
else matchesSingleTerrainFilter(filter, observingCiv)
|
else matchesSingleTerrainFilter(filter, observingCiv)
|
||||||
@ -586,11 +590,13 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
fun hasViewableResource(civInfo: Civilization): Boolean =
|
fun hasViewableResource(civInfo: Civilization): Boolean =
|
||||||
resource != null && civInfo.tech.isRevealed(tileResource)
|
resource != null && civInfo.tech.isRevealed(tileResource)
|
||||||
|
|
||||||
fun getViewableTilesList(distance: Int): List<Tile> = tileMap.getViewableTiles(position, distance)
|
|
||||||
fun getTilesInDistance(distance: Int): Sequence<Tile> = tileMap.getTilesInDistance(position, distance)
|
|
||||||
fun getTilesInDistanceRange(range: IntRange): Sequence<Tile> = tileMap.getTilesInDistanceRange(position, range)
|
|
||||||
fun getTilesAtDistance(distance: Int): Sequence<Tile> = tileMap.getTilesAtDistance(position, distance)
|
|
||||||
|
|
||||||
|
@Readonly fun getViewableTilesList(distance: Int): List<Tile> = tileMap.getViewableTiles(position, distance)
|
||||||
|
@Readonly fun getTilesInDistance(distance: Int): Sequence<Tile> = tileMap.getTilesInDistance(position, distance)
|
||||||
|
@Readonly fun getTilesInDistanceRange(range: IntRange): Sequence<Tile> = tileMap.getTilesInDistanceRange(position, range)
|
||||||
|
@Readonly fun getTilesAtDistance(distance: Int): Sequence<Tile> = tileMap.getTilesAtDistance(position, distance)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getDefensiveBonus(includeImprovementBonus: Boolean = true, unit: MapUnit? = null): Float {
|
fun getDefensiveBonus(includeImprovementBonus: Boolean = true, unit: MapUnit? = null): Float {
|
||||||
var bonus = baseTerrainObject.defenceBonus
|
var bonus = baseTerrainObject.defenceBonus
|
||||||
if (terrainFeatureObjects.isNotEmpty()) {
|
if (terrainFeatureObjects.isNotEmpty()) {
|
||||||
@ -612,6 +618,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
* @param otherTile Destination tile
|
* @param otherTile Destination tile
|
||||||
* @return Shortest distance from this [Tile] to [otherTile] in count of tiles including impassable tiles but not including origin tile
|
* @return Shortest distance from this [Tile] to [otherTile] in count of tiles including impassable tiles but not including origin tile
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun aerialDistanceTo(otherTile: Tile): Int {
|
fun aerialDistanceTo(otherTile: Tile): Int {
|
||||||
val xDelta = position.x - otherTile.position.x
|
val xDelta = position.x - otherTile.position.x
|
||||||
val yDelta = position.y - otherTile.position.y
|
val yDelta = position.y - otherTile.position.y
|
||||||
@ -628,6 +635,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return min(distance, wrappedDistance).toInt()
|
return min(distance, wrappedDistance).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun canBeSettled(): Boolean {
|
fun canBeSettled(): Boolean {
|
||||||
val modConstants = tileMap.gameInfo.ruleset.modOptions.constants
|
val modConstants = tileMap.gameInfo.ruleset.modOptions.constants
|
||||||
return when {
|
return when {
|
||||||
@ -641,6 +649,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The two tiles have a river between them */
|
/** The two tiles have a river between them */
|
||||||
|
@Readonly
|
||||||
fun isConnectedByRiver(otherTile: Tile): Boolean {
|
fun isConnectedByRiver(otherTile: Tile): Boolean {
|
||||||
if (otherTile == this) throw Exception("Should not be called to compare to self!")
|
if (otherTile == this) throw Exception("Should not be called to compare to self!")
|
||||||
|
|
||||||
@ -672,6 +681,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
* @returns whether units of [civInfo] can pass through this tile, considering only civ-wide filters.
|
* @returns whether units of [civInfo] can pass through this tile, considering only civ-wide filters.
|
||||||
* Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through a tile.
|
* Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through a tile.
|
||||||
*/
|
*/
|
||||||
|
@Readonly
|
||||||
fun canCivPassThrough(civInfo: Civilization): Boolean {
|
fun canCivPassThrough(civInfo: Civilization): Boolean {
|
||||||
val tileOwner = getOwner()
|
val tileOwner = getOwner()
|
||||||
// comparing the CivInfo objects is cheaper than comparing strings
|
// comparing the CivInfo objects is cheaper than comparing strings
|
||||||
@ -681,6 +691,7 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return civInfo.diplomacyFunctions.canPassThroughTiles(tileOwner)
|
return civInfo.diplomacyFunctions.canPassThroughTiles(tileOwner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasEnemyInvisibleUnit(viewingCiv: Civilization): Boolean {
|
fun hasEnemyInvisibleUnit(viewingCiv: Civilization): Boolean {
|
||||||
val unitsInTile = getUnits()
|
val unitsInTile = getUnits()
|
||||||
return when {
|
return when {
|
||||||
@ -691,28 +702,33 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasConnection(civInfo: Civilization) =
|
fun hasConnection(civInfo: Civilization) =
|
||||||
getUnpillagedRoad() != RoadStatus.None || forestOrJungleAreRoads(civInfo)
|
getUnpillagedRoad() != RoadStatus.None || forestOrJungleAreRoads(civInfo)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasRoadConnection(civInfo: Civilization, mustBeUnpillaged: Boolean) =
|
fun hasRoadConnection(civInfo: Civilization, mustBeUnpillaged: Boolean) =
|
||||||
if (mustBeUnpillaged)
|
if (mustBeUnpillaged)
|
||||||
(getUnpillagedRoad() == RoadStatus.Road) || forestOrJungleAreRoads(civInfo)
|
(getUnpillagedRoad() == RoadStatus.Road) || forestOrJungleAreRoads(civInfo)
|
||||||
else
|
else
|
||||||
roadStatus == RoadStatus.Road || forestOrJungleAreRoads(civInfo)
|
roadStatus == RoadStatus.Road || forestOrJungleAreRoads(civInfo)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun hasRailroadConnection(mustBeUnpillaged: Boolean) =
|
fun hasRailroadConnection(mustBeUnpillaged: Boolean) =
|
||||||
if (mustBeUnpillaged)
|
if (mustBeUnpillaged)
|
||||||
getUnpillagedRoad() == RoadStatus.Railroad
|
getUnpillagedRoad() == RoadStatus.Railroad
|
||||||
else
|
else
|
||||||
roadStatus == RoadStatus.Railroad
|
roadStatus == RoadStatus.Railroad
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun forestOrJungleAreRoads(civInfo: Civilization) =
|
private fun forestOrJungleAreRoads(civInfo: Civilization) =
|
||||||
civInfo.nation.forestsAndJunglesAreRoads
|
civInfo.nation.forestsAndJunglesAreRoads
|
||||||
&& (terrainFeatures.contains(Constants.jungle) || terrainFeatures.contains(Constants.forest))
|
&& (terrainFeatures.contains(Constants.jungle) || terrainFeatures.contains(Constants.forest))
|
||||||
&& isFriendlyTerritory(civInfo)
|
&& isFriendlyTerritory(civInfo)
|
||||||
|
|
||||||
|
@Readonly
|
||||||
fun getRulesetIncompatibility(ruleset: Ruleset): HashSet<String> {
|
fun getRulesetIncompatibility(ruleset: Ruleset): HashSet<String> {
|
||||||
|
@LocalState
|
||||||
val out = HashSet<String>()
|
val out = HashSet<String>()
|
||||||
if (!ruleset.terrains.containsKey(baseTerrain))
|
if (!ruleset.terrains.containsKey(baseTerrain))
|
||||||
out.add("Base terrain [$baseTerrain] does not exist in ruleset!")
|
out.add("Base terrain [$baseTerrain] does not exist in ruleset!")
|
||||||
@ -727,15 +743,17 @@ class Tile : IsPartOfGameInfoSerialization, Json.Serializable {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Readonly @Suppress("purity") // should be auto-recognized as readonly
|
||||||
fun getContinent() = continent
|
fun getContinent() = continent
|
||||||
|
|
||||||
/** Checks if this tile is marked as target tile for a building with a [UniqueType.CreatesOneImprovement] unique */
|
/** Checks if this tile is marked as target tile for a building with a [UniqueType.CreatesOneImprovement] unique */
|
||||||
fun isMarkedForCreatesOneImprovement() =
|
@Readonly fun isMarkedForCreatesOneImprovement() =
|
||||||
turnsToImprovement < 0 && improvementInProgress != null
|
turnsToImprovement < 0 && improvementInProgress != null
|
||||||
/** Checks if this tile is marked as target tile for a building with a [UniqueType.CreatesOneImprovement] unique creating a specific [improvement] */
|
/** Checks if this tile is marked as target tile for a building with a [UniqueType.CreatesOneImprovement] unique creating a specific [improvement] */
|
||||||
fun isMarkedForCreatesOneImprovement(improvement: String) =
|
@Readonly fun isMarkedForCreatesOneImprovement(improvement: String) =
|
||||||
turnsToImprovement < 0 && improvementInProgress == improvement
|
turnsToImprovement < 0 && improvementInProgress == improvement
|
||||||
|
|
||||||
|
@Readonly
|
||||||
private fun approximateMajorDepositDistribution(): Double {
|
private fun approximateMajorDepositDistribution(): Double {
|
||||||
// We can't replicate the MapRegions resource distributor, so let's try to get
|
// We can't replicate the MapRegions resource distributor, so let's try to get
|
||||||
// a close probability of major deposits per tile
|
// a close probability of major deposits per tile
|
||||||
|
@ -13,6 +13,7 @@ import com.unciv.models.stats.GameResource
|
|||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
import com.unciv.ui.objectdescriptions.uniquesToCivilopediaTextLines
|
||||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||||
|
import yairm210.purity.annotations.Readonly
|
||||||
|
|
||||||
class TileResource : RulesetStatsObject(), GameResource {
|
class TileResource : RulesetStatsObject(), GameResource {
|
||||||
|
|
||||||
@ -52,6 +53,7 @@ class TileResource : RulesetStatsObject(), GameResource {
|
|||||||
* @see improvedBy
|
* @see improvedBy
|
||||||
* @see UniqueType.ImprovesResources
|
* @see UniqueType.ImprovesResources
|
||||||
*/
|
*/
|
||||||
|
@Readonly @Suppress("purity") // requires some plumbing
|
||||||
fun getImprovements(): Set<String> {
|
fun getImprovements(): Set<String> {
|
||||||
if (improvementsInitialized) return allImprovements
|
if (improvementsInitialized) return allImprovements
|
||||||
val ruleset = this.ruleset
|
val ruleset = this.ruleset
|
||||||
|
Loading…
x
Reference in New Issue
Block a user