diff --git a/core/src/com/unciv/logic/BarbarianManager.kt b/core/src/com/unciv/logic/BarbarianManager.kt index 55b7524b29..cc04ae24b2 100644 --- a/core/src/com/unciv/logic/BarbarianManager.kt +++ b/core/src/com/unciv/logic/BarbarianManager.kt @@ -110,7 +110,7 @@ class BarbarianManager { val viableTiles = fogTiles.filter { !it.isImpassible() && it.resource == null - && it.terrainFeatures.none { feature -> gameInfo.ruleSet.terrains[feature]!!.hasUnique("Only [] improvements may be built on this tile") } + && it.terrainFeatureObjects.none { feature -> feature.hasUnique("Only [] improvements may be built on this tile") } && it.neighbors.any { neighbor -> neighbor.isLand } && it !in tooCloseToCapitals && it !in tooCloseToCamps diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 18f9fa0f5f..939fc1ae31 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -712,13 +712,12 @@ object Battle { } tile.roadStatus = RoadStatus.None if (tile.isLand && !tile.isImpassible() && !tile.terrainFeatures.contains("Fallout")) { - val ruleset = tile.ruleset val destructionChance = if (tile.hasUnique(UniqueType.ResistsNukes)) 0.25f else 0.5f if (Random().nextFloat() < destructionChance) { - for (terrainFeature in tile.terrainFeatures) - if (ruleset.terrains[terrainFeature]!!.hasUnique(UniqueType.DestroyableByNukes)) - tile.removeTerrainFeature(terrainFeature) + for (terrainFeature in tile.terrainFeatureObjects) + if (terrainFeature.hasUnique(UniqueType.DestroyableByNukes)) + tile.removeTerrainFeature(terrainFeature.name) tile.addTerrainFeature("Fallout") } } diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index aeed256973..1694fef3b5 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -66,6 +66,11 @@ open class TileInfo { var position: Vector2 = Vector2.Zero lateinit var baseTerrain: String var terrainFeatures: List = listOf() + private set + + @Transient + var terrainFeatureObjects: List = listOf() + private set var naturalWonder: String? = null @@ -235,11 +240,10 @@ open class TileInfo { return civInfo.isAtWarWith(tileOwner) } - fun getTerrainFeaturesObjects(): List = terrainFeatures.mapNotNull { ruleset.terrains[it] } fun getAllTerrains(): Sequence = sequence { yield(baseTerrainObject) if (naturalWonder != null) yield(getNaturalWonder()) - yieldAll(terrainFeatures.asSequence().mapNotNull { ruleset.terrains[it] }) + yieldAll(terrainFeatureObjects) } fun isRoughTerrain() = getAllTerrains().any{ it.isRough() } @@ -269,7 +273,7 @@ open class TileInfo { val stateForConditionals = StateForConditionals(civInfo = observingCiv, cityInfo = city, tile = this); - for (terrainFeatureBase in getTerrainFeaturesObjects()) { + for (terrainFeatureBase in terrainFeatureObjects) { when { terrainFeatureBase.hasUnique(UniqueType.NullifyYields) -> return terrainFeatureBase.cloneStats() @@ -365,7 +369,7 @@ open class TileInfo { private fun getTileStartYield(isCenter: Boolean): Float { var stats = getBaseTerrain().cloneStats() - for (terrainFeatureBase in getTerrainFeaturesObjects()) { + for (terrainFeatureBase in terrainFeatureObjects) { if (terrainFeatureBase.overrideStats) stats = terrainFeatureBase.cloneStats() else @@ -871,13 +875,16 @@ open class TileInfo { } } - fun addTerrainFeature(terrainFeature:String) { - terrainFeatures = ArrayList(terrainFeatures).apply { add(terrainFeature) } + fun setTerrainFeatures(terrainFeatureList:List){ + terrainFeatures = terrainFeatureList + terrainFeatureObjects = terrainFeatureList.mapNotNull { ruleset.terrains[it] } } - fun removeTerrainFeature(terrainFeature: String) { - terrainFeatures = ArrayList(terrainFeatures).apply { remove(terrainFeature) } - } + fun addTerrainFeature(terrainFeature:String) = + setTerrainFeatures(ArrayList(terrainFeatures).apply { add(terrainFeature) }) + + fun removeTerrainFeature(terrainFeature: String) = + setTerrainFeatures(ArrayList(terrainFeatures).apply { remove(terrainFeature) }) /** If the unit isn't in the ruleset we can't even know what type of unit this is! So check each place @@ -906,7 +913,7 @@ open class TileInfo { if (naturalWonder != null) { val naturalWonder = ruleset.terrains[naturalWonder]!! baseTerrain = naturalWonder.turnsInto!! - terrainFeatures = listOf() + setTerrainFeatures(listOf()) resource = null improvement = null } @@ -962,7 +969,7 @@ open class TileInfo { val newTerrainFeatures = ArrayList() newTerrainFeatures.add(Constants.hill) newTerrainFeatures.addAll(copy) - terrainFeatures = newTerrainFeatures + setTerrainFeatures(newTerrainFeatures) } } diff --git a/core/src/com/unciv/logic/map/mapgenerator/MapRegions.kt b/core/src/com/unciv/logic/map/mapgenerator/MapRegions.kt index 2d9c8fb8a8..5c27a093b7 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/MapRegions.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/MapRegions.kt @@ -476,7 +476,7 @@ class MapRegions (val ruleset: Ruleset){ val panicPosition = region.rect.getPosition(Vector2()) val panicTerrain = ruleset.terrains.values.first { it.type == TerrainType.Land }.name region.tileMap[panicPosition].baseTerrain = panicTerrain - region.tileMap[panicPosition].terrainFeatures = listOf() + region.tileMap[panicPosition].setTerrainFeatures(listOf()) setRegionStart(region, panicPosition) } @@ -487,7 +487,7 @@ class MapRegions (val ruleset: Ruleset){ private fun normalizeStart(startTile: TileInfo, tileMap: TileMap, minorCiv: Boolean) { // Remove ice-like features adjacent to start for (tile in startTile.neighbors) { - val lastTerrain = tile.getTerrainFeaturesObjects().lastOrNull { it.impassable } + val lastTerrain = tile.terrainFeatureObjects.lastOrNull { it.impassable } if (lastTerrain != null) { tile.removeTerrainFeature(lastTerrain.name) } @@ -608,7 +608,7 @@ class MapRegions (val ruleset: Ruleset){ // Start with list of candidate plots sorted in ring order 1,2,3 val candidatePlots = startTile.getTilesInDistanceRange(1..rangeForBonuses) - .filter { it.resource == null && oasisEquivalent !in it.getTerrainFeaturesObjects() } + .filter { it.resource == null && oasisEquivalent !in it.terrainFeatureObjects } .shuffled().sortedBy { it.aerialDistanceTo(startTile) }.toMutableList() // Place food bonuses (and oases) as able @@ -1658,8 +1658,8 @@ class MapRegions (val ruleset: Ruleset){ // Check first available out of unbuildable features, then other features, then base terrain val terrainToCheck = if (tile.terrainFeatures.isEmpty()) tile.getBaseTerrain() - else tile.getTerrainFeaturesObjects().firstOrNull { it.unbuildable } - ?: tile.getTerrainFeaturesObjects().first() + else tile.terrainFeatureObjects.firstOrNull { it.unbuildable } + ?: tile.terrainFeatureObjects.first() // Add all applicable qualities for (unique in terrainToCheck.getMatchingUniques(UniqueType.HasQuality, StateForConditionals(region = region))) { @@ -1765,7 +1765,7 @@ class Region (val tileMap: TileMap, val rect: Rectangle, val continentID: Int = terrainCounts.clear() for (tile in tiles) { val terrainsToCount = if (tile.getAllTerrains().any { it.hasUnique(UniqueType.IgnoreBaseTerrainForRegion) }) - tile.getTerrainFeaturesObjects().map { it.name }.asSequence() + tile.terrainFeatureObjects.map { it.name }.asSequence() else tile.getAllTerrains().map { it.name } for (terrain in terrainsToCount) { diff --git a/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt index 541142f810..a85985ac40 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt @@ -167,7 +167,7 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration } private fun clearTile(tile: TileInfo){ - tile.terrainFeatures = listOf() + tile.setTerrainFeatures(listOf()) tile.resource = null tile.improvement = null tile.setTerrainTransients() diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorOptionsTable.kt b/core/src/com/unciv/ui/mapeditor/MapEditorOptionsTable.kt index 23642fac3c..80cf912291 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorOptionsTable.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorOptionsTable.kt @@ -83,7 +83,7 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(BaseScr terrainFeaturesTable.add(getHex(ImageGetter.getRedCross(50f, 0.6f)).apply { onClick { tileAction = { - it.terrainFeatures = listOf() + it.setTerrainFeatures(listOf()) it.naturalWonder = null it.hasBottomRiver = false it.hasBottomLeftRiver = false @@ -321,6 +321,7 @@ class MapEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(BaseScr private fun addTerrainOptions(terrainFeaturesTable: Table, baseTerrainTable: Table) { for (terrain in ruleset.terrains.values) { val tileInfo = TileInfo() + tileInfo.ruleset = ruleset if (terrain.type == TerrainType.TerrainFeature) { tileInfo.baseTerrain = when { terrain.occursOn.isNotEmpty() -> terrain.occursOn.first() diff --git a/tests/src/com/unciv/logic/map/TileMapTests.kt b/tests/src/com/unciv/logic/map/TileMapTests.kt index 6270abfc7a..245443023e 100644 --- a/tests/src/com/unciv/logic/map/TileMapTests.kt +++ b/tests/src/com/unciv/logic/map/TileMapTests.kt @@ -87,7 +87,7 @@ class TileMapTests { tile1.baseTerrain = Constants.hill tile1.setTerrainTransients() tile2.baseTerrain = Constants.grassland - tile2.terrainFeatures = listOf(Constants.forest) + tile2.setTerrainFeatures(listOf(Constants.forest)) tile2.setTerrainTransients() tile3.baseTerrain = Constants.coast tile3.setTerrainTransients() @@ -114,7 +114,7 @@ class TileMapTests { @Test fun canSeeMountainFromForestOverHills() { tile1.baseTerrain = Constants.grassland - tile1.terrainFeatures = listOf(Constants.forest) + tile1.setTerrainFeatures(listOf(Constants.forest)) tile1.setTerrainTransients() tile2.baseTerrain = Constants.hill tile2.setTerrainTransients() @@ -131,7 +131,7 @@ class TileMapTests { tile1.baseTerrain = Constants.hill tile1.setTerrainTransients() tile2.baseTerrain = Constants.grassland - tile2.terrainFeatures = listOf(Constants.forest) + tile1.setTerrainFeatures(listOf(Constants.forest)) tile2.setTerrainTransients() tile3.baseTerrain = Constants.hill tile3.setTerrainTransients() @@ -172,10 +172,10 @@ class TileMapTests { @Test fun canNOTSeeOutThroughForest() { tile1.baseTerrain = Constants.grassland - tile1.terrainFeatures = listOf(Constants.forest) + tile1.setTerrainFeatures(listOf(Constants.forest)) tile1.setTerrainTransients() tile2.baseTerrain = Constants.grassland - tile2.terrainFeatures = listOf(Constants.forest) + tile2.setTerrainFeatures(listOf(Constants.forest)) tile2.setTerrainTransients() tile3.baseTerrain = Constants.grassland tile3.setTerrainTransients() @@ -190,7 +190,7 @@ class TileMapTests { tile1.baseTerrain = Constants.coast tile1.setTerrainTransients() tile2.baseTerrain = Constants.grassland - tile2.terrainFeatures = listOf(Constants.jungle) + tile2.setTerrainFeatures(listOf(Constants.forest)) tile2.setTerrainTransients() tile3.baseTerrain = Constants.coast tile3.setTerrainTransients() diff --git a/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt b/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt index 9d7a10fcb7..a97148c7ba 100644 --- a/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt +++ b/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt @@ -54,7 +54,7 @@ class UnitMovementAlgorithmsTests { fun canPassThroughPassableTerrains() { for (terrain in ruleSet.terrains.values) { tile.baseTerrain = terrain.name - tile.terrainFeatures = listOf() + tile.setTerrainFeatures(listOf()) tile.setTransients() unit.baseUnit = BaseUnit().apply { unitType = "Sword"; ruleset = ruleSet } @@ -112,7 +112,7 @@ class UnitMovementAlgorithmsTests { @Test fun canNOTEnterIce() { tile.baseTerrain = Constants.ocean - tile.terrainFeatures = listOf(Constants.ice) + tile.setTerrainFeatures(listOf(Constants.ice)) tile.setTransients() for (type in ruleSet.unitTypes) {