diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index a1449b67..bdb2f616 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -52,8 +52,8 @@ class UncivGame(parameters: UncivGameParameters) : Game() { * Does not update World View changes until finished. * Set false to disable. */ - val simulateMaxTurns: Int = 2000 - val simulateUntilWin = false + var simulateMaxTurns: Int = 1500 + var simulateUntilWin = false /** Console log battles */ diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 6f767f98..7953e0be 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -102,9 +102,7 @@ class GameInfo { if (thisPlayer.victoryManager.hasWon() && simulateUntilWin) { // stop simulation simulateUntilWin = false - println("Simulation stopped on turn $turns") - val victoryType = thisPlayer.victoryManager.hasWonVictoryType() - println("$thisPlayer won $victoryType victory") + break } } switchTurn() @@ -113,8 +111,6 @@ class GameInfo { currentPlayer = thisPlayer.civName currentPlayerCiv = getCivilization(currentPlayer) - if (turns == UncivGame.Current.simulateMaxTurns && UncivGame.Current.simulateUntilWin) - println ("Max simulation turns reached $turns: Draw") // Start our turn immediately before the player can made decisions - affects whether our units can commit automated actions and then be attacked immediately etc. notifyOfCloseEnemyUnits(thisPlayer) @@ -379,6 +375,4 @@ class GameInfo { cityConstructions.inProgressConstructions.remove(oldBuildingName) } } - - } diff --git a/core/src/com/unciv/logic/GameSaver.kt b/core/src/com/unciv/logic/GameSaver.kt index 31c360c1..e2238edc 100644 --- a/core/src/com/unciv/logic/GameSaver.kt +++ b/core/src/com/unciv/logic/GameSaver.kt @@ -57,7 +57,11 @@ object GameSaver { } fun getGeneralSettingsFile(): FileHandle { - return Gdx.files.local(settingsFileName) + try { + return Gdx.files.local(settingsFileName) + } catch (ex: NullPointerException) { + return FileHandle(settingsFileName) + } } fun getGeneralSettings(): GameSettings { diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 8cd790aa..a156e15f 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -372,7 +372,8 @@ class CityInfo { isPuppet = false cityConstructions.inProgressConstructions.clear() // undo all progress of the previous civ on units etc. cityStats.update() - UncivGame.Current.worldScreen.shouldUpdate = true + if (!UncivGame.Current.consoleMode) + UncivGame.Current.worldScreen.shouldUpdate = true } /** This happens when we either puppet OR annex, basically whenever we conquer a city and don't liberate it */ diff --git a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt index e9f04b6e..26e2a44e 100644 --- a/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt +++ b/core/src/com/unciv/logic/map/mapgenerator/MapGenerator.kt @@ -51,9 +51,9 @@ class MapGenerator(val ruleset: Ruleset) { return map } - private fun seedRNG(seed: Long) { + private fun seedRNG(seed: Long, verbose: Boolean = false) { randomness.RNG = Random(seed) - println("RNG seeded with $seed") + if (verbose) println("RNG seeded with $seed") } private fun spawnLakesAndCoasts(map: TileMap) { diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index 0f68f4d4..298e9d97 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -39,13 +39,13 @@ class GameSettings { init { // 26 = Android Oreo. Versions below may display permanent icon in notification bar. - if (Gdx.app.type == Application.ApplicationType.Android && Gdx.app.version < 26) { + if (Gdx.app?.type == Application.ApplicationType.Android && Gdx.app.version < 26) { multiplayerTurnCheckerPersistentNotificationEnabled = false } } fun save(){ - if (!isFreshlyCreated && Gdx.app.type == Application.ApplicationType.Desktop) { + if (!isFreshlyCreated && Gdx.app?.type == Application.ApplicationType.Desktop) { windowState = WindowState( Gdx.graphics.width, Gdx.graphics.height) } GameSaver.setGeneralSettings(this) diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index 0a976820..3eead34b 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -1,5 +1,6 @@ package com.unciv.models.ruleset +import com.badlogic.gdx.Files import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle import com.unciv.Constants @@ -181,9 +182,20 @@ class Ruleset { object RulesetCache :HashMap() { val vanillaRuleset = "Civ V - Vanilla" fun loadRulesets() { - this[""] = Ruleset().apply { load(Gdx.files.internal("jsons/$vanillaRuleset")) } + try { + this[""] = Ruleset().apply { load(Gdx.files.internal("jsons/$vanillaRuleset")) } + } catch (e: NullPointerException) { + this[""] = Ruleset().apply { load(FileHandle("jsons/$vanillaRuleset")) } + } - for (modFolder in Gdx.files.local("mods").list()) { + var modsHandles: Array + try { + modsHandles = Gdx.files.local("mods").list() + } catch (ex: NullPointerException) { + modsHandles = FileHandle("mods").list() + } + + for (modFolder in modsHandles) { if (modFolder.name().startsWith('.')) continue try { val modRuleset = Ruleset() diff --git a/core/src/com/unciv/models/simulation/Simulation.kt b/core/src/com/unciv/models/simulation/Simulation.kt new file mode 100644 index 00000000..66f0bbf3 --- /dev/null +++ b/core/src/com/unciv/models/simulation/Simulation.kt @@ -0,0 +1,125 @@ +package com.unciv.models.simulation + +import com.unciv.logic.GameInfo +import com.unciv.logic.GameStarter +import com.unciv.models.ruleset.VictoryType +import com.unciv.ui.newgamescreen.GameSetupInfo +import java.lang.Integer.max +import java.time.Duration +import kotlin.concurrent.thread + +class Simulation(val newGameInfo: GameInfo, + val simulationsPerThread: Int = 5, + val threadsNumber: Int = 1 +) { + val maxSimulations = threadsNumber * simulationsPerThread + val civilizations = newGameInfo.civilizations.filter { it.civName != "Spectator" }.map { it.civName } + private var startTime: Long = 0 + private var endTime: Long = 0 + var steps = ArrayList() + var winRate = mutableMapOf() + var winRateByVictory = HashMap>() + var avgSpeed = 0f + var avgDuration: Duration = Duration.ZERO + private var totalTurns = 0 + private var totalDuration: Duration = Duration.ZERO + var stepCounter: Int = 0 + + + init{ + for (civ in civilizations) { + this.winRate[civ] = MutableInt(0) + winRateByVictory[civ] = mutableMapOf() + for (victory in VictoryType.values()) + winRateByVictory[civ]!![victory] = MutableInt(0) + } + } + + fun start() { + + startTime = System.currentTimeMillis() + val threads: ArrayList = ArrayList() + for (threadId in 1..threadsNumber) { + threads.add(thread { + for (i in 1..simulationsPerThread) { + val gameInfo = GameStarter.startNewGame(GameSetupInfo(newGameInfo)) + gameInfo.nextTurn() + + var step = SimulationStep(gameInfo) + + if (step.victoryType != null) { + step.winner = step.currentPlayer + printWinner(step) + } + else + printDraw(step) + + updateCounter(threadId) + add(step) + } + }) + } + // wait for all threads to finish + for (thread in threads) thread.join() + endTime = System.currentTimeMillis() + } + + @Synchronized fun add(step: SimulationStep, threadId: Int = 1) { +// println("Thread $threadId: End simulation ($stepCounter/$maxSimulations)") + steps.add(step) + } + + @Synchronized fun updateCounter(threadId: Int = 1) { + stepCounter++ +// println("Thread $threadId: Start simulation ($stepCounter/$maxSimulations)") + println("Simulation step ($stepCounter/$maxSimulations)") + } + + private fun printWinner(step: SimulationStep) { + println("%s won %s victory on %d turn".format( + step.winner, + step.victoryType, + step.turns + )) + } + + private fun printDraw(step: SimulationStep) { + println("Max simulation %d turns reached : Draw".format( + step.turns + )) + } + + fun getStats() { + // win Rate + steps.forEach { + if (it.winner != null) { + winRate[it.winner!!]!!.inc() + winRateByVictory[it.winner!!]!![it.victoryType]!!.inc() + } + } + totalTurns = steps.sumBy { it.turns } + totalDuration = Duration.ofMillis(endTime - startTime) + avgSpeed = totalTurns.toFloat() / totalDuration.seconds + avgDuration = totalDuration.dividedBy(steps.size.toLong()) + } + + override fun toString(): String { + var outString = "" + for (civ in civilizations) { + outString += "\n$civ:\n" + val wins = winRate[civ]!!.value!! * 100 / max(steps.size, 1) + outString += "$wins% total win rate \n" + for (victory in VictoryType.values()) { + val winsVictory = winRateByVictory[civ]!![victory]!!.value * 100 / max(winRate[civ]!!.value, 1) + outString += "$victory: $winsVictory% " + } + outString += "\n" + } + outString += "\nAverage speed: %.1f turns/s \n".format(avgSpeed) + outString += "Average game duration: " + formatDuration(avgDuration) + "\n" + outString += "Total time: " + formatDuration(totalDuration) + "\n" + + return outString + } +} + diff --git a/core/src/com/unciv/models/simulation/SimulationStep.kt b/core/src/com/unciv/models/simulation/SimulationStep.kt new file mode 100644 index 00000000..6ee016d4 --- /dev/null +++ b/core/src/com/unciv/models/simulation/SimulationStep.kt @@ -0,0 +1,15 @@ +package com.unciv.models.simulation + +import com.unciv.logic.GameInfo +import com.unciv.models.ruleset.VictoryType +import java.time.Duration + +class SimulationStep (gameInfo: GameInfo) { + var turns = gameInfo.turns + var victoryType = gameInfo.currentPlayerCiv.victoryManager.hasWonVictoryType() + var winner: String? = null + val currentPlayer = gameInfo.currentPlayer +// val durationString: String = formatDuration(Duration.ofMillis(System.currentTimeMillis() - startTime)) +} + + diff --git a/core/src/com/unciv/models/simulation/Utils.kt b/core/src/com/unciv/models/simulation/Utils.kt new file mode 100644 index 00000000..589ded25 --- /dev/null +++ b/core/src/com/unciv/models/simulation/Utils.kt @@ -0,0 +1,30 @@ +package com.unciv.models.simulation + +import java.time.Duration + +class MutableInt(var value: Int = 0) { + fun inc() { ++value } + fun get(): Int { return value } + fun set(newValue: Int) { value = newValue } + + override fun toString(): String { + return value.toString() + } +} + +fun formatDuration(d: Duration): String { + var d = d + val days = d.toDays() + d = d.minusDays(days) + val hours = d.toHours() + d = d.minusHours(hours) + val minutes = d.toMinutes() + d = d.minusMinutes(minutes) + val seconds = d.seconds + d = d.minusSeconds(seconds) + val millis = d.toMillis() + return (if (days == 0L) "" else "$days"+"d ") + + (if (hours == 0L) "" else "$hours"+"h ") + + (if (minutes == 0L) "" else "$minutes"+"m ") + + (if (seconds == 0L) "$millis"+"ms" else "$seconds"+"."+"$millis".take(2)+"s") +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/mapeditor/EditorMapHolder.kt b/core/src/com/unciv/ui/mapeditor/EditorMapHolder.kt index c4799e96..69a95cce 100644 --- a/core/src/com/unciv/ui/mapeditor/EditorMapHolder.kt +++ b/core/src/com/unciv/ui/mapeditor/EditorMapHolder.kt @@ -31,7 +31,7 @@ class EditorMapHolder(internal val mapEditorScreen: MapEditorScreen, internal va // This is a hack to make the unit icons render correctly on the game, even though the map isn't part of a game // and the units aren't assigned to any "real" CivInfo tileGroup.tileInfo.getUnits().forEach { it.civInfo= CivilizationInfo() - .apply { nation=mapEditorScreen.gameSetupInfo.ruleset.nations[it.owner]!! } } + .apply { nation=mapEditorScreen.ruleset.nations[it.owner]!! } } tileGroup.showEntireMap = true tileGroup.update() diff --git a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt index 8d491743..05b7bdfd 100644 --- a/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/GameParametersScreen.kt @@ -2,6 +2,7 @@ package com.unciv.ui.mapeditor import com.unciv.UncivGame import com.unciv.logic.map.Scenario +import com.unciv.models.ruleset.Ruleset import com.unciv.ui.newgamescreen.GameOptionsTable import com.unciv.ui.newgamescreen.GameSetupInfo import com.unciv.ui.newgamescreen.PlayerPickerTable @@ -16,10 +17,11 @@ import com.unciv.ui.utils.* * @param [mapEditorScreen] previous screen from map editor. */ class GameParametersScreen(var mapEditorScreen: MapEditorScreen): IPreviousScreen, PickerScreen() { - override var gameSetupInfo: GameSetupInfo = mapEditorScreen.gameSetupInfo + override var ruleset: Ruleset = mapEditorScreen.ruleset var playerPickerTable = PlayerPickerTable(this, this.gameSetupInfo.gameParameters) - var gameOptionsTable = GameOptionsTable(mapEditorScreen.gameSetupInfo) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } + var gameOptionsTable = GameOptionsTable(mapEditorScreen) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } + init { setDefaultCloseAction(mapEditorScreen) @@ -32,6 +34,7 @@ class GameParametersScreen(var mapEditorScreen: MapEditorScreen): IPreviousScree rightSideButton.onClick { mapEditorScreen.gameSetupInfo = gameSetupInfo mapEditorScreen.scenario = Scenario(mapEditorScreen.tileMap, mapEditorScreen.gameSetupInfo.gameParameters) + mapEditorScreen.ruleset = ruleset //TODO: figure out whether it is necessary mapEditorScreen.tileEditorOptions.update() mapEditorScreen.mapHolder.updateTileGroups() UncivGame.Current.setScreen(mapEditorScreen) diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt index 1eb1a5d8..9353fa1f 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt @@ -12,6 +12,7 @@ import com.unciv.logic.MapSaver import com.unciv.logic.map.Scenario 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.GameSetupInfo import com.unciv.ui.newgamescreen.IPreviousScreen @@ -25,6 +26,7 @@ class MapEditorScreen(): IPreviousScreen, CameraStageBaseScreen() { var tileMap = TileMap() var scenarioName = "" // when loading map: mapName is taken as default for scenarioName var scenario: Scenario? = null // main indicator whether scenario information is present + override var ruleset = RulesetCache.getBaseRuleset() override var gameSetupInfo = GameSetupInfo() lateinit var mapHolder: EditorMapHolder @@ -66,7 +68,7 @@ class MapEditorScreen(): IPreviousScreen, CameraStageBaseScreen() { } fun initialize() { - tileMap.setTransients(gameSetupInfo.ruleset,false) + tileMap.setTransients(ruleset,false) mapHolder = EditorMapHolder(this, tileMap) mapHolder.addTiles(stage.width) diff --git a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt index 6af4b5f5..88c019dd 100644 --- a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt +++ b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt @@ -34,7 +34,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera var brushSize = 1 private var currentHex: Actor = Group() - private val ruleset = mapEditorScreen.gameSetupInfo.ruleset + private val ruleset = mapEditorScreen.ruleset private val gameParameters = mapEditorScreen.gameSetupInfo.gameParameters private val scrollPanelHeight = mapEditorScreen.stage.height*0.7f - 100f // -100 reserved for currentHex table @@ -353,7 +353,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera // for the tile image val tileInfo = TileInfo() - tileInfo.ruleset = mapEditorScreen.gameSetupInfo.ruleset + tileInfo.ruleset = mapEditorScreen.ruleset val terrain = resource.terrainsCanBeFoundOn.first() val terrainObject = ruleset.terrains[terrain]!! if (terrainObject.type == TerrainType.TerrainFeature) { @@ -446,7 +446,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera } private fun makeTileGroup(tileInfo: TileInfo): TileGroup { - tileInfo.ruleset = mapEditorScreen.gameSetupInfo.ruleset + tileInfo.ruleset = mapEditorScreen.ruleset tileInfo.setTerrainTransients() val group = TileGroup(tileInfo, TileSetStrings()) group.showEntireMap = true diff --git a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index 47e981c1..01d21b63 100644 --- a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -10,10 +10,10 @@ import com.unciv.models.ruleset.VictoryType import com.unciv.models.translations.tr import com.unciv.ui.utils.* -class GameOptionsTable(gameSetupInfo: GameSetupInfo, val updatePlayerPickerTable:(desiredCiv:String)->Unit) +class GameOptionsTable(previousScreen: IPreviousScreen, val updatePlayerPickerTable:(desiredCiv:String)->Unit) : Table(CameraStageBaseScreen.skin) { - var gameParameters = gameSetupInfo.gameParameters - val ruleset = gameSetupInfo.ruleset + var gameParameters = previousScreen.gameSetupInfo.gameParameters + val ruleset = previousScreen.ruleset var locked = false init { diff --git a/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt b/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt index 5684592d..0b4f43d0 100644 --- a/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/IPreviousScreen.kt @@ -12,6 +12,7 @@ import com.unciv.ui.utils.CameraStageBaseScreen interface IPreviousScreen { val gameSetupInfo: GameSetupInfo var stage: Stage + val ruleset: Ruleset /** * Method added for compatibility with [PlayerPickerTable] which addresses diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index 61b27cfd..88efaf29 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -20,7 +20,7 @@ import kotlin.concurrent.thread class GameSetupInfo(var gameId:String, var gameParameters: GameParameters, var mapParameters: MapParameters) { - var ruleset = RulesetCache.getComplexRuleset(gameParameters.mods) +// var ruleset = RulesetCache.getComplexRuleset(gameParameters.mods) constructor() : this("", GameParameters(), MapParameters()) constructor(gameInfo: GameInfo) : this("", gameInfo.gameParameters.clone(), gameInfo.tileMap.mapParameters) @@ -29,8 +29,9 @@ class GameSetupInfo(var gameId:String, var gameParameters: GameParameters, var m class NewGameScreen(previousScreen:CameraStageBaseScreen, _gameSetupInfo: GameSetupInfo?=null): IPreviousScreen, PickerScreen() { override val gameSetupInfo = _gameSetupInfo ?: GameSetupInfo() + override val ruleset = RulesetCache.getComplexRuleset(gameSetupInfo.gameParameters.mods) var playerPickerTable = PlayerPickerTable(this, gameSetupInfo.gameParameters) - var newGameOptionsTable = GameOptionsTable(gameSetupInfo) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } + var newGameOptionsTable = GameOptionsTable(this) { desiredCiv: String -> playerPickerTable.update(desiredCiv) } var mapOptionsTable = MapOptionsTable(this) diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index 39ba7483..7dbbd5c5 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -15,10 +15,12 @@ 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.ruleset.Ruleset import com.unciv.models.translations.tr import com.unciv.ui.mapeditor.GameParametersScreen import com.unciv.ui.utils.* import java.util.* +import kotlin.reflect.typeOf /** * This [Table] is used to pick or edit players information for new game/scenario creation. @@ -55,10 +57,10 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: */ fun update(desiredCiv: String = "") { playerListTable.clear() - val ruleset = previousScreen.gameSetupInfo.ruleset // the mod picking changes this ruleset + val gameBasics = previousScreen.ruleset // the mod picking changes this ruleset reassignRemovedModReferences() - val newRulesetPlayableCivs = previousScreen.gameSetupInfo.ruleset.nations.count { it.key != Constants.barbarians } + 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) @@ -66,7 +68,7 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: for (player in gameParameters.players) { playerListTable.add(getPlayerTable(player)).width(civBlocksWidth).padBottom(20f).row() } - if (gameParameters.players.count() < ruleset.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 { @@ -85,7 +87,7 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: */ private fun reassignRemovedModReferences() { for (player in gameParameters.players) { - if (!previousScreen.gameSetupInfo.ruleset.nations.containsKey(player.chosenCiv)) + if (!previousScreen.ruleset.nations.containsKey(player.chosenCiv)) player.chosenCiv = "Random" } } @@ -118,7 +120,6 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: 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 @@ -184,7 +185,7 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: .apply { this.setAlignment(Align.center) } .surroundWithCircle(36f).apply { circle.color = Color.BLACK } .surroundWithCircle(40f, false).apply { circle.color = Color.WHITE } - else ImageGetter.getNationIndicator(previousScreen.gameSetupInfo.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 @@ -225,10 +226,9 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: if (player.chosenCiv == nation.name) continue - nationListTable.add(NationTable(nation, nationsPopupWidth, previousScreen.gameSetupInfo.ruleset).onClick { - if (previousScreen is GameParametersScreen) { + nationListTable.add(NationTable(nation, nationsPopupWidth, previousScreen.ruleset).onClick { + if (previousScreen is GameParametersScreen) previousScreen.mapEditorScreen.tileMap.switchPlayersNation(player, nation) - } player.chosenCiv = nation.name nationsPopup.close() update() @@ -259,7 +259,7 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: */ private fun getAvailablePlayerCivs(): ArrayList { var nations = ArrayList() - for (nation in previousScreen.gameSetupInfo.ruleset.nations.values + for (nation in previousScreen.ruleset.nations.values .filter { it.isMajorCiv() }) { if (gameParameters.players.any { it.chosenCiv == nation.name }) continue @@ -267,5 +267,4 @@ class PlayerPickerTable(val previousScreen: IPreviousScreen, var gameParameters: } return nations } - -} +} \ No newline at end of file diff --git a/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt b/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt new file mode 100644 index 00000000..99373626 --- /dev/null +++ b/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt @@ -0,0 +1,88 @@ +package com.unciv.app.desktop + +import com.unciv.UncivGame +import com.unciv.UncivGameParameters +import com.unciv.logic.GameStarter +import com.unciv.logic.civilization.PlayerType +import com.unciv.logic.map.MapParameters +import com.unciv.logic.map.MapSize +import com.unciv.models.metadata.GameParameters +import com.unciv.models.metadata.GameSettings +import com.unciv.models.metadata.GameSpeed +import com.unciv.models.metadata.Player +import com.unciv.models.ruleset.RulesetCache +import com.unciv.models.simulation.Simulation +import com.unciv.models.simulation.SimulationStep +import com.unciv.models.simulation.formatDuration +import com.unciv.ui.newgamescreen.GameSetupInfo +import java.time.Duration +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +internal object ConsoleLauncher { + @JvmStatic + fun main(arg: Array) { + + val version = "0.1" + val consoleParameters = UncivGameParameters( + version, + null, + { exitProcess(0) }, + null, + null, + true + ) + val game = UncivGame(consoleParameters) + + UncivGame.Current = game + UncivGame.Current.settings = GameSettings().apply { showTutorials = false } + UncivGame.Current.simulateMaxTurns = 1000 + UncivGame.Current.simulateUntilWin = true + + RulesetCache.loadRulesets() + + val gameParameters = getGameParameters("China", "Greece") + val mapParameters = getMapParameters() + val gameSetupInfo = GameSetupInfo(gameParameters, mapParameters) + val newGame = GameStarter.startNewGame(gameSetupInfo) + UncivGame.Current.gameInfo = newGame + + var simulation = Simulation(newGame,25,4) + + simulation.start() + + simulation.getStats() + println(simulation) + } + + private fun getMapParameters(): MapParameters { + return MapParameters().apply { + size = MapSize.Tiny + noRuins = true + noNaturalWonders = true + } + } + + private fun getGameParameters(civilization1: String, civilization2: String): GameParameters { + return GameParameters().apply { + difficulty = "Chieftain" + gameSpeed = GameSpeed.Quick + noBarbarians = true + players = ArrayList().apply { + add(Player().apply { + playerType = PlayerType.AI + chosenCiv = civilization1 + }) + add(Player().apply { + playerType = PlayerType.AI + chosenCiv = civilization2 + }) + add(Player().apply { + playerType = PlayerType.Human + chosenCiv = "Spectator" + }) + } + } + } + +} \ No newline at end of file