diff --git a/.gitignore b/.gitignore index 8a075a8f..236af35d 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,4 @@ android/release/ android/assets/mods/ android/assets/SaveFiles/ android/assets/GameSettingsOld.json +android/assets/scenarios/ diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index 5f997e8c..1ec943cd 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -56,6 +56,9 @@ class UncivGame( /** Console log battles */ val alertBattle = true + /** Debug new Scenario functionality + */ + val scenarioDebugSwitch = false lateinit var worldScreen: WorldScreen diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 28c00930..1165c840 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -21,7 +21,9 @@ object GameStarter { gameInfo.gameParameters = gameSetupInfo.gameParameters val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters.mods) - if (gameSetupInfo.mapParameters.name != "") + if (gameSetupInfo.mapParameters.type == MapType.scenario) + gameInfo.tileMap = MapSaver.loadScenario(gameSetupInfo.mapParameters.name).tileMap + else if (gameSetupInfo.mapParameters.name != "") gameInfo.tileMap = MapSaver.loadMap(gameSetupInfo.mapParameters.name) else gameInfo.tileMap = MapGenerator(ruleset).generateMap(gameSetupInfo.mapParameters) gameInfo.tileMap.mapParameters = gameSetupInfo.mapParameters diff --git a/core/src/com/unciv/logic/MapSaver.kt b/core/src/com/unciv/logic/MapSaver.kt index 6b711e4a..e34c3e06 100644 --- a/core/src/com/unciv/logic/MapSaver.kt +++ b/core/src/com/unciv/logic/MapSaver.kt @@ -1,6 +1,7 @@ package com.unciv.logic import com.badlogic.gdx.Gdx +import com.unciv.logic.map.Scenario import com.unciv.logic.map.TileMap import com.unciv.ui.saves.Gzip @@ -9,23 +10,36 @@ object MapSaver { fun json() = GameSaver.json() private const val mapsFolder = "maps" + private const val scenariosFolder = "scenarios" private fun getMap(mapName:String) = Gdx.files.local("$mapsFolder/$mapName") - + private fun getScenario(scenarioName:String) = Gdx.files.local("$scenariosFolder/$scenarioName") + fun saveMap(mapName: String,tileMap: TileMap) { getMap(mapName).writeString(Gzip.zip(json().toJson(tileMap)), false) } + fun saveScenario(scenarioName:String, scenario: Scenario) { + getScenario(scenarioName).writeString(json().toJson(scenario), false) + } + fun loadMap(mapName: String): TileMap { val gzippedString = getMap(mapName).readString() val unzippedJson = Gzip.unzip(gzippedString) return json().fromJson(TileMap::class.java, unzippedJson) } + fun loadScenario(scenarioName: String): Scenario { + val scenarioJson = getScenario(scenarioName).readString() + return json().fromJson(Scenario::class.java, scenarioJson) + } + fun deleteMap(mapName: String) = getMap(mapName).delete() fun getMaps() = Gdx.files.local(mapsFolder).list().map { it.name() } + fun getScenarios() = Gdx.files.local(scenariosFolder).list().map { it.name() } + fun mapFromJson(json:String): TileMap = json().fromJson(TileMap::class.java, json) } \ No newline at end of file diff --git a/core/src/com/unciv/logic/map/MapParameters.kt b/core/src/com/unciv/logic/map/MapParameters.kt index 5ceb383d..43b3aea1 100644 --- a/core/src/com/unciv/logic/map/MapParameters.kt +++ b/core/src/com/unciv/logic/map/MapParameters.kt @@ -25,6 +25,9 @@ object MapType { // Non-generated maps const val custom = "Custom" + // Loaded scenario + const val scenario = "Scenario" + // All ocean tiles const val empty = "Empty" } diff --git a/core/src/com/unciv/logic/map/Scenario.kt b/core/src/com/unciv/logic/map/Scenario.kt new file mode 100644 index 00000000..9b8d6711 --- /dev/null +++ b/core/src/com/unciv/logic/map/Scenario.kt @@ -0,0 +1,16 @@ +package com.unciv.logic.map + +import com.unciv.models.metadata.GameParameters + +class Scenario { + lateinit var tileMap: TileMap + lateinit var gameParameters: GameParameters + + /** for json parsing, we need to have a default constructor */ + constructor() + + constructor(tileMap:TileMap, gameParameters: GameParameters) { + this.tileMap = tileMap + this.gameParameters = gameParameters + } +} diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt index 1c78a218..08ed9a79 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt @@ -9,6 +9,11 @@ import com.unciv.UncivGame import com.unciv.logic.MapSaver import com.unciv.logic.map.MapType import com.unciv.logic.map.RoadStatus +import com.unciv.logic.map.Scenario +import com.unciv.logic.map.TileMap +import com.unciv.models.metadata.Player +import com.unciv.ui.newgamescreen.GameOptionsTable +import com.unciv.ui.newgamescreen.PlayerPickerTable import com.unciv.ui.saves.Gzip import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.mainmenu.DropBox @@ -118,6 +123,32 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): Popup(mapEditorScree } add(uploadMapButton).row() + if (UncivGame.Current.scenarioDebugSwitch) { + val createScenarioButton = "Create scenario".toTextButton() + add(createScenarioButton).row() + createScenarioButton.onClick { + remove() + mapEditorScreen.gameSetupInfo.gameParameters.players = getPlayersFromMap(mapEditorScreen.tileMap) // update players list from tileMap starting locations + + val gameParametersPopup = Popup(screen) + val playerPickerTable = PlayerPickerTable(mapEditorScreen, mapEditorScreen.gameSetupInfo.gameParameters) + val gameOptionsTable = GameOptionsTable(mapEditorScreen) {desiredCiv: String -> playerPickerTable.update(desiredCiv)} + val scenarioNameEditor = TextField(mapEditorScreen.mapName, skin) + + gameParametersPopup.add(playerPickerTable) + gameParametersPopup.addSeparatorVertical() + gameParametersPopup.add(gameOptionsTable).row() + gameParametersPopup.add(scenarioNameEditor) + gameParametersPopup.addButton("Save scenario"){ + mapEditorScreen.tileMap.mapParameters.type=MapType.scenario + MapSaver.saveScenario(scenarioNameEditor.text, Scenario(mapEditorScreen.tileMap, mapEditorScreen.gameSetupInfo.gameParameters)) + ResponsePopup("Scenario saved", mapEditorScreen) + gameParametersPopup.close() + }.row() + gameParametersPopup.addCloseButton().row() + gameParametersPopup.open() + } + } val exitMapEditorButton = "Exit map editor".toTextButton() add(exitMapEditorButton ).row() @@ -128,3 +159,15 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): Popup(mapEditorScree add(closeOptionsButton).row() } } + +private fun getPlayersFromMap(tileMap: TileMap): ArrayList { + val tilesWithStartingLocations = tileMap.values + .filter { it.improvement != null && it.improvement!!.startsWith("StartingLocation ") } + var players = ArrayList() + for (tile in tilesWithStartingLocations) { + players.add(Player().apply{ + chosenCiv = tile.improvement!!.removePrefix("StartingLocation ") + }) + } + return players +} diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt index 7f6c199c..7534271f 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt @@ -5,17 +5,24 @@ import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.scenes.scene2d.InputEvent import com.badlogic.gdx.scenes.scene2d.InputListener import com.badlogic.gdx.scenes.scene2d.actions.Actions +import com.badlogic.gdx.scenes.scene2d.ui.SelectBox +import com.badlogic.gdx.scenes.scene2d.ui.Skin +import com.badlogic.gdx.utils.Array import com.unciv.logic.MapSaver import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileMap import com.unciv.models.ruleset.RulesetCache +import com.unciv.models.translations.tr +import com.unciv.ui.newgamescreen.GameParametersPreviousScreen +import com.unciv.ui.newgamescreen.GameSetupInfo import com.unciv.ui.utils.* -class MapEditorScreen(): CameraStageBaseScreen() { - val ruleset = RulesetCache.getBaseRuleset() +class MapEditorScreen(): GameParametersPreviousScreen() { + override val ruleset = RulesetCache.getBaseRuleset() var mapName = "" var tileMap = TileMap() + override var gameSetupInfo = GameSetupInfo() lateinit var mapHolder: EditorMapHolder val tileEditorOptions = TileEditorOptionsTable(this) @@ -149,4 +156,19 @@ class MapEditorScreen(): CameraStageBaseScreen() { } } +class TranslatedSelectBox(values : Collection, default:String, skin: Skin) : SelectBox(skin) { + class TranslatedString(val value: String) { + val translation = value.tr() + override fun toString() = translation + } + + init { + val array = Array() + values.forEach { array.add(TranslatedString(it)) } + items = array + val defaultItem = array.firstOrNull { it.value == default } + selected = if (defaultItem != null) defaultItem else array.first() + } +} + diff --git a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt index 776f56b3..e85a4f38 100644 --- a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt +++ b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt @@ -12,6 +12,8 @@ import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.MapUnit import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo +import com.unciv.logic.map.TileMap +import com.unciv.models.ruleset.Nation import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.translations.tr @@ -48,8 +50,10 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera .onClick { setImprovements() } tabPickerTable.add(improvementsButton) -// val unitsButton = "Units".toTextButton().onClick { setUnits() } -// tabPickerTable.add(unitsButton) + if (UncivGame.Current.scenarioDebugSwitch) { + val unitsButton = "Units".toTextButton().onClick { setUnits() } + tabPickerTable.add(unitsButton) + } tabPickerTable.pack() @@ -154,11 +158,15 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera } val nationsTable = Table() - for(nation in ruleset.nations.values){ + val nations = nationsFromMap(mapEditorScreen.tileMap) + val barbarians = ruleset.nations.values.filter { it.isBarbarian()} + + for(nation in nations + barbarians){ val nationImage = ImageGetter.getNationIndicator(nation, 40f) nationsTable.add(nationImage).row() nationImage.onClick { currentNation = nation; setUnitTileAction() } } + editorPickTable.add(ScrollPane(nationsTable)).height(stage.height*0.8f) val unitsTable = Table() @@ -170,6 +178,18 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera editorPickTable.add(ScrollPane(unitsTable)).height(stage.height*0.8f) } + private fun nationsFromMap(tileMap: TileMap): ArrayList { + val tilesWithStartingLocations = tileMap.values + .filter { it.improvement != null && it.improvement!!.startsWith("StartingLocation ") } + var nations = ArrayList() + for (tile in tilesWithStartingLocations) { + var civName = tile.improvement!!.removePrefix("StartingLocation ") + nations.add(ruleset.nations[civName]!!) + } + return nations + } + + private fun getRedCross(size: Float, alpha: Float): Actor { val redCross = ImageGetter.getImage("OtherIcons/Close") redCross.setSize( size, size) diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt similarity index 70% rename from core/src/com/unciv/ui/newgamescreen/NewGameOptionsTable.kt rename to core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index 6ac5dd06..43b2a916 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -8,17 +8,24 @@ import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.VictoryType import com.unciv.models.translations.tr -import com.unciv.ui.utils.CameraStageBaseScreen -import com.unciv.ui.utils.ImageGetter -import com.unciv.ui.utils.onChange -import com.unciv.ui.utils.toLabel +import com.unciv.ui.utils.* -class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTable:(desiredCiv:String)->Unit) +class GameOptionsTable(previousScreen: GameParametersPreviousScreen, val updatePlayerPickerTable:(desiredCiv:String)->Unit) : Table(CameraStageBaseScreen.skin) { - val newGameParameters = newGameScreen.gameSetupInfo.gameParameters - val ruleset = newGameScreen.ruleset + var gameParameters = previousScreen.gameSetupInfo.gameParameters + val ruleset = previousScreen.ruleset + var locked = false init { + getGameOptionsTable() + } + + fun update() { + clear() + getGameOptionsTable() + } + + private fun getGameOptionsTable() { top() defaults().pad(5f) @@ -46,26 +53,27 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa private fun Table.addCheckbox(text: String, initialState: Boolean, onChange: (newValue: Boolean) -> Unit) { val checkbox = CheckBox(text.tr(), CameraStageBaseScreen.skin) checkbox.isChecked = initialState + checkbox.isDisabled = locked checkbox.onChange { onChange(checkbox.isChecked) } add(checkbox).colspan(2).left().row() } private fun Table.addBarbariansCheckbox() = - addCheckbox("No Barbarians", newGameParameters.noBarbarians) - { newGameParameters.noBarbarians = it } + addCheckbox("No Barbarians", gameParameters.noBarbarians) + { gameParameters.noBarbarians = it } private fun Table.addOneCityChallengeCheckbox() = - addCheckbox("One City Challenge", newGameParameters.oneCityChallenge) - { newGameParameters.oneCityChallenge = it } + addCheckbox("One City Challenge", gameParameters.oneCityChallenge) + { gameParameters.oneCityChallenge = it } private fun Table.addNuclearWeaponsCheckbox() = - addCheckbox("Enable nuclear weapons", newGameParameters.nuclearWeaponsEnabled) - { newGameParameters.nuclearWeaponsEnabled = it } + addCheckbox("Enable nuclear weapons", gameParameters.nuclearWeaponsEnabled) + { gameParameters.nuclearWeaponsEnabled = it } private fun Table.addIsOnlineMultiplayerCheckbox() = - addCheckbox("Online Multiplayer", newGameParameters.isOnlineMultiplayer) - { newGameParameters.isOnlineMultiplayer = it + addCheckbox("Online Multiplayer", gameParameters.isOnlineMultiplayer) + { gameParameters.isOnlineMultiplayer = it updatePlayerPickerTable("") } private fun addCityStatesSelectBox() { @@ -78,34 +86,36 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa (0..numberOfCityStates).forEach { cityStatesArray.add(it) } cityStatesSelectBox.items = cityStatesArray - cityStatesSelectBox.selected = newGameParameters.numberOfCityStates + cityStatesSelectBox.selected = gameParameters.numberOfCityStates add(cityStatesSelectBox).width(50f).row() + cityStatesSelectBox.isDisabled = locked cityStatesSelectBox.onChange { - newGameParameters.numberOfCityStates = cityStatesSelectBox.selected + gameParameters.numberOfCityStates = cityStatesSelectBox.selected } } fun Table.addSelectBox(text: String, values: Collection, initialState: String, onChange: (newValue: String) -> Unit) { add(text.toLabel()).left() val selectBox = TranslatedSelectBox(values, initialState, CameraStageBaseScreen.skin) + selectBox.isDisabled = locked selectBox.onChange { onChange(selectBox.selected.value) } add(selectBox).fillX().row() } private fun Table.addDifficultySelectBox() { - addSelectBox("{Difficulty}:", ruleset.difficulties.keys, newGameParameters.difficulty) - { newGameParameters.difficulty = it } + addSelectBox("{Difficulty}:", ruleset.difficulties.keys, gameParameters.difficulty) + { gameParameters.difficulty = it } } private fun Table.addGameSpeedSelectBox() { - addSelectBox("{Game Speed}:", GameSpeed.values().map { it.name }, newGameParameters.gameSpeed.name) - { newGameParameters.gameSpeed = GameSpeed.valueOf(it) } + addSelectBox("{Game Speed}:", GameSpeed.values().map { it.name }, gameParameters.gameSpeed.name) + { gameParameters.gameSpeed = GameSpeed.valueOf(it) } } private fun Table.addEraSelectBox() { val eras = ruleset.technologies.values.map { it.era() }.distinct() - addSelectBox("{Starting Era}:", eras, newGameParameters.startingEra) - { newGameParameters.startingEra = it } + addSelectBox("{Starting Era}:", eras, gameParameters.startingEra) + { gameParameters.startingEra = it } } @@ -119,13 +129,14 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa if (victoryType == VictoryType.Neutral) continue val victoryCheckbox = CheckBox(victoryType.name.tr(), CameraStageBaseScreen.skin) victoryCheckbox.name = victoryType.name - victoryCheckbox.isChecked = newGameParameters.victoryTypes.contains(victoryType) + victoryCheckbox.isChecked = gameParameters.victoryTypes.contains(victoryType) + victoryCheckbox.isDisabled = locked victoryCheckbox.onChange { // If the checkbox is checked, adds the victoryTypes else remove it if (victoryCheckbox.isChecked) { - newGameParameters.victoryTypes.add(victoryType) + gameParameters.victoryTypes.add(victoryType) } else { - newGameParameters.victoryTypes.remove(victoryType) + gameParameters.victoryTypes.remove(victoryType) } } victoryConditionsTable.add(victoryCheckbox).left() @@ -141,9 +152,9 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa fun reloadMods() { ruleset.clear() - val newRuleset = RulesetCache.getComplexRuleset(newGameParameters.mods) + val newRuleset = RulesetCache.getComplexRuleset(gameParameters.mods) ruleset.add(newRuleset) - ruleset.mods += newGameParameters.mods + ruleset.mods += gameParameters.mods ruleset.modOptions = newRuleset.modOptions ImageGetter.ruleset = ruleset @@ -154,10 +165,11 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa val modCheckboxTable = Table().apply { defaults().pad(5f) } for (mod in modRulesets) { val checkBox = CheckBox(mod.name.tr(), CameraStageBaseScreen.skin) - if (mod.name in newGameParameters.mods) checkBox.isChecked = true + checkBox.isDisabled = locked + if (mod.name in gameParameters.mods) checkBox.isChecked = true checkBox.onChange { - if (checkBox.isChecked) newGameParameters.mods.add(mod.name) - else newGameParameters.mods.remove(mod.name) + if (checkBox.isChecked) gameParameters.mods.add(mod.name) + else gameParameters.mods.remove(mod.name) reloadMods() var desiredCiv = "" if (checkBox.isChecked) { diff --git a/core/src/com/unciv/ui/newgamescreen/GameParametersPreviousScreen.kt b/core/src/com/unciv/ui/newgamescreen/GameParametersPreviousScreen.kt new file mode 100644 index 00000000..12d5f844 --- /dev/null +++ b/core/src/com/unciv/ui/newgamescreen/GameParametersPreviousScreen.kt @@ -0,0 +1,11 @@ +package com.unciv.ui.newgamescreen + +import com.badlogic.gdx.scenes.scene2d.Stage +import com.unciv.models.ruleset.Ruleset +import com.unciv.ui.pickerscreens.PickerScreen +import com.unciv.ui.utils.CameraStageBaseScreen + +abstract class GameParametersPreviousScreen: PickerScreen() { + abstract var gameSetupInfo: GameSetupInfo + abstract val ruleset: Ruleset +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt index 19bb55cc..4d802ce9 100644 --- a/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt @@ -15,10 +15,10 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() { private var mapTypeSpecificTable = Table() private val generatedMapOptionsTable = MapParametersTable(mapParameters) private val savedMapOptionsTable = Table() + private val savedScenarioOptionsTable = Table() init { defaults().pad(5f) - add("Map Options".toLabel(fontSize = 24)).top().padBottom(20f).colspan(2).row() addMapTypeSelection() } @@ -28,6 +28,7 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() { add("{Map Type}:".toLabel()) val mapTypes = arrayListOf("Generated") if (MapSaver.getMaps().isNotEmpty()) mapTypes.add(MapType.custom) + if (MapSaver.getScenarios().isNotEmpty()) mapTypes.add(MapType.scenario) val mapTypeSelectBox = TranslatedSelectBox(mapTypes, "Generated", CameraStageBaseScreen.skin) val mapFileSelectBox = getMapFileSelectBox() @@ -37,16 +38,39 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() { savedMapOptionsTable.add(mapFileSelectBox).maxWidth(newGameScreen.stage.width / 2) .right().row() + val scenarioFileSelectBox = getScenarioFileSelectBox() + savedScenarioOptionsTable.defaults().pad(5f) + savedScenarioOptionsTable.add("{Scenario file}:".toLabel()).left() + // because SOME people gotta give the hugest names to their maps + savedScenarioOptionsTable.add(scenarioFileSelectBox).maxWidth(newGameScreen.stage.width / 2) + .right().row() + fun updateOnMapTypeChange() { mapTypeSpecificTable.clear() if (mapTypeSelectBox.selected.value == MapType.custom) { mapParameters.type = MapType.custom mapParameters.name = mapFileSelectBox.selected mapTypeSpecificTable.add(savedMapOptionsTable) + newGameScreen.gameSetupInfo = GameSetupInfo() + newGameScreen.unlockTables() + newGameScreen.updateTables() + } else if (mapTypeSelectBox.selected.value == MapType.scenario) { + mapParameters.type = MapType.scenario + mapParameters.name = scenarioFileSelectBox.selected + mapTypeSpecificTable.add(savedScenarioOptionsTable) + val scenario = MapSaver.loadScenario(mapParameters.name) + newGameScreen.gameSetupInfo.gameParameters = scenario.gameParameters + newGameScreen.gameSetupInfo.mapParameters = mapParameters + // update PlayerTable and GameOptionsTable + newGameScreen.lockTables() + newGameScreen.updateTables() } else { mapParameters.name = "" mapParameters.type = generatedMapOptionsTable.mapTypeSelectBox.selected.value mapTypeSpecificTable.add(generatedMapOptionsTable) + newGameScreen.gameSetupInfo = GameSetupInfo() + newGameScreen.unlockTables() + newGameScreen.updateTables() } } @@ -59,7 +83,6 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() { add(mapTypeSpecificTable).colspan(2).row() } - private fun getMapFileSelectBox(): SelectBox { val mapFileSelectBox = SelectBox(CameraStageBaseScreen.skin) val mapNames = Array() @@ -71,4 +94,21 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() { return mapFileSelectBox } + private fun getScenarioFileSelectBox(): SelectBox { + val scenarioFileSelectBox = SelectBox(CameraStageBaseScreen.skin) + val scenarioNames = Array() + for (scenarioName in MapSaver.getScenarios()) scenarioNames.add(scenarioName) + scenarioFileSelectBox.items = scenarioNames + if (mapParameters.name in scenarioNames) scenarioFileSelectBox.selected = mapParameters.name + + scenarioFileSelectBox.onChange { + mapParameters.name = scenarioFileSelectBox.selected!! + val scenario = MapSaver.loadScenario(mapParameters.name) + newGameScreen.gameSetupInfo.gameParameters = scenario.gameParameters + newGameScreen.updateTables() + } + return scenarioFileSelectBox + } + + } \ No newline at end of file diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index 5997c96f..ebe9d319 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -2,20 +2,18 @@ package com.unciv.ui.newgamescreen import com.unciv.ui.utils.AutoScrollPane as ScrollPane import com.badlogic.gdx.Gdx +import com.badlogic.gdx.scenes.scene2d.ui.CheckBox import com.badlogic.gdx.scenes.scene2d.ui.SelectBox import com.badlogic.gdx.scenes.scene2d.ui.Skin import com.badlogic.gdx.utils.Array import com.unciv.UncivGame -import com.unciv.logic.GameInfo -import com.unciv.logic.GameSaver -import com.unciv.logic.GameStarter -import com.unciv.logic.IdChecker +import com.unciv.logic.* import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.MapParameters +import com.unciv.logic.map.MapType import com.unciv.models.metadata.GameParameters import com.unciv.models.ruleset.RulesetCache import com.unciv.models.translations.tr -import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer import java.util.* @@ -27,18 +25,21 @@ class GameSetupInfo(var gameId:String, var gameParameters: GameParameters, var m constructor(gameInfo: GameInfo) : this("", gameInfo.gameParameters.clone(), gameInfo.tileMap.mapParameters) } -class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSetupInfo?=null): PickerScreen() { +class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSetupInfo?=null): GameParametersPreviousScreen() { - var gameSetupInfo: GameSetupInfo = _gameSetupInfo ?: GameSetupInfo() - val ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods) + override var gameSetupInfo: GameSetupInfo = _gameSetupInfo ?: GameSetupInfo() + override val ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods) + var playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) + var newGameOptionsTable = GameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } + var mapOptionsTable = MapOptionsTable(this) init { setDefaultCloseAction(previousScreen) scrollPane.setScrollingDisabled(true, true) - val playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) - val newGameOptionsTable = NewGameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } - topTable.add(ScrollPane(MapOptionsTable(this)).apply { setOverscroll(false, false) }) +// val playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) +// val newGameOptionsTable = GameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } + topTable.add(ScrollPane(mapOptionsTable).apply { setOverscroll(false, false) }) .maxHeight(topTable.parent.height).width(stage.width / 3).padTop(20f).top() topTable.addSeparatorVertical() topTable.add(playerPickerTable).maxHeight(topTable.parent.height).width(stage.width / 3).padTop(20f).top() @@ -124,11 +125,27 @@ class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSe Gdx.graphics.requestRendering() } - fun setNewGameButtonEnabled(bool: Boolean) { - if (bool) rightSideButton.enable() - else rightSideButton.disable() +// fun setNewGameButtonEnabled(bool: Boolean) { +// if (bool) rightSideButton.enable() +// else rightSideButton.disable() +// } + + fun lockTables() { + playerPickerTable.locked = true + newGameOptionsTable.locked = true } + fun unlockTables() { + playerPickerTable.locked = false + newGameOptionsTable.locked = false + } + + fun updateTables() { + playerPickerTable.gameParameters = gameSetupInfo.gameParameters + playerPickerTable.update() + newGameOptionsTable.gameParameters = gameSetupInfo.gameParameters + newGameOptionsTable.update() + } var newGame: GameInfo? = null diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index a2ddc767..802cbb16 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.ui.TextField import com.badlogic.gdx.utils.Align import com.unciv.Constants @@ -20,10 +19,12 @@ import com.unciv.models.translations.tr import com.unciv.ui.utils.* import java.util.* -class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: GameParameters): Table() { +class PlayerPickerTable(val previousScreen: GameParametersPreviousScreen, var gameParameters: GameParameters): Table() { val playerListTable = Table() - val nationsPopupWidth = newGameScreen.stage.width / 2f - val civBlocksWidth = newGameScreen.stage.width / 3 + val nationsPopupWidth = previousScreen.stage.width / 2f + val civBlocksWidth = previousScreen.stage.width / 3 + var locked = false + init { top() @@ -34,36 +35,37 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: fun update(desiredCiv: String = "") { playerListTable.clear() - val gameBasics = newGameScreen.ruleset // the mod picking changes this ruleset + val gameBasics = previousScreen.ruleset // the mod picking changes this ruleset reassignRemovedModReferences() - val newRulesetPlayableCivs = newGameScreen.ruleset.nations.count { it.key != Constants.barbarians } - if (newGameParameters.players.size > newRulesetPlayableCivs) - newGameParameters.players = ArrayList(newGameParameters.players.subList(0, newRulesetPlayableCivs)) + val newRulesetPlayableCivs = previousScreen.ruleset.nations.count { it.key != Constants.barbarians } + if (gameParameters.players.size > newRulesetPlayableCivs) + gameParameters.players = ArrayList(gameParameters.players.subList(0, newRulesetPlayableCivs)) if (desiredCiv.isNotEmpty()) assignDesiredCiv(desiredCiv) - for (player in newGameParameters.players) { + for (player in gameParameters.players) { playerListTable.add(getPlayerTable(player, gameBasics)).width(civBlocksWidth).padBottom(20f).row() } - if (newGameParameters.players.count() < gameBasics.nations.values.count { it.isMajorCiv() }) { + if (gameParameters.players.count() < gameBasics.nations.values.count { it.isMajorCiv() } + && !locked) { playerListTable.add("+".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) } - .surroundWithCircle(50f).onClick { newGameParameters.players.add(Player()); update() }).pad(10f) + .surroundWithCircle(50f).onClick { gameParameters.players.add(Player()); update() }).pad(10f) } - newGameScreen.setNewGameButtonEnabled(newGameParameters.players.size > 1) + previousScreen.setRightSideButtonEnabled(gameParameters.players.size > 1) } private fun reassignRemovedModReferences() { - for (player in newGameParameters.players) { - if (!newGameScreen.ruleset.nations.containsKey(player.chosenCiv)) + for (player in gameParameters.players) { + if (!previousScreen.ruleset.nations.containsKey(player.chosenCiv)) player.chosenCiv = "Random" } } private fun assignDesiredCiv(desiredCiv: String) { // No auto-select if desiredCiv already used - if (newGameParameters.players.any { it.chosenCiv == desiredCiv }) return + if (gameParameters.players.any { it.chosenCiv == desiredCiv }) return // Do auto-select, silently no-op if no suitable slot (human with 'random' choice) - newGameParameters.players.firstOrNull { it.chosenCiv == "Random" && it.playerType == PlayerType.Human }?.chosenCiv = desiredCiv + gameParameters.players.firstOrNull { it.chosenCiv == "Random" && it.playerType == PlayerType.Human }?.chosenCiv = desiredCiv } fun getPlayerTable(player: Player, ruleset: Ruleset): Table { @@ -76,16 +78,19 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: val playerTypeTextbutton = player.playerType.name.toTextButton() playerTypeTextbutton.onClick { + if (locked) return@onClick if (player.playerType == PlayerType.AI) player.playerType = PlayerType.Human else player.playerType = PlayerType.AI update() } playerTable.add(playerTypeTextbutton).width(100f).pad(5f).right() - playerTable.add("-".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) } - .surroundWithCircle(40f) - .onClick { newGameParameters.players.remove(player); update() }).pad(5f).right().row() - if (newGameParameters.isOnlineMultiplayer && player.playerType == PlayerType.Human) { + if (!locked) { + playerTable.add("-".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) } + .surroundWithCircle(40f) + .onClick { gameParameters.players.remove(player); update() }).pad(5f).right().row() + } + if (gameParameters.isOnlineMultiplayer && player.playerType == PlayerType.Human) { val playerIdTextfield = TextField(player.playerId, CameraStageBaseScreen.skin) playerIdTextfield.messageText = "Please input Player ID!".tr() @@ -129,7 +134,7 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: .apply { this.setAlignment(Align.center) } .surroundWithCircle(36f).apply { circle.color = Color.BLACK } .surroundWithCircle(40f, false).apply { circle.color = Color.WHITE } - else ImageGetter.getNationIndicator(newGameScreen.ruleset.nations[player.chosenCiv]!!, 40f) + else ImageGetter.getNationIndicator(previousScreen.ruleset.nations[player.chosenCiv]!!, 40f) nationTable.add(nationImage).pad(5f) nationTable.add(player.chosenCiv.toLabel()).pad(5f) nationTable.touchable = Touchable.enabled @@ -140,7 +145,7 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: } private fun popupNationPicker(player: Player) { - val nationsPopup = Popup(newGameScreen) + val nationsPopup = Popup(previousScreen) val nationListTable = Table() val randomPlayerTable = Table() @@ -160,18 +165,18 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: nationListTable.add(randomPlayerTable).pad(10f).width(nationsPopupWidth).row() - for (nation in newGameScreen.ruleset.nations.values + for (nation in previousScreen.ruleset.nations.values .filter { !it.isCityState() && it.name != Constants.barbarians }) { - if (player.chosenCiv != nation.name && newGameParameters.players.any { it.chosenCiv == nation.name }) + if (player.chosenCiv != nation.name && gameParameters.players.any { it.chosenCiv == nation.name }) continue - nationListTable.add(NationTable(nation, nationsPopupWidth, newGameScreen.ruleset).onClick { + nationListTable.add(NationTable(nation, nationsPopupWidth, previousScreen.ruleset).onClick { player.chosenCiv = nation.name nationsPopup.close() update() }).pad(10f).width(nationsPopupWidth).row() } - nationsPopup.add(ScrollPane(nationListTable)).height(newGameScreen.stage.height * 0.8f) + nationsPopup.add(ScrollPane(nationListTable)).height(previousScreen.stage.height * 0.8f) nationsPopup.pack() val closeImage = ImageGetter.getImage("OtherIcons/Close") diff --git a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt index 353e92a4..c83d89d7 100644 --- a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt @@ -53,6 +53,11 @@ open class PickerScreen : CameraStageBaseScreen() { } } + fun setRightSideButtonEnabled(bool: Boolean) { + if (bool) rightSideButton.enable() + else rightSideButton.disable() + } + protected fun pick(rightButtonText: String) { if(UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable() rightSideButton.setText(rightButtonText) diff --git a/tests/src/com/unciv/testing/BasicTests.kt b/tests/src/com/unciv/testing/BasicTests.kt index 1585322a..20cfb421 100644 --- a/tests/src/com/unciv/testing/BasicTests.kt +++ b/tests/src/com/unciv/testing/BasicTests.kt @@ -39,7 +39,9 @@ class BasicTests { Assert.assertTrue("This test will only pass if the game is not run with debug modes", !game.superchargedForDebug && !game.viewEntireMapForDebug - && game.simulateUntilTurnForDebug <= 0) + && game.simulateUntilTurnForDebug <= 0 + && game.simulateUntilWinOrLose <= 0 + && !game.scenarioDebugSwitch) } // If there's a unit that obsoletes with no upgrade then when it obsoletes