diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index c30cb88d21..9ee1845ce9 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -40,8 +40,10 @@ open class TileInfo { // This will be called often - farm can be built on Hill and tundra if adjacent to fresh water // and farms on adjacent to fresh water tiles will have +1 additional Food after researching Civil Service @delegate:Transient - val isAdjacentToFreshwater: Boolean by lazy { matchesUniqueFilter("River") || matchesUniqueFilter("Fresh water") - || neighbors.any { it.matchesUniqueFilter("Fresh water") } } + val isAdjacentToFreshwater: Boolean by lazy { + matchesUniqueFilter("River") || matchesUniqueFilter("Fresh water") + || neighbors.any { it.matchesUniqueFilter("Fresh water") } + } var militaryUnit: MapUnit? = null var civilianUnit: MapUnit? = null @@ -50,9 +52,11 @@ open class TileInfo { var position: Vector2 = Vector2.Zero lateinit var baseTerrain: String val terrainFeatures: ArrayList = ArrayList() + @Transient // So it won't be serialized from now on var terrainFeature: String? = null - get() = terrainFeatures.firstOrNull() ?: field //if terrainFeatures contains no terrainFeature maybe one got deserialized to field + get() = terrainFeatures.firstOrNull() + ?: field //if terrainFeatures contains no terrainFeature maybe one got deserialized to field set(value) { if (terrainFeatures.isNotEmpty()) { if (value == null) terrainFeatures.removeAt(0) @@ -139,7 +143,7 @@ open class TileInfo { fun getTileResource(): TileResource = if (resource == null) throw Exception("No resource exists for this tile!") - else if(!ruleset.tileResources.containsKey(resource!!)) throw Exception("Resource $resource does not exist in this ruleset!") + else if (!ruleset.tileResources.containsKey(resource!!)) throw Exception("Resource $resource does not exist in this ruleset!") else ruleset.tileResources[resource!!]!! fun getNaturalWonder(): Terrain = @@ -340,10 +344,10 @@ open class TileInfo { // Road improvements can change on tiles withh irremovable improvements - nothing else can, though. improvement.name != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name && improvement.name != "Remove Road" && improvement.name != "Remove Railroad" - && getTileImprovement().let { it!=null && it.hasUnique("Irremovable") } -> false + && getTileImprovement().let { it != null && it.hasUnique("Irremovable") } -> false // Tiles with no terrains, and no turns to build, are like great improvements - they're placeable - improvement.terrainsCanBeBuiltOn.isEmpty() && improvement.turnsToBuild==0 && isLand -> true + improvement.terrainsCanBeBuiltOn.isEmpty() && improvement.turnsToBuild == 0 && isLand -> true improvement.terrainsCanBeBuiltOn.contains(topTerrain.name) -> true improvement.uniqueObjects.filter { it.placeholderText == "Must be next to []" }.any { val filter = it.params[0] @@ -363,7 +367,7 @@ open class TileInfo { } } - fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo?=null): Boolean { + fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean { return filter == baseTerrain || filter == Constants.hill && isHill() || filter == "River" && isAdjacentToRiver() @@ -501,7 +505,6 @@ open class TileInfo { } - fun hasEnemyInvisibleUnit(viewingCiv: CivilizationInfo): Boolean { val unitsInTile = getUnits() if (unitsInTile.none()) return false @@ -521,7 +524,7 @@ open class TileInfo { && (terrainFeature == Constants.jungle || terrainFeature == Constants.forest) && isFriendlyTerritory(civInfo) - fun getRulesetIncompatability(ruleset: Ruleset):String{ + fun getRulesetIncompatability(ruleset: Ruleset): String { if (!ruleset.terrains.containsKey(baseTerrain)) return "Base terrain $baseTerrain does not exist in ruleset!" if (terrainFeature != null && !ruleset.terrains.containsKey(terrainFeature)) return "Terrain feature $terrainFeature does not exist in ruleset!" if (resource != null && !ruleset.tileResources.containsKey(resource)) return "Resource $resource does not exist in ruleset!" @@ -586,21 +589,24 @@ open class TileInfo { turnsToImprovement = 0 } - fun normalizeToRuleset(ruleset: Ruleset){ + fun normalizeToRuleset(ruleset: Ruleset) { if (!ruleset.terrains.containsKey(naturalWonder)) naturalWonder = null if (naturalWonder != null) { val naturalWonder = ruleset.terrains[naturalWonder]!! baseTerrain = naturalWonder.turnsInto!! - terrainFeature = null + terrainFeatures.clear() resource = null improvement = null } - if (!ruleset.terrains.containsKey(terrainFeature)) terrainFeature = null - if (terrainFeature != null) { + for (terrainFeature in terrainFeatures.toList()) { + if (!ruleset.terrains.containsKey(terrainFeature)) { + terrainFeatures.remove(terrainFeature) + continue + } val terrainFeatureObject = ruleset.terrains[terrainFeature]!! if (terrainFeatureObject.occursOn.isNotEmpty() && !terrainFeatureObject.occursOn.contains(baseTerrain)) - terrainFeature = null + terrainFeatures.remove(terrainFeature) } @@ -611,16 +617,16 @@ open class TileInfo { resource = null } - if (improvement != null) normalizeTileImprovement(ruleset) + // If we're checking this at gameInfo.setTransients, we can't check the top terrain + if (improvement != null && ::baseTerrainObject.isInitialized) normalizeTileImprovement(ruleset) if (isWater || isImpassible()) roadStatus = RoadStatus.None } private fun normalizeTileImprovement(ruleset: Ruleset) { - val topTerrain = getLastTerrain() if (improvement!!.startsWith("StartingLocation")) { - if (!isLand || topTerrain.impassable) improvement = null + if (!isLand || getLastTerrain().impassable) improvement = null return } val improvementObject = ruleset.tileImprovements[improvement]!! @@ -634,4 +640,4 @@ open class TileInfo { } //endregion -} +} \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt index f7eb4a8db1..939e71d2e9 100644 --- a/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt +++ b/core/src/com/unciv/logic/map/UnitMovementAlgorithms.kt @@ -37,7 +37,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) { if (unit.ignoresTerrainCost) return 1f + extraCost if (areConnectedByRiver) return 100f // Rivers take the entire turn to cross - if (unit.doubleMovementInForestAndJungle && (to.terrainFeature == Constants.forest || to.terrainFeature == Constants.jungle)) + if (unit.doubleMovementInForestAndJungle && + (to.terrainFeatures.contains(Constants.forest) || to.terrainFeatures.contains(Constants.jungle))) return 1f + extraCost // usually forest and jungle take 2 movements, so here it is 1 if (civInfo.nation.ignoreHillMovementCost && to.isHill()) return 1f + extraCost // usually hills take 2 movements, so here it is 1 @@ -335,7 +336,7 @@ class UnitMovementAlgorithms(val unit:MapUnit) { if (tile.isImpassible()) { // special exception - ice tiles are technically impassible, but some units can move through them anyway // helicopters can pass through impassable tiles like mountains - if (!(tile.terrainFeature == Constants.ice && unit.canEnterIceTiles) && !unit.canPassThroughImpassableTiles) + if (!(tile.terrainFeatures.contains(Constants.ice) && unit.canEnterIceTiles) && !unit.canPassThroughImpassableTiles) return false } if (tile.isLand diff --git a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt index 01c827e931..c14fbcc3c3 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt @@ -270,7 +270,7 @@ class MapGenerator(val ruleset: Ruleset) { val rareFeatures = ruleset.terrains.values.filter { it.type == TerrainType.TerrainFeature && it.uniques.contains("Rare feature") } - for (tile in tileMap.values.asSequence().filter { it.terrainFeature == null }) { + for (tile in tileMap.values.asSequence().filter { it.terrainFeatures.isEmpty() }) { if (randomness.RNG.nextDouble() <= tileMap.mapParameters.rareFeaturesRichness) { val possibleFeatures = rareFeatures.filter { it.occursOn.contains(tile.baseTerrain) && (!tile.isHill() || it.occursOn.contains(Constants.hill)) } @@ -287,7 +287,7 @@ class MapGenerator(val ruleset: Ruleset) { tileMap.setTransients(ruleset) val temperatureSeed = randomness.RNG.nextInt().toDouble() for (tile in tileMap.values) { - if (tile.baseTerrain !in Constants.sea || tile.terrainFeature != null) + if (tile.baseTerrain !in Constants.sea || tile.terrainFeatures.any()) continue val randomTemperature = randomness.getPerlinNoise(tile, temperatureSeed, scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble(), nOctaves = 1) @@ -295,7 +295,7 @@ class MapGenerator(val ruleset: Ruleset) { var temperature = ((latitudeTemperature + randomTemperature) / 2.0) temperature = abs(temperature).pow(1.0 - tileMap.mapParameters.temperatureExtremeness) * temperature.sign if (temperature < -0.8) - tile.terrainFeature = Constants.ice + tile.terrainFeatures.add(Constants.ice) } }