diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index ee2c83a727..d67cc0b568 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -349,6 +349,7 @@ Four Corners = Archipelago = Inner Sea = Perlin = +Select players from starting locations = Random number of Civilizations = Min number of Civilizations = Max number of Civilizations = diff --git a/core/src/com/unciv/logic/files/MapSaver.kt b/core/src/com/unciv/logic/files/MapSaver.kt index b9de870bf2..111d6203b9 100644 --- a/core/src/com/unciv/logic/files/MapSaver.kt +++ b/core/src/com/unciv/logic/files/MapSaver.kt @@ -40,22 +40,20 @@ object MapSaver { private fun mapFromJson(json: String): TileMap = json().fromJson(TileMap::class.java, json) - /** Class to parse only the parameters out of a map file */ - private class TileMapPreview { - val mapParameters = MapParameters() - } - fun loadMapParameters(mapFile: FileHandle): MapParameters { - return mapParametersFromSavedString(mapFile.readString()) + return loadMapPreview(mapFile).mapParameters } - @Suppress("MemberVisibilityCanBePrivate") - fun mapParametersFromSavedString(mapString: String): MapParameters { + fun loadMapPreview(mapFile: FileHandle): TileMap.Preview { + return mapPreviewFromSavedString(mapFile.readString()) + } + + private fun mapPreviewFromSavedString(mapString: String): TileMap.Preview { val unzippedJson = try { Gzip.unzip(mapString.trim()) } catch (_: Exception) { mapString } - return json().fromJson(TileMapPreview::class.java, unzippedJson).mapParameters + return json().fromJson(TileMap.Preview::class.java, unzippedJson) } } diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index ba8198c96e..c35952106b 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -106,7 +106,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { /** * creates a hexagonal map of given radius (filled with grassland) * - * To help you visualize how UnCiv hexagonal cooridinate system works, here's a small example: + * To help you visualize how UnCiv hexagonal coordinate system works, here's a small example: * * _____ _____ _____ * / \ / \ / \ @@ -119,10 +119,10 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { * / 1 ,-2 \_____/ 0,-1 \_____/ -1,0 \_____/ -2,1 \ * \ / \ / \ / \ / * \_____/ 0,-2 \_____/ -1,-1 \_____/ -2,0 \_____/ - * / \ / \ / \ / - * / 0,-3 \_____/ -1,-2 \_____/ -2,-1 \_____/ - * \ / \ / \ / - * \_____/ \_____/ \_____/ + * / \ / \ / \ / \ + * / 0,-3 \_____/ -1,-2 \_____/ -2,-1 \_____/ -3,0 \ + * \ / \ / \ / \ / + * \_____/ \_____/ \_____/ \_____/ * * * The rules are simple if you think about your X and Y axis as diagonal w.r.t. a standard carthesian plane. As such: @@ -132,8 +132,9 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { * moving "up-right" and "down-left": moving along Y axis * moving "up-left" and "down-right": moving along X axis * - * Tip: you can always use the in-game map editor if you have any doubt - * */ + * Tip: you can always use the in-game map editor if you have any doubt, + * and the "secret" options can turn on coordinate display on the main map. + */ constructor(radius: Int, ruleset: Ruleset, worldWrap: Boolean = false) : this (HexMath.getNumberOfTilesInHexagon(radius)) { startingLocations.clear() @@ -749,4 +750,11 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization { } } //endregion + + /** Class to parse only the parameters and starting locations out of a map file */ + class Preview { + val mapParameters = MapParameters() + private val startingLocations = arrayListOf() + fun getDeclaredNations() = startingLocations.asSequence().map { it.nation }.distinct() + } } diff --git a/core/src/com/unciv/ui/components/extensions/CollectionExtensions.kt b/core/src/com/unciv/ui/components/extensions/CollectionExtensions.kt index 6bef1b4f63..004b56fadc 100644 --- a/core/src/com/unciv/ui/components/extensions/CollectionExtensions.kt +++ b/core/src/com/unciv/ui/components/extensions/CollectionExtensions.kt @@ -75,6 +75,11 @@ fun Iterable.toGdxArray(): Array { for (it in this) arr.add(it) return arr } +fun Sequence.toGdxArray(): Array { + val arr = Array() + for (it in this) arr.add(it) + return arr +} /** [yield][SequenceScope.yield]s [element] if it's not null */ suspend fun SequenceScope.yieldIfNotNull(element: T?) { diff --git a/core/src/com/unciv/ui/components/widgets/LoadingImage.kt b/core/src/com/unciv/ui/components/widgets/LoadingImage.kt index 693983e510..8c524e0b44 100644 --- a/core/src/com/unciv/ui/components/widgets/LoadingImage.kt +++ b/core/src/com/unciv/ui/components/widgets/LoadingImage.kt @@ -132,6 +132,8 @@ class LoadingImage( if (animated) hideAnimated(onComplete) else hideDelayed(onComplete) + fun isShowing() = loadingIcon.isVisible && actions.isEmpty + //region Hiding helpers private fun hideAnimated(onComplete: (() -> Unit)?) { actions.clear() diff --git a/core/src/com/unciv/ui/screens/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/screens/newgamescreen/GameOptionsTable.kt index b342010c5e..03703a9aab 100644 --- a/core/src/com/unciv/ui/screens/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/screens/newgamescreen/GameOptionsTable.kt @@ -42,9 +42,9 @@ class GameOptionsTable( private val updatePlayerPickerTable: (desiredCiv: String) -> Unit, private val updatePlayerPickerRandomLabel: () -> Unit ) : Table(BaseScreen.skin) { - var gameParameters = previousScreen.gameSetupInfo.gameParameters - var ruleset = previousScreen.ruleset - var locked = false + private var gameParameters = previousScreen.gameSetupInfo.gameParameters + private var ruleset = previousScreen.ruleset + internal var locked = false private var baseRulesetHash = gameParameters.baseRuleset.hashCode() @@ -56,7 +56,7 @@ class GameOptionsTable( * * The second reason this is public: [NewGameScreen] accesses [ModCheckboxTable.savedModcheckResult] for display. */ - val modCheckboxes = getModCheckboxes(isPortrait = isPortrait) + internal val modCheckboxes = getModCheckboxes(isPortrait = isPortrait) // Remember this so we can unselect it when the pool dialog returns an empty pool private var randomNationsPoolCheckbox: CheckBox? = null @@ -74,12 +74,12 @@ class GameOptionsTable( clear() // Mods may have changed (e.g. custom map selection) + modCheckboxes.updateSelection() val newBaseRulesetHash = gameParameters.baseRuleset.hashCode() if (newBaseRulesetHash != baseRulesetHash) { baseRulesetHash = newBaseRulesetHash modCheckboxes.setBaseRuleset(gameParameters.baseRuleset) } - modCheckboxes.updateSelection() add(Table().apply { defaults().pad(5f) @@ -442,6 +442,7 @@ class GameOptionsTable( fun updateRuleset(ruleset: Ruleset) { this.ruleset = ruleset gameParameters.acceptedModCheckErrors = "" + modCheckboxes.updateSelection() modCheckboxes.setBaseRuleset(gameParameters.baseRuleset) } @@ -493,6 +494,11 @@ class GameOptionsTable( updatePlayerPickerTable(desiredCiv) } + + fun changeGameParameters(newGameParameters: GameParameters) { + gameParameters = newGameParameters + modCheckboxes.changeGameParameters(newGameParameters) + } } private class RandomNationPickerPopup( diff --git a/core/src/com/unciv/ui/screens/newgamescreen/MapFileSelectTable.kt b/core/src/com/unciv/ui/screens/newgamescreen/MapFileSelectTable.kt index 3c720e2f9f..5186a1eac3 100644 --- a/core/src/com/unciv/ui/screens/newgamescreen/MapFileSelectTable.kt +++ b/core/src/com/unciv/ui/screens/newgamescreen/MapFileSelectTable.kt @@ -1,57 +1,98 @@ package com.unciv.ui.screens.newgamescreen import com.badlogic.gdx.files.FileHandle +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.actions.Actions +import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Container import com.badlogic.gdx.scenes.scene2d.ui.SelectBox import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.UncivGame +import com.unciv.logic.civilization.PlayerType import com.unciv.logic.files.MapSaver import com.unciv.logic.map.MapParameters +import com.unciv.logic.map.TileMap +import com.unciv.models.metadata.Player import com.unciv.models.ruleset.RulesetCache +import com.unciv.models.ruleset.nation.Nation +import com.unciv.models.translations.tr +import com.unciv.ui.components.extensions.disable +import com.unciv.ui.components.extensions.enable import com.unciv.ui.components.extensions.pad +import com.unciv.ui.components.extensions.toGdxArray import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onChange +import com.unciv.ui.components.widgets.LoadingImage +import com.unciv.ui.popups.AnimatedMenuPopup import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.victoryscreen.LoadMapPreview import com.unciv.utils.Concurrency import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.isActive -import com.badlogic.gdx.utils.Array as GdxArray class MapFileSelectTable( private val newGameScreen: NewGameScreen, private val mapParameters: MapParameters ) : Table() { - + private val mapCategorySelectBox = SelectBox(BaseScreen.skin) private val mapFileSelectBox = SelectBox(BaseScreen.skin) + private val loadingIcon = LoadingImage(30f, LoadingImage.Style(loadingColor = Color.SCARLET)) + private val useNationsFromMapButton = "Select players from starting locations".toTextButton(AnimatedMenuPopup.SmallButtonStyle()) + private val useNationsButtonCell: Cell + private var mapNations = emptyList() private val miniMapWrapper = Container() private var mapPreviewJob: Job? = null + private var preselectedName = mapParameters.name // The SelectBox auto displays the text a object.toString(), which on the FileHandle itself includes the folder path. // So we wrap it in another object with a custom toString() - private class MapWrapper(val fileHandle: FileHandle, val mapParameters: MapParameters) { - override fun toString(): String = mapParameters.baseRuleset + " | " + fileHandle.name() + private class MapWrapper(val fileHandle: FileHandle, val mapPreview: TileMap.Preview) { + override fun toString(): String = fileHandle.name() + fun getCategoryName(): String = fileHandle.parent().parent().name() + .ifEmpty { mapPreview.mapParameters.baseRuleset } } private val mapWrappers = ArrayList() private val columnWidth = newGameScreen.getColumnWidth() + private val collator = UncivGame.Current.settings.getCollatorFromLocale() + init { - defaults().pad(5f, 10f) // Must stay same as in MapParametersTable - val mapFileLabel = "{Map file}:".toLabel() - add(mapFileLabel).left() - add(mapFileSelectBox) + add(Table().apply { + defaults().pad(5f, 10f) // Must stay same as in MapParametersTable + val mapCategoryLabel = "{Map Mod}:".toLabel() + val mapFileLabel = "{Map file}:".toLabel() // because SOME people gotta give the hugest names to their maps - .width(columnWidth - 40f - mapFileLabel.prefWidth) - .right().row() + val selectBoxWidth = columnWidth - 80f - + mapFileLabel.prefWidth.coerceAtLeast(mapCategoryLabel.prefWidth) + add(mapCategoryLabel).left() + add(mapCategorySelectBox).width(selectBoxWidth).right().row() + add(mapFileLabel).left() + add(mapFileSelectBox).width(selectBoxWidth).right().row() + }).growX() + + add(loadingIcon).padRight(5f).padLeft(0f).row() + + useNationsButtonCell = add().pad(0f) + row() + add(miniMapWrapper) .pad(15f) .maxWidth(columnWidth - 20f) .colspan(2).center().row() - mapFileSelectBox.onChange { onSelectBoxChange() } + mapCategorySelectBox.onChange { onCategorySelectBoxChange() } + mapFileSelectBox.onChange { onFileSelectBoxChange() } + useNationsFromMapButton.onActivation { onUseNationsFromMap() } addMapWrappersAsync() } @@ -66,21 +107,58 @@ class MapFileSelectTable( }.sortedByDescending { it.lastModified() } private fun addMapWrappersAsync() { - val mapFilesSequence = getMapFilesSequence() + val mapFilesFlow = getMapFilesSequence().asFlow().map { + MapWrapper(it, MapSaver.loadMapPreview(it)) + } + loadingIcon.show() Concurrency.run { - for (mapFile in mapFilesSequence) { - val mapParameters = try { - MapSaver.loadMapParameters(mapFile) - } catch (_: Exception) { - continue + mapFilesFlow + .onEach { + mapWrappers.add(it) + Concurrency.runOnGLThread { + addAsyncEntryToSelectBoxes(it) + } } - mapWrappers.add(MapWrapper(mapFile, mapParameters)) + .catch {} + .collect() + Concurrency.runOnGLThread { + loadingIcon.hide { + loadingIcon.remove() + } + onCategorySelectBoxChange() // re-sort lower SelectBox } - Concurrency.runOnGLThread { fillMapFileSelectBox() } } } + private fun addAsyncEntryToSelectBoxes(mapWrapper: MapWrapper) { + // Take the mod name where the map is stored, or if it's not a mod map, the base ruleset it's saved for + val categoryName = mapWrapper.getCategoryName() + + if (!mapCategorySelectBox.items.contains(categoryName, false)) { + val sortToTop = newGameScreen.gameSetupInfo.gameParameters.baseRuleset + val select = if (mapCategorySelectBox.selection.isEmpty) categoryName + else mapCategorySelectBox.selected + // keep Ruleset SelectBox sorted while async is running - few entries + val newItems = (mapCategorySelectBox.items.asSequence() + categoryName) + .sortedWith( + compareBy { it != sortToTop } + .thenBy(collator) { it } + ).toGdxArray() + mapCategorySelectBox.selection.setProgrammaticChangeEvents(false) + mapCategorySelectBox.items = newItems + mapCategorySelectBox.selected = select + mapCategorySelectBox.selection.setProgrammaticChangeEvents(true) + } + + if (mapCategorySelectBox.selected != categoryName) return + + // .. but add the maps themselves as they come + mapFileSelectBox.selection.setProgrammaticChangeEvents(false) + mapFileSelectBox.items.add(mapWrapper) + mapFileSelectBox.items = mapFileSelectBox.items // Call setItems so SelectBox sees the change + mapFileSelectBox.selection.setProgrammaticChangeEvents(true) + } private val firstMap: FileHandle? by lazy { getMapFilesSequence().firstOrNull { @@ -93,36 +171,42 @@ class MapFileSelectTable( } } + private fun FileHandle.isRecentlyModified() = lastModified() > System.currentTimeMillis() - 900000 // 900s = quarter hour fun isNotEmpty() = firstMap != null - fun recentlySavedMapExists() = firstMap!=null && firstMap!!.lastModified() > System.currentTimeMillis() - 900000 + fun recentlySavedMapExists() = firstMap != null && firstMap!!.isRecentlyModified() - private fun fillMapFileSelectBox() { - if (!mapFileSelectBox.items.isEmpty) return + fun activateCustomMaps() { + if (loadingIcon.isShowing()) return // Default map selection will be handled when background loading finishes + preselectedName = mapParameters.name + onFileSelectBoxChange() + } - val mapFiles = GdxArray() - mapWrappers - .sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.toString() }) - .sortedByDescending { it.mapParameters.baseRuleset == newGameScreen.gameSetupInfo.gameParameters.baseRuleset } - .forEach { mapFiles.add(it) } + private fun onCategorySelectBoxChange() { + val selectedRuleset: String? = mapCategorySelectBox.selected + val mapFiles = mapWrappers.asSequence() + .filter { it.getCategoryName() == selectedRuleset } + .sortedWith(compareBy(collator) { it.toString() }) + .toGdxArray() + fun getPreselect(): MapWrapper? { + if (mapFiles.isEmpty) return null + val recent = mapFiles.asSequence() + .filter { it.fileHandle.isRecentlyModified() } + .maxByOrNull { it.fileHandle.lastModified() } + val oldestTimestamp = mapFiles.minOfOrNull { it.fileHandle.lastModified() } ?: 0L + // Do not use most recent if all maps in the category have the same time within a tenth of a second (like a mod unzip does) + if (recent != null && (recent.fileHandle.lastModified() - oldestTimestamp) > 100 || mapFiles.size == 1) + return recent + val named = mapFiles.firstOrNull { it.fileHandle.name() == preselectedName } + if (named != null) + return named + return mapFiles.first() + } + val selectedItem = getPreselect() - // Pre-select: a) map saved within last 15min or b) map named in mapParameters or c) alphabetically first - // This is a kludge - the better way would be to have a "play this map now" menu button in the editor - // (which would ideally not even require a save file - which makes implementation non-trivial) - val selectedItem = - mapFiles.maxByOrNull { it.fileHandle.lastModified() } - ?.takeIf { it.fileHandle.lastModified() > System.currentTimeMillis() - 900000 } - ?: mapFiles.firstOrNull { it.fileHandle.name() == mapParameters.name } - ?: mapFiles.firstOrNull() - ?: return - - // since mapFileSelectBox.selection.setProgrammaticChangeEvents() defaults to true, this would - // kill the mapParameters.name we would like to look for when determining what to pre-select - - // so do it ***after*** getting selectedItem - but control programmaticChangeEvents anyway - // to avoid the overhead of doing a full updateRuleset + updateTables + startMapPreview + // avoid the overhead of doing a full updateRuleset + updateTables + startMapPreview // (all expensive) for something that will be overthrown momentarily mapFileSelectBox.selection.setProgrammaticChangeEvents(false) mapFileSelectBox.items = mapFiles - // Now, we want this ON because the event removes map selections which are pulling mods // that trip updateRuleset - so that code should still be active for the pre-selection mapFileSelectBox.selection.setProgrammaticChangeEvents(true) @@ -131,17 +215,38 @@ class MapFileSelectTable( // Do NOT try to put back the "bad" preselection! } - fun onSelectBoxChange() { + private fun onFileSelectBoxChange() { cancelBackgroundJobs() if (mapFileSelectBox.selection.isEmpty) return - val mapFile = mapFileSelectBox.selected.fileHandle - mapParameters.name = mapFile.name() - newGameScreen.gameSetupInfo.mapFile = mapFile - val mapMods = mapFileSelectBox.selected.mapParameters.mods.partition { RulesetCache[it]?.modOptions?.isBaseRuleset == true } + val selection = mapFileSelectBox.selected + + val mapMods = selection.mapPreview.mapParameters.mods + .partition { RulesetCache[it]?.modOptions?.isBaseRuleset == true } newGameScreen.gameSetupInfo.gameParameters.mods = LinkedHashSet(mapMods.second) newGameScreen.gameSetupInfo.gameParameters.baseRuleset = mapMods.first.firstOrNull() - ?: mapFileSelectBox.selected.mapParameters.baseRuleset + ?: selection.mapPreview.mapParameters.baseRuleset val success = newGameScreen.tryUpdateRuleset(updateUI = true) + + mapNations = if (success) + selection.mapPreview.getDeclaredNations() + .mapNotNull { newGameScreen.ruleset.nations[it] } + .filter { it.isMajorCiv } + .toList() + else emptyList() + + if (mapNations.isEmpty()) { + useNationsButtonCell.setActor(null) + useNationsButtonCell.height(0f).pad(0f) + } else { + useNationsFromMapButton.enable() + useNationsButtonCell.setActor(useNationsFromMapButton) + useNationsButtonCell.height(useNationsFromMapButton.prefHeight).padLeft(5f).padTop(10f) + } + + val mapFile = selection.fileHandle + mapParameters.name = mapFile.name() + newGameScreen.gameSetupInfo.mapFile = mapFile + newGameScreen.updateTables() hideMiniMap() if (success) { @@ -153,7 +258,7 @@ class MapFileSelectTable( items.removeIndex(mapFileSelectBox.selectedIndex) // Changing the array itself is not enough, SelectBox gets out of sync, need to call setItems() mapFileSelectBox.items = items - // Note - this will have triggered a nested onSelectBoxChange()! + // Note - this will have triggered a nested onFileSelectBoxChange()! } } @@ -211,4 +316,19 @@ class MapFileSelectTable( ) ) } + + private fun onUseNationsFromMap() { + useNationsFromMapButton.disable() + val players = newGameScreen.playerPickerTable.gameParameters.players + players.clear() + val pickForHuman = mapNations.random().name + mapNations.asSequence() + .map { it.name to it.name.tr(hideIcons = true) } // Sort by translation but keep untranslated name + .sortedWith( + compareBy>{ it.first != pickForHuman } + .thenBy(collator) { it.second } + ).map { Player(it.first, if (it.first == pickForHuman) PlayerType.Human else PlayerType.AI) } + .toCollection(players) + newGameScreen.playerPickerTable.update() + } } diff --git a/core/src/com/unciv/ui/screens/newgamescreen/MapOptionsTable.kt b/core/src/com/unciv/ui/screens/newgamescreen/MapOptionsTable.kt index f6f66f5357..7cbb2f1186 100644 --- a/core/src/com/unciv/ui/screens/newgamescreen/MapOptionsTable.kt +++ b/core/src/com/unciv/ui/screens/newgamescreen/MapOptionsTable.kt @@ -38,7 +38,7 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen, isReset: Boolean MapGeneratedMainType.custom -> { mapParameters.type = MapGeneratedMainType.custom mapTypeSpecificTable.add(savedMapOptionsTable) - savedMapOptionsTable.onSelectBoxChange() + savedMapOptionsTable.activateCustomMaps() newGameScreen.unlockTables() } MapGeneratedMainType.generated -> { diff --git a/core/src/com/unciv/ui/screens/newgamescreen/ModCheckboxTable.kt b/core/src/com/unciv/ui/screens/newgamescreen/ModCheckboxTable.kt index 9110ed5afb..d0a0b3297a 100644 --- a/core/src/com/unciv/ui/screens/newgamescreen/ModCheckboxTable.kt +++ b/core/src/com/unciv/ui/screens/newgamescreen/ModCheckboxTable.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.scenes.scene2d.ui.CheckBox import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener +import com.unciv.models.metadata.GameParameters import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.validation.ModCompatibility @@ -18,14 +19,14 @@ import com.unciv.ui.screens.basescreen.BaseScreen * A widget containing one expander for extension mods. * Manages compatibility checks, warns or prevents incompatibilities. * - * @param mods In/out set of active mods, modified in place + * @param mods **Reference**: In/out set of active mods, modified in place: If this needs to change, call [changeGameParameters] * @param initialBaseRuleset The selected base Ruleset, only for running mod checks against. Use [setBaseRuleset] to change on the fly. * @param screen Parent screen, used only to show [ToastPopup]s * @param isPortrait Used only for minor layout tweaks, arrangement is always vertical * @param onUpdate Callback, parameter is the mod name, called after any checks that may prevent mod selection succeed. */ class ModCheckboxTable( - private val mods: LinkedHashSet, + private var mods: LinkedHashSet, initialBaseRuleset: String, private val screen: BaseScreen, isPortrait: Boolean = false, @@ -217,4 +218,8 @@ class ModCheckboxTable( .filter { it.widget.isChecked } .map { it.mod } .asIterable() + + fun changeGameParameters(newGameParameters: GameParameters) { + mods = newGameParameters.mods + } } diff --git a/core/src/com/unciv/ui/screens/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/screens/newgamescreen/NewGameScreen.kt index b8bf0b6507..c949a096c0 100644 --- a/core/src/com/unciv/ui/screens/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/screens/newgamescreen/NewGameScreen.kt @@ -41,9 +41,9 @@ import com.unciv.ui.screens.pickerscreens.PickerScreen import com.unciv.utils.Concurrency import com.unciv.utils.Log import com.unciv.utils.launchOnGLThread -import kotlinx.coroutines.coroutineScope import java.net.URL import java.util.UUID +import kotlinx.coroutines.coroutineScope import kotlin.math.floor import com.unciv.ui.components.widgets.AutoScrollPane as ScrollPane @@ -55,7 +55,7 @@ class NewGameScreen( override var gameSetupInfo = defaultGameSetupInfo ?: GameSetupInfo.fromSettings() override val ruleset = Ruleset() // updateRuleset will clear and add private val newGameOptionsTable: GameOptionsTable - private val playerPickerTable: PlayerPickerTable + internal val playerPickerTable: PlayerPickerTable private val mapOptionsTable: MapOptionsTable init { @@ -406,7 +406,7 @@ class NewGameScreen( fun updateTables() { playerPickerTable.gameParameters = gameSetupInfo.gameParameters playerPickerTable.update() - newGameOptionsTable.gameParameters = gameSetupInfo.gameParameters + newGameOptionsTable.changeGameParameters(gameSetupInfo.gameParameters) newGameOptionsTable.update() }