mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-04 15:27:50 +07:00
Allow generation of "Default" Deciv redux maps (#6821)
This commit is contained in:
@ -498,6 +498,7 @@ Starting location(s): [param] =
|
|||||||
Continent: [param] ([amount] tiles) =
|
Continent: [param] ([amount] tiles) =
|
||||||
Change map to fit selected ruleset? =
|
Change map to fit selected ruleset? =
|
||||||
Area: [amount] tiles, [amount2] continents/islands =
|
Area: [amount] tiles, [amount2] continents/islands =
|
||||||
|
Area: [amount] tiles, [amount2]% water, [amount3] continents/islands =
|
||||||
Do you want to leave without saving the recent changes? =
|
Do you want to leave without saving the recent changes? =
|
||||||
Do you want to load another map without saving the recent changes? =
|
Do you want to load another map without saving the recent changes? =
|
||||||
Invalid map: Area ([area]) does not match saved dimensions ([dimensions]). =
|
Invalid map: Area ([area]) does not match saved dimensions ([dimensions]). =
|
||||||
|
@ -75,7 +75,11 @@ class MainMenuScreen: BaseScreen() {
|
|||||||
|
|
||||||
crashHandlingThread(name = "ShowMapBackground") {
|
crashHandlingThread(name = "ShowMapBackground") {
|
||||||
val newMap = MapGenerator(RulesetCache.getVanillaRuleset())
|
val newMap = MapGenerator(RulesetCache.getVanillaRuleset())
|
||||||
.generateMap(MapParameters().apply { mapSize = MapSizeNew(MapSize.Small); type = MapType.default })
|
.generateMap(MapParameters().apply {
|
||||||
|
mapSize = MapSizeNew(MapSize.Small)
|
||||||
|
type = MapType.default
|
||||||
|
waterThreshold = -0.055f // Gives the same level as when waterThreshold was unused in MapType.default
|
||||||
|
})
|
||||||
postCrashHandlingRunnable { // for GL context
|
postCrashHandlingRunnable { // for GL context
|
||||||
ImageGetter.setNewRuleset(RulesetCache.getVanillaRuleset())
|
ImageGetter.setNewRuleset(RulesetCache.getVanillaRuleset())
|
||||||
val mapHolder = EditorMapHolder(this, newMap) {}
|
val mapHolder = EditorMapHolder(this, newMap) {}
|
||||||
|
@ -2,10 +2,10 @@ package com.unciv.logic.map
|
|||||||
|
|
||||||
import com.badlogic.gdx.math.Rectangle
|
import com.badlogic.gdx.math.Rectangle
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.unciv.Constants
|
|
||||||
import com.unciv.logic.GameInfo
|
import com.unciv.logic.GameInfo
|
||||||
import com.unciv.logic.HexMath
|
import com.unciv.logic.HexMath
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
|
import com.unciv.logic.map.mapgenerator.MapLandmassGenerator
|
||||||
import com.unciv.models.metadata.Player
|
import com.unciv.models.metadata.Player
|
||||||
import com.unciv.models.ruleset.Nation
|
import com.unciv.models.ruleset.Nation
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
@ -95,7 +95,7 @@ class TileMap {
|
|||||||
/** creates a hexagonal map of given radius (filled with grassland) */
|
/** creates a hexagonal map of given radius (filled with grassland) */
|
||||||
constructor(radius: Int, ruleset: Ruleset, worldWrap: Boolean = false) {
|
constructor(radius: Int, ruleset: Ruleset, worldWrap: Boolean = false) {
|
||||||
startingLocations.clear()
|
startingLocations.clear()
|
||||||
val firstAvailableLandTerrain = getInitializationTerrain(ruleset)
|
val firstAvailableLandTerrain = MapLandmassGenerator.getInitializationTerrain(ruleset, TerrainType.Land)
|
||||||
for (vector in HexMath.getVectorsInDistance(Vector2.Zero, radius, worldWrap))
|
for (vector in HexMath.getVectorsInDistance(Vector2.Zero, radius, worldWrap))
|
||||||
tileList.add(TileInfo().apply { position = vector; baseTerrain = firstAvailableLandTerrain })
|
tileList.add(TileInfo().apply { position = vector; baseTerrain = firstAvailableLandTerrain })
|
||||||
setTransients(ruleset)
|
setTransients(ruleset)
|
||||||
@ -104,7 +104,7 @@ class TileMap {
|
|||||||
/** creates a rectangular map of given width and height (filled with grassland) */
|
/** creates a rectangular map of given width and height (filled with grassland) */
|
||||||
constructor(width: Int, height: Int, ruleset: Ruleset, worldWrap: Boolean = false) {
|
constructor(width: Int, height: Int, ruleset: Ruleset, worldWrap: Boolean = false) {
|
||||||
startingLocations.clear()
|
startingLocations.clear()
|
||||||
val firstAvailableLandTerrain = getInitializationTerrain(ruleset)
|
val firstAvailableLandTerrain = MapLandmassGenerator.getInitializationTerrain(ruleset, TerrainType.Land)
|
||||||
|
|
||||||
// world-wrap maps must always have an even width, so round down
|
// world-wrap maps must always have an even width, so round down
|
||||||
val wrapAdjustedWidth = if (worldWrap && width % 2 != 0) width -1 else width
|
val wrapAdjustedWidth = if (worldWrap && width % 2 != 0) width -1 else width
|
||||||
@ -121,10 +121,6 @@ class TileMap {
|
|||||||
setTransients(ruleset)
|
setTransients(ruleset)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInitializationTerrain(ruleset: Ruleset) =
|
|
||||||
ruleset.terrains.values.firstOrNull { it.type == TerrainType.Land }?.name
|
|
||||||
?: throw Exception("Cannot create map - no land terrains found!")
|
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region Operators and Standards
|
//region Operators and Standards
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.unciv.logic.map.mapgenerator
|
package com.unciv.logic.map.mapgenerator
|
||||||
|
|
||||||
import com.unciv.Constants
|
|
||||||
import com.unciv.logic.HexMath
|
import com.unciv.logic.HexMath
|
||||||
import com.unciv.logic.map.*
|
import com.unciv.logic.map.*
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
@ -11,18 +10,28 @@ import kotlin.math.pow
|
|||||||
|
|
||||||
class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRandomness) {
|
class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRandomness) {
|
||||||
//region _Fields
|
//region _Fields
|
||||||
private val firstLandTerrain = ruleset.terrains.values.first { it.type==TerrainType.Land }
|
private val landTerrainName = getInitializationTerrain(ruleset, TerrainType.Land)
|
||||||
private val landTerrainName = firstLandTerrain.name
|
private val waterTerrainName: String = try {
|
||||||
private val firstWaterTerrain = ruleset.terrains.values.firstOrNull { it.type==TerrainType.Water }
|
getInitializationTerrain(ruleset, TerrainType.Water)
|
||||||
private val waterTerrainName = firstWaterTerrain?.name ?: ""
|
} catch (_: Exception) {
|
||||||
|
landTerrainName
|
||||||
|
}
|
||||||
|
private val landOnlyMod: Boolean = waterTerrainName == landTerrainName
|
||||||
private var waterThreshold = 0.0
|
private var waterThreshold = 0.0
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// this is called from TileMap constructors as well
|
||||||
|
internal fun getInitializationTerrain(ruleset: Ruleset, type: TerrainType) =
|
||||||
|
ruleset.terrains.values.firstOrNull { it.type == type }?.name
|
||||||
|
?: throw Exception("Cannot create map - no $type terrains found!")
|
||||||
|
}
|
||||||
|
|
||||||
fun generateLand(tileMap: TileMap) {
|
fun generateLand(tileMap: TileMap) {
|
||||||
// This is to accommodate land-only mods
|
// This is to accommodate land-only mods
|
||||||
if (firstWaterTerrain==null) {
|
if (landOnlyMod) {
|
||||||
for (tile in tileMap.values)
|
for (tile in tileMap.values)
|
||||||
tile.baseTerrain = firstLandTerrain.name
|
tile.baseTerrain = landTerrainName
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +62,11 @@ class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRa
|
|||||||
if (randomness.RNG.nextFloat() > threshold)
|
if (randomness.RNG.nextFloat() > threshold)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
val numberOfLandNeighbors = tileInfo.neighbors.count { it.baseTerrain == Constants.grassland }
|
val numberOfLandNeighbors = tileInfo.neighbors.count { it.baseTerrain == landTerrainName }
|
||||||
if (numberOfLandNeighbors > 3)
|
if (numberOfLandNeighbors > 3)
|
||||||
tileInfo.baseTerrain = Constants.grassland
|
tileInfo.baseTerrain = landTerrainName
|
||||||
else if (numberOfLandNeighbors < 3)
|
else if (numberOfLandNeighbors < 3)
|
||||||
tileInfo.baseTerrain = Constants.ocean
|
tileInfo.baseTerrain = waterTerrainName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +198,15 @@ class MapLandmassGenerator(val ruleset: Ruleset, val randomness: MapGenerationRa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateLandCellularAutomata(tileMap: TileMap) {
|
private fun generateLandCellularAutomata(tileMap: TileMap) {
|
||||||
|
// Empiric nice looking range: 0.37..0.72 giving ~15%-85% water
|
||||||
|
// The old code had 0.55 (inverted) hard-coded, so to get the same we need waterThreshold = -0.055 for the MainMenu background.
|
||||||
|
waterThreshold = 0.545 + 1.75 * waterThreshold
|
||||||
|
|
||||||
for (tile in tileMap.values) {
|
for (tile in tileMap.values) {
|
||||||
tile.baseTerrain =
|
spawnLandOrWater(tile, randomness.RNG.nextDouble())
|
||||||
if (randomness.RNG.nextDouble() < 0.55) Constants.grassland else Constants.ocean
|
|
||||||
|
|
||||||
tile.setTransients()
|
tile.setTransients()
|
||||||
}
|
}
|
||||||
|
|
||||||
smoothen(tileMap)
|
smoothen(tileMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,11 @@ class EditorMapHolder(
|
|||||||
val positionalCoords = tileGroupMap.getPositionalVector(stageCoords)
|
val positionalCoords = tileGroupMap.getPositionalVector(stageCoords)
|
||||||
val hexPosition = HexMath.world2HexCoords(positionalCoords)
|
val hexPosition = HexMath.world2HexCoords(positionalCoords)
|
||||||
val rounded = HexMath.roundHexCoords(hexPosition)
|
val rounded = HexMath.roundHexCoords(hexPosition)
|
||||||
return tileMap.getOrNull(rounded)
|
|
||||||
|
if (!tileMap.mapParameters.worldWrap)
|
||||||
|
return tileMap.getOrNull(rounded)
|
||||||
|
val wrapped = HexMath.getUnwrappedNearestTo(rounded, Vector2.Zero, tileMap.maxLongitude)
|
||||||
|
//todo this works, but means getUnwrappedNearestTo fails - on the x-y == maxLongitude vertical
|
||||||
|
return tileMap.getOrNull(wrapped) ?: tileMap.getOrNull(rounded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,10 @@ class MapEditorGenerateTab(
|
|||||||
when (step) {
|
when (step) {
|
||||||
MapGeneratorSteps.All -> {
|
MapGeneratorSteps.All -> {
|
||||||
val generatedMap = generator!!.generateMap(mapParameters)
|
val generatedMap = generator!!.generateMap(mapParameters)
|
||||||
|
val savedScale = editorScreen.mapHolder.scaleX
|
||||||
Gdx.app.postRunnable {
|
Gdx.app.postRunnable {
|
||||||
freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 0)
|
freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 0)
|
||||||
|
editorScreen.mapHolder.zoom(savedScale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MapGeneratorSteps.Landmass -> {
|
MapGeneratorSteps.Landmass -> {
|
||||||
|
@ -20,6 +20,7 @@ import com.unciv.ui.utils.*
|
|||||||
|
|
||||||
//todo normalize properly
|
//todo normalize properly
|
||||||
|
|
||||||
|
//todo Remove "Area: [amount] tiles, [amount2] continents/islands = " after 2022-07-01
|
||||||
//todo Direct Strategic Resource abundance control
|
//todo Direct Strategic Resource abundance control
|
||||||
//todo functional Tab for Units (empty Tab is prepared but commented out in MapEditorEditTab.AllEditSubTabs)
|
//todo functional Tab for Units (empty Tab is prepared but commented out in MapEditorEditTab.AllEditSubTabs)
|
||||||
//todo copy/paste tile areas? (As tool tab, brush sized, floodfill forbidden, tab displays copied area)
|
//todo copy/paste tile areas? (As tool tab, brush sized, floodfill forbidden, tab displays copied area)
|
||||||
|
@ -76,7 +76,10 @@ class MapEditorViewTab(
|
|||||||
ToastPopup("Error assigning continents: ${ex.message}", editorScreen)
|
ToastPopup("Error assigning continents: ${ex.message}", editorScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
val statsText = "Area: [${tileMap.values.size}] tiles, [${tileMap.continentSizes.size}] continents/islands"
|
val area = tileMap.values.size
|
||||||
|
val waterPercent = (tileMap.values.count { it.isWater } * 100f / area).toInt()
|
||||||
|
val continents = tileMap.continentSizes.size
|
||||||
|
val statsText = "Area: [$area] tiles, $waterPercent% water, [$continents] continents/islands"
|
||||||
val statsLabel = WrappableLabel(statsText, labelWidth)
|
val statsLabel = WrappableLabel(statsText, labelWidth)
|
||||||
add(statsLabel.apply { wrap = true }).row()
|
add(statsLabel.apply { wrap = true }).row()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user