diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index be90e9830f..03aa39cc3a 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -501,6 +501,7 @@ Map copy and paste = Position: [param] = Starting location(s): [param] = Continent: [param] ([amount] tiles) = +Resource abundance = Change map to fit selected ruleset? = Area: [amount] tiles, [amount2] continents/islands = Area: [amount] tiles, [amount2]% water, [amount3] continents/islands = diff --git a/core/src/com/unciv/logic/map/tile/Tile.kt b/core/src/com/unciv/logic/map/tile/Tile.kt index 82dc2c540e..98d5fd849a 100644 --- a/core/src/com/unciv/logic/map/tile/Tile.kt +++ b/core/src/com/unciv/logic/map/tile/Tile.kt @@ -8,9 +8,11 @@ import com.unciv.logic.city.City import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.HexMath +import com.unciv.logic.map.MapParameters // Kdoc only import com.unciv.logic.map.MapResources import com.unciv.logic.map.TileMap import com.unciv.logic.map.mapunit.MapUnit +import com.unciv.logic.map.mapunit.UnitMovement // Kdoc only import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.Terrain @@ -676,7 +678,7 @@ open class Tile : IsPartOfGameInfoSerialization { /** * @returns whether units of [civInfo] can pass through this tile, considering only civ-wide filters. - * Use [UnitMovementAlgorithms.canPassThrough] to check whether a specific unit can pass through a tile. + * Use [UnitMovement.canPassThrough] to check whether a specific unit can pass through a tile. */ fun canCivPassThrough(civInfo: Civilization): Boolean { val tileOwner = getOwner() @@ -785,7 +787,10 @@ open class Tile : IsPartOfGameInfoSerialization { fun setTileResource(newResource: TileResource, majorDeposit: Boolean? = null, rng: Random = Random.Default) { resource = newResource.name - if (newResource.resourceType != ResourceType.Strategic) return + if (newResource.resourceType != ResourceType.Strategic) { + resourceAmount = 0 + return + } for (unique in newResource.getMatchingUniques(UniqueType.ResourceAmountOnTiles, StateForConditionals(tile = this))) { if (matchesTerrainFilter(unique.params[0])) { diff --git a/core/src/com/unciv/ui/components/tilegroups/layers/TileLayerMisc.kt b/core/src/com/unciv/ui/components/tilegroups/layers/TileLayerMisc.kt index 3e9dd2a85e..774e25a66e 100644 --- a/core/src/com/unciv/ui/components/tilegroups/layers/TileLayerMisc.kt +++ b/core/src/com/unciv/ui/components/tilegroups/layers/TileLayerMisc.kt @@ -83,6 +83,7 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si private var hexOutlineIcon: Actor? = null private var resourceName: String? = null + private var resourceAmount: Int = -1 private var resourceIcon: Actor? = null private var workedIcon: Actor? = null @@ -168,15 +169,16 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si } // If resource has changed (e.g. tech researched) - force new icon next time it's needed - if (resourceName != tile().resource) { + if (resourceName != tile().resource || resourceAmount != tile().resourceAmount) { resourceName = tile().resource + resourceAmount = tile().resourceAmount resourceIcon?.remove() resourceIcon = null } // Get a fresh Icon if and only if necessary if (resourceName != null && effectiveVisible && resourceIcon == null) { - val icon = ImageGetter.getResourcePortrait(resourceName!!, 20f, tile().resourceAmount) + val icon = ImageGetter.getResourcePortrait(resourceName!!, 20f, resourceAmount) icon.center(tileGroup) icon.x -= 22 // left icon.y += 10 // top diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorFilesTable.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorFilesTable.kt index 0a95291e9d..48fbf5b776 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorFilesTable.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorFilesTable.kt @@ -12,13 +12,15 @@ import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.components.extensions.keyShortcuts import com.unciv.ui.components.extensions.onClick +import com.unciv.ui.components.extensions.onDoubleClick import com.unciv.ui.components.extensions.pad import com.unciv.ui.components.extensions.toLabel class MapEditorFilesTable( initWidth: Float, private val includeMods: Boolean = false, - private val onSelect: (FileHandle) -> Unit + private val onSelect: (FileHandle) -> Unit, + private val onDoubleClick: () -> Unit ): Table(BaseScreen.skin) { private var selectedIndex = -1 @@ -41,7 +43,7 @@ class MapEditorFilesTable( onSelect(sortedFiles[row].file) } - fun moveSelection(delta: Int) { + private fun moveSelection(delta: Int) { selectedIndex = when { selectedIndex + delta in sortedFiles.indices -> selectedIndex + delta @@ -92,6 +94,10 @@ class MapEditorFilesTable( mapButton.onClick { markSelection(mapButton, index) } + mapButton.onDoubleClick { + markSelection(mapButton, index) + onDoubleClick() + } add(mapButton).row() } layout() diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorScreen.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorScreen.kt index 914c86d458..053e959125 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/MapEditorScreen.kt @@ -22,12 +22,15 @@ import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.KeyboardPanningListener import com.unciv.ui.screens.basescreen.RecreateOnResize import com.unciv.ui.screens.worldscreen.ZoomButtonPair +import com.unciv.utils.Concurrency +import com.unciv.utils.Dispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job //todo normalize properly //todo Remove "Area: [amount] tiles, [amount2] continents/islands = " after 2022-07-01 -//todo Direct Strategic Resource abundance control //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 Synergy with Civilopedia for drawing loose tiles / terrain icons @@ -73,6 +76,9 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize { private val highlightedTileGroups = mutableListOf() + // Control of background jobs - make them cancel on context changes like exit editor or resize screen + private val jobs = ArrayDeque(3) + init { if (map == null) { ruleset = RulesetCache[BaseRuleset.Civ_V_GnK.fullName]!! @@ -189,6 +195,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize { "Do you want to leave without saving the recent changes?", "Leave" ) { + cancelJobs() game.popScreen() } } @@ -216,5 +223,32 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize { highlightTile(tile, color) } - override fun recreate(): BaseScreen = MapEditorScreen(tileMap) + override fun recreate(): BaseScreen { + cancelJobs() + return MapEditorScreen(tileMap) + } + + override fun dispose() { + cancelJobs() + super.dispose() + } + + fun startBackgroundJob( + name: String, + isDaemon: Boolean = true, + block: suspend CoroutineScope.() -> Unit + ) { + val scope = CoroutineScope(if (isDaemon) Dispatcher.DAEMON else Dispatcher.NON_DAEMON) + val newJob = Concurrency.run(name, scope, block) + jobs.add(newJob) + newJob.invokeOnCompletion { + jobs.remove(newJob) + } + } + + private fun cancelJobs() { + for (job in jobs) + job.cancel() + jobs.clear() + } } diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt index 1930533027..2b8a2e25bc 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditSubTabs.kt @@ -156,6 +156,7 @@ class MapEditorEditResourcesTab( add(eraser.render(0f).apply { onClick { editTab.setBrush("Remove resource", eraserIcon, true) { tile -> tile.resource = null + tile.resourceAmount = 0 } } }).padBottom(0f).row() add( @@ -165,7 +166,10 @@ class MapEditorEditResourcesTab( ) { resourceName -> val resource = ruleset.tileResources[resourceName]!! editTab.setBrush(resourceName, resource.makeLink()) { - it.setTileResource(resource, rng = editTab.randomness.RNG) + if (it.resource == resourceName && resource.resourceType == ResourceType.Strategic) + it.resourceAmount = (it.resourceAmount + 1).coerceAtMost(42) + else + it.setTileResource(resource, rng = editTab.randomness.RNG) } }).padTop(0f).row() } diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditTab.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditTab.kt index 9329080c6f..be8aa22dca 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditTab.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorEditTab.kt @@ -11,26 +11,19 @@ import com.unciv.logic.map.mapgenerator.RiverGenerator import com.unciv.logic.map.tile.Tile import com.unciv.models.ruleset.Ruleset import com.unciv.models.translations.tr -import com.unciv.ui.screens.civilopediascreen.FormattedLine -import com.unciv.ui.images.ImageGetter -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditFeaturesTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditImprovementsTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditResourcesTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditRiversTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditStartsTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditTerrainTab -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorEditWondersTab -import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen -import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer -import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorOptionsTab.TileMatchFuzziness -import com.unciv.ui.popups.ToastPopup -import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.TabbedPager import com.unciv.ui.components.UncivSlider import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.keyShortcuts import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.popups.ToastPopup +import com.unciv.ui.screens.basescreen.BaseScreen +import com.unciv.ui.screens.civilopediascreen.FormattedLine +import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen +import com.unciv.ui.screens.mapeditorscreen.TileInfoNormalizer +import com.unciv.ui.screens.mapeditorscreen.tabs.MapEditorOptionsTab.TileMatchFuzziness import com.unciv.utils.Log class MapEditorEditTab( @@ -190,7 +183,7 @@ class MapEditorEditTab( editorScreen.tileClickHandler = null } - fun tileClickHandler(tile: Tile) { + private fun tileClickHandler(tile: Tile) { if (brushSize < -1 || brushSize > 5 || brushHandlerType == BrushHandlerType.None) return if (editorScreen.mapHolder.isPanning || editorScreen.mapHolder.isZooming()) return editorScreen.hideSelection() diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorGenerateTab.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorGenerateTab.kt index 8606ab032a..1bbeb7b9f9 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorGenerateTab.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorGenerateTab.kt @@ -29,8 +29,8 @@ import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.toCheckBox import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.utils.Concurrency import com.unciv.utils.Log -import kotlin.concurrent.thread class MapEditorGenerateTab( private val editorScreen: MapEditorScreen @@ -73,7 +73,7 @@ class MapEditorGenerateTab( val mapParameters = editorScreen.newMapParameters.clone() // this clone is very important here val message = mapParameters.mapSize.fixUndesiredSizes(mapParameters.worldWrap) if (message != null) { - Gdx.app.postRunnable { + Concurrency.runOnGLThread { ToastPopup( message, editorScreen, 4000 ) newTab.mapParametersTable.run { mapParameters.mapSize.also { customMapSizeRadius.text = it.radius.toString() @@ -113,7 +113,7 @@ class MapEditorGenerateTab( } // Map generation can take a while and we don't want ANRs - thread(name = "MapGenerator", isDaemon = true) { + editorScreen.startBackgroundJob("MapEditor.MapGenerator") { try { val (newRuleset, generator) = if (step > MapGeneratorSteps.Landmass) null to null else { @@ -124,7 +124,7 @@ class MapEditorGenerateTab( MapGeneratorSteps.All -> { val generatedMap = generator!!.generateMap(mapParameters) val savedScale = editorScreen.mapHolder.scaleX - Gdx.app.postRunnable { + Concurrency.runOnGLThread { freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 0) editorScreen.mapHolder.zoom(savedScale) } @@ -136,7 +136,7 @@ class MapEditorGenerateTab( mapParameters.type = editorScreen.newMapParameters.type generator.generateSingleStep(generatedMap, step) val savedScale = editorScreen.mapHolder.scaleX - Gdx.app.postRunnable { + Concurrency.runOnGLThread { freshMapCompleted(generatedMap, mapParameters, newRuleset!!, selectPage = 1) editorScreen.mapHolder.zoom(savedScale) } @@ -144,14 +144,14 @@ class MapEditorGenerateTab( else -> { editorScreen.tileMap.mapParameters.seed = mapParameters.seed MapGenerator(editorScreen.ruleset).generateSingleStep(editorScreen.tileMap, step) - Gdx.app.postRunnable { + Concurrency.runOnGLThread { stepCompleted(step) } } } } catch (exception: Exception) { Log.error("Exception while generating map", exception) - Gdx.app.postRunnable { + Concurrency.runOnGLThread { setButtonsEnabled(true) Gdx.input.inputProcessor = editorScreen.stage Popup(editorScreen).apply { diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorLoadTab.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorLoadTab.kt index b8b6059349..f641b64e6c 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorLoadTab.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorLoadTab.kt @@ -22,8 +22,10 @@ import com.unciv.ui.components.extensions.isEnabled import com.unciv.ui.components.extensions.keyShortcuts import com.unciv.ui.components.extensions.onActivation import com.unciv.ui.components.extensions.toTextButton +import com.unciv.utils.Concurrency import com.unciv.utils.Log -import kotlin.concurrent.thread +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.isActive class MapEditorLoadTab( private val editorScreen: MapEditorScreen, @@ -32,7 +34,9 @@ class MapEditorLoadTab( private val mapFiles = MapEditorFilesTable( initWidth = editorScreen.getToolsWidth() - 20f, includeMods = true, - this::selectFile) + this::selectFile, + this::loadHandler + ) private val loadButton = "Load map".toTextButton() private val deleteButton = "Delete map".toTextButton() @@ -53,7 +57,7 @@ class MapEditorLoadTab( val fileTableHeight = editorScreen.stage.height - headerHeight - buttonTable.height - 2f val scrollPane = AutoScrollPane(mapFiles, skin) scrollPane.setOverscroll(false, true) - add(scrollPane).height(fileTableHeight).width(editorScreen.getToolsWidth() - 20f).row() + add(scrollPane).size(editorScreen.getToolsWidth() - 20f, fileTableHeight).padTop(10f).row() add(buttonTable).row() } @@ -63,7 +67,7 @@ class MapEditorLoadTab( "Do you want to load another map without saving the recent changes?", "Load map" ) { - thread(name = "MapLoader", isDaemon = true, block = this::loaderThread) + editorScreen.startBackgroundJob("MapLoader") { loaderThread() } } } @@ -89,18 +93,18 @@ class MapEditorLoadTab( pager.setScrollDisabled(false) } - fun selectFile(file: FileHandle?) { + private fun selectFile(file: FileHandle?) { chosenMap = file loadButton.isEnabled = (file != null) deleteButton.isEnabled = (file != null) deleteButton.color = if (file != null) Color.SCARLET else Color.BROWN } - fun loaderThread() { + private fun CoroutineScope.loaderThread() { var popup: Popup? = null var needPopup = true // loadMap can fail faster than postRunnable runs - Gdx.app.postRunnable { - if (!needPopup) return@postRunnable + Concurrency.runOnGLThread { + if (!needPopup) return@runOnGLThread popup = Popup(editorScreen).apply { addGoodSizedLabel(Constants.loading) open() @@ -108,6 +112,7 @@ class MapEditorLoadTab( } try { val map = MapSaver.loadMap(chosenMap!!) + if (!isActive) return val missingMods = map.mapParameters.mods.filter { it !in RulesetCache }.toMutableList() // [TEMPORARY] conversion of old maps with a base ruleset contained in the mods @@ -117,12 +122,12 @@ class MapEditorLoadTab( if (map.mapParameters.baseRuleset !in RulesetCache) missingMods += map.mapParameters.baseRuleset if (missingMods.isNotEmpty()) { - Gdx.app.postRunnable { + Concurrency.runOnGLThread { needPopup = false popup?.close() ToastPopup("Missing mods: [${missingMods.joinToString()}]", editorScreen) } - } else Gdx.app.postRunnable { + } else Concurrency.runOnGLThread { Gdx.input.inputProcessor = null // This is to stop ANRs happening here, until the map editor screen sets up. try { // For deprecated maps, set the base ruleset field if it's still saved in the mods field @@ -155,7 +160,7 @@ class MapEditorLoadTab( } } catch (ex: Throwable) { needPopup = false - Gdx.app.postRunnable { + Concurrency.runOnGLThread { popup?.close() Log.error("Error loading map \"$chosenMap\"", ex) diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorSaveTab.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorSaveTab.kt index 2137842768..844c73c5c4 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorSaveTab.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorSaveTab.kt @@ -1,6 +1,5 @@ package com.unciv.ui.screens.mapeditorscreen.tabs -import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.ui.Table @@ -25,8 +24,10 @@ import com.unciv.ui.components.extensions.onActivation import com.unciv.ui.components.extensions.onChange import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.toTextButton +import com.unciv.utils.Concurrency import com.unciv.utils.Log -import kotlin.concurrent.thread +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.isActive class MapEditorSaveTab( private val editorScreen: MapEditorScreen, @@ -35,7 +36,9 @@ class MapEditorSaveTab( private val mapFiles = MapEditorFilesTable( initWidth = editorScreen.getToolsWidth() - 40f, includeMods = false, - this::selectFile) + this::selectFile, + this::saveHandler + ) private val saveButton = "Save map".toTextButton() private val deleteButton = "Delete map".toTextButton() @@ -76,11 +79,17 @@ class MapEditorSaveTab( add(buttonTable).row() } + private fun setSaveButton(enabled: Boolean) { + saveButton.isEnabled = enabled + saveButton.setText((if (enabled) "Save map" else "Working...").tr()) + } + private fun saveHandler() { if (mapNameTextField.text.isBlank()) return editorScreen.tileMap.mapParameters.name = mapNameTextField.text editorScreen.tileMap.mapParameters.type = MapGeneratedMainType.custom - thread(name = "MapSaver", block = this::saverThread) + setSaveButton(false) + editorScreen.startBackgroundJob("MapSaver", false) { saverThread() } } private fun deleteHandler() { @@ -106,7 +115,7 @@ class MapEditorSaveTab( stage.keyboardFocus = null } - fun selectFile(file: FileHandle?) { + private fun selectFile(file: FileHandle?) { chosenMap = file mapNameTextField.text = file?.name() ?: editorScreen.tileMap.mapParameters.name if (mapNameTextField.text.isBlank()) mapNameTextField.text = "My new map".tr() @@ -117,22 +126,26 @@ class MapEditorSaveTab( deleteButton.color = if (file != null) Color.SCARLET else Color.BROWN } - private fun saverThread() { + private fun CoroutineScope.saverThread() { try { val mapToSave = editorScreen.getMapCloneForSave() + if (!isActive) return mapToSave.assignContinents(TileMap.AssignContinentsMode.Reassign) + if (!isActive) return MapSaver.saveMap(mapNameTextField.text, mapToSave) - Gdx.app.postRunnable { + Concurrency.runOnGLThread { ToastPopup("Map saved successfully!", editorScreen) } editorScreen.isDirty = false + setSaveButton(true) } catch (ex: Exception) { Log.error("Failed to save map", ex) - Gdx.app.postRunnable { + Concurrency.runOnGLThread { val cantLoadGamePopup = Popup(editorScreen) cantLoadGamePopup.addGoodSizedLabel("It looks like your map can't be saved!").row() cantLoadGamePopup.addCloseButton() cantLoadGamePopup.open(force = true) + setSaveButton(true) } } } diff --git a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorViewTab.kt b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorViewTab.kt index 60ad2da793..e916728c79 100644 --- a/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorViewTab.kt +++ b/core/src/com/unciv/ui/screens/mapeditorscreen/tabs/MapEditorViewTab.kt @@ -3,6 +3,7 @@ package com.unciv.ui.screens.mapeditorscreen.tabs import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.logic.GameInfo import com.unciv.logic.civilization.Civilization @@ -12,15 +13,18 @@ import com.unciv.logic.map.tile.TileDescription import com.unciv.models.Counter import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.nation.Nation +import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.stats.Stats import com.unciv.models.translations.tr import com.unciv.ui.components.ExpanderTab import com.unciv.ui.components.TabbedPager +import com.unciv.ui.components.UncivSlider import com.unciv.ui.components.WrappableLabel import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.pad +import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.popups.ToastPopup import com.unciv.ui.screens.basescreen.BaseScreen @@ -43,6 +47,8 @@ class MapEditorViewTab( init { top() + // Note on width: max expander content width + 2 * expander.defaultPad + 2 * the following horizontal pad + // should not exceed editorScreen.getToolsWidth() or the page will scroll horizontally! defaults().pad(5f, 20f) update() } @@ -72,7 +78,8 @@ class MapEditorViewTab( val headerText = tileMap.mapParameters.name.ifEmpty { "New map" } add(ExpanderTab( headerText, - startsOutOpened = false + startsOutOpened = false, + defaultPad = 0f // See note in init ) { val mapParameterText = tileMap.mapParameters.toString() .replace("\"${tileMap.mapParameters.name}\" ", "") @@ -196,7 +203,7 @@ class MapEditorViewTab( lines += FormattedLine("Continent: [$continent] ([${tile.tileMap.continentSizes[continent]}] tiles)", link = "continent") } - tileDataCell?.setActor(MarkupRenderer.render(lines, labelWidth) { + val renderedInfo = MarkupRenderer.render(lines, labelWidth) { if (it == "continent") { // Visualize the continent this tile is on editorScreen.hideSelection() @@ -209,7 +216,25 @@ class MapEditorViewTab( // This needs CivilopediaScreen to be able to work without a GameInfo! UncivGame.Current.pushScreen(CivilopediaScreen(tile.ruleset, link = it)) } - }) + } + + if (tile.resource != null && (tile.resourceAmount > 0 || tile.tileResource.resourceType == ResourceType.Strategic)) { + renderedInfo.addSeparator(Color.GRAY) + renderedInfo.add(Table().apply { + add("Resource abundance".toLabel(alignment = Align.left)).left().growX() + val slider = UncivSlider(0f, 42f, 1f, + initial = tile.resourceAmount.toFloat() + ) { + tile.resourceAmount = it.toInt() + editorScreen.updateTile(tile) + editorScreen.isDirty = true + } + slider.setSnapToValues(floatArrayOf(0f,1f,2f,3f,4f,5f,6f,7f,8f,9f,10f,12f,15f,20f,30f,40f), 5f) + add(slider).right().minWidth(80f).fillX().padTop(15f) + }).fillX() + } + + tileDataCell?.setActor(renderedInfo) editorScreen.hideSelection() editorScreen.highlightTile(tile, Color.CORAL)