diff --git a/core/src/com/unciv/logic/HexMath.kt b/core/src/com/unciv/logic/HexMath.kt index 145a48d7bd..85cf98f82d 100644 --- a/core/src/com/unciv/logic/HexMath.kt +++ b/core/src/com/unciv/logic/HexMath.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector3 import kotlin.math.* +@Suppress("MemberVisibilityCanBePrivate", "unused") // this is a library offering optional services object HexMath { fun getVectorForAngle(angle: Float): Vector2 { @@ -19,8 +20,12 @@ object HexMath { if (size < 0) return 0 return 1 + 6 * size * (size + 1) / 2 } + + /** Almost inverse of [getNumberOfTilesInHexagon] - get equivalent fractional Hexagon radius for an Area */ + fun getHexagonalRadiusForArea(numberOfTiles: Int) = + if (numberOfTiles < 1) 0f else ((sqrt(12f * numberOfTiles - 3) - 3) / 6) - /* In our reference system latitude, i.e. how distant from equator we are is proportional to x + y*/ + // In our reference system latitude, i.e. how distant from equator we are, is proportional to x + y fun getLatitude(vector: Vector2): Float { return vector.x + vector.y } @@ -30,7 +35,7 @@ object HexMath { } /** returns a vector containing width and height a rectangular map should have to have - * approximately the same number of tiles as an hexagonal map given a height/width ratio */ + * approximately the same number of tiles as an hexagonal map given a height/width ratio */ fun getEquivalentRectangularSize(size: Int, ratio: Float = 0.65f): Vector2 { if (size < 0) return Vector2.Zero @@ -41,15 +46,10 @@ object HexMath { return Vector2(width, height) } - /** Returns a radius of a hexagonal map that have approximately the same number of - * tiles as a rectangular map of a given width/height - */ - fun getEquivalentHexagonalRadius(width: Int, height: Int): Int { - val nTiles = width * height.toFloat() - if (nTiles < 1) return 0 - val radius = ((sqrt(12*nTiles - 3) - 3) / 6).roundToInt() - return radius - } + /** Returns a radius of a hexagonal map that has approximately the same number of + * tiles as a rectangular map of a given width/height */ + fun getEquivalentHexagonalRadius(width: Int, height: Int) = + getHexagonalRadiusForArea(width * height).roundToInt() fun getAdjacentVectors(origin: Vector2): ArrayList { val vectors = arrayListOf( @@ -78,6 +78,7 @@ object HexMath { return xVector.scl(hexCoord.x).add(yVector.scl(hexCoord.y)) } + @Suppress("LocalVariableName") // clearer fun world2HexCoords(worldCoord: Vector2): Vector2 { // D: diagonal, A: antidiagonal versors val D = getVectorByClockHour(10).scl(sqrt(3.0).toFloat()) @@ -173,12 +174,12 @@ object HexMath { } fun getDistance(origin: Vector2, destination: Vector2): Int { - val relative_x = origin.x - destination.x - val relative_y = origin.y - destination.y - if (relative_x * relative_y >= 0) - return max(abs(relative_x), abs(relative_y)).toInt() + val relativeX = origin.x - destination.x + val relativeY = origin.y - destination.y + return if (relativeX * relativeY >= 0) + max(abs(relativeX), abs(relativeY)).toInt() else - return (abs(relative_x) + abs(relative_y)).toInt() + (abs(relativeX) + abs(relativeY)).toInt() } // Statically allocate the Vectors (in World coordinates) diff --git a/core/src/com/unciv/logic/map/MapParameters.kt b/core/src/com/unciv/logic/map/MapParameters.kt index 07279bd751..2532f33943 100644 --- a/core/src/com/unciv/logic/map/MapParameters.kt +++ b/core/src/com/unciv/logic/map/MapParameters.kt @@ -92,6 +92,9 @@ class MapSizeNew { // tell the caller that map dimensions have changed and why return message } + + // For debugging and MapGenerator console output + override fun toString() = if (name == Constants.custom) "${width}x${height}" else name } object MapShape { @@ -125,7 +128,7 @@ class MapParameters { var noNaturalWonders = false var worldWrap = false - /** This is used mainly for the map editor, so you can continue editing a map under the ame ruleset you started with */ + /** This is used mainly for the map editor, so you can continue editing a map under the same ruleset you started with */ var mods = LinkedHashSet() var seed: Long = System.currentTimeMillis() @@ -153,4 +156,7 @@ class MapParameters { resourceRichness = 0.1f waterThreshold = 0f } + + // For debugging and MapGenerator console output + override fun toString() = "($mapSize ${if (worldWrap)"wrapped " else ""}$shape $type, Seed $seed, $elevationExponent/$temperatureExtremeness/$resourceRichness/$vegetationRichness/$rareFeaturesRichness/$maxCoastExtension/$tilesPerBiomeArea/$waterThreshold)" } diff --git a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt index 87ef87a821..b29db6efd7 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt @@ -7,12 +7,19 @@ import com.unciv.logic.map.* import com.unciv.models.Counter import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.tile.ResourceType +import com.unciv.models.ruleset.tile.Terrain import com.unciv.models.ruleset.tile.TerrainType import kotlin.math.* import kotlin.random.Random class MapGenerator(val ruleset: Ruleset) { + companion object { + // temporary instrumentation while tuning/debugging + const val consoleOutput = false + private const val consoleTimings = false + } + private var randomness = MapGenerationRandomness() fun generateMap(mapParameters: MapParameters): TileMap { @@ -40,23 +47,55 @@ class MapGenerator(val ruleset: Ruleset) { return map } - MapLandmassGenerator(ruleset, randomness).generateLand(map) - raiseMountainsAndHills(map) - applyHumidityAndTemperature(map) - spawnLakesAndCoasts(map) - spawnVegetation(map) - spawnRareFeatures(map) - spawnIce(map) - NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map) - RiverGenerator(randomness).spawnRivers(map) - spreadResources(map) - spreadAncientRuins(map) + if (consoleOutput || consoleTimings) println("\nMapGenerator run with parameters $mapParameters") + runAndMeasure("MapLandmassGenerator") { + MapLandmassGenerator(ruleset, randomness).generateLand(map) + } + runAndMeasure("raiseMountainsAndHills") { + raiseMountainsAndHills(map) + } + runAndMeasure("applyHumidityAndTemperature") { + applyHumidityAndTemperature(map) + } + runAndMeasure("spawnLakesAndCoasts") { + spawnLakesAndCoasts(map) + } + runAndMeasure("spawnVegetation") { + spawnVegetation(map) + } + runAndMeasure("spawnRareFeatures") { + spawnRareFeatures(map) + } + runAndMeasure("spawnIce") { + spawnIce(map) + } + runAndMeasure("NaturalWonderGenerator") { + NaturalWonderGenerator(ruleset, randomness).spawnNaturalWonders(map) + } + runAndMeasure("RiverGenerator") { + RiverGenerator(randomness).spawnRivers(map) + } + runAndMeasure("spreadResources") { + spreadResources(map) + } + runAndMeasure("spreadAncientRuins") { + spreadAncientRuins(map) + } return map } - private fun seedRNG(seed: Long, verbose: Boolean = false) { + private fun runAndMeasure(text: String, action: ()->Unit) { + if (!consoleTimings) return action() + val startNanos = System.nanoTime() + action() + val delta = System.nanoTime() - startNanos + println("MapGenerator.$text took ${delta/1000000L}.${(delta/10000L).rem(100)}ms") + } + + //todo: Why is this unused? + private fun seedRNG(seed: Long) { randomness.RNG = Random(seed) - if (verbose) println("RNG seeded with $seed") + if (consoleOutput) println("RNG seeded with $seed") } private fun spawnLakesAndCoasts(map: TileMap) { @@ -110,23 +149,23 @@ class MapGenerator(val ruleset: Ruleset) { return val suitableTiles = map.values.filter { it.isLand && !it.isImpassible() } val locations = randomness.chooseSpreadOutLocations(suitableTiles.size / 50, - suitableTiles, 10) + suitableTiles, map.mapParameters.mapSize.radius) for (tile in locations) tile.improvement = ruinsEquivalents.keys.random() } private fun spreadResources(tileMap: TileMap) { - val distance = tileMap.mapParameters.mapSize.radius + val mapRadius = tileMap.mapParameters.mapSize.radius for (tile in tileMap.values) tile.resource = null - spreadStrategicResources(tileMap, distance) - spreadResources(tileMap, distance, ResourceType.Luxury) - spreadResources(tileMap, distance, ResourceType.Bonus) + spreadStrategicResources(tileMap, mapRadius) + spreadResources(tileMap, mapRadius, ResourceType.Luxury) + spreadResources(tileMap, mapRadius, ResourceType.Bonus) } // Here, we need each specific resource to be spread over the map - it matters less if specific resources are near each other - private fun spreadStrategicResources(tileMap: TileMap, distance: Int) { + private fun spreadStrategicResources(tileMap: TileMap, mapRadius: Int) { val strategicResources = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic } // passable land tiles (no mountains, no wonders) without resources yet val candidateTiles = tileMap.values.filter { it.resource == null && !it.isImpassible() } @@ -139,17 +178,18 @@ class MapGenerator(val ruleset: Ruleset) { .filter { it.resource == null && resource.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } - val locations = randomness.chooseSpreadOutLocations(resourcesPerType, suitableTiles, distance) + val locations = randomness.chooseSpreadOutLocations(resourcesPerType, suitableTiles, mapRadius) for (location in locations) location.resource = resource.name } } /** - * Spreads resources of type [resourceType] picking locations at [distance] from each other. + * Spreads resources of type [resourceType] picking locations at a minimum distance from each other, + * which is determined from [mapRadius] and then tuned down until the desired number fits. * [MapParameters.resourceRichness] used to control how many resources to spawn. */ - private fun spreadResources(tileMap: TileMap, distance: Int, resourceType: ResourceType) { + private fun spreadResources(tileMap: TileMap, mapRadius: Int, resourceType: ResourceType) { val resourcesOfType = ruleset.tileResources.values.filter { it.resourceType == resourceType } val suitableTiles = tileMap.values @@ -157,7 +197,7 @@ class MapGenerator(val ruleset: Ruleset) { .filter { it.resource == null && resourcesOfType.any { r -> r.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } } val numberOfResources = tileMap.values.count { it.isLand && !it.isImpassible() } * tileMap.mapParameters.resourceRichness - val locations = randomness.chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, distance) + val locations = randomness.chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, mapRadius) val resourceToNumber = Counter() @@ -177,23 +217,23 @@ class MapGenerator(val ruleset: Ruleset) { * [MapParameters.elevationExponent] favors high elevation */ private fun raiseMountainsAndHills(tileMap: TileMap) { - val mountain = ruleset.terrains.values.filter { it.uniques.contains("Occurs in chains at high elevations") }.firstOrNull()?.name - val hill = ruleset.terrains.values.filter { it.uniques.contains("Occurs in groups around high elevations") }.firstOrNull()?.name - val flat = ruleset.terrains.values.filter { !it.impassable && it.type == TerrainType.Land && !it.uniques.contains("Rough Terrain") }.firstOrNull()?.name + val mountain = ruleset.terrains.values.firstOrNull { it.uniques.contains("Occurs in chains at high elevations") }?.name + val hill = ruleset.terrains.values.firstOrNull { it.uniques.contains("Occurs in groups around high elevations") }?.name + val flat = ruleset.terrains.values.firstOrNull { !it.impassable && it.type == TerrainType.Land && !it.uniques.contains("Rough Terrain") }?.name if (flat == null) { println("Ruleset seems to contain no flat terrain - can't generate heightmap") return } - if (mountain != null) - println("Mountainlike generation for " + mountain) - if (hill != null) - println("Hill-like generation for " + hill) + if (consoleOutput && mountain != null) + println("Mountain-like generation for $mountain") + if (consoleOutput && hill != null) + println("Hill-like generation for $hill") val elevationSeed = randomness.RNG.nextInt().toDouble() tileMap.setTransients(ruleset) - for (tile in tileMap.values.filter { !it.isWater }) { + for (tile in tileMap.values.asSequence().filter { !it.isWater }) { var elevation = randomness.getPerlinNoise(tile, elevationSeed, scale = 2.0) elevation = abs(elevation).pow(1.0 - tileMap.mapParameters.elevationExponent.toDouble()) * elevation.sign @@ -263,7 +303,7 @@ class MapGenerator(val ruleset: Ruleset) { for (i in 1..5) { var totalHills = tileMap.values.count { it.terrainFeatures.contains(hill) } - for (tile in tileMap.values.filter { !it.isWater && (mountain == null || it.baseTerrain != mountain) }) { + for (tile in tileMap.values.asSequence().filter { !it.isWater && (mountain == null || it.baseTerrain != mountain) }) { val adjacentMountains = if (mountain == null) 0 else tile.neighbors.count { it.baseTerrain == mountain } val adjacentHills = @@ -279,7 +319,7 @@ class MapGenerator(val ruleset: Ruleset) { } - for (tile in tileMap.values.filter { !it.isWater && (mountain == null || it.baseTerrain != mountain) }) { + for (tile in tileMap.values.asSequence().filter { !it.isWater && (mountain == null || it.baseTerrain != mountain) }) { if (tile.terrainFeatures.remove(Constants.rising) && (totalHills <= targetHills || i == 1) ) { if (!tile.terrainFeatures.contains(hill)) { tile.terrainFeatures.add(hill) @@ -287,10 +327,8 @@ class MapGenerator(val ruleset: Ruleset) { } } if (tile.terrainFeatures.remove(Constants.lowering) && (totalHills >= targetHills * 0.9f || i == 1)) { - if (tile.terrainFeatures.contains(hill)) { - tile.terrainFeatures.remove(hill) + if (tile.terrainFeatures.remove(hill)) totalHills-- - } } } } @@ -307,9 +345,29 @@ class MapGenerator(val ruleset: Ruleset) { tileMap.setTransients(ruleset) val scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble() + val temperatureExtremeness = tileMap.mapParameters.temperatureExtremeness + + class TerrainOccursRange( + val terrain: Terrain, + val tempFrom: Float, val tempTo: Float, + val humidFrom: Float, val humidTo: Float + ) + val limitsMap: List = + // List is OK here as it's only sequentially scanned + ruleset.terrains.values.flatMap { terrain -> + terrain.uniqueObjects.filter { + it.placeholderText == "Occurs at temperature between [] and [] and humidity between [] and []" + }.map { unique -> + TerrainOccursRange(terrain, + unique.params[0].toFloat(), unique.params[1].toFloat(), + unique.params[2].toFloat(), unique.params[3].toFloat()) + } + } + val noTerrainUniques = limitsMap.isEmpty() + val elevationTerrains = arrayOf(Constants.mountain, Constants.hill) - for (tile in tileMap.values) { - if (tile.isWater || tile.baseTerrain in arrayOf(Constants.mountain, Constants.hill)) + for (tile in tileMap.values.asSequence()) { + if (tile.isWater || tile.baseTerrain in elevationTerrains) continue val humidity = (randomness.getPerlinNoise(tile, humiditySeed, scale = scale, nOctaves = 1) + 1.0) / 2.0 @@ -317,36 +375,32 @@ class MapGenerator(val ruleset: Ruleset) { val randomTemperature = randomness.getPerlinNoise(tile, temperatureSeed, scale = scale, nOctaves = 1) val latitudeTemperature = 1.0 - 2.0 * abs(tile.latitude) / tileMap.maxLatitude var temperature = (5.0 * latitudeTemperature + randomTemperature) / 6.0 - temperature = abs(temperature).pow(1.0 - tileMap.mapParameters.temperatureExtremeness) * temperature.sign + temperature = abs(temperature).pow(1.0 - temperatureExtremeness) * temperature.sign // Old, static map generation rules - necessary for existing base ruleset mods to continue to function - if (ruleset.terrains.values.asSequence().flatMap { it.uniqueObjects } - .none { it.placeholderText == "Occurs at temperature between [] and [] and humidity between [] and []" }) { + if (noTerrainUniques) { tile.baseTerrain = when { temperature < -0.4 -> if (humidity < 0.5) Constants.snow else Constants.tundra temperature < 0.8 -> if (humidity < 0.5) Constants.plains else Constants.grassland temperature <= 1.0 -> if (humidity < 0.7) Constants.desert else Constants.plains else -> { - println(temperature) - Constants.lakes + println("applyHumidityAndTemperature: Invalid temperature $temperature") + Constants.grassland } } tile.setTerrainTransients() continue } - val matchingTerrain = ruleset.terrains.values.firstOrNull { terrain -> - terrain.uniqueObjects.any { - it.placeholderText == "Occurs at temperature between [] and [] and humidity between [] and []" - && it.params[0].toFloat() < temperature && temperature <= it.params[1].toFloat() - && it.params[2].toFloat() < humidity && humidity <= it.params[3].toFloat() - } + val matchingTerrain = limitsMap.firstOrNull { + it.tempFrom < temperature && temperature <= it.tempTo + && it.humidFrom < humidity && humidity <= it.humidTo } - if (matchingTerrain != null) tile.baseTerrain = matchingTerrain.name + if (matchingTerrain != null) tile.baseTerrain = matchingTerrain.terrain.name else { - tile.baseTerrain = ruleset.terrains.keys.first() - println("Temperature: $temperature, humidity: $humidity") + tile.baseTerrain = ruleset.terrains.values.firstOrNull { it.type == TerrainType.Land }?.name ?: Constants.grassland + println("applyHumidityAndTemperature: No terrain found for temperature: $temperature, humidity: $humidity") } tile.setTerrainTransients() } @@ -391,7 +445,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.terrainFeatures.any()) + if (tile.baseTerrain !in Constants.sea || tile.terrainFeatures.isNotEmpty()) continue val randomTemperature = randomness.getPerlinNoise(tile, temperatureSeed, scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble(), nOctaves = 1) @@ -430,35 +484,52 @@ class MapGenerationRandomness{ } - fun chooseSpreadOutLocations(number: Int, suitableTiles: List, initialDistance: Int): ArrayList { - for (distanceBetweenResources in initialDistance downTo 1) { - var availableTiles = suitableTiles.toList() - val chosenTiles = ArrayList() + fun chooseSpreadOutLocations(number: Int, suitableTiles: List, mapRadius: Int): ArrayList { + if (number <= 0) return ArrayList(0) - // If possible, we want to equalize the base terrains upon which - // the resources are found, so we save how many have been - // found for each base terrain and try to get one from the lowerst - val baseTerrainsToChosenTiles = HashMap() - for(tileInfo in availableTiles){ - if(tileInfo.baseTerrain !in baseTerrainsToChosenTiles) - baseTerrainsToChosenTiles[tileInfo.baseTerrain] = 0 - } + // Determine sensible initial distance from number of desired placements and mapRadius + // empiric formula comes very close to eliminating retries for distance. + // The `if` means if we need to fill 60% or more of the available tiles, no sense starting with minimum distance 2. + val sparsityFactor = (HexMath.getHexagonalRadiusForArea(suitableTiles.size) / mapRadius).pow(0.333f) + val initialDistance = if (number == 1 || number * 5 >= suitableTiles.size * 3) 1 + else max(1, (mapRadius * 0.666f / HexMath.getHexagonalRadiusForArea(number).pow(0.9f) * sparsityFactor + 0.5).toInt()) + + // If possible, we want to equalize the base terrains upon which + // the resources are found, so we save how many have been + // found for each base terrain and try to get one from the lowest + val baseTerrainsToChosenTiles = HashMap() + for (tileInfo in suitableTiles){ + if (tileInfo.baseTerrain !in baseTerrainsToChosenTiles) + baseTerrainsToChosenTiles[tileInfo.baseTerrain] = 0 + } + + for (distanceBetweenResources in initialDistance downTo 1) { + var availableTiles = suitableTiles + val chosenTiles = ArrayList(number) + + for (terrain in baseTerrainsToChosenTiles.keys) + baseTerrainsToChosenTiles[terrain] = 0 for (i in 1..number) { if (availableTiles.isEmpty()) break val orderedKeys = baseTerrainsToChosenTiles.entries .sortedBy { it.value }.map { it.key } val firstKeyWithTilesLeft = orderedKeys - .first { availableTiles.any { tile -> tile.baseTerrain== it} } - val chosenTile = availableTiles.filter { it.baseTerrain==firstKeyWithTilesLeft }.random(RNG) + .first { availableTiles.any { tile -> tile.baseTerrain == it} } + val chosenTile = availableTiles.filter { it.baseTerrain == firstKeyWithTilesLeft }.random(RNG) availableTiles = availableTiles.filter { it.aerialDistanceTo(chosenTile) > distanceBetweenResources } chosenTiles.add(chosenTile) - baseTerrainsToChosenTiles[firstKeyWithTilesLeft] = baseTerrainsToChosenTiles[firstKeyWithTilesLeft]!!+1 + baseTerrainsToChosenTiles[firstKeyWithTilesLeft] = baseTerrainsToChosenTiles[firstKeyWithTilesLeft]!! + 1 + } + if (chosenTiles.size == number || distanceBetweenResources == 1) { + // Either we got them all, or we're not going to get anything better + if (MapGenerator.consoleOutput && distanceBetweenResources < initialDistance) + println("chooseSpreadOutLocations: distance $distanceBetweenResources < initial $initialDistance") + return chosenTiles } - // Either we got them all, or we're not going to get anything better - if (chosenTiles.size == number || distanceBetweenResources == 1) return chosenTiles } - throw Exception("Couldn't choose suitable tiles for $number resources!") + // unreachable due to last loop iteration always returning and initialDistance >= 1 + throw Exception() } } @@ -475,15 +546,15 @@ class RiverCoordinate(val position: Vector2, val bottomRightOrLeft: BottomRightO fun getAdjacentPositions(): Sequence { // What's nice is that adjacents are always the OPPOSITE in terms of right-left - rights are adjacent to only lefts, and vice-versa // This means that a lot of obviously-wrong assignments are simple to spot - if (bottomRightOrLeft == BottomRightOrLeft.BottomLeft) { - return sequenceOf(RiverCoordinate(position, BottomRightOrLeft.BottomRight), // same tile, other side - RiverCoordinate(position.cpy().add(1f, 0f), BottomRightOrLeft.BottomRight), // tile to MY top-left, take its bottom right corner - RiverCoordinate(position.cpy().add(0f, -1f), BottomRightOrLeft.BottomRight) // Tile to MY bottom-left, take its bottom right + return if (bottomRightOrLeft == BottomRightOrLeft.BottomLeft) { + sequenceOf(RiverCoordinate(position, BottomRightOrLeft.BottomRight), // same tile, other side + RiverCoordinate(position.cpy().add(1f, 0f), BottomRightOrLeft.BottomRight), // tile to MY top-left, take its bottom right corner + RiverCoordinate(position.cpy().add(0f, -1f), BottomRightOrLeft.BottomRight) // Tile to MY bottom-left, take its bottom right ) } else { - return sequenceOf(RiverCoordinate(position, BottomRightOrLeft.BottomLeft), // same tile, other side - RiverCoordinate(position.cpy().add(0f, 1f), BottomRightOrLeft.BottomLeft), // tile to MY top-right, take its bottom left - RiverCoordinate(position.cpy().add(-1f, 0f), BottomRightOrLeft.BottomLeft) // tile to MY bottom-right, take its bottom left + sequenceOf(RiverCoordinate(position, BottomRightOrLeft.BottomLeft), // same tile, other side + RiverCoordinate(position.cpy().add(0f, 1f), BottomRightOrLeft.BottomLeft), // tile to MY top-right, take its bottom left + RiverCoordinate(position.cpy().add(-1f, 0f), BottomRightOrLeft.BottomLeft) // tile to MY bottom-right, take its bottom left ) } } diff --git a/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt index a5da1ef3b8..e427fddff5 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/NaturalWonderGenerator.kt @@ -40,7 +40,8 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration } } - println("Natural Wonders for this game: $toBeSpawned") + if (MapGenerator.consoleOutput) + println("Natural Wonders for this game: $toBeSpawned") for (wonder in toBeSpawned) { when (wonder.name) { @@ -67,7 +68,8 @@ class NaturalWonderGenerator(val ruleset: Ruleset, val randomness: MapGeneration return location } - println("No suitable location for ${wonder.name}") + if (MapGenerator.consoleOutput) + println("No suitable location for ${wonder.name}") return null } diff --git a/core/src/com/unciv/logic/map/mapgenerator/RiverGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/RiverGenerator.kt index 5a32e17b74..738aca1253 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/RiverGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/RiverGenerator.kt @@ -16,8 +16,8 @@ class RiverGenerator(val randomness: MapGenerationRandomness) { if (optionalTiles.size < numberOfRivers) optionalTiles = map.values.filter { it.isLand && it.aerialDistanceTo(getClosestWaterTile(it)) > 4 }.toMutableList() - - val riverStarts = randomness.chooseSpreadOutLocations(numberOfRivers, optionalTiles, 10) + val mapRadius = map.mapParameters.mapSize.radius + val riverStarts = randomness.chooseSpreadOutLocations(numberOfRivers, optionalTiles, mapRadius) for (tile in riverStarts) spawnRiver(tile, map) for (tile in map.values) {