More multiple terrain feature changes

This commit is contained in:
Yair Morgenstern 2021-03-11 23:09:05 +02:00
parent 01877fee7c
commit 02cd1a2ef3
3 changed files with 30 additions and 23 deletions

View File

@ -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 // 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 // and farms on adjacent to fresh water tiles will have +1 additional Food after researching Civil Service
@delegate:Transient @delegate:Transient
val isAdjacentToFreshwater: Boolean by lazy { matchesUniqueFilter("River") || matchesUniqueFilter("Fresh water") val isAdjacentToFreshwater: Boolean by lazy {
|| neighbors.any { it.matchesUniqueFilter("Fresh water") } } matchesUniqueFilter("River") || matchesUniqueFilter("Fresh water")
|| neighbors.any { it.matchesUniqueFilter("Fresh water") }
}
var militaryUnit: MapUnit? = null var militaryUnit: MapUnit? = null
var civilianUnit: MapUnit? = null var civilianUnit: MapUnit? = null
@ -50,9 +52,11 @@ open class TileInfo {
var position: Vector2 = Vector2.Zero var position: Vector2 = Vector2.Zero
lateinit var baseTerrain: String lateinit var baseTerrain: String
val terrainFeatures: ArrayList<String> = ArrayList() val terrainFeatures: ArrayList<String> = ArrayList()
@Transient // So it won't be serialized from now on @Transient // So it won't be serialized from now on
var terrainFeature: String? = null 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) { set(value) {
if (terrainFeatures.isNotEmpty()) { if (terrainFeatures.isNotEmpty()) {
if (value == null) terrainFeatures.removeAt(0) if (value == null) terrainFeatures.removeAt(0)
@ -139,7 +143,7 @@ open class TileInfo {
fun getTileResource(): TileResource = fun getTileResource(): TileResource =
if (resource == null) throw Exception("No resource exists for this tile!") 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!!]!! else ruleset.tileResources[resource!!]!!
fun getNaturalWonder(): Terrain = fun getNaturalWonder(): Terrain =
@ -340,10 +344,10 @@ open class TileInfo {
// Road improvements can change on tiles withh irremovable improvements - nothing else can, though. // 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 != RoadStatus.Railroad.name && improvement.name != RoadStatus.Railroad.name
&& improvement.name != "Remove Road" && improvement.name != "Remove Railroad" && 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 // 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.terrainsCanBeBuiltOn.contains(topTerrain.name) -> true
improvement.uniqueObjects.filter { it.placeholderText == "Must be next to []" }.any { improvement.uniqueObjects.filter { it.placeholderText == "Must be next to []" }.any {
val filter = it.params[0] 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 return filter == baseTerrain
|| filter == Constants.hill && isHill() || filter == Constants.hill && isHill()
|| filter == "River" && isAdjacentToRiver() || filter == "River" && isAdjacentToRiver()
@ -501,7 +505,6 @@ open class TileInfo {
} }
fun hasEnemyInvisibleUnit(viewingCiv: CivilizationInfo): Boolean { fun hasEnemyInvisibleUnit(viewingCiv: CivilizationInfo): Boolean {
val unitsInTile = getUnits() val unitsInTile = getUnits()
if (unitsInTile.none()) return false if (unitsInTile.none()) return false
@ -521,7 +524,7 @@ open class TileInfo {
&& (terrainFeature == Constants.jungle || terrainFeature == Constants.forest) && (terrainFeature == Constants.jungle || terrainFeature == Constants.forest)
&& isFriendlyTerritory(civInfo) && 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 (!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 (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!" if (resource != null && !ruleset.tileResources.containsKey(resource)) return "Resource $resource does not exist in ruleset!"
@ -586,21 +589,24 @@ open class TileInfo {
turnsToImprovement = 0 turnsToImprovement = 0
} }
fun normalizeToRuleset(ruleset: Ruleset){ fun normalizeToRuleset(ruleset: Ruleset) {
if (!ruleset.terrains.containsKey(naturalWonder)) naturalWonder = null if (!ruleset.terrains.containsKey(naturalWonder)) naturalWonder = null
if (naturalWonder != null) { if (naturalWonder != null) {
val naturalWonder = ruleset.terrains[naturalWonder]!! val naturalWonder = ruleset.terrains[naturalWonder]!!
baseTerrain = naturalWonder.turnsInto!! baseTerrain = naturalWonder.turnsInto!!
terrainFeature = null terrainFeatures.clear()
resource = null resource = null
improvement = null improvement = null
} }
if (!ruleset.terrains.containsKey(terrainFeature)) terrainFeature = null for (terrainFeature in terrainFeatures.toList()) {
if (terrainFeature != null) { if (!ruleset.terrains.containsKey(terrainFeature)) {
terrainFeatures.remove(terrainFeature)
continue
}
val terrainFeatureObject = ruleset.terrains[terrainFeature]!! val terrainFeatureObject = ruleset.terrains[terrainFeature]!!
if (terrainFeatureObject.occursOn.isNotEmpty() && !terrainFeatureObject.occursOn.contains(baseTerrain)) if (terrainFeatureObject.occursOn.isNotEmpty() && !terrainFeatureObject.occursOn.contains(baseTerrain))
terrainFeature = null terrainFeatures.remove(terrainFeature)
} }
@ -611,16 +617,16 @@ open class TileInfo {
resource = null 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()) if (isWater || isImpassible())
roadStatus = RoadStatus.None roadStatus = RoadStatus.None
} }
private fun normalizeTileImprovement(ruleset: Ruleset) { private fun normalizeTileImprovement(ruleset: Ruleset) {
val topTerrain = getLastTerrain()
if (improvement!!.startsWith("StartingLocation")) { if (improvement!!.startsWith("StartingLocation")) {
if (!isLand || topTerrain.impassable) improvement = null if (!isLand || getLastTerrain().impassable) improvement = null
return return
} }
val improvementObject = ruleset.tileImprovements[improvement]!! val improvementObject = ruleset.tileImprovements[improvement]!!
@ -634,4 +640,4 @@ open class TileInfo {
} }
//endregion //endregion
} }

View File

@ -37,7 +37,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
if (unit.ignoresTerrainCost) return 1f + extraCost if (unit.ignoresTerrainCost) return 1f + extraCost
if (areConnectedByRiver) return 100f // Rivers take the entire turn to cross 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 return 1f + extraCost // usually forest and jungle take 2 movements, so here it is 1
if (civInfo.nation.ignoreHillMovementCost && to.isHill()) if (civInfo.nation.ignoreHillMovementCost && to.isHill())
return 1f + extraCost // usually hills take 2 movements, so here it is 1 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()) { if (tile.isImpassible()) {
// special exception - ice tiles are technically impassible, but some units can move through them anyway // special exception - ice tiles are technically impassible, but some units can move through them anyway
// helicopters can pass through impassable tiles like mountains // 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 return false
} }
if (tile.isLand if (tile.isLand

View File

@ -270,7 +270,7 @@ class MapGenerator(val ruleset: Ruleset) {
val rareFeatures = ruleset.terrains.values.filter { val rareFeatures = ruleset.terrains.values.filter {
it.type == TerrainType.TerrainFeature && it.uniques.contains("Rare feature") 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) { if (randomness.RNG.nextDouble() <= tileMap.mapParameters.rareFeaturesRichness) {
val possibleFeatures = rareFeatures.filter { it.occursOn.contains(tile.baseTerrain) val possibleFeatures = rareFeatures.filter { it.occursOn.contains(tile.baseTerrain)
&& (!tile.isHill() || it.occursOn.contains(Constants.hill)) } && (!tile.isHill() || it.occursOn.contains(Constants.hill)) }
@ -287,7 +287,7 @@ class MapGenerator(val ruleset: Ruleset) {
tileMap.setTransients(ruleset) tileMap.setTransients(ruleset)
val temperatureSeed = randomness.RNG.nextInt().toDouble() val temperatureSeed = randomness.RNG.nextInt().toDouble()
for (tile in tileMap.values) { for (tile in tileMap.values) {
if (tile.baseTerrain !in Constants.sea || tile.terrainFeature != null) if (tile.baseTerrain !in Constants.sea || tile.terrainFeatures.any())
continue continue
val randomTemperature = randomness.getPerlinNoise(tile, temperatureSeed, scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble(), nOctaves = 1) 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) var temperature = ((latitudeTemperature + randomTemperature) / 2.0)
temperature = abs(temperature).pow(1.0 - tileMap.mapParameters.temperatureExtremeness) * temperature.sign temperature = abs(temperature).pow(1.0 - tileMap.mapParameters.temperatureExtremeness) * temperature.sign
if (temperature < -0.8) if (temperature < -0.8)
tile.terrainFeature = Constants.ice tile.terrainFeatures.add(Constants.ice)
} }
} }