Adding units on map editor. (#2667)

* Adding units to map editor.

* loadScenario checkbox Prototype added to MapOptions table.

* adds switch for Scenario and Unit editor debug

* New Scenario class

* Background step1:
1. Create a new class Scenario, containing TileMap, GameParameters and string name (doesn't really matter where, we can move it around later)
2. Create SaveScenario and LoadScenario functions in MapSaver (save to/ load from scenario name)

* Prototype of Save/Load scenario implementation.

* Add update method to NewGameOptionsTable

* First working Save/Load scenario prototype

* First working prototype of Load/Save scenario

* Added test conditions for the new debug modes

* Resolve merge conflict

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
Alexander Korolyov 2020-06-13 15:53:04 -04:00 committed by GitHub
parent 1961aa7245
commit c3da044c43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 297 additions and 81 deletions

1
.gitignore vendored
View file

@ -137,3 +137,4 @@ android/release/
android/assets/mods/ android/assets/mods/
android/assets/SaveFiles/ android/assets/SaveFiles/
android/assets/GameSettingsOld.json android/assets/GameSettingsOld.json
android/assets/scenarios/

View file

@ -56,6 +56,9 @@ class UncivGame(
/** Console log battles /** Console log battles
*/ */
val alertBattle = true val alertBattle = true
/** Debug new Scenario functionality
*/
val scenarioDebugSwitch = false
lateinit var worldScreen: WorldScreen lateinit var worldScreen: WorldScreen

View file

@ -21,7 +21,9 @@ object GameStarter {
gameInfo.gameParameters = gameSetupInfo.gameParameters gameInfo.gameParameters = gameSetupInfo.gameParameters
val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters.mods) 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) gameInfo.tileMap = MapSaver.loadMap(gameSetupInfo.mapParameters.name)
else gameInfo.tileMap = MapGenerator(ruleset).generateMap(gameSetupInfo.mapParameters) else gameInfo.tileMap = MapGenerator(ruleset).generateMap(gameSetupInfo.mapParameters)
gameInfo.tileMap.mapParameters = gameSetupInfo.mapParameters gameInfo.tileMap.mapParameters = gameSetupInfo.mapParameters

View file

@ -1,6 +1,7 @@
package com.unciv.logic package com.unciv.logic
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.unciv.logic.map.Scenario
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
import com.unciv.ui.saves.Gzip import com.unciv.ui.saves.Gzip
@ -9,23 +10,36 @@ object MapSaver {
fun json() = GameSaver.json() fun json() = GameSaver.json()
private const val mapsFolder = "maps" private const val mapsFolder = "maps"
private const val scenariosFolder = "scenarios"
private fun getMap(mapName:String) = Gdx.files.local("$mapsFolder/$mapName") 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) { fun saveMap(mapName: String,tileMap: TileMap) {
getMap(mapName).writeString(Gzip.zip(json().toJson(tileMap)), false) 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 { fun loadMap(mapName: String): TileMap {
val gzippedString = getMap(mapName).readString() val gzippedString = getMap(mapName).readString()
val unzippedJson = Gzip.unzip(gzippedString) val unzippedJson = Gzip.unzip(gzippedString)
return json().fromJson(TileMap::class.java, unzippedJson) 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 deleteMap(mapName: String) = getMap(mapName).delete()
fun getMaps() = Gdx.files.local(mapsFolder).list().map { it.name() } 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) fun mapFromJson(json:String): TileMap = json().fromJson(TileMap::class.java, json)
} }

View file

@ -25,6 +25,9 @@ object MapType {
// Non-generated maps // Non-generated maps
const val custom = "Custom" const val custom = "Custom"
// Loaded scenario
const val scenario = "Scenario"
// All ocean tiles // All ocean tiles
const val empty = "Empty" const val empty = "Empty"
} }

View file

@ -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
}
}

View file

@ -9,6 +9,11 @@ import com.unciv.UncivGame
import com.unciv.logic.MapSaver import com.unciv.logic.MapSaver
import com.unciv.logic.map.MapType import com.unciv.logic.map.MapType
import com.unciv.logic.map.RoadStatus 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.saves.Gzip
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.mainmenu.DropBox import com.unciv.ui.worldscreen.mainmenu.DropBox
@ -118,6 +123,32 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): Popup(mapEditorScree
} }
add(uploadMapButton).row() 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() val exitMapEditorButton = "Exit map editor".toTextButton()
add(exitMapEditorButton ).row() add(exitMapEditorButton ).row()
@ -128,3 +159,15 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): Popup(mapEditorScree
add(closeOptionsButton).row() add(closeOptionsButton).row()
} }
} }
private fun getPlayersFromMap(tileMap: TileMap): ArrayList<Player> {
val tilesWithStartingLocations = tileMap.values
.filter { it.improvement != null && it.improvement!!.startsWith("StartingLocation ") }
var players = ArrayList<Player>()
for (tile in tilesWithStartingLocations) {
players.add(Player().apply{
chosenCiv = tile.improvement!!.removePrefix("StartingLocation ")
})
}
return players
}

View file

@ -5,17 +5,24 @@ import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.InputEvent import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.InputListener import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.actions.Actions 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.MapSaver
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap import com.unciv.logic.map.TileMap
import com.unciv.models.ruleset.RulesetCache 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.* import com.unciv.ui.utils.*
class MapEditorScreen(): CameraStageBaseScreen() { class MapEditorScreen(): GameParametersPreviousScreen() {
val ruleset = RulesetCache.getBaseRuleset() override val ruleset = RulesetCache.getBaseRuleset()
var mapName = "" var mapName = ""
var tileMap = TileMap() var tileMap = TileMap()
override var gameSetupInfo = GameSetupInfo()
lateinit var mapHolder: EditorMapHolder lateinit var mapHolder: EditorMapHolder
val tileEditorOptions = TileEditorOptionsTable(this) val tileEditorOptions = TileEditorOptionsTable(this)
@ -149,4 +156,19 @@ class MapEditorScreen(): CameraStageBaseScreen() {
} }
} }
class TranslatedSelectBox(values : Collection<String>, default:String, skin: Skin) : SelectBox<TranslatedSelectBox.TranslatedString>(skin) {
class TranslatedString(val value: String) {
val translation = value.tr()
override fun toString() = translation
}
init {
val array = Array<TranslatedString>()
values.forEach { array.add(TranslatedString(it)) }
items = array
val defaultItem = array.firstOrNull { it.value == default }
selected = if (defaultItem != null) defaultItem else array.first()
}
}

View file

@ -12,6 +12,8 @@ import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.MapUnit import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo 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.ResourceType
import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
@ -48,8 +50,10 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
.onClick { setImprovements() } .onClick { setImprovements() }
tabPickerTable.add(improvementsButton) tabPickerTable.add(improvementsButton)
// val unitsButton = "Units".toTextButton().onClick { setUnits() } if (UncivGame.Current.scenarioDebugSwitch) {
// tabPickerTable.add(unitsButton) val unitsButton = "Units".toTextButton().onClick { setUnits() }
tabPickerTable.add(unitsButton)
}
tabPickerTable.pack() tabPickerTable.pack()
@ -154,11 +158,15 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
} }
val nationsTable = Table() 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) val nationImage = ImageGetter.getNationIndicator(nation, 40f)
nationsTable.add(nationImage).row() nationsTable.add(nationImage).row()
nationImage.onClick { currentNation = nation; setUnitTileAction() } nationImage.onClick { currentNation = nation; setUnitTileAction() }
} }
editorPickTable.add(ScrollPane(nationsTable)).height(stage.height*0.8f) editorPickTable.add(ScrollPane(nationsTable)).height(stage.height*0.8f)
val unitsTable = Table() val unitsTable = Table()
@ -170,6 +178,18 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
editorPickTable.add(ScrollPane(unitsTable)).height(stage.height*0.8f) editorPickTable.add(ScrollPane(unitsTable)).height(stage.height*0.8f)
} }
private fun nationsFromMap(tileMap: TileMap): ArrayList<Nation> {
val tilesWithStartingLocations = tileMap.values
.filter { it.improvement != null && it.improvement!!.startsWith("StartingLocation ") }
var nations = ArrayList<Nation>()
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 { private fun getRedCross(size: Float, alpha: Float): Actor {
val redCross = ImageGetter.getImage("OtherIcons/Close") val redCross = ImageGetter.getImage("OtherIcons/Close")
redCross.setSize( size, size) redCross.setSize( size, size)

View file

@ -8,17 +8,24 @@ import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.VictoryType
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.*
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.onChange
import com.unciv.ui.utils.toLabel
class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTable:(desiredCiv:String)->Unit) class GameOptionsTable(previousScreen: GameParametersPreviousScreen, val updatePlayerPickerTable:(desiredCiv:String)->Unit)
: Table(CameraStageBaseScreen.skin) { : Table(CameraStageBaseScreen.skin) {
val newGameParameters = newGameScreen.gameSetupInfo.gameParameters var gameParameters = previousScreen.gameSetupInfo.gameParameters
val ruleset = newGameScreen.ruleset val ruleset = previousScreen.ruleset
var locked = false
init { init {
getGameOptionsTable()
}
fun update() {
clear()
getGameOptionsTable()
}
private fun getGameOptionsTable() {
top() top()
defaults().pad(5f) 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) { private fun Table.addCheckbox(text: String, initialState: Boolean, onChange: (newValue: Boolean) -> Unit) {
val checkbox = CheckBox(text.tr(), CameraStageBaseScreen.skin) val checkbox = CheckBox(text.tr(), CameraStageBaseScreen.skin)
checkbox.isChecked = initialState checkbox.isChecked = initialState
checkbox.isDisabled = locked
checkbox.onChange { onChange(checkbox.isChecked) } checkbox.onChange { onChange(checkbox.isChecked) }
add(checkbox).colspan(2).left().row() add(checkbox).colspan(2).left().row()
} }
private fun Table.addBarbariansCheckbox() = private fun Table.addBarbariansCheckbox() =
addCheckbox("No Barbarians", newGameParameters.noBarbarians) addCheckbox("No Barbarians", gameParameters.noBarbarians)
{ newGameParameters.noBarbarians = it } { gameParameters.noBarbarians = it }
private fun Table.addOneCityChallengeCheckbox() = private fun Table.addOneCityChallengeCheckbox() =
addCheckbox("One City Challenge", newGameParameters.oneCityChallenge) addCheckbox("One City Challenge", gameParameters.oneCityChallenge)
{ newGameParameters.oneCityChallenge = it } { gameParameters.oneCityChallenge = it }
private fun Table.addNuclearWeaponsCheckbox() = private fun Table.addNuclearWeaponsCheckbox() =
addCheckbox("Enable nuclear weapons", newGameParameters.nuclearWeaponsEnabled) addCheckbox("Enable nuclear weapons", gameParameters.nuclearWeaponsEnabled)
{ newGameParameters.nuclearWeaponsEnabled = it } { gameParameters.nuclearWeaponsEnabled = it }
private fun Table.addIsOnlineMultiplayerCheckbox() = private fun Table.addIsOnlineMultiplayerCheckbox() =
addCheckbox("Online Multiplayer", newGameParameters.isOnlineMultiplayer) addCheckbox("Online Multiplayer", gameParameters.isOnlineMultiplayer)
{ newGameParameters.isOnlineMultiplayer = it { gameParameters.isOnlineMultiplayer = it
updatePlayerPickerTable("") } updatePlayerPickerTable("") }
private fun addCityStatesSelectBox() { private fun addCityStatesSelectBox() {
@ -78,34 +86,36 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa
(0..numberOfCityStates).forEach { cityStatesArray.add(it) } (0..numberOfCityStates).forEach { cityStatesArray.add(it) }
cityStatesSelectBox.items = cityStatesArray cityStatesSelectBox.items = cityStatesArray
cityStatesSelectBox.selected = newGameParameters.numberOfCityStates cityStatesSelectBox.selected = gameParameters.numberOfCityStates
add(cityStatesSelectBox).width(50f).row() add(cityStatesSelectBox).width(50f).row()
cityStatesSelectBox.isDisabled = locked
cityStatesSelectBox.onChange { cityStatesSelectBox.onChange {
newGameParameters.numberOfCityStates = cityStatesSelectBox.selected gameParameters.numberOfCityStates = cityStatesSelectBox.selected
} }
} }
fun Table.addSelectBox(text: String, values: Collection<String>, initialState: String, onChange: (newValue: String) -> Unit) { fun Table.addSelectBox(text: String, values: Collection<String>, initialState: String, onChange: (newValue: String) -> Unit) {
add(text.toLabel()).left() add(text.toLabel()).left()
val selectBox = TranslatedSelectBox(values, initialState, CameraStageBaseScreen.skin) val selectBox = TranslatedSelectBox(values, initialState, CameraStageBaseScreen.skin)
selectBox.isDisabled = locked
selectBox.onChange { onChange(selectBox.selected.value) } selectBox.onChange { onChange(selectBox.selected.value) }
add(selectBox).fillX().row() add(selectBox).fillX().row()
} }
private fun Table.addDifficultySelectBox() { private fun Table.addDifficultySelectBox() {
addSelectBox("{Difficulty}:", ruleset.difficulties.keys, newGameParameters.difficulty) addSelectBox("{Difficulty}:", ruleset.difficulties.keys, gameParameters.difficulty)
{ newGameParameters.difficulty = it } { gameParameters.difficulty = it }
} }
private fun Table.addGameSpeedSelectBox() { private fun Table.addGameSpeedSelectBox() {
addSelectBox("{Game Speed}:", GameSpeed.values().map { it.name }, newGameParameters.gameSpeed.name) addSelectBox("{Game Speed}:", GameSpeed.values().map { it.name }, gameParameters.gameSpeed.name)
{ newGameParameters.gameSpeed = GameSpeed.valueOf(it) } { gameParameters.gameSpeed = GameSpeed.valueOf(it) }
} }
private fun Table.addEraSelectBox() { private fun Table.addEraSelectBox() {
val eras = ruleset.technologies.values.map { it.era() }.distinct() val eras = ruleset.technologies.values.map { it.era() }.distinct()
addSelectBox("{Starting Era}:", eras, newGameParameters.startingEra) addSelectBox("{Starting Era}:", eras, gameParameters.startingEra)
{ newGameParameters.startingEra = it } { gameParameters.startingEra = it }
} }
@ -119,13 +129,14 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa
if (victoryType == VictoryType.Neutral) continue if (victoryType == VictoryType.Neutral) continue
val victoryCheckbox = CheckBox(victoryType.name.tr(), CameraStageBaseScreen.skin) val victoryCheckbox = CheckBox(victoryType.name.tr(), CameraStageBaseScreen.skin)
victoryCheckbox.name = victoryType.name victoryCheckbox.name = victoryType.name
victoryCheckbox.isChecked = newGameParameters.victoryTypes.contains(victoryType) victoryCheckbox.isChecked = gameParameters.victoryTypes.contains(victoryType)
victoryCheckbox.isDisabled = locked
victoryCheckbox.onChange { victoryCheckbox.onChange {
// If the checkbox is checked, adds the victoryTypes else remove it // If the checkbox is checked, adds the victoryTypes else remove it
if (victoryCheckbox.isChecked) { if (victoryCheckbox.isChecked) {
newGameParameters.victoryTypes.add(victoryType) gameParameters.victoryTypes.add(victoryType)
} else { } else {
newGameParameters.victoryTypes.remove(victoryType) gameParameters.victoryTypes.remove(victoryType)
} }
} }
victoryConditionsTable.add(victoryCheckbox).left() victoryConditionsTable.add(victoryCheckbox).left()
@ -141,9 +152,9 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa
fun reloadMods() { fun reloadMods() {
ruleset.clear() ruleset.clear()
val newRuleset = RulesetCache.getComplexRuleset(newGameParameters.mods) val newRuleset = RulesetCache.getComplexRuleset(gameParameters.mods)
ruleset.add(newRuleset) ruleset.add(newRuleset)
ruleset.mods += newGameParameters.mods ruleset.mods += gameParameters.mods
ruleset.modOptions = newRuleset.modOptions ruleset.modOptions = newRuleset.modOptions
ImageGetter.ruleset = ruleset ImageGetter.ruleset = ruleset
@ -154,10 +165,11 @@ class NewGameOptionsTable(newGameScreen: NewGameScreen, val updatePlayerPickerTa
val modCheckboxTable = Table().apply { defaults().pad(5f) } val modCheckboxTable = Table().apply { defaults().pad(5f) }
for (mod in modRulesets) { for (mod in modRulesets) {
val checkBox = CheckBox(mod.name.tr(), CameraStageBaseScreen.skin) 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 { checkBox.onChange {
if (checkBox.isChecked) newGameParameters.mods.add(mod.name) if (checkBox.isChecked) gameParameters.mods.add(mod.name)
else newGameParameters.mods.remove(mod.name) else gameParameters.mods.remove(mod.name)
reloadMods() reloadMods()
var desiredCiv = "" var desiredCiv = ""
if (checkBox.isChecked) { if (checkBox.isChecked) {

View file

@ -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
}

View file

@ -15,10 +15,10 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() {
private var mapTypeSpecificTable = Table() private var mapTypeSpecificTable = Table()
private val generatedMapOptionsTable = MapParametersTable(mapParameters) private val generatedMapOptionsTable = MapParametersTable(mapParameters)
private val savedMapOptionsTable = Table() private val savedMapOptionsTable = Table()
private val savedScenarioOptionsTable = Table()
init { init {
defaults().pad(5f) defaults().pad(5f)
add("Map Options".toLabel(fontSize = 24)).top().padBottom(20f).colspan(2).row() add("Map Options".toLabel(fontSize = 24)).top().padBottom(20f).colspan(2).row()
addMapTypeSelection() addMapTypeSelection()
} }
@ -28,6 +28,7 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() {
add("{Map Type}:".toLabel()) add("{Map Type}:".toLabel())
val mapTypes = arrayListOf("Generated") val mapTypes = arrayListOf("Generated")
if (MapSaver.getMaps().isNotEmpty()) mapTypes.add(MapType.custom) if (MapSaver.getMaps().isNotEmpty()) mapTypes.add(MapType.custom)
if (MapSaver.getScenarios().isNotEmpty()) mapTypes.add(MapType.scenario)
val mapTypeSelectBox = TranslatedSelectBox(mapTypes, "Generated", CameraStageBaseScreen.skin) val mapTypeSelectBox = TranslatedSelectBox(mapTypes, "Generated", CameraStageBaseScreen.skin)
val mapFileSelectBox = getMapFileSelectBox() val mapFileSelectBox = getMapFileSelectBox()
@ -37,16 +38,39 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() {
savedMapOptionsTable.add(mapFileSelectBox).maxWidth(newGameScreen.stage.width / 2) savedMapOptionsTable.add(mapFileSelectBox).maxWidth(newGameScreen.stage.width / 2)
.right().row() .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() { fun updateOnMapTypeChange() {
mapTypeSpecificTable.clear() mapTypeSpecificTable.clear()
if (mapTypeSelectBox.selected.value == MapType.custom) { if (mapTypeSelectBox.selected.value == MapType.custom) {
mapParameters.type = MapType.custom mapParameters.type = MapType.custom
mapParameters.name = mapFileSelectBox.selected mapParameters.name = mapFileSelectBox.selected
mapTypeSpecificTable.add(savedMapOptionsTable) 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 { } else {
mapParameters.name = "" mapParameters.name = ""
mapParameters.type = generatedMapOptionsTable.mapTypeSelectBox.selected.value mapParameters.type = generatedMapOptionsTable.mapTypeSelectBox.selected.value
mapTypeSpecificTable.add(generatedMapOptionsTable) 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() add(mapTypeSpecificTable).colspan(2).row()
} }
private fun getMapFileSelectBox(): SelectBox<String> { private fun getMapFileSelectBox(): SelectBox<String> {
val mapFileSelectBox = SelectBox<String>(CameraStageBaseScreen.skin) val mapFileSelectBox = SelectBox<String>(CameraStageBaseScreen.skin)
val mapNames = Array<String>() val mapNames = Array<String>()
@ -71,4 +94,21 @@ class MapOptionsTable(val newGameScreen: NewGameScreen): Table() {
return mapFileSelectBox return mapFileSelectBox
} }
private fun getScenarioFileSelectBox(): SelectBox<String> {
val scenarioFileSelectBox = SelectBox<String>(CameraStageBaseScreen.skin)
val scenarioNames = Array<String>()
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
}
} }

View file

@ -2,20 +2,18 @@ package com.unciv.ui.newgamescreen
import com.unciv.ui.utils.AutoScrollPane as ScrollPane import com.unciv.ui.utils.AutoScrollPane as ScrollPane
import com.badlogic.gdx.Gdx 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.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Skin import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.Array
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.GameInfo import com.unciv.logic.*
import com.unciv.logic.GameSaver
import com.unciv.logic.GameStarter
import com.unciv.logic.IdChecker
import com.unciv.logic.civilization.PlayerType import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.map.MapParameters import com.unciv.logic.map.MapParameters
import com.unciv.logic.map.MapType
import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.GameParameters
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer
import java.util.* 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) 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() override var gameSetupInfo: GameSetupInfo = _gameSetupInfo ?: GameSetupInfo()
val ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods) 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 { init {
setDefaultCloseAction(previousScreen) setDefaultCloseAction(previousScreen)
scrollPane.setScrollingDisabled(true, true) scrollPane.setScrollingDisabled(true, true)
val playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) // val playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters)
val newGameOptionsTable = NewGameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } // val newGameOptionsTable = GameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) }
topTable.add(ScrollPane(MapOptionsTable(this)).apply { setOverscroll(false, false) }) topTable.add(ScrollPane(mapOptionsTable).apply { setOverscroll(false, false) })
.maxHeight(topTable.parent.height).width(stage.width / 3).padTop(20f).top() .maxHeight(topTable.parent.height).width(stage.width / 3).padTop(20f).top()
topTable.addSeparatorVertical() topTable.addSeparatorVertical()
topTable.add(playerPickerTable).maxHeight(topTable.parent.height).width(stage.width / 3).padTop(20f).top() 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() Gdx.graphics.requestRendering()
} }
fun setNewGameButtonEnabled(bool: Boolean) { // fun setNewGameButtonEnabled(bool: Boolean) {
if (bool) rightSideButton.enable() // if (bool) rightSideButton.enable()
else rightSideButton.disable() // 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 var newGame: GameInfo? = null

View file

@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Table 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.scenes.scene2d.ui.TextField
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
@ -20,10 +19,12 @@ import com.unciv.models.translations.tr
import com.unciv.ui.utils.* import com.unciv.ui.utils.*
import java.util.* 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 playerListTable = Table()
val nationsPopupWidth = newGameScreen.stage.width / 2f val nationsPopupWidth = previousScreen.stage.width / 2f
val civBlocksWidth = newGameScreen.stage.width / 3 val civBlocksWidth = previousScreen.stage.width / 3
var locked = false
init { init {
top() top()
@ -34,36 +35,37 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
fun update(desiredCiv: String = "") { fun update(desiredCiv: String = "") {
playerListTable.clear() playerListTable.clear()
val gameBasics = newGameScreen.ruleset // the mod picking changes this ruleset val gameBasics = previousScreen.ruleset // the mod picking changes this ruleset
reassignRemovedModReferences() reassignRemovedModReferences()
val newRulesetPlayableCivs = newGameScreen.ruleset.nations.count { it.key != Constants.barbarians } val newRulesetPlayableCivs = previousScreen.ruleset.nations.count { it.key != Constants.barbarians }
if (newGameParameters.players.size > newRulesetPlayableCivs) if (gameParameters.players.size > newRulesetPlayableCivs)
newGameParameters.players = ArrayList(newGameParameters.players.subList(0, newRulesetPlayableCivs)) gameParameters.players = ArrayList(gameParameters.players.subList(0, newRulesetPlayableCivs))
if (desiredCiv.isNotEmpty()) assignDesiredCiv(desiredCiv) 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() 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) } 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() { private fun reassignRemovedModReferences() {
for (player in newGameParameters.players) { for (player in gameParameters.players) {
if (!newGameScreen.ruleset.nations.containsKey(player.chosenCiv)) if (!previousScreen.ruleset.nations.containsKey(player.chosenCiv))
player.chosenCiv = "Random" player.chosenCiv = "Random"
} }
} }
private fun assignDesiredCiv(desiredCiv: String) { private fun assignDesiredCiv(desiredCiv: String) {
// No auto-select if desiredCiv already used // 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) // 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 { fun getPlayerTable(player: Player, ruleset: Ruleset): Table {
@ -76,16 +78,19 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
val playerTypeTextbutton = player.playerType.name.toTextButton() val playerTypeTextbutton = player.playerType.name.toTextButton()
playerTypeTextbutton.onClick { playerTypeTextbutton.onClick {
if (locked) return@onClick
if (player.playerType == PlayerType.AI) if (player.playerType == PlayerType.AI)
player.playerType = PlayerType.Human player.playerType = PlayerType.Human
else player.playerType = PlayerType.AI else player.playerType = PlayerType.AI
update() update()
} }
playerTable.add(playerTypeTextbutton).width(100f).pad(5f).right() playerTable.add(playerTypeTextbutton).width(100f).pad(5f).right()
if (!locked) {
playerTable.add("-".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) } playerTable.add("-".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) }
.surroundWithCircle(40f) .surroundWithCircle(40f)
.onClick { newGameParameters.players.remove(player); update() }).pad(5f).right().row() .onClick { gameParameters.players.remove(player); update() }).pad(5f).right().row()
if (newGameParameters.isOnlineMultiplayer && player.playerType == PlayerType.Human) { }
if (gameParameters.isOnlineMultiplayer && player.playerType == PlayerType.Human) {
val playerIdTextfield = TextField(player.playerId, CameraStageBaseScreen.skin) val playerIdTextfield = TextField(player.playerId, CameraStageBaseScreen.skin)
playerIdTextfield.messageText = "Please input Player ID!".tr() playerIdTextfield.messageText = "Please input Player ID!".tr()
@ -129,7 +134,7 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
.apply { this.setAlignment(Align.center) } .apply { this.setAlignment(Align.center) }
.surroundWithCircle(36f).apply { circle.color = Color.BLACK } .surroundWithCircle(36f).apply { circle.color = Color.BLACK }
.surroundWithCircle(40f, false).apply { circle.color = Color.WHITE } .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(nationImage).pad(5f)
nationTable.add(player.chosenCiv.toLabel()).pad(5f) nationTable.add(player.chosenCiv.toLabel()).pad(5f)
nationTable.touchable = Touchable.enabled nationTable.touchable = Touchable.enabled
@ -140,7 +145,7 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
} }
private fun popupNationPicker(player: Player) { private fun popupNationPicker(player: Player) {
val nationsPopup = Popup(newGameScreen) val nationsPopup = Popup(previousScreen)
val nationListTable = Table() val nationListTable = Table()
val randomPlayerTable = Table() val randomPlayerTable = Table()
@ -160,18 +165,18 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
nationListTable.add(randomPlayerTable).pad(10f).width(nationsPopupWidth).row() 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 }) { .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 continue
nationListTable.add(NationTable(nation, nationsPopupWidth, newGameScreen.ruleset).onClick { nationListTable.add(NationTable(nation, nationsPopupWidth, previousScreen.ruleset).onClick {
player.chosenCiv = nation.name player.chosenCiv = nation.name
nationsPopup.close() nationsPopup.close()
update() update()
}).pad(10f).width(nationsPopupWidth).row() }).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() nationsPopup.pack()
val closeImage = ImageGetter.getImage("OtherIcons/Close") val closeImage = ImageGetter.getImage("OtherIcons/Close")

View file

@ -53,6 +53,11 @@ open class PickerScreen : CameraStageBaseScreen() {
} }
} }
fun setRightSideButtonEnabled(bool: Boolean) {
if (bool) rightSideButton.enable()
else rightSideButton.disable()
}
protected fun pick(rightButtonText: String) { protected fun pick(rightButtonText: String) {
if(UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable() if(UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable()
rightSideButton.setText(rightButtonText) rightSideButton.setText(rightButtonText)

View file

@ -39,7 +39,9 @@ class BasicTests {
Assert.assertTrue("This test will only pass if the game is not run with debug modes", Assert.assertTrue("This test will only pass if the game is not run with debug modes",
!game.superchargedForDebug !game.superchargedForDebug
&& !game.viewEntireMapForDebug && !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 // If there's a unit that obsoletes with no upgrade then when it obsoletes