Snow, Ice, Atoll & Map Generation (#1909)

* Snow, Atoll & Ice

* Fix White Hexagon + Small NW refactor

* More Land in Continents #1886

* Atoll can spawn only on Coast

* Added new constants and turned Constant into an object

* Latitude and Longitude utility methods

* New MapGenerator steps

* New MapParameters & MapGenerator cleanup

* Added New Map option to MapEditor menu

* New parameters default values and limits

* archipelagos map type

* Translations & Atlas

* removing unneeded octave displacement

* Fix Archipelago

* Perlin noise parameters & no-elvis in TileMap

* Rebuilt Atlas

Co-authored-by: Eddh <remi.dufour@protonmail.com>
This commit is contained in:
Federico Luongo 2020-03-11 10:39:37 +01:00 committed by GitHub
parent 15098d877c
commit 2a67294554
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 3233 additions and 3106 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 907 KiB

After

Width:  |  Height:  |  Size: 885 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 KiB

After

Width:  |  Height:  |  Size: 394 KiB

View file

@ -68,7 +68,6 @@
"impassable": true,
"RGB": [89, 45, 0]
},
/*
{
"name": "Snow",
"type": "Land",
@ -76,7 +75,6 @@
"defenceBonus": -0.1,
"RGB": [153, 255, 255]
},
*/
// Terrain features
{
@ -139,6 +137,21 @@
"defenceBonus": -0.1,
"occursOn": ["Desert"]
},
{
"name": "Ice",
"type": "TerrainFeature",
"impassable": true,
"overrideStats": true,
"occursOn": ["Ocean", "Coast"]
},
{
"name": "Atoll",
"type": "TerrainFeature",
"movementCost": 1,
"food": 1,
"production": 1,
"occursOn": ["Coast"]
},
// Natural Wonders
{

View file

@ -48,7 +48,7 @@
{
"name": "Stone",
"resourceType": "Bonus",
"terrainsCanBeFoundOn": ["Plains","Desert"],
"terrainsCanBeFoundOn": ["Plains","Desert","Snow"],
"production": 1,
"improvement": "Quarry",
"improvementStats": {"production": 1},

View file

@ -537,11 +537,11 @@ Hide advanced settings = Nascondi avanzate
Map Height = Altezza mappa
Temperature extremeness = Estremità temperatura
Resource richness = Abbondanza risorse
Terrain Features richness = Abbondanza caratteristiche terrene
Vegetation richness = Abbondanza vegetazione
Rare features richness = Abbondanza caratteristiche terrene
Max Coast extension = Estensione delle coste
Biome areas extension = Estensioni biomi
Water percent = Percentuale d'acqua
Land percent = Percentuale terrestre
Water level = Livello dell'acqua
Reset to default = Ripristina default
HIGHLY EXPERIMENTAL - YOU HAVE BEEN WARNED! = IN FASE SPERIMENTALE - TI ABBIAMO AVVERTITO!
@ -1360,6 +1360,8 @@ Coast = Costa
Ocean = Oceano
Flood plains = Pianure allagate
Impassible = Inaccessibile
Atoll = Atollo
Ice = Ghiaccio
# Natural Wonders

View file

@ -535,11 +535,11 @@ Hide advanced settings =
Map Height =
Temperature extremeness =
Resource richness =
Terrain Features richness =
Vegetation richness =
Rare features richness =
Max Coast extension =
Biome areas extension =
Water percent =
Land percent =
Water level =
Reset to default =
HIGHLY EXPERIMENTAL - YOU HAVE BEEN WARNED! =
@ -1358,6 +1358,8 @@ Coast =
Ocean =
Flood plains =
Impassible =
Atoll =
Ice =
# Natural Wonders

View file

@ -1,51 +1,55 @@
package com.unciv
class Constants{
companion object {
const val worker = "Worker"
const val settler = "Settler"
const val greatGeneral = "Great General"
object Constants {
const val worker = "Worker"
const val settler = "Settler"
const val greatGeneral = "Great General"
const val ocean="Ocean"
const val mountain="Mountain"
const val forest = "Forest"
const val jungle = "Jungle"
const val hill = "Hill"
const val coast = "Coast"
const val plains = "Plains"
const val lakes = "Lakes"
const val desert = "Desert"
const val grassland = "Grassland"
const val tundra = "Tundra"
const val ocean = "Ocean"
const val coast = "Coast"
const val mountain = "Mountain"
const val hill = "Hill"
const val plains = "Plains"
const val lakes = "Lakes"
const val desert = "Desert"
const val grassland = "Grassland"
const val tundra = "Tundra"
const val snow = "Snow"
const val marsh = "Marsh"
const val forest = "Forest"
const val jungle = "Jungle"
const val barringerCrater = "Barringer Crater"
const val grandMesa = "Grand Mesa"
const val greatBarrierReef = "Great Barrier Reef"
const val krakatoa = "Krakatoa"
const val mountFuji = "Mount Fuji"
const val oldFaithful = "Old Faithful"
const val rockOfGibraltar = "Rock of Gibraltar"
const val cerroDePotosi = "Cerro de Potosi"
const val elDorado = "El Dorado"
const val fountainOfYouth = "Fountain of Youth"
const val marsh = "Marsh"
const val oasis = "Oasis"
const val atoll = "Atoll"
const val ice = "Ice"
val vegetation = arrayOf(forest, jungle)
val sea = arrayOf(ocean, coast)
const val barbarianEncampment = "Barbarian encampment"
const val ancientRuins = "Ancient ruins"
const val barringerCrater = "Barringer Crater"
const val grandMesa = "Grand Mesa"
const val greatBarrierReef = "Great Barrier Reef"
const val krakatoa = "Krakatoa"
const val mountFuji = "Mount Fuji"
const val oldFaithful = "Old Faithful"
const val rockOfGibraltar = "Rock of Gibraltar"
const val cerroDePotosi = "Cerro de Potosi"
const val elDorado = "El Dorado"
const val fountainOfYouth = "Fountain of Youth"
const val peaceTreaty = "Peace Treaty"
const val researchAgreement = "Research Agreement"
const val openBorders = "Open Borders"
const val random = "Random"
val greatImprovements = listOf("Academy", "Landmark", "Manufactory", "Customs house")
const val barbarianEncampment = "Barbarian encampment"
const val ancientRuins = "Ancient ruins"
val unitActionSetUp = "Set Up"
val unitActionSleep = "Sleep"
val unitActionSleepUntilHealed = "Sleep until healed"
val unitActionAutomation = "Automate"
val unitActionExplore = "Explore"
val futureTech = "Future Tech"
const val peaceTreaty = "Peace Treaty"
const val researchAgreement = "Research Agreement"
const val openBorders = "Open Borders"
const val random = "Random"
val greatImprovements = listOf("Academy", "Landmark", "Manufactory", "Customs house")
}
val unitActionSetUp = "Set Up"
val unitActionSleep = "Sleep"
val unitActionSleepUntilHealed = "Sleep until healed"
val unitActionAutomation = "Automate"
val unitActionExplore = "Explore"
val futureTech = "Future Tech"
}

View file

@ -34,13 +34,15 @@ class MapGenerator(val ruleset: Ruleset) {
seedRNG(seed)
generateLand(map)
divideIntoBiomes(map)
raiseMountainsAndHills(map)
applyHumidityAndTemperature(map)
spawnLakesAndCoasts(map)
randomizeTiles(map)
spawnVegetation(map)
spawnRareFeatures(map)
spawnIce(map)
spreadResources(map)
spreadAncientRuins(map)
spawnNaturalWonders(map)
return map
}
@ -94,120 +96,6 @@ class MapGenerator(val ruleset: Ruleset) {
}
}
private fun randomizeTiles(tileMap: TileMap) {
for (tile in tileMap.values) {
if (tile.getBaseTerrain().type == TerrainType.Land && RNG.nextDouble() < tileMap.mapParameters.mountainProbability) {
tile.baseTerrain = Constants.mountain
tile.setTransients()
}
addRandomTerrainFeature(tile, tileMap.mapParameters)
}
}
private fun divideIntoBiomes(tileMap: TileMap) {
val averageTilesPerArea = tileMap.mapParameters.tilesPerBiomeArea
val waterPercent = tileMap.mapParameters.waterProbability
val maxLatitude = tileMap.values.map { abs(HexMath.getLatitude(it.position)) }.max()!!
val areas = ArrayList<Area>()
val terrains = ruleset.terrains.values
.filter { it.type === TerrainType.Land && it.name != Constants.lakes && it.name != Constants.mountain }
// So we know it's not chosen
for (tile in tileMap.values.filter { it.baseTerrain == Constants.grassland })
tile.baseTerrain = ""
while (tileMap.values.any { it.baseTerrain == "" }) // the world could be split into lots off tiny islands, and every island deserves land types
{
val emptyTiles = tileMap.values.filter { it.baseTerrain == "" }.toMutableList()
val numberOfSeeds = ceil(emptyTiles.size / averageTilesPerArea.toFloat()).toInt()
for (i in 0 until numberOfSeeds) {
var terrain = if (RNG.nextDouble() < waterPercent) Constants.ocean
else terrains.random(RNG).name
val tile = emptyTiles.random(RNG)
val desertBand = maxLatitude * 0.5 * tileMap.mapParameters.temperatureExtremeness
val tundraBand = maxLatitude * (1 - 0.5 * tileMap.mapParameters.temperatureExtremeness)
if (abs(HexMath.getLatitude(tile.position)) < desertBand) {
if (terrain in arrayOf(Constants.grassland, Constants.tundra))
terrain = Constants.desert
} else if (abs(HexMath.getLatitude(tile.position)) > tundraBand) {
if (terrain in arrayOf(Constants.grassland, Constants.plains, Constants.desert, Constants.ocean))
terrain = Constants.tundra
} else {
if (terrain == Constants.tundra) terrain = Constants.plains
else if (terrain == Constants.desert) terrain = Constants.grassland
}
val area = Area(terrain)
emptyTiles -= tile
area.addTile(tile)
areas += area
}
expandAreas(areas)
expandAreas(areas)
}
for (tile in tileMap.values)
tile.setTransients()
}
private fun expandAreas(areas: ArrayList<Area>) {
val expandableAreas = ArrayList<Area>(areas)
while (expandableAreas.isNotEmpty()) {
val areaToExpand = expandableAreas.random(RNG)
if (areaToExpand.tiles.size >= 20) {
expandableAreas -= areaToExpand
continue
}
val availableExpansionTiles = areaToExpand.tiles
.flatMap { it.neighbors }.distinct()
.filter { it.baseTerrain == "" }
if (availableExpansionTiles.isEmpty()) expandableAreas -= areaToExpand
else {
val expansionTile = availableExpansionTiles.random(RNG)
areaToExpand.addTile(expansionTile)
val areasToJoin = areas.filter {
it.terrain == areaToExpand.terrain
&& it != areaToExpand
&& it.tiles.any { tile -> tile in expansionTile.neighbors }
}
for (area in areasToJoin) {
areaToExpand.tiles += area.tiles
areas.remove(area)
expandableAreas.remove(area)
}
}
}
}
private fun addRandomTerrainFeature(tileInfo: TileInfo, mapParameters: MapParameters) {
if (tileInfo.getBaseTerrain().canHaveOverlay && RNG.nextDouble() < mapParameters.terrainFeatureRichness) {
val secondaryTerrains = ruleset.terrains.values
.filter { it.type === TerrainType.TerrainFeature &&
it.occursOn != null &&
it.occursOn.contains(tileInfo.baseTerrain) }
if (secondaryTerrains.any())
tileInfo.terrainFeature = secondaryTerrains.random(RNG).name
}
}
private fun spreadAncientRuins(map: TileMap) {
if(map.mapParameters.noRuins)
return
@ -218,15 +106,15 @@ class MapGenerator(val ruleset: Ruleset) {
tile.improvement = Constants.ancientRuins
}
private fun spreadResources(mapToReturn: TileMap) {
val distance = mapToReturn.mapParameters.size.radius
for (tile in mapToReturn.values)
private fun spreadResources(tileMap: TileMap) {
val distance = tileMap.mapParameters.size.radius
for (tile in tileMap.values)
if (tile.resource != null)
tile.resource = null
spreadStrategicResources(mapToReturn, distance)
spreadResource(mapToReturn, distance, ResourceType.Luxury)
spreadResource(mapToReturn, distance, ResourceType.Bonus)
spreadStrategicResources(tileMap, distance)
spreadResources(tileMap, distance, ResourceType.Luxury)
spreadResources(tileMap, distance, ResourceType.Bonus)
}
//region natural-wonders
@ -264,16 +152,16 @@ class MapGenerator(val ruleset: Ruleset) {
for (wonder in toBeSpawned) {
when (wonder.name) {
Constants.barringerCrater -> spawnBarringerCrater(tileMap, ruleset)
Constants.mountFuji -> spawnMountFuji(tileMap, ruleset)
Constants.grandMesa -> spawnGrandMesa(tileMap, ruleset)
Constants.greatBarrierReef -> spawnGreatBarrierReef(tileMap, ruleset, mapRadius)
Constants.krakatoa -> spawnKrakatoa(tileMap, ruleset)
Constants.rockOfGibraltar -> spawnRockOfGibraltar(tileMap, ruleset)
Constants.oldFaithful -> spawnOldFaithful(tileMap, ruleset)
Constants.cerroDePotosi -> spawnCerroDePotosi(tileMap, ruleset)
Constants.elDorado -> spawnElDorado(tileMap, ruleset)
Constants.fountainOfYouth -> spawnFountainOfYouth(tileMap, ruleset)
Constants.barringerCrater -> spawnBarringerCrater(tileMap)
Constants.mountFuji -> spawnMountFuji(tileMap)
Constants.grandMesa -> spawnGrandMesa(tileMap)
Constants.greatBarrierReef -> spawnGreatBarrierReef(tileMap)
Constants.krakatoa -> spawnKrakatoa(tileMap)
Constants.rockOfGibraltar -> spawnRockOfGibraltar(tileMap)
Constants.oldFaithful -> spawnOldFaithful(tileMap)
Constants.cerroDePotosi -> spawnCerroDePotosi(tileMap)
Constants.elDorado -> spawnElDorado(tileMap)
Constants.fountainOfYouth -> spawnFountainOfYouth(tileMap)
}
}
}
@ -296,9 +184,9 @@ class MapGenerator(val ruleset: Ruleset) {
Must be in tundra or desert; cannot be adjacent to grassland; can be adjacent to a maximum
of 2 mountains and a maximum of 4 hills and mountains; avoids oceans; becomes mountain
*/
private fun spawnBarringerCrater(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnBarringerCrater(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.barringerCrater]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
&& it.neighbors.count{ neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 2
@ -312,9 +200,9 @@ class MapGenerator(val ruleset: Ruleset) {
Mt. Fuji: Must be in grass or plains; cannot be adjacent to tundra, desert, marsh, or mountains;
can be adjacent to a maximum of 2 hills; becomes mountain
*/
private fun spawnMountFuji(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnMountFuji(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.mountFuji]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.tundra }
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.desert }
@ -330,9 +218,9 @@ class MapGenerator(val ruleset: Ruleset) {
Grand Mesa: Must be in plains, desert, or tundra, and must be adjacent to at least 2 hills;
cannot be adjacent to grass; can be adjacent to a maximum of 2 mountains; avoids oceans; becomes mountain
*/
private fun spawnGrandMesa(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnGrandMesa(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.grandMesa]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.count{ neighbor -> neighbor.getBaseTerrain().name == Constants.hill } >= 2
&& it.neighbors.none { neighbor -> neighbor.getBaseTerrain().name == Constants.grassland }
@ -345,15 +233,13 @@ class MapGenerator(val ruleset: Ruleset) {
/*
Great Barrier Reef: Specifics currently unknown;
Assumption: at least 1 neighbour not water; no tundra; at least 1 neighbour coast; becomes coast
TODO: investigate Great Barrier Reef placement requirements
*/
private fun spawnGreatBarrierReef(mapToReturn: TileMap, ruleset: Ruleset, mapRadius: Int) {
private fun spawnGreatBarrierReef(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.greatBarrierReef]!!
val maxLatitude = abs(HexMath.getLatitude(Vector2(mapRadius.toFloat(), mapRadius.toFloat())))
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& abs(HexMath.getLatitude(it.position)) > maxLatitude * 0.1
&& abs(HexMath.getLatitude(it.position)) < maxLatitude * 0.7
&& abs(it.latitude) > tileMap.maxLatitude * 0.1
&& abs(it.latitude) < tileMap.maxLatitude * 0.7
&& it.neighbors.all {neighbor -> neighbor.isWater}
&& it.neighbors.any {neighbor ->
neighbor.resource == null && neighbor.improvement == null
@ -378,13 +264,13 @@ class MapGenerator(val ruleset: Ruleset) {
/*
Krakatoa: Must spawn in the ocean next to at least 1 shallow water tile; cannot be adjacent
to ice; changes tiles around it to shallow water; mountain
TODO: cannot be adjacent to ice
*/
private fun spawnKrakatoa(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnKrakatoa(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.krakatoa]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.any { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
&& it.neighbors.none { neighbor -> neighbor.getLastTerrain().name == Constants.ice}
}
val location = trySpawnOnSuitableLocation(suitableLocations, wonder)
@ -403,11 +289,10 @@ class MapGenerator(val ruleset: Ruleset) {
Rock of Gibraltar: Specifics currently unknown
Assumption: spawn on grassland, at least 1 coast and 1 mountain adjacent;
turn neighbours into coast)
TODO: investigate Rock of Gibraltar placement requirements
*/
private fun spawnRockOfGibraltar(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnRockOfGibraltar(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.rockOfGibraltar]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.any { neighbor -> neighbor.getBaseTerrain().name == Constants.coast }
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } == 1
@ -432,9 +317,9 @@ class MapGenerator(val ruleset: Ruleset) {
more than 4 mountains, and cannot be adjacent to more than 3 desert or 3 tundra tiles;
avoids oceans; becomes mountain
*/
private fun spawnOldFaithful(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnOldFaithful(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.oldFaithful]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain } <= 4
&& it.neighbors.count { neighbor -> neighbor.getBaseTerrain().name == Constants.mountain ||
@ -449,9 +334,9 @@ class MapGenerator(val ruleset: Ruleset) {
/*
Cerro de Potosi: Must be adjacent to at least 1 hill; avoids oceans; becomes mountain
*/
private fun spawnCerroDePotosi(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnCerroDePotosi(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.cerroDePotosi]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.any { neighbor -> neighbor.getBaseTerrain().name == Constants.hill }
}
@ -462,9 +347,9 @@ class MapGenerator(val ruleset: Ruleset) {
/*
El Dorado: Must be next to at least 1 jungle tile; avoids oceans; becomes flatland plains
*/
private fun spawnElDorado(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnElDorado(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.elDorado]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name)
&& it.neighbors.any { neighbor -> neighbor.getLastTerrain().name == Constants.jungle }
}
@ -475,9 +360,9 @@ class MapGenerator(val ruleset: Ruleset) {
/*
Fountain of Youth: Avoids oceans; becomes flatland plains
*/
private fun spawnFountainOfYouth(mapToReturn: TileMap, ruleset: Ruleset) {
private fun spawnFountainOfYouth(tileMap: TileMap) {
val wonder = ruleset.terrains[Constants.fountainOfYouth]!!
val suitableLocations = mapToReturn.values.filter { it.resource == null && it.improvement == null
val suitableLocations = tileMap.values.filter { it.resource == null && it.improvement == null
&& wonder.occursOn!!.contains(it.getLastTerrain().name) }
trySpawnOnSuitableLocation(suitableLocations, wonder)
@ -485,30 +370,32 @@ class MapGenerator(val ruleset: Ruleset) {
//endregion
// 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(mapToReturn: TileMap, distance: Int) {
val resourcesOfType = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic }
val totalNumberOfResources = mapToReturn.values.count { it.isLand && !it.getBaseTerrain().impassable } *
mapToReturn.mapParameters.resourceRichness
val resourcesPerType = (totalNumberOfResources/resourcesOfType.size).toInt()
for (resource in resourcesOfType) {
val suitableTiles = mapToReturn.values
private fun spreadStrategicResources(tileMap: TileMap, distance: Int) {
val strategicResources = ruleset.tileResources.values.filter { it.resourceType == ResourceType.Strategic }
val totalNumberOfResources = tileMap.values.count { it.isLand && !it.getBaseTerrain().impassable } *
tileMap.mapParameters.resourceRichness
val resourcesPerType = (totalNumberOfResources/strategicResources.size).toInt()
for (resource in strategicResources) {
val suitableTiles = tileMap.values
.filter { it.resource == null && resource.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) }
val locations = chooseSpreadOutLocations(resourcesPerType, suitableTiles, distance)
for (location in locations) location.resource = resource.name
}
}
// Here, we need there to be some luxury/bonus resource - it matters less what
private fun spreadResource(mapToReturn: TileMap, distance: Int, resourceType: ResourceType) {
/**
* Spreads resources of type [resourceType] picking locations at [distance] from each other.
* [MapParameters.resourceRichness] used to control how many resources to spawn.
*/
private fun spreadResources(tileMap: TileMap, distance: Int, resourceType: ResourceType) {
val resourcesOfType = ruleset.tileResources.values.filter { it.resourceType == resourceType }
val suitableTiles = mapToReturn.values
val suitableTiles = tileMap.values
.filter { it.resource == null && resourcesOfType.any { r -> r.terrainsCanBeFoundOn.contains(it.getLastTerrain().name) } }
val numberOfResources = mapToReturn.values.count { it.isLand && !it.getBaseTerrain().impassable } *
mapToReturn.mapParameters.resourceRichness
val numberOfResources = tileMap.values.count { it.isLand && !it.getBaseTerrain().impassable } *
tileMap.mapParameters.resourceRichness
val locations = chooseSpreadOutLocations(numberOfResources.toInt(), suitableTiles, distance)
val resourceToNumber = Counter<String>()
@ -533,10 +420,10 @@ class MapGenerator(val ruleset: Ruleset) {
// 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<String,Int>()
val baseTerrainsToChosenTiles = HashMap<String, Int>()
for(tileInfo in availableTiles){
if(tileInfo.baseTerrain !in baseTerrainsToChosenTiles)
baseTerrainsToChosenTiles.put(tileInfo.baseTerrain,0)
baseTerrainsToChosenTiles[tileInfo.baseTerrain] = 0
}
for (i in 1..numberOfResources) {
@ -556,6 +443,123 @@ class MapGenerator(val ruleset: Ruleset) {
throw Exception("Couldn't choose suitable tiles for $numberOfResources resources!")
}
/**
* [MapParameters.elevationExponent] favors high elevation
*/
private fun raiseMountainsAndHills(tileMap: TileMap) {
val elevationSeed = RNG.nextInt().toDouble()
tileMap.setTransients(ruleset)
for (tile in tileMap.values.filter { !it.isWater }) {
var elevation = getPerlinNoise(tile, elevationSeed, scale = 3.0)
elevation = abs(elevation).pow(1.0 - tileMap.mapParameters.elevationExponent.toDouble()) * elevation.sign
if (elevation <= 0.5) tile.baseTerrain = Constants.plains
else if (elevation <= 0.7) tile.baseTerrain = Constants.hill
else if (elevation <= 1.0) tile.baseTerrain = Constants.mountain
}
}
/**
* [MapParameters.tilesPerBiomeArea] to set biomes size
* [MapParameters.temperatureExtremeness] to favor very high and very low temperatures
*/
private fun applyHumidityAndTemperature(tileMap: TileMap) {
val humiditySeed = RNG.nextInt().toDouble()
val temperatureSeed = RNG.nextInt().toDouble()
tileMap.setTransients(ruleset)
val scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble()
for (tile in tileMap.values) {
if (tile.isWater || tile.baseTerrain in arrayOf(Constants.mountain, Constants.hill))
continue
val humidity = (getPerlinNoise(tile, humiditySeed, scale = scale, nOctaves = 1) + 1.0) / 2.0
val randomTemperature = 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
tile.baseTerrain = when {
temperature < -0.4 -> {
when {
humidity < 0.5 -> Constants.snow
else -> Constants.tundra
}
}
temperature < 0.8 -> {
when {
humidity < 0.5 -> Constants.plains
else -> Constants.grassland
}
}
temperature <= 1.0 -> {
when {
humidity < 0.7 -> Constants.desert
else -> Constants.plains
}
}
else -> {
println(temperature)
Constants.lakes
}
}
}
}
/**
* [MapParameters.vegetationOccurrance] is the threshold for vegetation spawn
*/
private fun spawnVegetation(tileMap: TileMap) {
val vegetationSeed = RNG.nextInt().toDouble()
val candidateTerrains = Constants.vegetation.flatMap{ ruleset.terrains[it]!!.occursOn!! }
for (tile in tileMap.values.asSequence().filter { it.baseTerrain in candidateTerrains && it.terrainFeature == null}) {
val vegetation = (getPerlinNoise(tile, vegetationSeed, scale = 3.0, nOctaves = 1) + 1.0) / 2.0
if (vegetation <= tileMap.mapParameters.vegetationRichness)
tile.terrainFeature = Constants.vegetation.filter { ruleset.terrains[it]!!.occursOn!!.contains(tile.baseTerrain) }.random(RNG)
}
}
/**
* [MapParameters.rareFeaturesProbability] is the probability of spawning a rare feature
*/
private fun spawnRareFeatures(tileMap: TileMap) {
val rareFeatures = ruleset.terrains.values.filter {
it.type == TerrainType.TerrainFeature &&
it.name !in Constants.vegetation &&
it.name != Constants.ice
}
for (tile in tileMap.values.asSequence().filter { it.terrainFeature == null }) {
if (RNG.nextDouble() <= tileMap.mapParameters.rareFeaturesRichness) {
val possibleFeatures = rareFeatures.filter { it.occursOn != null && it.occursOn.contains(tile.baseTerrain) }
if (possibleFeatures.any())
tile.terrainFeature = possibleFeatures.random(RNG).name
}
}
}
/**
* [MapParameters.temperatureExtremeness] as in [applyHumidityAndTemperature]
*/
private fun spawnIce(tileMap: TileMap) {
tileMap.setTransients(ruleset)
val temperatureSeed = RNG.nextInt().toDouble()
for (tile in tileMap.values) {
if (tile.baseTerrain !in Constants.sea || tile.terrainFeature != null)
continue
val randomTemperature = getPerlinNoise(tile, temperatureSeed, scale = tileMap.mapParameters.tilesPerBiomeArea.toDouble(), nOctaves = 1)
val latitudeTemperature = 1.0 - 2.0 * abs(tile.latitude) / tileMap.maxLatitude
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
}
}
companion object MapLandmassGenerator {
var RNG = Random(42)
@ -564,9 +568,16 @@ class MapGenerator(val ruleset: Ruleset) {
MapType.pangaea -> createPangea(tileMap)
MapType.continents -> createTwoContinents(tileMap)
MapType.perlin -> createPerlin(tileMap)
MapType.archipelago -> createArchipelago(tileMap)
MapType.default -> generateLandCellularAutomata(tileMap)
}
}
private fun spawnLandOrWater(tile: TileInfo, elevation: Double, threshold: Double) {
when {
elevation < threshold -> tile.baseTerrain = Constants.ocean
else -> tile.baseTerrain = Constants.grassland
}
}
private fun smooth(tileMap: TileMap) {
for (tileInfo in tileMap.values) {
@ -585,11 +596,15 @@ class MapGenerator(val ruleset: Ruleset) {
val elevationSeed = RNG.nextInt().toDouble()
for (tile in tileMap.values) {
var elevation = getPerlinNoise(tile, elevationSeed)
spawnLandOrWater(tile, elevation, tileMap.mapParameters.waterThreshold.toDouble())
}
}
when {
elevation < 0 -> tile.baseTerrain = Constants.ocean
else -> tile.baseTerrain = Constants.grassland
}
private fun createArchipelago(tileMap: TileMap) {
val elevationSeed = RNG.nextInt().toDouble()
for (tile in tileMap.values) {
var elevation = getRidgedPerlinNoise(tile, elevationSeed)
spawnLandOrWater(tile, elevation, 0.25 + tileMap.mapParameters.waterThreshold.toDouble())
}
}
@ -598,11 +613,7 @@ class MapGenerator(val ruleset: Ruleset) {
for (tile in tileMap.values) {
var elevation = getPerlinNoise(tile, elevationSeed)
elevation = (elevation + getCircularNoise(tile, tileMap) ) / 2.0
when {
elevation < 0 -> tile.baseTerrain = Constants.ocean
else -> tile.baseTerrain = Constants.grassland
}
spawnLandOrWater(tile, elevation, tileMap.mapParameters.waterThreshold.toDouble())
}
}
@ -611,11 +622,7 @@ class MapGenerator(val ruleset: Ruleset) {
for (tile in tileMap.values) {
var elevation = getPerlinNoise(tile, elevationSeed)
elevation = (elevation + getTwoContinentsTransform(tile, tileMap)) / 2.0
when {
elevation < 0 -> tile.baseTerrain = Constants.ocean
else -> tile.baseTerrain = Constants.grassland
}
spawnLandOrWater(tile, elevation, tileMap.mapParameters.waterThreshold.toDouble())
}
}
@ -628,10 +635,9 @@ class MapGenerator(val ruleset: Ruleset) {
private fun getTwoContinentsTransform(tileInfo: TileInfo, tileMap: TileMap): Double {
val randomScale = RNG.nextDouble()
val maxLongitude = abs(tileMap.values.map { abs(HexMath.getLongitude(it.position)) }.max()!!)
val longitudeFactor = abs(HexMath.getLongitude(tileInfo.position))/maxLongitude
val longitudeFactor = abs(tileInfo.longitude) / tileMap.maxLongitude
return min(0.0,-1.0 + (5.0 * longitudeFactor.pow(0.7f) + randomScale) / 3.0)
return min(0.2,-1.0 + (5.0 * longitudeFactor.pow(0.6f) + randomScale) / 3.0)
}
private fun percentualDistanceToCenter(tileInfo: TileInfo, tileMap: TileMap): Double {
@ -644,6 +650,14 @@ class MapGenerator(val ruleset: Ruleset) {
}
}
/**
* Generates a perlin noise channel combining multiple octaves
*
* [nOctaves] is the number of octaves
* [persistence] is the scaling factor of octave amplitudes
* [lacunarity] is the scaling factor of octave frequencies
* [scale] is the distance the noise is observed from
*/
private fun getPerlinNoise(tile: TileInfo, seed: Double,
nOctaves: Int = 6,
persistence: Double = 0.5,
@ -653,6 +667,18 @@ class MapGenerator(val ruleset: Ruleset) {
return Perlin.noise3d(worldCoords.x.toDouble(), worldCoords.y.toDouble(), seed, nOctaves, persistence, lacunarity, scale)
}
/**
* Generates ridged perlin noise. As for parameters see [getPerlinNoise]
*/
private fun getRidgedPerlinNoise(tile: TileInfo, seed: Double,
nOctaves: Int = 10,
persistence: Double = 0.5,
lacunarity: Double = 2.0,
scale: Double = 15.0): Double {
val worldCoords = HexMath.hex2WorldCoords(tile.position)
return Perlin.ridgedNoise3d(worldCoords.x.toDouble(), worldCoords.y.toDouble(), seed, nOctaves, persistence, lacunarity, scale)
}
// region Cellular automata
private fun generateLandCellularAutomata(tileMap: TileMap) {
val mapRadius = tileMap.mapParameters.size.radius
@ -691,7 +717,6 @@ class MapGenerator(val ruleset: Ruleset) {
private fun getInitialTerrainCellularAutomata(tileInfo: TileInfo, mapParameters: MapParameters): TerrainType {
val landProbability = mapParameters.landProbability
val mapRadius = mapParameters.size.radius
// default
@ -701,18 +726,9 @@ class MapGenerator(val ruleset: Ruleset) {
if (HexMath.getDistance(Vector2.Zero, tileInfo.position) > 0.85f * mapRadius) {
if (RNG.nextDouble() < 0.2) return TerrainType.Land else return TerrainType.Water
}
if (RNG.nextDouble() < landProbability) return TerrainType.Land else return TerrainType.Water
if (RNG.nextDouble() < 0.55) return TerrainType.Land else return TerrainType.Water
}
// endregion
}
}
class Area(var terrain: String) {
val tiles = ArrayList<TileInfo>()
fun addTile(tileInfo: TileInfo) {
tiles += tileInfo
tileInfo.baseTerrain = terrain
}
}

View file

@ -17,6 +17,7 @@ object MapType {
const val pangaea = "Pangaea"
const val continents = "Continents"
const val perlin = "Perlin"
const val archipelago = "Archipelago"
// Cellular automata
const val default = "Default"
@ -39,21 +40,21 @@ class MapParameters {
var seed: Long = 0
var tilesPerBiomeArea = 6
var maxCoastExtension = 2
var mountainProbability = 0.10f
var temperatureExtremeness = 0.30f
var terrainFeatureRichness = 0.30f
var resourceRichness = 0.10f
var waterProbability = 0.05f
var landProbability = 0.55f
var elevationExponent = 0.8f
var temperatureExtremeness = 0.6f
var vegetationRichness = 0.4f
var rareFeaturesRichness = 0.05f
var resourceRichness = 0.1f
var waterThreshold = 0f
fun resetAdvancedSettings() {
tilesPerBiomeArea = 6
maxCoastExtension = 2
mountainProbability = 0.10f
temperatureExtremeness = 0.30f
terrainFeatureRichness = 0.30f
resourceRichness = 0.10f
waterProbability = 0.05f
landProbability = 0.55f
elevationExponent = 0.8f
temperatureExtremeness = 0.6f
vegetationRichness = 0.4f
rareFeaturesRichness = 0.05f
resourceRichness = 0.1f
waterThreshold = 0f
}
}

View file

@ -1,6 +1,7 @@
package com.unciv.logic.map
import kotlin.math.floor
import kotlin.math.abs
// version 1.1.3
// From https://rosettacode.org/wiki/Perlin_noise#Kotlin
@ -54,6 +55,29 @@ object Perlin {
return total/max
}
fun ridgedNoise3d(x: Double, y: Double, z: Double,
nOctaves: Int = 3,
persistence: Double = 0.5,
lacunarity: Double = 2.0,
scale: Double = 10.0): Double {
var freq = 1.0
var amp = 1.0
var max = 0.0
var total = 0.0
for (i in 0 until nOctaves) {
var value = noise(
x * freq / scale,
y * freq / scale,
z * freq / scale)
value = abs(value)
total += amp * value
max += amp
freq *= lacunarity
amp *= persistence
}
return total/max
}
fun noise(x: Double, y: Double, z: Double): Double {
// Find unit cube that contains point
val xi = floor(x).toInt() and 255

View file

@ -4,6 +4,7 @@ import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.UniqueAbility
import com.unciv.logic.HexMath
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.ruleset.Ruleset
@ -42,6 +43,11 @@ open class TileInfo {
var hasBottomRiver = false
var hasBottomLeftRiver = false
val latitude: Float
get() = HexMath.getLatitude(position)
val longitude: Float
get() = HexMath.getLongitude(position)
fun clone(): TileInfo {
val toReturn = TileInfo()
if(militaryUnit!=null) toReturn.militaryUnit=militaryUnit!!.clone()

View file

@ -6,6 +6,7 @@ import com.unciv.logic.GameInfo
import com.unciv.logic.HexMath
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.ruleset.Ruleset
import kotlin.math.abs
class TileMap {
@ -13,25 +14,21 @@ class TileMap {
@Transient var tileMatrix = ArrayList<ArrayList<TileInfo?>>() // this works several times faster than a hashmap, the performance difference is really astounding
@Transient var leftX = 0
@Transient var bottomY = 0
@delegate:Transient val maxLatitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.latitude) }.max()!! }
@delegate:Transient val maxLongitude: Float by lazy { if (values.isEmpty()) 0f else values.map { abs(it.longitude) }.max()!! }
var mapParameters = MapParameters()
@Deprecated("as of 2.7.10")
private var tiles = HashMap<String, TileInfo>()
var mapParameters = MapParameters()
private var tileList = ArrayList<TileInfo>()
constructor() // for json parsing, we need to have a default constructor
fun clone(): TileMap {
val toReturn = TileMap()
toReturn.tileList.addAll(tileList.map { it.clone() })
toReturn.mapParameters = mapParameters
return toReturn
}
val values: Collection<TileInfo>
get() = tileList
/** for json parsing, we need to have a default constructor */
constructor()
/** generates an hexagonal map of given radius */
constructor(radius:Int, ruleset: Ruleset){
@ -50,6 +47,12 @@ class TileMap {
setTransients(ruleset)
}
fun clone(): TileMap {
val toReturn = TileMap()
toReturn.tileList.addAll(tileList.map { it.clone() })
toReturn.mapParameters = mapParameters
return toReturn
}
operator fun contains(vector: Vector2): Boolean {
return contains(vector.x.toInt(), vector.y.toInt())

View file

@ -22,6 +22,12 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): Popup(mapEditorScree
mapNameEditor.addListener{ mapEditorScreen.mapName=mapNameEditor.text; true }
add(mapNameEditor).row()
val newMapButton = TextButton("New map".tr(),skin)
newMapButton.onClick {
UncivGame.Current.setScreen(NewMapScreen())
}
add(newMapButton).row()
val clearCurrentMapButton = TextButton("Clear current map".tr(),skin)
clearCurrentMapButton.onClick {
for(tileGroup in mapEditorScreen.mapHolder.tileGroups.values)

View file

@ -62,6 +62,7 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
MapType.pangaea,
MapType.continents,
MapType.perlin,
MapType.archipelago,
if (isEmptyMapAllowed) MapType.empty else null
)
@ -142,19 +143,19 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
}
val averageHeightSlider = Slider(0f,1f,0.01f, false, skin).apply {
val elevationExponentSlider = Slider(0.5f,1f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.mountainProbability = this@apply.value
mapParameters.elevationExponent = this@apply.value
}
})
}
averageHeightSlider.value = mapParameters.mountainProbability
elevationExponentSlider.value = mapParameters.elevationExponent
advancedSettingsTable.add("Map Height".toLabel()).left()
advancedSettingsTable.add(averageHeightSlider).fillX().row()
advancedSettingsTable.add(elevationExponentSlider).fillX().row()
val tempExtremeSlider = Slider(0f,1f,0.01f, false, skin).apply {
val tempExtremeSlider = Slider(0.4f,0.8f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.temperatureExtremeness = this@apply.value
@ -166,7 +167,7 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
advancedSettingsTable.add(tempExtremeSlider).fillX().row()
val resourceRichnessSlider = Slider(0f,0.2f,0.01f, false, skin).apply {
val resourceRichnessSlider = Slider(0f,0.5f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.resourceRichness = this@apply.value
@ -177,17 +178,27 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
advancedSettingsTable.add("Resource richness".toLabel()).left()
advancedSettingsTable.add(resourceRichnessSlider).fillX().row()
val terrainFeatureRichnessSlider = Slider(0f,1f,0.01f, false, skin).apply {
val vegetationRichnessSlider = Slider(0f,1f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.terrainFeatureRichness = this@apply.value
mapParameters.vegetationRichness = this@apply.value
}
})
}
terrainFeatureRichnessSlider.value = mapParameters.terrainFeatureRichness
advancedSettingsTable.add("Terrain Features richness".toLabel()).left()
advancedSettingsTable.add(terrainFeatureRichnessSlider).fillX().row()
vegetationRichnessSlider.value = mapParameters.vegetationRichness
advancedSettingsTable.add("Vegetation richness".toLabel()).left()
advancedSettingsTable.add(vegetationRichnessSlider).fillX().row()
val rareFeaturesRichnessSlider = Slider(0f,0.5f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.rareFeaturesRichness = this@apply.value
}
})
}
rareFeaturesRichnessSlider.value = mapParameters.rareFeaturesRichness
advancedSettingsTable.add("Rare features richness".toLabel()).left()
advancedSettingsTable.add(rareFeaturesRichnessSlider).fillX().row()
val maxCoastExtensionSlider = Slider(0f,5f,1f, false, skin).apply {
@ -202,7 +213,7 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
advancedSettingsTable.add(maxCoastExtensionSlider).fillX().row()
val tilesPerBiomeAreaSlider = Slider(0f,15f,1f, false, skin).apply {
val tilesPerBiomeAreaSlider = Slider(1f,15f,1f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.tilesPerBiomeArea = this@apply.value.toInt()
@ -214,40 +225,28 @@ class MapParametersTable(val mapParameters: MapParameters, val isEmptyMapAllowed
advancedSettingsTable.add(tilesPerBiomeAreaSlider).fillX().row()
val waterPercentSlider = Slider(0f,1f,0.01f, false, skin).apply {
val waterThresholdSlider = Slider(-0.1f,0.1f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.waterProbability = this@apply.value
mapParameters.waterThreshold = this@apply.value
}
})
}
waterPercentSlider.value = mapParameters.waterProbability
advancedSettingsTable.add("Water percent".toLabel()).left()
advancedSettingsTable.add(waterPercentSlider).fillX().row()
val landPercentSlider = Slider(0f,1f,0.01f, false, skin).apply {
addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
mapParameters.landProbability = this@apply.value
}
})
}
landPercentSlider.value = mapParameters.landProbability
advancedSettingsTable.add("Land percent".toLabel()).left()
advancedSettingsTable.add(landPercentSlider).fillX().row()
waterThresholdSlider.value = mapParameters.waterThreshold
advancedSettingsTable.add("Water level".toLabel()).left()
advancedSettingsTable.add(waterThresholdSlider).fillX().row()
val resetToDefaultButton = TextButton("Reset to default".tr(), skin)
resetToDefaultButton.onClick {
mapParameters.resetAdvancedSettings()
averageHeightSlider.value = mapParameters.mountainProbability
elevationExponentSlider.value = mapParameters.elevationExponent
tempExtremeSlider.value = mapParameters.temperatureExtremeness
resourceRichnessSlider.value = mapParameters.resourceRichness
terrainFeatureRichnessSlider.value = mapParameters.terrainFeatureRichness
vegetationRichnessSlider.value = mapParameters.vegetationRichness
rareFeaturesRichnessSlider.value = mapParameters.rareFeaturesRichness
maxCoastExtensionSlider.value = mapParameters.maxCoastExtension.toFloat()
tilesPerBiomeAreaSlider.value = mapParameters.tilesPerBiomeArea.toFloat()
waterPercentSlider.value = mapParameters.waterProbability
landPercentSlider.value = mapParameters.landProbability
waterThresholdSlider.value = mapParameters.waterThreshold
}
advancedSettingsTable.add(resetToDefaultButton).colspan(2).row()
}

View file

@ -432,6 +432,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Water](https://thenounproject.com/term/water/1762848/) By Kozan for Marsh
* [Harvest](https://thenounproject.com/term/harvest/1022373/) By Made for Flood plains
* [Puddle](https://thenounproject.com/search/?q=puddle&i=1138155) By Bakunetsu Kaito for Lakes
* [Island](https://thenounproject.com/search/?q=island&i=1546376) By Chanut is Industries for Atoll
* [Iceberg](https://thenounproject.com/search/?q=iceberg&i=44820) By Jaime Carrion for Ice
## Nations