From de03a727f695900bcdcfcd05f2d6ad5740efd0f8 Mon Sep 17 00:00:00 2001 From: Alexander Korolyov <49795502+alkorolyov@users.noreply.github.com> Date: Wed, 24 Jun 2020 22:47:34 +0200 Subject: [PATCH] Scenarios editor first part of changes (#2764) * Unnecessary line. * First part of changes * All features required for basic functionality were implemented. Additional features: - Sync between player adding/deleting and it's unit on map editor - Sync between player's nation change and all it's units Final prototype ready for beta-test. * Second part of commits * Small fix of TileMap.stripAllUnits * Small post fixes. Bring back deleting rivers, accidentally removed during merging. * Fixes by your comments * reverse if statement for "Random" chosenCiv * tileEditorOptions take updated this.gameParameters from constructors * updated unit placement. Check validity by unit.canMoveTo() Correct airunit placement in carriers. * tileMap.stripAllUnits() refactor --- core/src/com/unciv/logic/GameInfo.kt | 1 + core/src/com/unciv/logic/GameStarter.kt | 5 +- core/src/com/unciv/logic/MapSaver.kt | 7 +- core/src/com/unciv/logic/map/TileInfo.kt | 4 + core/src/com/unciv/logic/map/TileMap.kt | 35 ++++ core/src/com/unciv/models/metadata/Player.kt | 3 +- .../ui/mapeditor/GameParametersScreen.kt | 73 ++------ .../unciv/ui/mapeditor/LoadScenarioScreen.kt | 3 +- .../unciv/ui/mapeditor/MapEditorMenuPopup.kt | 61 +++++- .../com/unciv/ui/mapeditor/MapEditorScreen.kt | 25 ++- .../ui/mapeditor/TileEditorOptionsTable.kt | 173 +++++++++++++----- ...sScreenInterface.kt => IPreviousScreen.kt} | 2 +- .../unciv/ui/newgamescreen/NewGameScreen.kt | 2 +- .../ui/newgamescreen/PlayerPickerTable.kt | 43 ++++- 14 files changed, 305 insertions(+), 132 deletions(-) rename core/src/com/unciv/ui/newgamescreen/{PreviousScreenInterface.kt => IPreviousScreen.kt} (95%) diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index c812788efc..437f7c8146 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -11,6 +11,7 @@ import com.unciv.logic.map.TileMap import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType import com.unciv.models.metadata.GameParameters +import com.unciv.models.metadata.Player import com.unciv.models.ruleset.Difficulty import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetCache diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 1165c840d0..e389d06020 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -114,12 +114,15 @@ object GameStarter { gameInfo.civilizations.filter { !it.isBarbarian() }, gameInfo.tileMap) - // remove starting locations one we're done + // remove starting locations once we're done for (tile in gameInfo.tileMap.values) { if (tile.improvement != null && tile.improvement!!.startsWith("StartingLocation ")) tile.improvement = null + // set max starting movement for units loaded from map + for(unit in tile.getUnits()) unit.currentMovement = unit.getMaxMovement().toFloat() } + // For later starting eras, or for civs like Polynesia with a different Warrior, we need different starting units fun getWarriorEquivalent(civ: CivilizationInfo): String { val availableMilitaryUnits = gameInfo.ruleSet.units.values.filter { diff --git a/core/src/com/unciv/logic/MapSaver.kt b/core/src/com/unciv/logic/MapSaver.kt index 3f31350495..29c27c5cae 100644 --- a/core/src/com/unciv/logic/MapSaver.kt +++ b/core/src/com/unciv/logic/MapSaver.kt @@ -20,7 +20,7 @@ object MapSaver { } fun saveScenario(scenarioName:String, scenario: Scenario) { - getScenario(scenarioName).writeString(json().toJson(scenario), false) + getScenario(scenarioName).writeString(Gzip.zip(json().toJson(scenario)), false) } fun loadMap(mapName: String): TileMap { @@ -30,8 +30,9 @@ object MapSaver { } fun loadScenario(scenarioName: String): Scenario { - val scenarioJson = getScenario(scenarioName).readString() - return json().fromJson(Scenario::class.java, scenarioJson) + val gzippedString = getScenario(scenarioName).readString() + val unzippedJson = Gzip.unzip(gzippedString) + return json().fromJson(Scenario::class.java, unzippedJson) } fun deleteMap(mapName: String) = getMap(mapName).delete() diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 0c3c23e138..29fb7509f5 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -429,6 +429,10 @@ open class TileInfo { } } + fun stripUnits() { + for (unit in this.getUnits()) unit.removeFromTile() + } + fun startWorkingOnImprovement(improvement: TileImprovement, civInfo: CivilizationInfo) { improvementInProgress = improvement.name turnsToImprovement = improvement.getTurnsToBuild(civInfo) diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 9c35be742b..0b0930ec06 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -5,6 +5,8 @@ import com.unciv.Constants import com.unciv.logic.GameInfo import com.unciv.logic.HexMath import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.models.metadata.Player +import com.unciv.models.ruleset.Nation import com.unciv.models.ruleset.Ruleset import kotlin.math.abs @@ -215,6 +217,39 @@ class TileMap { return viewableTiles } + /** Strips all units from [TileMap] + * @return stripped clone of [TileMap] + */ + fun stripAllUnits(): TileMap { + return clone().apply { tileList.forEach {it.stripUnits()} } + } + + /** Strips all units and starting location from [TileMap] for specified [Player] + * Operation in place + * @param player units of player to be stripped off + */ + fun stripPlayer(player: Player) { + tileList.forEach { + if (it.improvement == "StartingLocation " + player.chosenCiv) { it.improvement = null } + for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) unit.removeFromTile() + } + } + + /** Finds all units and starting location of [Player] and changes their [Nation] + * Operation in place + * @param player player whose all units will be changed + * @param newNation new nation to be set up + */ + fun switchPlayersNation(player: Player, newNation: Nation) { + tileList.forEach { + if (it.improvement == "StartingLocation " + player.chosenCiv) { it.improvement = "StartingLocation "+newNation.name } + for (unit in it.getUnits()) if (unit.owner == player.chosenCiv) { + unit.owner = newNation.name + unit.civInfo = CivilizationInfo(newNation.name).apply { nation=newNation } + } + } + } + fun setTransients(ruleset: Ruleset, setUnitCivTransients:Boolean=true) { // In the map editor, no Civs or Game exist, so we won't set the unit transients val topY= tileList.asSequence().map { it.position.y.toInt() }.max()!! bottomY= tileList.asSequence().map { it.position.y.toInt() }.min()!! diff --git a/core/src/com/unciv/models/metadata/Player.kt b/core/src/com/unciv/models/metadata/Player.kt index bffeb41356..cbb8a3eb1d 100644 --- a/core/src/com/unciv/models/metadata/Player.kt +++ b/core/src/com/unciv/models/metadata/Player.kt @@ -3,8 +3,7 @@ package com.unciv.models.metadata import com.unciv.Constants import com.unciv.logic.civilization.PlayerType -class Player { +class Player(var chosenCiv: String = Constants.random) { var playerType: PlayerType = PlayerType.AI - var chosenCiv = Constants.random var playerId="" } \ No newline at end of file diff --git a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt index 512fe03c49..055e779834 100644 --- a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt @@ -1,83 +1,36 @@ package com.unciv.ui.mapeditor -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.scenes.scene2d.ui.TextField -import com.unciv.logic.MapSaver -import com.unciv.logic.map.MapType +import com.unciv.UncivGame 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.GameSetupInfo import com.unciv.ui.newgamescreen.PlayerPickerTable -import com.unciv.ui.newgamescreen.PreviousScreenInterface +import com.unciv.ui.newgamescreen.IPreviousScreen import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.* -import kotlin.concurrent.thread -class GameParametersScreen(var mapEditorScreen: MapEditorScreen): PickerScreen() { - var playerPickerTable = PlayerPickerTable(mapEditorScreen, mapEditorScreen.gameSetupInfo.gameParameters) +class GameParametersScreen(var mapEditorScreen: MapEditorScreen): IPreviousScreen, PickerScreen() { + + override var gameSetupInfo: GameSetupInfo = mapEditorScreen.gameSetupInfo + var playerPickerTable = PlayerPickerTable(this, this.gameSetupInfo.gameParameters) var gameOptionsTable = GameOptionsTable(mapEditorScreen.gameSetupInfo) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } init { setDefaultCloseAction(mapEditorScreen) scrollPane.setScrollingDisabled(true, true) - // update players list from tileMap starting locations - if (mapEditorScreen.scenario == null) { - mapEditorScreen.gameSetupInfo.gameParameters.players = getPlayersFromMap(mapEditorScreen.tileMap) - } - - playerPickerTable.apply { locked = true }.update() - val scenarioNameEditor = TextField(mapEditorScreen.scenarioName, skin) - topTable.add(playerPickerTable) topTable.addSeparatorVertical() topTable.add(gameOptionsTable).row() - topTable.add(scenarioNameEditor) - rightSideButton.setText("Save scenario") + rightSideButton.setText("OK") rightSideButton.onClick { - thread(name = "SaveScenario") { - try { - mapEditorScreen.tileMap.mapParameters.type = MapType.scenario - mapEditorScreen.scenario = Scenario(mapEditorScreen.tileMap, mapEditorScreen.gameSetupInfo.gameParameters) - mapEditorScreen.scenarioName = scenarioNameEditor.text - MapSaver.saveScenario(scenarioNameEditor.text, mapEditorScreen.scenario!!) - - game.setScreen(mapEditorScreen) - Gdx.app.postRunnable { - ResponsePopup("Scenario saved", mapEditorScreen) // todo - add this text to translations - } - } catch (ex: Exception) { - ex.printStackTrace() - Gdx.app.postRunnable { - val cantLoadGamePopup = Popup(mapEditorScreen) - cantLoadGamePopup.addGoodSizedLabel("It looks like your scenario can't be saved!").row() - cantLoadGamePopup.addCloseButton() - cantLoadGamePopup.open(force = true) - } - } - } + mapEditorScreen.gameSetupInfo = gameSetupInfo + mapEditorScreen.scenario = Scenario(mapEditorScreen.tileMap, mapEditorScreen.gameSetupInfo.gameParameters) + mapEditorScreen.tileEditorOptions.update() + mapEditorScreen.mapHolder.updateTileGroups() + UncivGame.Current.setScreen(mapEditorScreen) + dispose() } - - rightSideButton.isEnabled = scenarioNameEditor.text.isNotEmpty() - scenarioNameEditor.addListener { - mapEditorScreen.scenarioName = scenarioNameEditor.text - rightSideButton.isEnabled = scenarioNameEditor.text.isNotEmpty() - true - } - } - - 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/LoadScenarioScreen.kt b/core/src/com/unciv/ui/mapeditor/LoadScenarioScreen.kt index 5849270bcf..6aa582e97c 100644 --- a/core/src/com/unciv/ui/mapeditor/LoadScenarioScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/LoadScenarioScreen.kt @@ -20,7 +20,8 @@ class LoadScenarioScreen(previousMap: TileMap?): PickerScreen(){ init { rightSideButton.setText("Load scenario".tr()) rightSideButton.onClick { - UncivGame.Current.setScreen(MapEditorScreen(MapSaver.loadScenario(chosenScenario)).apply { scenarioName = chosenScenario }) + val mapEditorScreen = MapEditorScreen(MapSaver.loadScenario(chosenScenario), chosenScenario) + UncivGame.Current.setScreen(mapEditorScreen) dispose() } diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt index f6d2192aa7..dc1a57ceda 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt @@ -1,6 +1,7 @@ package com.unciv.ui.mapeditor import com.badlogic.gdx.Gdx +import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextField import com.badlogic.gdx.utils.Json import com.unciv.Constants @@ -34,12 +35,11 @@ class MapEditorMenuPopup(var mapEditorScreen: MapEditorScreen): Popup(mapEditorS addCopyMapAsTextButton() addLoadMapButton() addUploadMapButton() - if (UncivGame.Current.scenarioDebugSwitch) { addScenarioButton() + addSaveScenarioButton() addLoadScenarioButton() } - addExitMapEditorButton() addCloseOptionsButton() } @@ -157,15 +157,54 @@ class MapEditorMenuPopup(var mapEditorScreen: MapEditorScreen): Popup(mapEditorS private fun Popup.addScenarioButton() { var scenarioButton = "".toTextButton() - if (mapEditorScreen.scenario != null) { + if (mapEditorScreen.hasScenario()) { scenarioButton.setText("Edit scenario") } else { scenarioButton.setText("Create scenario") + // for newly created scenarios read players from tileMap + val players = getPlayersFromMap(mapEditorScreen.tileMap) + mapEditorScreen.gameSetupInfo.gameParameters.players = players } add(scenarioButton).row() scenarioButton.onClick { - remove() - UncivGame.Current.setScreen(GameParametersScreen(mapEditorScreen)) + close() + UncivGame.Current.setScreen(GameParametersScreen(mapEditorScreen).apply { + playerPickerTable.noRandom = true + }) + } + } + + private fun Popup.addSaveScenarioButton() { + val saveScenarioButton = "Save scenario".toTextButton() + add(saveScenarioButton).row() + saveScenarioButton.onClick { + thread(name = "SaveScenario") { + try { + mapEditorScreen.tileMap.mapParameters.type = MapType.scenario + mapEditorScreen.scenario = Scenario(mapEditorScreen.tileMap, mapEditorScreen.gameSetupInfo.gameParameters) + mapEditorScreen.scenarioName = mapNameEditor.text + MapSaver.saveScenario(mapNameEditor.text, mapEditorScreen.scenario!!) + + close() + Gdx.app.postRunnable { + ResponsePopup("Scenario saved", mapEditorScreen) // todo - add this text to translations + } + } catch (ex: Exception) { + ex.printStackTrace() + Gdx.app.postRunnable { + val cantLoadGamePopup = Popup(mapEditorScreen) + cantLoadGamePopup.addGoodSizedLabel("It looks like your scenario can't be saved!").row() + cantLoadGamePopup.addCloseButton() + cantLoadGamePopup.open(force = true) + } + } + } + } + saveScenarioButton.isEnabled = mapNameEditor.text.isNotEmpty() && mapEditorScreen.hasScenario() + mapNameEditor.addListener { + mapEditorScreen.scenarioName = mapNameEditor.text + saveScenarioButton.isEnabled = mapNameEditor.text.isNotEmpty() && mapEditorScreen.hasScenario() + true } } @@ -190,4 +229,16 @@ class MapEditorMenuPopup(var mapEditorScreen: MapEditorScreen): Popup(mapEditorS 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 f7f8083b5b..1eb1a5d8de 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt @@ -1,6 +1,5 @@ package com.unciv.ui.mapeditor -import com.badlogic.gdx.Game import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.scenes.scene2d.InputEvent @@ -15,22 +14,22 @@ import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileMap import com.unciv.models.translations.tr import com.unciv.ui.newgamescreen.GameSetupInfo -import com.unciv.ui.newgamescreen.PreviousScreenInterface +import com.unciv.ui.newgamescreen.IPreviousScreen import com.unciv.ui.utils.* -class MapEditorScreen(): PreviousScreenInterface, CameraStageBaseScreen() { - // need for compatibility with NewGameScreen: PickerScreen +class MapEditorScreen(): IPreviousScreen, CameraStageBaseScreen() { + // need for compatibility with PickerScreen override fun setRightSideButtonEnabled(boolean: Boolean) {} var mapName = "" var tileMap = TileMap() - var scenarioName = "" - var scenario: Scenario? = null + var scenarioName = "" // when loading map: mapName is taken as default for scenarioName + var scenario: Scenario? = null // main indicator whether scenario information is present - override val gameSetupInfo = GameSetupInfo() + override var gameSetupInfo = GameSetupInfo() lateinit var mapHolder: EditorMapHolder - val tileEditorOptions = TileEditorOptionsTable(this) + lateinit var tileEditorOptions: TileEditorOptionsTable private val showHideEditorOptionsButton = ">".toTextButton() @@ -45,6 +44,7 @@ class MapEditorScreen(): PreviousScreenInterface, CameraStageBaseScreen() { if (mapToLoad != null) { mapName = mapToLoad + scenarioName = mapToLoad tileMap = MapSaver.loadMap(mapName) } @@ -56,9 +56,11 @@ class MapEditorScreen(): PreviousScreenInterface, CameraStageBaseScreen() { initialize() } - constructor(scenario: Scenario) : this() { + constructor(scenario: Scenario, scenarioName: String = "") : this() { tileMap = scenario.tileMap + mapName = scenarioName this.scenario = scenario + this.scenarioName = scenarioName gameSetupInfo.gameParameters = scenario.gameParameters initialize() } @@ -71,6 +73,7 @@ class MapEditorScreen(): PreviousScreenInterface, CameraStageBaseScreen() { stage.addActor(mapHolder) stage.scrollFocus = mapHolder + tileEditorOptions = TileEditorOptionsTable(this) stage.addActor(tileEditorOptions) tileEditorOptions.setPosition(stage.width - tileEditorOptions.width, 0f) @@ -166,6 +169,10 @@ class MapEditorScreen(): PreviousScreenInterface, CameraStageBaseScreen() { game.setScreen(MapEditorScreen(mapHolder.tileMap)) } } + + fun hasScenario(): Boolean { + return this.scenario != null + } } class TranslatedSelectBox(values : Collection, default:String, skin: Skin) : SelectBox(skin) { diff --git a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt index bdf9183c2e..f37250b1e0 100644 --- a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt +++ b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt @@ -6,6 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane import com.badlogic.gdx.scenes.scene2d.ui.Slider import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo @@ -13,9 +14,11 @@ 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.metadata.Player import com.unciv.models.ruleset.Nation import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.TerrainType +import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.translations.tr import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileSetStrings @@ -32,10 +35,16 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera private var currentHex: Actor = Group() private val ruleset = mapEditorScreen.gameSetupInfo.ruleset + private val gameParameters = mapEditorScreen.gameSetupInfo.gameParameters private val scrollPanelHeight = mapEditorScreen.stage.height*0.7f - 100f // -100 reserved for currentHex table init{ + update() + } + + fun update() { + clear() height = mapEditorScreen.stage.height width = mapEditorScreen.stage.width/3 @@ -50,7 +59,8 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera .onClick { setImprovements() } tabPickerTable.add(improvementsButton) - if (UncivGame.Current.scenarioDebugSwitch) { + // debug Scenario mode + if (UncivGame.Current.scenarioDebugSwitch && mapEditorScreen.hasScenario()) { val unitsButton = "Units".toTextButton().onClick { setUnits() } tabPickerTable.add(unitsButton) } @@ -125,10 +135,10 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera editorPickTable.clear() val improvementsTable = Table() - improvementsTable.add(getHex(Color.WHITE).apply { + improvementsTable.add(getHex(Color.WHITE, getRedCross(40f, 0.6f)).apply { onClick { tileAction = {it.improvement=null} - setCurrentHex(getHex(Color.WHITE), "Clear improvements") + setCurrentHex(getHex(Color.WHITE, getRedCross(40f, 0.6f)), "Clear improvements") } }).row() @@ -149,68 +159,138 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera } improvementsTable.add(improvementImage).row() } - editorPickTable.add(AutoScrollPane(improvementsTable)).height(scrollPanelHeight) + editorPickTable.add(AutoScrollPane(improvementsTable).apply { setScrollingDisabled(true,false) }).height(scrollPanelHeight) - val nationsTable = Table() - for(nation in ruleset.nations.values){ - val nationImage = getHex(Color.WHITE, ImageGetter.getNationIndicator(nation, 40f)) - nationImage.onClick { - val improvementName = "StartingLocation "+nation.name + val nationTable = Table() + + if (UncivGame.Current.scenarioDebugSwitch) { + /** new scenario/improvements functionality + * There shoudn't be random players in scenario + * */ + for (player in gameParameters.players) { + val playerIndex = gameParameters.players.indexOf(player) + 1 + if (player.chosenCiv != "Random") { + val nation = ruleset.nations[player.chosenCiv]!! + val nationImage = ImageGetter.getNationIndicator(nation, 40f) + nationImage.onClick { + val improvementName = "StartingLocation " + nation.name + tileAction = { + it.improvement = improvementName + for (tileGroup in mapEditorScreen.mapHolder.tileGroups.values) { + val tile = tileGroup.tileInfo + if (tile.improvement == improvementName && tile != it) + tile.improvement = null + tile.setTerrainTransients() + tileGroup.update() + } + } + + val nationIcon = getHex(Color.WHITE, ImageGetter.getNationIndicator(nation, 40f)) + setCurrentHex(nationIcon,"Player $playerIndex starting location") + } + nationTable.add(nationImage).row() - tileAction = { - it.improvement = improvementName - for (tileGroup in mapEditorScreen.mapHolder.tileGroups.values) { - val tile = tileGroup.tileInfo - if (tile.improvement == improvementName && tile != it) - tile.improvement = null - tile.setTerrainTransients() - tileGroup.update() } } + } else { + /** old way improvements for all civs + * */ + for(nation in ruleset.nations.values){ + val nationImage = getHex(Color.WHITE, ImageGetter.getNationIndicator(nation, 40f)) + nationImage.onClick { + val improvementName = "StartingLocation "+nation.name + tileAction = { + it.improvement = improvementName + for (tileGroup in mapEditorScreen.mapHolder.tileGroups.values) { + val tile = tileGroup.tileInfo + if (tile.improvement == improvementName && tile != it) + tile.improvement = null + tile.setTerrainTransients() + tileGroup.update() + } + } - val nationIcon = getHex(Color.WHITE, ImageGetter.getNationIndicator(nation, 40f)) - setCurrentHex(nationIcon, "[${nation.name}] starting location") + val nationIcon = getHex(Color.WHITE, ImageGetter.getNationIndicator(nation, 40f)) + setCurrentHex(nationIcon, "[${nation.name}] starting location") + } + nationTable.add(nationImage).row() } - nationsTable.add(nationImage).row() } - editorPickTable.add(AutoScrollPane(nationsTable)).height(scrollPanelHeight) + editorPickTable.add(AutoScrollPane(nationTable).apply { setScrollingDisabled(true,false) }).height(scrollPanelHeight) } fun setUnits(){ editorPickTable.clear() - var currentNation = ruleset.nations.values.first() + + val nationsTable = Table() + + // default player - first non-random player or barbarians + var currentPlayer = "" + var currentNation: Nation? = ruleset.nations.values.firstOrNull{ it.isBarbarian() } + var currentUnit = ruleset.units.values.first() + fun setUnitTileAction(){ - val unitImage = ImageGetter.getUnitIcon(currentUnit.name, currentNation.getInnerColor()) - .surroundWithCircle(40f).apply { color=currentNation.getOuterColor() } - setCurrentHex(unitImage, currentUnit.name.tr()+" - "+currentNation.name.tr()) + if (currentNation == null) return + val unitImage = ImageGetter.getUnitIcon(currentUnit.name, currentNation!!.getInnerColor()) + .surroundWithCircle(40f).apply { color=currentNation!!.getOuterColor() } + setCurrentHex(unitImage, currentUnit.name.tr()+ " - $currentPlayer ("+currentNation!!.name.tr()+")") tileAction = { val unit = MapUnit() unit.baseUnit = currentUnit unit.name = currentUnit.name - unit.owner = currentNation.name - unit.civInfo = CivilizationInfo(currentNation.name).apply { nation=currentNation } // needed for the unit icon to render correctly - when { - unit.type.isAirUnit() -> it.airUnits.add(unit) - unit.type.isCivilian() -> it.civilianUnit=unit - else -> it.militaryUnit=unit + unit.owner = currentNation!!.name + unit.civInfo = CivilizationInfo(currentNation!!.name).apply { nation=currentNation!! } // needed for the unit icon to render correctly + unit.updateUniques() + if (unit.movement.canMoveTo(it)) { + when { + unit.type.isAirUnit() -> { + it.airUnits.add(unit) + if (!it.isCityCenter()) unit.isTransported = true // if not city - air unit enters carrier + } + unit.type.isCivilian() -> { it.civilianUnit = unit } + else -> { it.militaryUnit = unit } + } + unit.currentTile=it // needed for unit icon - unit needs to know if it's embarked or not... } - unit.currentTile=it // needed for unit icon - unit needs to know if it's embarked or not... } } - val nationsTable = Table() - val nations = nationsFromMap(mapEditorScreen.tileMap) - val barbarians = ruleset.nations.values.filter { it.isBarbarian()} + // delete units icon + nationsTable.add(getCrossedIcon().onClick { + tileAction = { it.stripUnits() } + setCurrentHex(getCrossedIcon(), "Remove units") + }).row() - for(nation in nations + barbarians){ - val nationImage = ImageGetter.getNationIndicator(nation, 40f) - nationsTable.add(nationImage).row() - nationImage.onClick { currentNation = nation; setUnitTileAction() } + // player icons + for (player in gameParameters.players) { + if (player.chosenCiv != "Random") { + val nation = ruleset.nations[player.chosenCiv]!! + val nationImage = ImageGetter.getNationIndicator(nation, 40f) + nationsTable.add(nationImage).row() + nationImage.onClick { + currentNation = nation; + currentPlayer = getPlayerIndexString(player) + setUnitTileAction() } + } } - editorPickTable.add(ScrollPane(nationsTable)).height(stage.height*0.8f) + // barbarians icon + if (!gameParameters.noBarbarians) { + val barbarians = ruleset.nations.values.filter { it.isBarbarian()} + for (nation in barbarians) { + val nationImage = ImageGetter.getNationIndicator(nation, 40f) + nationsTable.add(nationImage).row() + nationImage.onClick { + currentNation = nation; + currentPlayer = "" + setUnitTileAction() + } + } + } + + editorPickTable.add(AutoScrollPane(nationsTable)).height(scrollPanelHeight) val unitsTable = Table() for(unit in ruleset.units.values){ @@ -218,7 +298,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera unitsTable.add(unitImage).row() unitImage.onClick { currentUnit = unit; setUnitTileAction() } } - editorPickTable.add(ScrollPane(unitsTable)).height(stage.height*0.8f) + editorPickTable.add(AutoScrollPane(unitsTable)).height(scrollPanelHeight) } private fun nationsFromMap(tileMap: TileMap): ArrayList { @@ -232,6 +312,17 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera return nations } + private fun getPlayerIndexString(player: Player): String { + val index = gameParameters.players.indexOf(player) + 1 + return "Player $index" + } + + private fun getCrossedIcon(): Actor { + return getRedCross(20f, 0.6f) + .surroundWithCircle(40f, false) + .apply { circle.color = Color.WHITE } + } + 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/PreviousScreenInterface.kt b/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt similarity index 95% rename from core/src/com/unciv/ui/newgamescreen/PreviousScreenInterface.kt rename to core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt index 58659684c9..06c2ab77ff 100644 --- a/core/src/com/unciv/ui/newgamescreen/PreviousScreenInterface.kt +++ b/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt @@ -11,7 +11,7 @@ import com.unciv.ui.utils.CameraStageBaseScreen * or CameraBackStageScreen class for map editing */ -interface PreviousScreenInterface { +interface IPreviousScreen { val gameSetupInfo: GameSetupInfo var stage: Stage diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index c7f8eb6bc9..61b27cfdce 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -27,7 +27,7 @@ class GameSetupInfo(var gameId:String, var gameParameters: GameParameters, var m constructor(gameParameters: GameParameters, mapParameters: MapParameters) : this("", gameParameters, mapParameters) } -class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSetupInfo?=null): PreviousScreenInterface, PickerScreen() { +class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSetupInfo?=null): IPreviousScreen, PickerScreen() { override val gameSetupInfo = _gameSetupInfo ?: GameSetupInfo() var playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) var newGameOptionsTable = GameOptionsTable(gameSetupInfo) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index 7a31102707..abca35764a 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -14,15 +14,18 @@ import com.unciv.logic.IdChecker import com.unciv.logic.civilization.PlayerType import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.Player +import com.unciv.models.ruleset.Nation import com.unciv.models.translations.tr +import com.unciv.ui.mapeditor.GameParametersScreen import com.unciv.ui.utils.* import java.util.* -class PlayerPickerTable(val previousScreen: PreviousScreenInterface, var gameParameters: GameParameters): Table() { +class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: GameParameters): Table() { val playerListTable = Table() val nationsPopupWidth = previousScreen.stage.width / 2f val civBlocksWidth = previousScreen.stage.width / 3 var locked = false + var noRandom = false init { top() @@ -47,7 +50,12 @@ class PlayerPickerTable(val previousScreen: PreviousScreenInterface, var gamePar if (gameParameters.players.count() < ruleset.nations.values.count { it.isMajorCiv() } && !locked) { playerListTable.add("+".toLabel(Color.BLACK, 30).apply { this.setAlignment(Align.center) } - .surroundWithCircle(50f).onClick { gameParameters.players.add(Player()); update() }).pad(10f) + .surroundWithCircle(50f).onClick { + var player = Player() + if (noRandom) { player = Player(getAvailablePlayerCivs().first().name) } + gameParameters.players.add(player) + update() + }).pad(10f) } previousScreen.setRightSideButtonEnabled(gameParameters.players.size > 1) } @@ -86,7 +94,11 @@ class PlayerPickerTable(val previousScreen: PreviousScreenInterface, var gamePar 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() + .onClick { + gameParameters.players.remove(player) + if (previousScreen is GameParametersScreen) previousScreen.mapEditorScreen.tileMap.stripPlayer(player) + update() + }).pad(5f).right().row() } if (gameParameters.isOnlineMultiplayer && player.playerType == PlayerType.Human) { @@ -160,20 +172,23 @@ class PlayerPickerTable(val previousScreen: PreviousScreenInterface, var gamePar nationsPopup.close() update() } - nationListTable.add(randomPlayerTable).pad(10f).width(nationsPopupWidth).row() + if (!noRandom) { nationListTable.add(randomPlayerTable).pad(10f).width(nationsPopupWidth).row() } - for (nation in previousScreen.gameSetupInfo.ruleset.nations.values - .filter { !it.isCityState() && it.name != Constants.barbarians }) { - if (player.chosenCiv != nation.name && gameParameters.players.any { it.chosenCiv == nation.name }) + for (nation in getAvailablePlayerCivs()) { + if (player.chosenCiv == nation.name) continue nationListTable.add(NationTable(nation, nationsPopupWidth, previousScreen.gameSetupInfo.ruleset).onClick { + if (previousScreen is GameParametersScreen) { + previousScreen.mapEditorScreen.tileMap.switchPlayersNation(player, nation) + } player.chosenCiv = nation.name nationsPopup.close() update() }).pad(10f).width(nationsPopupWidth).row() } + nationsPopup.add(ScrollPane(nationListTable)).height(previousScreen.stage.height * 0.8f) nationsPopup.pack() @@ -190,4 +205,16 @@ class PlayerPickerTable(val previousScreen: PreviousScreenInterface, var gamePar nationsPopup.open() update() } -} \ No newline at end of file + + private fun getAvailablePlayerCivs(): ArrayList { + var nations = ArrayList() + for (nation in previousScreen.gameSetupInfo.ruleset.nations.values + .filter { it.isMajorCiv() }) { + if (gameParameters.players.any { it.chosenCiv == nation.name }) + continue + nations.add(nation) + } + return nations + } + +}