From cdeabd044dc0e1e62e9ac3bb7d6bfef068e974f4 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Thu, 2 Jun 2022 07:57:33 +0200 Subject: [PATCH] MainMenu Background Map scaled to Screen and minor MapGen fixes (#7000) * MapGenerator fixes * MainMenu Background Map scaled to Screen * MainMenu Background Map scaled to Screen - groupSize as public const --- core/src/com/unciv/MainMenuScreen.kt | 23 ++++++-- .../logic/map/mapgenerator/MapGenerator.kt | 56 +++++++++++++------ core/src/com/unciv/ui/map/TileGroupMap.kt | 47 ++++++++++------ 3 files changed, 90 insertions(+), 36 deletions(-) diff --git a/core/src/com/unciv/MainMenuScreen.kt b/core/src/com/unciv/MainMenuScreen.kt index 5e91c29414..a5546560d1 100644 --- a/core/src/com/unciv/MainMenuScreen.kt +++ b/core/src/com/unciv/MainMenuScreen.kt @@ -10,7 +10,6 @@ import com.unciv.logic.GameInfo import com.unciv.logic.GameStarter import com.unciv.logic.map.MapParameters import com.unciv.logic.map.MapShape -import com.unciv.logic.map.MapSize import com.unciv.logic.map.MapSizeNew import com.unciv.logic.map.MapType import com.unciv.logic.map.mapgenerator.MapGenerator @@ -23,6 +22,7 @@ import com.unciv.ui.civilopedia.CivilopediaScreen import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.images.ImageGetter +import com.unciv.ui.map.TileGroupMap import com.unciv.ui.newgamescreen.NewGameScreen import com.unciv.ui.pickerscreens.ModManagementScreen import com.unciv.ui.popup.* @@ -31,6 +31,8 @@ import com.unciv.ui.saves.QuickSave import com.unciv.ui.utils.* import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip import com.unciv.ui.worldscreen.mainmenu.WorldScreenMenuPopup +import kotlin.math.min + class MainMenuScreen: BaseScreen() { private val backgroundTable = Table().apply { background= ImageGetter.getBackground(Color.WHITE) } @@ -76,16 +78,29 @@ class MainMenuScreen: BaseScreen() { ImageGetter.ruleset = RulesetCache.getVanillaRuleset() launchCrashHandling("ShowMapBackground") { - val newMap = MapGenerator(RulesetCache.getVanillaRuleset()) + var scale = 1f + var mapWidth = stage.width / TileGroupMap.groupHorizontalAdvance + var mapHeight = stage.height / TileGroupMap.groupSize + if (mapWidth * mapHeight > 3000f) { // 3000 as max estimated number of tiles is arbitrary (we had typically 721 before) + scale = mapWidth * mapHeight / 3000f + mapWidth /= scale + mapHeight /= scale + scale = min(scale, 20f) + } + + val mapRuleset = RulesetCache.getVanillaRuleset() + val newMap = MapGenerator(mapRuleset) .generateMap(MapParameters().apply { shape = MapShape.rectangular - mapSize = MapSizeNew(MapSize.Small) + mapSize = MapSizeNew(mapWidth.toInt() + 1, mapHeight.toInt() + 1) type = MapType.default waterThreshold = -0.055f // Gives the same level as when waterThreshold was unused in MapType.default }) + postCrashHandlingRunnable { // for GL context - ImageGetter.setNewRuleset(RulesetCache.getVanillaRuleset()) + ImageGetter.setNewRuleset(mapRuleset) val mapHolder = EditorMapHolder(this@MainMenuScreen, newMap) {} + mapHolder.setScale(scale) backgroundTable.addAction(Actions.sequence( Actions.fadeOut(0f), Actions.run { diff --git a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt index 09b82d1213..05445e20ae 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt @@ -25,6 +25,7 @@ import kotlin.math.max import kotlin.math.pow import kotlin.math.roundToInt import kotlin.math.sign +import kotlin.math.ulp import kotlin.random.Random @@ -45,13 +46,26 @@ class MapGenerator(val ruleset: Ruleset) { /** builds a [TerrainOccursRange] for [terrain] from a [unique] (type [UniqueType.TileGenerationConditions]) */ constructor(terrain: Terrain, unique: Unique) : this(terrain, - unique.params[0].toFloat(), unique.params[1].toFloat(), - unique.params[2].toFloat(), unique.params[3].toFloat()) - /** checks if both [temperature] and [humidity] satisfy their ranges (>From, <=To) */ + unique.params[0].toFloatMakeInclusive(-1f), unique.params[1].toFloat(), + unique.params[2].toFloatMakeInclusive(0f), unique.params[3].toFloat()) + + /** Checks if both [temperature] and [humidity] satisfy their ranges (>From, <=To) + * Note the lowest allowed limit has been made inclusive (temp -1 nudged down by 1 [Float.ulp], humidity at 0) + */ + // Yes this does implicit conversions Float/Double fun matches(temperature: Double, humidity: Double) = tempFrom < temperature && temperature <= tempTo && humidFrom < humidity && humidity <= humidTo + + companion object { + /** A [toFloat] that also nudges the value slightly down if it matches [limit] to make the resulting range inclusive on the lower end */ + private fun String.toFloatMakeInclusive(limit: Float): Float { + val result = toFloat() + if (result != limit) return result + return result - result.ulp + } + } } private fun Terrain.getGenerationConditions() = getMatchingUniques(UniqueType.TileGenerationConditions) @@ -463,11 +477,15 @@ class MapGenerator(val ruleset: Ruleset) { // List is OK here as it's only sequentially scanned val limitsMap: List = - ruleset.terrains.values.flatMap { - it.getGenerationConditions() - } + ruleset.terrains.values.filter { it.type == TerrainType.Land } + .flatMap { it.getGenerationConditions() } val noTerrainUniques = limitsMap.isEmpty() - val elevationTerrains = arrayOf(Constants.mountain, Constants.hill) + val elevationTerrains = ruleset.terrains.values.asSequence() + .filter { + it.hasUnique(UniqueType.OccursInChains) + }.mapTo(mutableSetOf()) { it.name } + if (elevationTerrains.isEmpty()) + elevationTerrains.add(Constants.mountain) for (tile in tileMap.values.asSequence()) { if (tile.isWater || tile.baseTerrain in elevationTerrains) @@ -526,6 +544,7 @@ class MapGenerator(val ruleset: Ruleset) { } } } + /** * [MapParameters.rareFeaturesRichness] is the probability of spawning a rare feature */ @@ -600,16 +619,21 @@ class MapGenerationRandomness { /** * 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 + * @param tile Source for x / x coordinates. + * @param seed Misnomer: actually the z value the Perlin cloud is 'cut' on. + * @param nOctaves is the number of octaves. + * @param persistence is the scaling factor of octave amplitudes. + * @param lacunarity is the scaling factor of octave frequencies. + * @param scale is the distance the noise is observed from. */ - fun getPerlinNoise(tile: TileInfo, seed: Double, - nOctaves: Int = 6, - persistence: Double = 0.5, - lacunarity: Double = 2.0, - scale: Double = 10.0): Double { + fun getPerlinNoise( + tile: TileInfo, + seed: Double, + nOctaves: Int = 6, + persistence: Double = 0.5, + lacunarity: Double = 2.0, + scale: Double = 10.0 + ): Double { val worldCoords = HexMath.hex2WorldCoords(tile.position) return Perlin.noise3d(worldCoords.x.toDouble(), worldCoords.y.toDouble(), seed, nOctaves, persistence, lacunarity, scale) } diff --git a/core/src/com/unciv/ui/map/TileGroupMap.kt b/core/src/com/unciv/ui/map/TileGroupMap.kt index 09e7312501..c5d8142c8f 100644 --- a/core/src/com/unciv/ui/map/TileGroupMap.kt +++ b/core/src/com/unciv/ui/map/TileGroupMap.kt @@ -25,6 +25,21 @@ class TileGroupMap( worldWrap: Boolean = false, tileGroupsToUnwrap: Set? = null ): Group() { + companion object { + /** Vertical size of a hex in world coordinates, or the distance between the centers of any two opposing edges + * (the hex is oriented so it has corners to the left and right of the center and its upper and lower bounds are horizontal edges) */ + const val groupSize = 50f + /** Length of the diagonal of a hex, or distance between two opposing corners */ + const val groupSizeDiagonal = groupSize * 1.1547005f // groupSize * sqrt(4/3) + /** Horizontal displacement per hex, meaning the increase in overall map size (in world coordinates) when adding a column. + * On the hex, this can be visualized as the horizontal distance between the leftmost corner and the + * line connecting the two corners at 2 and 4 o'clock. */ + const val groupHorizontalAdvance = groupSizeDiagonal * 3 / 4 + //TODO magic numbers that **seem** like they might depend on these values can be found in + // TileGroupMap.getPositionalVector, TileGroup.updateArrows, TileGroup.updateRoadImages + // and other places. I can't understand them so I'm leaving cleanup of hardcoding to someone else. + } + /** If the [act] method should be performed. If this is false, every child within this [TileGroupMap] will not get their [act] method called * and thus not perform any [com.badlogic.gdx.scenes.scene2d.Action]s. * Most children here already do not do anything in their [act] methods. However, even iterating through all of them */ @@ -34,7 +49,6 @@ class TileGroupMap( private var topY = -Float.MAX_VALUE private var bottomX = Float.MAX_VALUE private var bottomY = Float.MAX_VALUE - private val groupSize = 50 private val mirrorTileGroups = HashMap>() init { @@ -54,8 +68,8 @@ class TileGroupMap( HexMath.hex2WorldCoords(tileGroup.tileInfo.position) } - tileGroup.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(), - positionalVector.y * 0.8f * groupSize.toFloat()) + tileGroup.setPosition(positionalVector.x * 0.8f * groupSize, + positionalVector.y * 0.8f * groupSize) topX = if (worldWrap) @@ -82,12 +96,12 @@ class TileGroupMap( for (mirrorTiles in mirrorTileGroups.values){ val positionalVector = HexMath.hex2WorldCoords(mirrorTiles.first.tileInfo.position) - mirrorTiles.first.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(), - positionalVector.y * 0.8f * groupSize.toFloat()) + mirrorTiles.first.setPosition(positionalVector.x * 0.8f * groupSize, + positionalVector.y * 0.8f * groupSize) mirrorTiles.first.moveBy(-bottomX - bottomX * 2, -bottomY ) - mirrorTiles.second.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(), - positionalVector.y * 0.8f * groupSize.toFloat()) + mirrorTiles.second.setPosition(positionalVector.x * 0.8f * groupSize, + positionalVector.y * 0.8f * groupSize) mirrorTiles.second.moveBy(-bottomX + bottomX * 2, -bottomY) } } @@ -157,21 +171,22 @@ class TileGroupMap( * Returns the positional coordinates of the TileGroupMap center. */ fun getPositionalVector(stageCoords: Vector2): Vector2 { - val trueGroupSize = 0.8f * groupSize.toFloat() + val trueGroupSize = 0.8f * groupSize return Vector2(bottomX, bottomY) .add(stageCoords) - .sub(groupSize.toFloat() / 2f, groupSize.toFloat() / 2f) + .sub(groupSize / 2f, groupSize / 2f) .scl(1f / trueGroupSize) } fun getMirrorTiles(): HashMap> = mirrorTileGroups + override fun act(delta: Float) { + if(shouldAct) { + super.act(delta) + } + } + // For debugging purposes - override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) } - @Suppress("RedundantOverride") - override fun act(delta: Float) { - if(shouldAct) { - super.act(delta) - } - } + override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) } + }