Refactor: Change UncivGame.worldScreen and UncivGame.gameInfo to be of nullable type (#7114)

* Refactor: Make Popups work on Stages instead of BaseScreens

* Refactor: Change UncivGame.worldScreen and UncivGame.gameInfo to be of nullable type

* Fix "Resume" game loading not fully handling exceptions

* Fix one missed refactoring

* Refactor: remove useless postRunnable
This commit is contained in:
Timo T 2022-06-11 21:14:44 +02:00 committed by GitHub
parent 72b197fdc3
commit 9008d242a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 427 additions and 346 deletions

View File

@ -70,13 +70,13 @@ open class AndroidLauncher : AndroidApplication() {
override fun onPause() { override fun onPause() {
if (UncivGame.isCurrentInitialized() if (UncivGame.isCurrentInitialized()
&& UncivGame.Current.isGameInfoInitialized() && UncivGame.Current.gameInfo != null
&& UncivGame.Current.settings.multiplayer.turnCheckerEnabled && UncivGame.Current.settings.multiplayer.turnCheckerEnabled
&& UncivGame.Current.gameSaver.getMultiplayerSaves().any() && UncivGame.Current.gameSaver.getMultiplayerSaves().any()
) { ) {
MultiplayerTurnCheckWorker.startTurnChecker( MultiplayerTurnCheckWorker.startTurnChecker(
applicationContext, UncivGame.Current.gameSaver, applicationContext, UncivGame.Current.gameSaver,
UncivGame.Current.gameInfo, UncivGame.Current.settings.multiplayer UncivGame.Current.gameInfo!!, UncivGame.Current.settings.multiplayer
) )
} }
super.onPause() super.onPause()

View File

@ -198,7 +198,7 @@ class MainMenuScreen: BaseScreen() {
private fun resumeGame() { private fun resumeGame() {
val curWorldScreen = game.getWorldScreenOrNull() val curWorldScreen = game.worldScreen
if (curWorldScreen != null) { if (curWorldScreen != null) {
game.resetToWorldScreen() game.resetToWorldScreen()
curWorldScreen.popups.filterIsInstance(WorldScreenMenuPopup::class.java).forEach(Popup::close) curWorldScreen.popups.filterIsInstance(WorldScreenMenuPopup::class.java).forEach(Popup::close)

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.Application
import com.badlogic.gdx.Game import com.badlogic.gdx.Game
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.Screen
import com.badlogic.gdx.scenes.scene2d.actions.Actions import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
@ -22,13 +23,13 @@ import com.unciv.ui.audio.SoundPlayer
import com.unciv.ui.crashhandling.closeExecutors import com.unciv.ui.crashhandling.closeExecutors
import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.multiplayer.LoadDeepLinkScreen import com.unciv.ui.multiplayer.LoadDeepLinkScreen
import com.unciv.ui.multiplayer.MultiplayerHelpers import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.popup.Popup import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.center import com.unciv.ui.utils.extensions.center
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
import com.unciv.ui.worldscreen.PlayerReadyScreen import com.unciv.ui.worldscreen.PlayerReadyScreen
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
import com.unciv.utils.debug import com.unciv.utils.debug
@ -49,8 +50,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
private val audioExceptionHelper = parameters.audioExceptionHelper private val audioExceptionHelper = parameters.audioExceptionHelper
var deepLinkedMultiplayerGame: String? = null var deepLinkedMultiplayerGame: String? = null
lateinit var gameInfo: GameInfo var gameInfo: GameInfo? = null
fun isGameInfoInitialized() = this::gameInfo.isInitialized
lateinit var settings: GameSettings lateinit var settings: GameSettings
lateinit var musicController: MusicController lateinit var musicController: MusicController
lateinit var onlineMultiplayer: OnlineMultiplayer lateinit var onlineMultiplayer: OnlineMultiplayer
@ -70,9 +70,8 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
*/ */
var simulateUntilTurnForDebug: Int = 0 var simulateUntilTurnForDebug: Int = 0
lateinit var worldScreen: WorldScreen var worldScreen: WorldScreen? = null
private set private set
fun getWorldScreenOrNull() = if (this::worldScreen.isInitialized) worldScreen else null
var isInitialized = false var isInitialized = false
@ -105,7 +104,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
* - Font (hence Fonts.resetFont() inside setSkin()) * - Font (hence Fonts.resetFont() inside setSkin())
*/ */
settings = gameSaver.getGeneralSettings() // needed for the screen settings = gameSaver.getGeneralSettings() // needed for the screen
screen = LoadingScreen() // NOT dependent on any atlas or skin setScreen(LoadingScreen()) // NOT dependent on any atlas or skin
GameSounds.init() GameSounds.init()
musicController = MusicController() // early, but at this point does only copy volume from settings musicController = MusicController() // early, but at this point does only copy volume from settings
audioExceptionHelper?.installHooks( audioExceptionHelper?.installHooks(
@ -152,49 +151,66 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
} }
} }
fun loadGame(gameInfo: GameInfo) { fun loadGame(gameInfo: GameInfo): WorldScreen {
this.gameInfo = gameInfo this.gameInfo = gameInfo
ImageGetter.setNewRuleset(gameInfo.ruleSet) ImageGetter.setNewRuleset(gameInfo.ruleSet)
// Clone the mod list and add the base ruleset to it // Clone the mod list and add the base ruleset to it
val fullModList = gameInfo.gameParameters.getModsAndBaseRuleset() val fullModList = gameInfo.gameParameters.getModsAndBaseRuleset()
musicController.setModList(fullModList) musicController.setModList(fullModList)
Gdx.input.inputProcessor = null // Since we will set the world screen when we're ready, Gdx.input.inputProcessor = null // Since we will set the world screen when we're ready,
if (gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1 && !gameInfo.gameParameters.isOnlineMultiplayer) val worldScreen = WorldScreen(gameInfo, gameInfo.getPlayerToViewAs())
setScreen(PlayerReadyScreen(gameInfo, gameInfo.getPlayerToViewAs())) val newScreen = if (gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1 && !gameInfo.gameParameters.isOnlineMultiplayer)
PlayerReadyScreen(worldScreen)
else { else {
resetToWorldScreen(WorldScreen(gameInfo, gameInfo.getPlayerToViewAs())) worldScreen
} }
} setScreen(newScreen)
return worldScreen
fun setScreen(screen: BaseScreen) {
val oldScreen = getScreen()
Gdx.input.inputProcessor = screen.stage
super.setScreen(screen)
if (oldScreen != getWorldScreenOrNull()) oldScreen.dispose()
} }
/** /**
* If called with null [newWorldScreen], disposes of the current screen and sets it to the current stored world screen. * Sets the screen of the game and automatically disposes the old screen as long as it isn't the world screen.
* If the current screen is already the world screen, the only thing that happens is that the world screen updates. *
* @param screen must be a subclass of [BaseScreen].
*/ */
fun resetToWorldScreen(newWorldScreen: WorldScreen? = null) { override fun setScreen(screen: Screen) {
if (newWorldScreen != null) { if (screen !is BaseScreen) throw IllegalArgumentException("Call to setScreen with screen that does not inherit BaseScreen: " + screen.javaClass.simpleName)
debug("Reset to new WorldScreen, gameId: %s, turn: %s, curCiv: %s", setScreen(screen)
newWorldScreen.gameInfo.gameId, newWorldScreen.gameInfo.turns, newWorldScreen.gameInfo.currentPlayer)
val oldWorldScreen = getWorldScreenOrNull()
worldScreen = newWorldScreen
// setScreen disposes the current screen, but the old world screen is not the current screen, so need to dispose here
if (screen != oldWorldScreen) {
oldWorldScreen?.dispose()
} }
} else {
val oldWorldScreen = getWorldScreenOrNull()!! override fun getScreen(): BaseScreen? {
debug("Reset to old WorldScreen, gameId: %s, turn: %s, curCiv: %s", val curScreen = super.getScreen()
oldWorldScreen.gameInfo.gameId, oldWorldScreen.gameInfo.turns, oldWorldScreen.gameInfo.currentPlayer) return if (curScreen == null) { null } else { curScreen as BaseScreen }
} }
setScreen(worldScreen)
worldScreen.shouldUpdate = true // This can set the screen to the policy picker or tech picker screen, so the input processor must come before /** Sets the screen of the game and automatically [disposes][Screen.dispose] the old screen as long as it isn't the world screen. */
fun setScreen(newScreen: BaseScreen) {
if (newScreen is WorldScreen) {
debug(
"Setting new world screen: gameId: %s, turn: %s, curCiv: %s",
newScreen.gameInfo.gameId, newScreen.gameInfo.turns, newScreen.gameInfo.currentPlayer
)
if (newScreen != worldScreen) worldScreen?.dispose()
worldScreen = newScreen
newScreen.shouldUpdate = true
Gdx.graphics.requestRendering() Gdx.graphics.requestRendering()
} else {
debug("Setting new screen: %s", newScreen)
}
val oldScreen = screen
Gdx.input.inputProcessor = newScreen.stage
super.setScreen(newScreen) // This can set the screen to the policy picker or tech picker screen, so the input processor must be set before
if (oldScreen !is WorldScreen) { // we want to keep the world screen around, because it's expensive to re-create it
oldScreen?.dispose()
}
}
/**
* Resets the game to the stored world screen and automatically [disposes][Screen.dispose] the old screen.
*/
fun resetToWorldScreen() {
setScreen(worldScreen!!)
} }
private fun tryLoadDeepLinkedGame() = launchCrashHandling("LoadDeepLinkedGame") { private fun tryLoadDeepLinkedGame() = launchCrashHandling("LoadDeepLinkedGame") {
@ -233,7 +249,8 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
} }
override fun pause() { override fun pause() {
if (isGameInfoInitialized()) gameSaver.autoSave(this.gameInfo) val curGameInfo = gameInfo
if (curGameInfo != null) gameSaver.autoSave(curGameInfo)
musicController.pause() musicController.pause()
super.pause() super.pause()
} }
@ -252,14 +269,15 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
if (::musicController.isInitialized) musicController.gracefulShutdown() // Do allow fade-out if (::musicController.isInitialized) musicController.gracefulShutdown() // Do allow fade-out
closeExecutors() closeExecutors()
if (isGameInfoInitialized()) { val curGameInfo = gameInfo
if (curGameInfo != null) {
val autoSaveJob = gameSaver.autoSaveJob val autoSaveJob = gameSaver.autoSaveJob
if (autoSaveJob != null && autoSaveJob.isActive) { if (autoSaveJob != null && autoSaveJob.isActive) {
// auto save is already in progress (e.g. started by onPause() event) // auto save is already in progress (e.g. started by onPause() event)
// let's allow it to finish and do not try to autosave second time // let's allow it to finish and do not try to autosave second time
autoSaveJob.join() autoSaveJob.join()
} else { } else {
gameSaver.autoSaveSingleThreaded(gameInfo) // NO new thread gameSaver.autoSaveSingleThreaded(curGameInfo) // NO new thread
} }
} }
settings.save() settings.save()
@ -277,10 +295,15 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
} }
} }
/** Returns the [worldScreen] if it is the currently active screen of the game */
fun getWorldScreenIfActive(): WorldScreen? {
return if (screen == worldScreen) worldScreen else null
}
companion object { companion object {
lateinit var Current: UncivGame lateinit var Current: UncivGame
fun isCurrentInitialized() = this::Current.isInitialized fun isCurrentInitialized() = this::Current.isInitialized
fun isCurrentGame(gameId: String): Boolean = isCurrentInitialized() && Current.isGameInfoInitialized() && Current.gameInfo.gameId == gameId fun isCurrentGame(gameId: String): Boolean = isCurrentInitialized() && Current.gameInfo != null && Current.gameInfo!!.gameId == gameId
fun isDeepLinkedGameLoading() = isCurrentInitialized() && Current.deepLinkedMultiplayerGame != null fun isDeepLinkedGameLoading() = isCurrentInitialized() && Current.deepLinkedMultiplayerGame != null
} }
} }

View File

@ -208,7 +208,7 @@ object Battle {
// CS friendship from killing barbarians // CS friendship from killing barbarians
if (defeatedUnit.matchesCategory("Barbarian") && defeatedUnit.matchesCategory("Military") && civUnit.getCivInfo().isMajorCiv()) { if (defeatedUnit.matchesCategory("Barbarian") && defeatedUnit.matchesCategory("Military") && civUnit.getCivInfo().isMajorCiv()) {
for (cityState in UncivGame.Current.gameInfo.getAliveCityStates()) { for (cityState in UncivGame.Current.gameInfo!!.getAliveCityStates()) {
if (civUnit.getCivInfo().knows(cityState) && defeatedUnit.unit.threatensCiv(cityState)) { if (civUnit.getCivInfo().knows(cityState) && defeatedUnit.unit.threatensCiv(cityState)) {
cityState.cityStateFunctions.threateningBarbarianKilledBy(civUnit.getCivInfo()) cityState.cityStateFunctions.threateningBarbarianKilledBy(civUnit.getCivInfo())
} }
@ -216,7 +216,7 @@ object Battle {
} }
// CS war with major pseudo-quest // CS war with major pseudo-quest
for (cityState in UncivGame.Current.gameInfo.getAliveCityStates()) { for (cityState in UncivGame.Current.gameInfo!!.getAliveCityStates()) {
cityState.questManager.militaryUnitKilledBy(civUnit.getCivInfo(), defeatedUnit.getCivInfo()) cityState.questManager.militaryUnitKilledBy(civUnit.getCivInfo(), defeatedUnit.getCivInfo())
} }
} }

View File

@ -663,8 +663,8 @@ class CityConstructions {
cityInfo.cityStats.update() cityInfo.cityStats.update()
cityInfo.civInfo.updateDetailedCivResources() cityInfo.civInfo.updateDetailedCivResources()
// If bought the worldscreen will not have been marked to update, and the new improvement won't show until later... // If bought the worldscreen will not have been marked to update, and the new improvement won't show until later...
if (UncivGame.isCurrentInitialized()) if (UncivGame.isCurrentInitialized() && UncivGame.Current.worldScreen != null)
UncivGame.Current.worldScreen.shouldUpdate = true UncivGame.Current.worldScreen!!.shouldUpdate = true
} }
/** Support for [UniqueType.CreatesOneImprovement]: /** Support for [UniqueType.CreatesOneImprovement]:

View File

@ -155,8 +155,10 @@ class CityInfoConquestFunctions(val city: CityInfo){
city.isPuppet = false city.isPuppet = false
city.cityConstructions.inProgressConstructions.clear() // undo all progress of the previous civ on units etc. city.cityConstructions.inProgressConstructions.clear() // undo all progress of the previous civ on units etc.
city.cityStats.update() city.cityStats.update()
if (!UncivGame.Current.consoleMode) val worldScreen = UncivGame.Current.worldScreen
UncivGame.Current.worldScreen.shouldUpdate = true if (!UncivGame.Current.consoleMode && worldScreen != null) {
worldScreen.shouldUpdate = true
}
} }
private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) { private fun diplomaticRepercussionsForConqueringCity(oldCiv: CivilizationInfo, conqueringCiv: CivilizationInfo) {

View File

@ -62,8 +62,11 @@ class CivilizationInfo {
/** Returns an instance of WorkerAutomation valid for the duration of the current turn /** Returns an instance of WorkerAutomation valid for the duration of the current turn
* This instance carries cached data common for all Workers of this civ */ * This instance carries cached data common for all Workers of this civ */
fun getWorkerAutomation(): WorkerAutomation { fun getWorkerAutomation(): WorkerAutomation {
val currentTurn = if (UncivGame.Current.isInitialized && UncivGame.Current.isGameInfoInitialized()) val currentTurn = if (UncivGame.Current.isInitialized && UncivGame.Current.gameInfo != null) {
UncivGame.Current.gameInfo.turns else 0 UncivGame.Current.gameInfo!!.turns
} else {
0
}
if (workerAutomationCache == null || workerAutomationCache!!.cachedForTurn != currentTurn) if (workerAutomationCache == null || workerAutomationCache!!.cachedForTurn != currentTurn)
workerAutomationCache = WorkerAutomation(this, currentTurn) workerAutomationCache = WorkerAutomation(this, currentTurn)
return workerAutomationCache!! return workerAutomationCache!!

View File

@ -919,11 +919,11 @@ class AssignedQuest(val questName: String = "",
when (questName) { when (questName) {
QuestName.ClearBarbarianCamp.value -> { QuestName.ClearBarbarianCamp.value -> {
game.resetToWorldScreen() game.resetToWorldScreen()
game.worldScreen.mapHolder.setCenterPosition(Vector2(data1.toFloat(), data2.toFloat()), selectUnit = false) game.worldScreen!!.mapHolder.setCenterPosition(Vector2(data1.toFloat(), data2.toFloat()), selectUnit = false)
} }
QuestName.Route.value -> { QuestName.Route.value -> {
game.resetToWorldScreen() game.resetToWorldScreen()
game.worldScreen.mapHolder.setCenterPosition(gameInfo.getCivilization(assigner).getCapital()!!.location, selectUnit = false) game.worldScreen!!.mapHolder.setCenterPosition(gameInfo.getCivilization(assigner).getCapital()!!.location, selectUnit = false)
} }
} }
} }

View File

@ -67,8 +67,9 @@ class OnlineMultiplayer {
} }
private fun getCurrentGame(): OnlineMultiplayerGame? { private fun getCurrentGame(): OnlineMultiplayerGame? {
if (UncivGame.isCurrentInitialized() && UncivGame.Current.isGameInfoInitialized()) { val gameInfo = UncivGame.Current.gameInfo
return getGameByGameId(UncivGame.Current.gameInfo.gameId) if (gameInfo != null) {
return getGameByGameId(gameInfo.gameId)
} else { } else {
return null return null
} }

View File

@ -13,7 +13,7 @@ data class TradeOffer(val name: String, val type: TradeType, var amount: Int = 1
name: String, name: String,
type: TradeType, type: TradeType,
amount: Int = 1, amount: Int = 1,
gameSpeed: GameSpeed = UncivGame.Current.gameInfo.gameParameters.gameSpeed gameSpeed: GameSpeed = UncivGame.Current.gameInfo!!.gameParameters.gameSpeed
) : this(name, type, amount, duration = -1) { ) : this(name, type, amount, duration = -1) {
duration = when { duration = when {
type.isImmediate -> -1 // -1 for offers that are immediate (e.g. gold transfer) type.isImmediate -> -1 // -1 for offers that are immediate (e.g. gold transfer)
@ -36,7 +36,7 @@ data class TradeOffer(val name: String, val type: TradeType, var amount: Int = 1
var offerText = when(type){ var offerText = when(type){
TradeType.WarDeclaration -> "Declare war on [$name]" TradeType.WarDeclaration -> "Declare war on [$name]"
TradeType.Introduction -> "Introduction to [$name]" TradeType.Introduction -> "Introduction to [$name]"
TradeType.City -> UncivGame.Current.gameInfo.getCities().firstOrNull{ it.id == name }?.name ?: "Non-existent city" TradeType.City -> UncivGame.Current.gameInfo!!.getCities().firstOrNull{ it.id == name }?.name ?: "Non-existent city"
else -> name else -> name
}.tr() }.tr()

View File

@ -47,8 +47,9 @@ class Belief() : RulesetObject() {
// private but potentially reusable, therefore not folded into getCivilopediaTextMatching // private but potentially reusable, therefore not folded into getCivilopediaTextMatching
private fun getBeliefsMatching(name: String, ruleset: Ruleset): Sequence<Belief> { private fun getBeliefsMatching(name: String, ruleset: Ruleset): Sequence<Belief> {
if (!UncivGame.isCurrentInitialized()) return sequenceOf() if (!UncivGame.isCurrentInitialized()) return sequenceOf()
if (!UncivGame.Current.isGameInfoInitialized()) return sequenceOf() val gameInfo = UncivGame.Current.gameInfo
if (!UncivGame.Current.gameInfo.isReligionEnabled()) return sequenceOf() if (gameInfo == null) return sequenceOf()
if (!gameInfo.isReligionEnabled()) return sequenceOf()
return ruleset.beliefs.asSequence().map { it.value } return ruleset.beliefs.asSequence().map { it.value }
.filter { belief -> belief.uniqueObjects.any { unique -> unique.params.any { it == name } } .filter { belief -> belief.uniqueObjects.any { unique -> unique.params.any { it == name } }
} }

View File

@ -137,10 +137,11 @@ class Nation : RulesetObject() {
textList += FormattedLine("{Type}: {$cityStateType}", header = 4, color = cityStateType!!.color) textList += FormattedLine("{Type}: {$cityStateType}", header = 4, color = cityStateType!!.color)
val era = if (UncivGame.isCurrentInitialized() && UncivGame.Current.isGameInfoInitialized()) val era = if (UncivGame.isCurrentInitialized() && UncivGame.Current.gameInfo != null) {
UncivGame.Current.gameInfo.currentPlayerCiv.getEra() UncivGame.Current.gameInfo!!.currentPlayerCiv.getEra()
else } else {
ruleset.eras.values.first() ruleset.eras.values.first()
}
var showResources = false var showResources = false
val friendBonus = era.friendBonus[cityStateType!!.name] val friendBonus = era.friendBonus[cityStateType!!.name]
@ -185,7 +186,7 @@ class Nation : RulesetObject() {
when { when {
building.uniqueTo != name -> continue building.uniqueTo != name -> continue
building.hasUnique(UniqueType.HiddenFromCivilopedia) -> continue building.hasUnique(UniqueType.HiddenFromCivilopedia) -> continue
UncivGame.Current.isGameInfoInitialized() && !UncivGame.Current.gameInfo.isReligionEnabled() && building.hasUnique(UniqueType.HiddenWithoutReligion) -> continue // This seems consistent with existing behaviour of CivilopediaScreen's init.<locals>.shouldBeDisplayed(), and Technology().getEnabledUnits(). Otherwise there are broken links in the Civilopedia (E.G. to "Pyramid" and "Shrine", from "The Maya"). UncivGame.Current.gameInfo != null && !UncivGame.Current.gameInfo!!.isReligionEnabled() && building.hasUnique(UniqueType.HiddenWithoutReligion) -> continue // This seems consistent with existing behaviour of CivilopediaScreen's init.<locals>.shouldBeDisplayed(), and Technology().getEnabledUnits(). Otherwise there are broken links in the Civilopedia (E.G. to "Pyramid" and "Shrine", from "The Maya").
} }
yield(FormattedLine("{${building.name}} -", link=building.makeLink())) yield(FormattedLine("{${building.name}} -", link=building.makeLink()))
if (building.replaces != null && ruleset.buildings.containsKey(building.replaces!!)) { if (building.replaces != null && ruleset.buildings.containsKey(building.replaces!!)) {

View File

@ -51,7 +51,7 @@ class Technology: RulesetObject() {
} }
} }
val viewingCiv = UncivGame.Current.worldScreen.viewingCiv val viewingCiv = UncivGame.Current.worldScreen!!.viewingCiv
val enabledUnits = getEnabledUnits(ruleset, viewingCiv) val enabledUnits = getEnabledUnits(ruleset, viewingCiv)
if (enabledUnits.any()) { if (enabledUnits.any()) {
lineList += "{Units enabled}: " lineList += "{Units enabled}: "
@ -225,7 +225,7 @@ class Technology: RulesetObject() {
} }
} }
val viewingCiv = UncivGame.Current.getWorldScreenOrNull()?.viewingCiv val viewingCiv = UncivGame.Current.worldScreen?.viewingCiv
val enabledUnits = getEnabledUnits(ruleset, viewingCiv) val enabledUnits = getEnabledUnits(ruleset, viewingCiv)
if (enabledUnits.any()) { if (enabledUnits.any()) {
lineList += FormattedLine() lineList += FormattedLine()

View File

@ -176,9 +176,9 @@ class TileImprovement : RulesetStatsObject() {
if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) { if (isAncientRuinsEquivalent() && ruleset.ruinRewards.isNotEmpty()) {
val difficulty: String val difficulty: String
val religionEnabled: Boolean val religionEnabled: Boolean
if (UncivGame.isCurrentInitialized() && UncivGame.Current.isGameInfoInitialized()) { if (UncivGame.isCurrentInitialized() && UncivGame.Current.gameInfo != null) {
difficulty = UncivGame.Current.gameInfo.gameParameters.difficulty difficulty = UncivGame.Current.gameInfo!!.gameParameters.difficulty
religionEnabled = UncivGame.Current.gameInfo.isReligionEnabled() religionEnabled = UncivGame.Current.gameInfo!!.isReligionEnabled()
} else { } else {
difficulty = "Prince" // most factors == 1 difficulty = "Prince" // most factors == 1
religionEnabled = true religionEnabled = true

View File

@ -38,7 +38,7 @@ class Simulation(
for (civ in civilizations) { for (civ in civilizations) {
this.winRate[civ] = MutableInt(0) this.winRate[civ] = MutableInt(0)
winRateByVictory[civ] = mutableMapOf() winRateByVictory[civ] = mutableMapOf()
for (victory in UncivGame.Current.gameInfo.ruleSet.victories.keys) for (victory in UncivGame.Current.gameInfo!!.ruleSet.victories.keys)
winRateByVictory[civ]!![victory] = MutableInt(0) winRateByVictory[civ]!![victory] = MutableInt(0)
} }
} }
@ -121,7 +121,7 @@ class Simulation(
outString += "\n$civ:\n" outString += "\n$civ:\n"
val wins = winRate[civ]!!.value * 100 / max(steps.size, 1) val wins = winRate[civ]!!.value * 100 / max(steps.size, 1)
outString += "$wins% total win rate \n" outString += "$wins% total win rate \n"
for (victory in UncivGame.Current.gameInfo.ruleSet.victories.keys) { for (victory in UncivGame.Current.gameInfo!!.ruleSet.victories.keys) {
val winsVictory = winRateByVictory[civ]!![victory]!!.value * 100 / max(winRate[civ]!!.value, 1) val winsVictory = winRateByVictory[civ]!![victory]!!.value * 100 / max(winRate[civ]!!.value, 1)
outString += "$victory: $winsVictory% " outString += "$victory: $winsVictory% "
} }

View File

@ -250,21 +250,27 @@ object TranslationActiveModsCache {
} }
private set private set
private fun getCurrentHash() = UncivGame.Current.run { private fun getCurrentHash(): Int {
if (isGameInfoInitialized()) val gameInfo = UncivGame.Current.gameInfo
return if (gameInfo != null) {
gameInfo.gameParameters.mods.hashCode() + gameInfo.gameParameters.baseRuleset.hashCode() * 31 gameInfo.gameParameters.mods.hashCode() + gameInfo.gameParameters.baseRuleset.hashCode() * 31
else translations.translationActiveMods.hashCode() * 31 * 31 } else {
UncivGame.Current.translations.translationActiveMods.hashCode() * 31 * 31
}
} }
private fun getCurrentSet() = UncivGame.Current.run { private fun getCurrentSet(): LinkedHashSet<String> {
if (isGameInfoInitialized()) { val gameInfo = UncivGame.Current.gameInfo
return if (gameInfo != null) {
val par = gameInfo.gameParameters val par = gameInfo.gameParameters
// This is equivalent to (par.mods + par.baseRuleset) without the cast down to `Set` // This is equivalent to (par.mods + par.baseRuleset) without the cast down to `Set`
LinkedHashSet<String>(par.mods.size + 1).apply { LinkedHashSet<String>(par.mods.size + 1).apply {
addAll(par.mods) addAll(par.mods)
add(par.baseRuleset) add(par.baseRuleset)
} }
} else translations.translationActiveMods } else {
UncivGame.Current.translations.translationActiveMods
}
} }
} }

View File

@ -49,6 +49,5 @@ class LanguagePickerScreen : PickerScreen() {
game.translations.tryReadTranslationForCurrentLanguage() game.translations.tryReadTranslationForCurrentLanguage()
game.setScreen(MainMenuScreen()) game.setScreen(MainMenuScreen())
dispose()
} }
} }

View File

@ -59,7 +59,8 @@ object SoundPlayer {
val game = UncivGame.Current val game = UncivGame.Current
// Get a hash covering all mods - quickly, so don't map, cast or copy the Set types // Get a hash covering all mods - quickly, so don't map, cast or copy the Set types
val hash1 = if (game.isGameInfoInitialized()) game.gameInfo.ruleSet.mods.hashCode() else 0 val gameInfo = game.gameInfo
val hash1 = if (gameInfo != null) gameInfo.ruleSet.mods.hashCode() else 0
val newHash = hash1.xor(game.settings.visualMods.hashCode()) val newHash = hash1.xor(game.settings.visualMods.hashCode())
// If hash the same, leave the cache as is // If hash the same, leave the cache as is
@ -91,8 +92,10 @@ object SoundPlayer {
// audiovisual mods after game mods but before built-in sounds // audiovisual mods after game mods but before built-in sounds
// (these can already be available when game.gameInfo is not) // (these can already be available when game.gameInfo is not)
val modList: MutableSet<String> = mutableSetOf() val modList: MutableSet<String> = mutableSetOf()
if (game.isGameInfoInitialized()) val gameInfo = game.gameInfo
modList.addAll(game.gameInfo.ruleSet.mods) // Sounds from game mods if (gameInfo != null) {
modList.addAll(gameInfo.ruleSet.mods) // Sounds from game mods
}
modList.addAll(game.settings.visualMods) modList.addAll(game.settings.visualMods)
// Translate the basic mod list into relative folder names so only sounds/name.ext needs // Translate the basic mod list into relative folder names so only sounds/name.ext needs

View File

@ -516,10 +516,9 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
"Would you like to purchase [${construction.name}] for [$constructionBuyCost] [${stat.character}]?".tr() "Would you like to purchase [${construction.name}] for [$constructionBuyCost] [${stat.character}]?".tr()
YesNoPopup( YesNoPopup(
purchasePrompt, purchasePrompt,
action = { purchaseConstruction(construction, stat, tile) },
screen = cityScreen, screen = cityScreen,
restoreDefault = { cityScreen.update() } restoreDefault = { cityScreen.update() }
).open() ) { purchaseConstruction(construction, stat, tile) }.open()
} }
/** This tests whether the buy button should be _shown_ */ /** This tests whether the buy button should be _shown_ */

View File

@ -138,17 +138,17 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin)
cityScreen.closeAllPopups() cityScreen.closeAllPopups()
YesNoPopup("Are you sure you want to sell this [${building.name}]?".tr(), YesNoPopup("Are you sure you want to sell this [${building.name}]?".tr(),
{ cityScreen, {
cityScreen.update()
}
) {
cityScreen.city.sellBuilding(building.name) cityScreen.city.sellBuilding(building.name)
cityScreen.update() cityScreen.update()
}, cityScreen, }.open()
{
cityScreen.update()
}).open()
} }
if (cityScreen.city.hasSoldBuildingThisTurn && !cityScreen.city.civInfo.gameInfo.gameParameters.godMode if (cityScreen.city.hasSoldBuildingThisTurn && !cityScreen.city.civInfo.gameInfo.gameParameters.godMode
|| cityScreen.city.isPuppet || cityScreen.city.isPuppet
|| !UncivGame.Current.worldScreen.isPlayersTurn || !cityScreen.canChangeState) || !UncivGame.Current.worldScreen!!.isPlayersTurn || !cityScreen.canChangeState)
sellBuildingButton.disable() sellBuildingButton.disable()
} }
it.addSeparator() it.addSeparator()

View File

@ -81,7 +81,7 @@ class CityReligionInfoTable(
icon.onClick { icon.onClick {
val newScreen = if (religion == iconName) val newScreen = if (religion == iconName)
EmpireOverviewScreen(civInfo, EmpireOverviewCategories.Religion.name, religion) EmpireOverviewScreen(civInfo, EmpireOverviewCategories.Religion.name, religion)
else CivilopediaScreen(gameInfo.ruleSet, UncivGame.Current.screen as BaseScreen, CivilopediaCategories.Belief, religion ) else CivilopediaScreen(gameInfo.ruleSet, UncivGame.Current.screen!!, CivilopediaCategories.Belief, religion )
UncivGame.Current.setScreen(newScreen) UncivGame.Current.setScreen(newScreen)
} }
return icon return icon

View File

@ -41,7 +41,7 @@ class CityScreen(
} }
/** Toggles or adds/removes all state changing buttons */ /** Toggles or adds/removes all state changing buttons */
val canChangeState = UncivGame.Current.worldScreen.canChangeState val canChangeState = UncivGame.Current.worldScreen!!.canChangeState
/** Toggle between Constructions and cityInfo (buildings, specialists etc. */ /** Toggle between Constructions and cityInfo (buildings, specialists etc. */
var showConstructionsTable = true var showConstructionsTable = true
@ -402,8 +402,8 @@ class CityScreen(
fun exit() { fun exit() {
game.resetToWorldScreen() game.resetToWorldScreen()
game.worldScreen.mapHolder.setCenterPosition(city.location) game.worldScreen!!.mapHolder.setCenterPosition(city.location)
game.worldScreen.bottomUnitTable.selectUnit() game.worldScreen!!.bottomUnitTable.selectUnit()
} }
fun page(delta: Int) { fun page(delta: Int) {

View File

@ -112,15 +112,14 @@ class CityScreenTileTable(private val cityScreen: CityScreen): Table() {
"Would you like to purchase [Tile] for [$goldCostOfTile] [${Stat.Gold.character}]?".tr() "Would you like to purchase [Tile] for [$goldCostOfTile] [${Stat.Gold.character}]?".tr()
YesNoPopup( YesNoPopup(
purchasePrompt, purchasePrompt,
action = { screen = cityScreen,
restoreDefault = { cityScreen.update() }
) {
SoundPlayer.play(UncivSound.Coin) SoundPlayer.play(UncivSound.Coin)
city.expansion.buyTile(selectedTile) city.expansion.buyTile(selectedTile)
// preselect the next tile on city screen rebuild so bulk buying can go faster // preselect the next tile on city screen rebuild so bulk buying can go faster
UncivGame.Current.setScreen(CityScreen(city, initSelectedTile = city.expansion.chooseNewTileToOwn())) UncivGame.Current.setScreen(CityScreen(city, initSelectedTile = city.expansion.chooseNewTileToOwn()))
}, }.open()
screen = cityScreen,
restoreDefault = { cityScreen.update() }
).open()
} }
/** This tests whether the buy button should be _shown_ */ /** This tests whether the buy button should be _shown_ */

View File

@ -81,7 +81,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
cityInfo.cityStats.update() cityInfo.cityStats.update()
cityScreen.update() cityScreen.update()
} }
if (cityInfo.population.getFreePopulation() == 0 || !UncivGame.Current.worldScreen.isPlayersTurn) if (cityInfo.population.getFreePopulation() == 0 || !UncivGame.Current.worldScreen!!.isPlayersTurn)
assignButton.clear() assignButton.clear()
return assignButton return assignButton
} }
@ -98,7 +98,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
} }
if (assignedSpecialists <= 0 || cityInfo.isPuppet) unassignButton.isVisible = false if (assignedSpecialists <= 0 || cityInfo.isPuppet) unassignButton.isVisible = false
if (!UncivGame.Current.worldScreen.isPlayersTurn) unassignButton.clear() if (!UncivGame.Current.worldScreen!!.isPlayersTurn) unassignButton.clear()
return unassignButton return unassignButton
} }

View File

@ -183,10 +183,9 @@ class CivilopediaScreen(
val imageSize = 50f val imageSize = 50f
onBackButtonClicked { game.setScreen(previousScreen) } onBackButtonClicked { game.setScreen(previousScreen) }
val religionEnabled = if (game.isGameInfoInitialized()) game.gameInfo.isReligionEnabled() val curGameInfo = game.gameInfo
else ruleset.beliefs.isNotEmpty() val religionEnabled = if (curGameInfo != null) curGameInfo.isReligionEnabled() else ruleset.beliefs.isNotEmpty()
val victoryTypes = if (game.isGameInfoInitialized()) game.gameInfo.gameParameters.victoryTypes val victoryTypes = if (curGameInfo != null) curGameInfo.gameParameters.victoryTypes else emptyList()
else listOf()
fun shouldBeDisplayed(obj: IHasUniques): Boolean { fun shouldBeDisplayed(obj: IHasUniques): Boolean {
return when { return when {
@ -254,7 +253,6 @@ class CivilopediaScreen(
val goToGameButton = Constants.close.toTextButton() val goToGameButton = Constants.close.toTextButton()
goToGameButton.onClick { goToGameButton.onClick {
game.setScreen(previousScreen) game.setScreen(previousScreen)
dispose()
} }
val topTable = Table() val topTable = Table()

View File

@ -164,10 +164,13 @@ class FormattedLine (
} }
return "" return ""
} }
private fun getCurrentRuleset() = when { private fun getCurrentRuleset(): Ruleset {
val gameInfo = UncivGame.Current.gameInfo
return when {
!UncivGame.isCurrentInitialized() -> Ruleset() !UncivGame.isCurrentInitialized() -> Ruleset()
!UncivGame.Current.isGameInfoInitialized() -> RulesetCache[BaseRuleset.Civ_V_Vanilla.fullName]!! gameInfo == null -> RulesetCache[BaseRuleset.Civ_V_Vanilla.fullName]!!
else -> UncivGame.Current.gameInfo.ruleSet else -> gameInfo.ruleSet
}
} }
private fun initNamesCategoryMap(ruleSet: Ruleset): HashMap<String, CivilopediaCategories> { private fun initNamesCategoryMap(ruleSet: Ruleset): HashMap<String, CivilopediaCategories> {
//val startTime = System.nanoTime() //val startTime = System.nanoTime()

View File

@ -47,7 +47,7 @@ class CrashScreen(val exception: Throwable): BaseScreen() {
/** Qualified class name of the game screen that was active at the construction of this instance, or an error note. */ /** Qualified class name of the game screen that was active at the construction of this instance, or an error note. */
private val lastScreenType = try { private val lastScreenType = try {
UncivGame.Current.screen::class.qualifiedName.toString() UncivGame.Current.screen!!::class.qualifiedName.toString()
} catch (e: Throwable) { } catch (e: Throwable) {
"Could not get screen type: $e" "Could not get screen type: $e"
} }
@ -58,11 +58,11 @@ class CrashScreen(val exception: Throwable): BaseScreen() {
/** @return The last active save game serialized as a compressed string if any, or an informational note otherwise. */ /** @return The last active save game serialized as a compressed string if any, or an informational note otherwise. */
private fun tryGetSaveGame(): String { private fun tryGetSaveGame(): String {
if (!UncivGame.isCurrentInitialized() || !UncivGame.Current.isGameInfoInitialized()) if (!UncivGame.isCurrentInitialized() || UncivGame.Current.gameInfo == null)
return "" return ""
return "\n**Save Data:**\n<details><summary>Show Saved Game</summary>\n\n```\n" + return "\n**Save Data:**\n<details><summary>Show Saved Game</summary>\n\n```\n" +
try { try {
GameSaver.gameInfoToString(UncivGame.Current.gameInfo, forceZip = true) GameSaver.gameInfoToString(UncivGame.Current.gameInfo!!, forceZip = true)
} catch (e: Throwable) { } catch (e: Throwable) {
"No save data: $e" // In theory .toString() could still error here. "No save data: $e" // In theory .toString() could still error here.
} + "\n```\n</details>\n" } + "\n```\n</details>\n"
@ -70,11 +70,11 @@ class CrashScreen(val exception: Throwable): BaseScreen() {
/** @return Mods from the last active save game if any, or an informational note otherwise. */ /** @return Mods from the last active save game if any, or an informational note otherwise. */
private fun tryGetSaveMods(): String { private fun tryGetSaveMods(): String {
if (!UncivGame.isCurrentInitialized() || !UncivGame.Current.isGameInfoInitialized()) if (!UncivGame.isCurrentInitialized() || UncivGame.Current.gameInfo == null)
return "" return ""
return "\n**Save Mods:**\n```\n" + return "\n**Save Mods:**\n```\n" +
try { // Also from old CrashController().buildReport(), also could still error at .toString(). try { // Also from old CrashController().buildReport(), also could still error at .toString().
LinkedHashSet(UncivGame.Current.gameInfo.gameParameters.getModsAndBaseRuleset()).toString() LinkedHashSet(UncivGame.Current.gameInfo!!.gameParameters.getModsAndBaseRuleset()).toString()
} catch (e: Throwable) { } catch (e: Throwable) {
"No mod data: $e" "No mod data: $e"
} + "\n```\n" } + "\n```\n"

View File

@ -62,10 +62,10 @@ class MapEditorLoadTab(
private fun deleteHandler() { private fun deleteHandler() {
if (chosenMap == null) return if (chosenMap == null) return
YesNoPopup("Are you sure you want to delete this map?", { YesNoPopup("Are you sure you want to delete this map?", editorScreen) {
chosenMap!!.delete() chosenMap!!.delete()
mapFiles.update() mapFiles.update()
}, editorScreen).open() }.open()
} }
override fun activated(index: Int, caption: String, pager: TabbedPager) { override fun activated(index: Int, caption: String, pager: TabbedPager) {

View File

@ -131,7 +131,7 @@ class MapEditorModsTab(
add(inc.toLabel()).row() add(inc.toLabel()).row()
} }
add(ScrollPane(incompatibilityTable)).colspan(2) add(ScrollPane(incompatibilityTable)).colspan(2)
.maxHeight(screen.stage.height * 0.8f).row() .maxHeight(stage.height * 0.8f).row()
addGoodSizedLabel("Change map to fit selected ruleset?", 24).colspan(2).row() addGoodSizedLabel("Change map to fit selected ruleset?", 24).colspan(2).row()
addButtonInRow(Constants.yes, 'y') { addButtonInRow(Constants.yes, 'y') {
onOK() onOK()

View File

@ -78,10 +78,10 @@ class MapEditorSaveTab(
private fun deleteHandler() { private fun deleteHandler() {
if (chosenMap == null) return if (chosenMap == null) return
YesNoPopup("Are you sure you want to delete this map?", { YesNoPopup("Are you sure you want to delete this map?", editorScreen) {
chosenMap!!.delete() chosenMap!!.delete()
mapFiles.update() mapFiles.update()
}, editorScreen).open() }.open()
} }
override fun activated(index: Int, caption: String, pager: TabbedPager) { override fun activated(index: Int, caption: String, pager: TabbedPager) {

View File

@ -191,9 +191,9 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen() {
fun askIfDirty(question: String, action: ()->Unit) { fun askIfDirty(question: String, action: ()->Unit) {
if (!isDirty) return action() if (!isDirty) return action()
YesNoPopup(question, action, screen = this, restoreDefault = { YesNoPopup(question, screen = this, restoreDefault = {
keyPressDispatcher[KeyCharAndCode.BACK] = this::closeEditor keyPressDispatcher[KeyCharAndCode.BACK] = this::closeEditor
}).open() }, action).open()
} }
fun hideSelection() { fun hideSelection() {

View File

@ -40,11 +40,11 @@ class EditFriendScreen(selectedFriend: FriendList.Friend, backScreen: ViewFriend
topTable.add(gameIDTable).padBottom(30f).row() topTable.add(gameIDTable).padBottom(30f).row()
deleteFriendButton.onClick { deleteFriendButton.onClick {
val askPopup = YesNoPopup("Are you sure you want to delete this friend?", { val askPopup = YesNoPopup("Are you sure you want to delete this friend?", this) {
friendlist.delete(selectedFriend) friendlist.delete(selectedFriend)
backScreen.game.setScreen(backScreen) backScreen.game.setScreen(backScreen)
backScreen.refreshFriendsList() backScreen.refreshFriendsList()
}, this) }
askPopup.open() askPopup.open()
}.apply { color = Color.RED } }.apply { color = Color.RED }
topTable.add(deleteFriendButton) topTable.add(deleteFriendButton)

View File

@ -27,22 +27,22 @@ class EditMultiplayerGameInfoScreen(val multiplayerGame: OnlineMultiplayerGame,
val deleteButton = "Delete save".toTextButton() val deleteButton = "Delete save".toTextButton()
deleteButton.onClick { deleteButton.onClick {
val askPopup = YesNoPopup("Are you sure you want to delete this map?", { val askPopup = YesNoPopup("Are you sure you want to delete this map?", this) {
try { try {
game.onlineMultiplayer.deleteGame(multiplayerGame) game.onlineMultiplayer.deleteGame(multiplayerGame)
game.setScreen(backScreen) game.setScreen(backScreen)
} catch (ex: Exception) { } catch (ex: Exception) {
ToastPopup("Could not delete game!", this) ToastPopup("Could not delete game!", this)
} }
}, this) }
askPopup.open() askPopup.open()
}.apply { color = Color.RED } }.apply { color = Color.RED }
val giveUpButton = "Resign".toTextButton() val giveUpButton = "Resign".toTextButton()
giveUpButton.onClick { giveUpButton.onClick {
val askPopup = YesNoPopup("Are you sure you want to resign?", { val askPopup = YesNoPopup("Are you sure you want to resign?", this) {
resign(multiplayerGame, backScreen) resign(multiplayerGame, backScreen)
}, this) }
askPopup.open() askPopup.open()
} }
giveUpButton.apply { color = Color.RED } giveUpButton.apply { color = Color.RED }

View File

@ -36,6 +36,7 @@ import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.pad import com.unciv.ui.utils.extensions.pad
import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton import com.unciv.ui.utils.extensions.toTextButton
import com.unciv.utils.Log
import java.net.URL import java.net.URL
import java.util.* import java.util.*
import com.unciv.ui.utils.AutoScrollPane as ScrollPane import com.unciv.ui.utils.AutoScrollPane as ScrollPane
@ -74,9 +75,9 @@ class NewGameScreen(
val resetToDefaultsButton = "Reset to defaults".toTextButton() val resetToDefaultsButton = "Reset to defaults".toTextButton()
rightSideGroup.addActorAt(0, resetToDefaultsButton) rightSideGroup.addActorAt(0, resetToDefaultsButton)
resetToDefaultsButton.onClick { resetToDefaultsButton.onClick {
YesNoPopup("Are you sure you want to reset all game options to defaults?", { YesNoPopup("Are you sure you want to reset all game options to defaults?", this) {
game.setScreen(NewGameScreen(previousScreen, GameSetupInfo())) game.setScreen(NewGameScreen(previousScreen, GameSetupInfo()))
}, this).open(true) }.open(true)
} }
} }
@ -155,7 +156,7 @@ class NewGameScreen(
val message = mapSize.fixUndesiredSizes(gameSetupInfo.mapParameters.worldWrap) val message = mapSize.fixUndesiredSizes(gameSetupInfo.mapParameters.worldWrap)
if (message != null) { if (message != null) {
postCrashHandlingRunnable { postCrashHandlingRunnable {
ToastPopup( message, UncivGame.Current.screen as BaseScreen, 4000 ) ToastPopup( message, UncivGame.Current.screen!!, 4000 )
with (mapOptionsTable.generatedMapOptionsTable) { with (mapOptionsTable.generatedMapOptionsTable) {
customMapSizeRadius.text = mapSize.radius.toString() customMapSizeRadius.text = mapSize.radius.toString()
customMapWidth.text = mapSize.width.toString() customMapWidth.text = mapSize.width.toString()
@ -275,6 +276,7 @@ class NewGameScreen(
rightSideButton.setText("Start game!".tr()) rightSideButton.setText("Start game!".tr())
return return
} catch (ex: Exception) { } catch (ex: Exception) {
Log.error("Error while creating game", ex)
postCrashHandlingRunnable { postCrashHandlingRunnable {
popup.reuseWith("Could not upload game!", true) popup.reuseWith("Could not upload game!", true)
} }
@ -286,13 +288,12 @@ class NewGameScreen(
} }
postCrashHandlingRunnable { postCrashHandlingRunnable {
game.loadGame(newGame) val worldScreen = game.loadGame(newGame)
previousScreen.dispose()
if (newGame.gameParameters.isOnlineMultiplayer) { if (newGame.gameParameters.isOnlineMultiplayer) {
// Save gameId to clipboard because you have to do it anyway. // Save gameId to clipboard because you have to do it anyway.
Gdx.app.clipboard.contents = newGame.gameId Gdx.app.clipboard.contents = newGame.gameId
// Popup to notify the User that the gameID got copied to the clipboard // Popup to notify the User that the gameID got copied to the clipboard
ToastPopup("Game ID copied to clipboard!".tr(), game.worldScreen, 2500) ToastPopup("Game ID copied to clipboard!".tr(), worldScreen, 2500)
} }
} }
} }

View File

@ -344,7 +344,7 @@ private class NationPickerPopup(
private val ruleset = previousScreen.ruleset private val ruleset = previousScreen.ruleset
// This Popup's body has two halves of same size, either side by side or arranged vertically // This Popup's body has two halves of same size, either side by side or arranged vertically
// depending on screen proportions - determine height for one of those // depending on screen proportions - determine height for one of those
private val partHeight = screen.stage.height * (if (screen.isNarrowerThan4to3()) 0.45f else 0.8f) private val partHeight = stage.height * (if (stage.isNarrowerThan4to3()) 0.45f else 0.8f)
private val civBlocksWidth = playerPicker.civBlocksWidth private val civBlocksWidth = playerPicker.civBlocksWidth
private val nationListTable = Table() private val nationListTable = Table()
private val nationListScroll = ScrollPane(nationListTable) private val nationListScroll = ScrollPane(nationListTable)
@ -356,7 +356,7 @@ private class NationPickerPopup(
nationListScroll.setOverscroll(false, false) nationListScroll.setOverscroll(false, false)
add(nationListScroll).size( civBlocksWidth + 10f, partHeight ) add(nationListScroll).size( civBlocksWidth + 10f, partHeight )
// +10, because the nation table has a 5f pad, for a total of +10f // +10, because the nation table has a 5f pad, for a total of +10f
if (screen.isNarrowerThan4to3()) row() if (stage.isNarrowerThan4to3()) row()
nationDetailsScroll.setOverscroll(false, false) nationDetailsScroll.setOverscroll(false, false)
add(nationDetailsScroll).size(civBlocksWidth + 10f, partHeight) // Same here, see above add(nationDetailsScroll).size(civBlocksWidth + 10f, partHeight) // Same here, see above

View File

@ -9,6 +9,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.Array
import com.unciv.UncivGame
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.translations.TranslationFileWriter import com.unciv.models.translations.TranslationFileWriter
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
@ -48,12 +49,12 @@ fun advancedTab(
addMaxZoomSlider(this, settings) addMaxZoomSlider(this, settings)
val screen = optionsPopup.screen val helper = UncivGame.Current.platformSpecificHelper
if (screen.game.platformSpecificHelper != null && Gdx.app.type == Application.ApplicationType.Android) { if (helper != null && Gdx.app.type == Application.ApplicationType.Android) {
optionsPopup.addCheckbox(this, "Enable portrait orientation", settings.allowAndroidPortrait) { optionsPopup.addCheckbox(this, "Enable portrait orientation", settings.allowAndroidPortrait) {
settings.allowAndroidPortrait = it settings.allowAndroidPortrait = it
// Note the following might close the options screen indirectly and delayed // Note the following might close the options screen indirectly and delayed
screen.game.platformSpecificHelper.allowPortrait(it) helper.allowPortrait(it)
} }
} }
@ -61,7 +62,7 @@ fun advancedTab(
addTranslationGeneration(this, optionsPopup) addTranslationGeneration(this, optionsPopup)
addSetUserId(this, settings, screen) addSetUserId(this, settings)
} }
private fun addAutosaveTurnsSelectBox(table: Table, settings: GameSettings) { private fun addAutosaveTurnsSelectBox(table: Table, settings: GameSettings) {
@ -161,22 +162,18 @@ private fun addTranslationGeneration(table: Table, optionsPopup: OptionsPopup) {
table.add(generateTranslationsButton).colspan(2).row() table.add(generateTranslationsButton).colspan(2).row()
} }
private fun addSetUserId(table: Table, settings: GameSettings, screen: BaseScreen) { private fun addSetUserId(table: Table, settings: GameSettings) {
val idSetLabel = "".toLabel() val idSetLabel = "".toLabel()
val takeUserIdFromClipboardButton = "Take user ID from clipboard".toTextButton() val takeUserIdFromClipboardButton = "Take user ID from clipboard".toTextButton()
.onClick { .onClick {
try { try {
val clipboardContents = Gdx.app.clipboard.contents.trim() val clipboardContents = Gdx.app.clipboard.contents.trim()
UUID.fromString(clipboardContents) UUID.fromString(clipboardContents)
YesNoPopup( YesNoPopup("Doing this will reset your current user ID to the clipboard contents - are you sure?",table.stage) {
"Doing this will reset your current user ID to the clipboard contents - are you sure?",
{
settings.multiplayer.userId = clipboardContents settings.multiplayer.userId = clipboardContents
settings.save() settings.save()
idSetLabel.setFontColor(Color.WHITE).setText("ID successfully set!".tr()) idSetLabel.setFontColor(Color.WHITE).setText("ID successfully set!".tr())
}, }.open(true)
screen
).open(true)
idSetLabel.isVisible = true idSetLabel.isVisible = true
} catch (ex: Exception) { } catch (ex: Exception) {
idSetLabel.isVisible = true idSetLabel.isVisible = true

View File

@ -19,6 +19,8 @@ fun debugTab() = Table(BaseScreen.skin).apply {
defaults().pad(5f) defaults().pad(5f)
val game = UncivGame.Current val game = UncivGame.Current
val worldScreen = game.worldScreen
if (worldScreen != null) {
val simulateButton = "Simulate until turn:".toTextButton() val simulateButton = "Simulate until turn:".toTextButton()
val simulateTextField = TextField(game.simulateUntilTurnForDebug.toString(), BaseScreen.skin) val simulateTextField = TextField(game.simulateUntilTurnForDebug.toString(), BaseScreen.skin)
val invalidInputLabel = "This is not a valid integer!".toLabel().also { it.isVisible = false } val invalidInputLabel = "This is not a valid integer!".toLabel().also { it.isVisible = false }
@ -30,11 +32,12 @@ fun debugTab() = Table(BaseScreen.skin).apply {
} }
game.simulateUntilTurnForDebug = simulateUntilTurns game.simulateUntilTurnForDebug = simulateUntilTurns
invalidInputLabel.isVisible = false invalidInputLabel.isVisible = false
game.worldScreen.nextTurn() worldScreen.nextTurn()
} }
add(simulateButton) add(simulateButton)
add(simulateTextField).row() add(simulateTextField).row()
add(invalidInputLabel).colspan(2).row() add(invalidInputLabel).colspan(2).row()
}
add("Supercharged".toCheckBox(game.superchargedForDebug) { add("Supercharged".toCheckBox(game.superchargedForDebug) {
game.superchargedForDebug = it game.superchargedForDebug = it
@ -42,9 +45,10 @@ fun debugTab() = Table(BaseScreen.skin).apply {
add("View entire map".toCheckBox(game.viewEntireMapForDebug) { add("View entire map".toCheckBox(game.viewEntireMapForDebug) {
game.viewEntireMapForDebug = it game.viewEntireMapForDebug = it
}).colspan(2).row() }).colspan(2).row()
if (game.isGameInfoInitialized()) { val curGameInfo = game.gameInfo
add("God mode (current game)".toCheckBox(game.gameInfo.gameParameters.godMode) { if (curGameInfo != null) {
game.gameInfo.gameParameters.godMode = it add("God mode (current game)".toCheckBox(curGameInfo.gameParameters.godMode) {
curGameInfo.gameParameters.godMode = it
}).colspan(2).row() }).colspan(2).row()
} }
add("Save games compressed".toCheckBox(GameSaver.saveZipped) { add("Save games compressed".toCheckBox(GameSaver.saveZipped) {
@ -73,25 +77,25 @@ fun debugTab() = Table(BaseScreen.skin).apply {
val unlockTechsButton = "Unlock all techs".toTextButton() val unlockTechsButton = "Unlock all techs".toTextButton()
unlockTechsButton.onClick { unlockTechsButton.onClick {
if (!game.isGameInfoInitialized()) if (curGameInfo == null)
return@onClick return@onClick
for (tech in game.gameInfo.ruleSet.technologies.keys) { for (tech in curGameInfo.ruleSet.technologies.keys) {
if (tech !in game.gameInfo.getCurrentPlayerCivilization().tech.techsResearched) { if (tech !in curGameInfo.getCurrentPlayerCivilization().tech.techsResearched) {
game.gameInfo.getCurrentPlayerCivilization().tech.addTechnology(tech) curGameInfo.getCurrentPlayerCivilization().tech.addTechnology(tech)
game.gameInfo.getCurrentPlayerCivilization().popupAlerts.removeLastOrNull() curGameInfo.getCurrentPlayerCivilization().popupAlerts.removeLastOrNull()
} }
} }
game.gameInfo.getCurrentPlayerCivilization().updateSightAndResources() curGameInfo.getCurrentPlayerCivilization().updateSightAndResources()
game.worldScreen.shouldUpdate = true if (worldScreen != null) worldScreen.shouldUpdate = true
} }
add(unlockTechsButton).colspan(2).row() add(unlockTechsButton).colspan(2).row()
val giveResourcesButton = "Get all strategic resources".toTextButton() val giveResourcesButton = "Get all strategic resources".toTextButton()
giveResourcesButton.onClick { giveResourcesButton.onClick {
if (!game.isGameInfoInitialized()) if (curGameInfo == null)
return@onClick return@onClick
val ownedTiles = game.gameInfo.tileMap.values.asSequence().filter { it.getOwner() == game.gameInfo.getCurrentPlayerCivilization() } val ownedTiles = curGameInfo.tileMap.values.asSequence().filter { it.getOwner() == curGameInfo.getCurrentPlayerCivilization() }
val resourceTypes = game.gameInfo.ruleSet.tileResources.values.asSequence().filter { it.resourceType == ResourceType.Strategic } val resourceTypes = curGameInfo.ruleSet.tileResources.values.asSequence().filter { it.resourceType == ResourceType.Strategic }
for ((tile, resource) in ownedTiles zip resourceTypes) { for ((tile, resource) in ownedTiles zip resourceTypes) {
tile.resource = resource.name tile.resource = resource.name
tile.resourceAmount = 999 tile.resourceAmount = 999
@ -99,8 +103,8 @@ fun debugTab() = Table(BaseScreen.skin).apply {
// If this becomes a problem, check if such an improvement exists and otherwise plop down a great improvement or so // If this becomes a problem, check if such an improvement exists and otherwise plop down a great improvement or so
tile.improvement = resource.getImprovements().first() tile.improvement = resource.getImprovements().first()
} }
game.gameInfo.getCurrentPlayerCivilization().updateSightAndResources() curGameInfo.getCurrentPlayerCivilization().updateSightAndResources()
game.worldScreen.shouldUpdate = true if (worldScreen != null) worldScreen.shouldUpdate = true
} }
add(giveResourcesButton).colspan(2).row() add(giveResourcesButton).colspan(2).row()
} }

View File

@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.Array
import com.unciv.UncivGame
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.tilesets.TileSetCache import com.unciv.models.tilesets.TileSetCache
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
@ -41,7 +42,7 @@ fun displayTab(
optionsPopup.addCheckbox(this, "Experimental Demographics scoreboard", settings.useDemographics, true) { settings.useDemographics = it } optionsPopup.addCheckbox(this, "Experimental Demographics scoreboard", settings.useDemographics, true) { settings.useDemographics = it }
optionsPopup.addCheckbox(this, "Show zoom buttons in world screen", settings.showZoomButtons, true) { settings.showZoomButtons = it } optionsPopup.addCheckbox(this, "Show zoom buttons in world screen", settings.showZoomButtons, true) { settings.showZoomButtons = it }
addMinimapSizeSlider(this, settings, optionsPopup.screen, optionsPopup.selectBoxMinWidth) addMinimapSizeSlider(this, settings, optionsPopup.selectBoxMinWidth)
addResolutionSelectBox(this, settings, optionsPopup.selectBoxMinWidth, onResolutionChange) addResolutionSelectBox(this, settings, optionsPopup.selectBoxMinWidth, onResolutionChange)
@ -62,7 +63,7 @@ fun displayTab(
} }
private fun addMinimapSizeSlider(table: Table, settings: GameSettings, screen: BaseScreen, selectBoxMinWidth: Float) { private fun addMinimapSizeSlider(table: Table, settings: GameSettings, selectBoxMinWidth: Float) {
table.add("Show minimap".toLabel()).left().fillX() table.add("Show minimap".toLabel()).left().fillX()
// The meaning of the values needs a formula to be synchronized between here and // The meaning of the values needs a formula to be synchronized between here and
@ -88,8 +89,9 @@ private fun addMinimapSizeSlider(table: Table, settings: GameSettings, screen: B
settings.minimapSize = size settings.minimapSize = size
} }
settings.save() settings.save()
if (screen is WorldScreen) val worldScreen = UncivGame.Current.getWorldScreenIfActive()
screen.shouldUpdate = true if (worldScreen != null)
worldScreen.shouldUpdate = true
} }
table.add(minimapSlider).minWidth(selectBoxMinWidth).pad(10f).row() table.add(minimapSlider).minWidth(selectBoxMinWidth).pad(10f).row()
} }

View File

@ -1,6 +1,7 @@
package com.unciv.ui.options package com.unciv.ui.options
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.UncivGame
import com.unciv.logic.civilization.PlayerType import com.unciv.logic.civilization.PlayerType
import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
@ -12,16 +13,16 @@ fun gameplayTab(
defaults().pad(5f) defaults().pad(5f)
val settings = optionsPopup.settings val settings = optionsPopup.settings
val screen = optionsPopup.screen
optionsPopup.addCheckbox(this, "Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it } optionsPopup.addCheckbox(this, "Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it }
optionsPopup.addCheckbox(this, "Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it } optionsPopup.addCheckbox(this, "Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it }
optionsPopup.addCheckbox(this, "Auto-assign city production", settings.autoAssignCityProduction, true) { optionsPopup.addCheckbox(this, "Auto-assign city production", settings.autoAssignCityProduction, true) { shouldAutoAssignCityProduction ->
settings.autoAssignCityProduction = it settings.autoAssignCityProduction = shouldAutoAssignCityProduction
if (it && screen is WorldScreen && val worldScreen = UncivGame.Current.getWorldScreenIfActive()
screen.viewingCiv.isCurrentPlayer() && screen.viewingCiv.playerType == PlayerType.Human if (shouldAutoAssignCityProduction && worldScreen != null &&
worldScreen.viewingCiv.isCurrentPlayer() && worldScreen.viewingCiv.playerType == PlayerType.Human
) { ) {
screen.gameInfo.currentPlayerCiv.cities.forEach { city -> worldScreen.gameInfo.currentPlayerCiv.cities.forEach { city ->
city.cityConstructions.chooseNextConstruction() city.cityConstructions.chooseNextConstruction()
} }
} }

View File

@ -1,6 +1,7 @@
package com.unciv.ui.options package com.unciv.ui.options
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.UncivGame
import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.LanguageTable.Companion.addLanguageTables import com.unciv.ui.utils.LanguageTable.Companion.addLanguageTables
import com.unciv.ui.utils.extensions.onClick import com.unciv.ui.utils.extensions.onClick
@ -17,7 +18,7 @@ fun languageTab(
fun selectLanguage() { fun selectLanguage() {
settings.language = chosenLanguage settings.language = chosenLanguage
settings.updateLocaleFromLanguage() settings.updateLocaleFromLanguage()
optionsPopup.screen.game.translations.tryReadTranslationForCurrentLanguage() UncivGame.Current.translations.tryReadTranslationForCurrentLanguage()
onLanguageSelected() onLanguageSelected()
} }

View File

@ -12,7 +12,6 @@ import com.unciv.models.metadata.GameSetting
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr
import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.popup.Popup import com.unciv.ui.popup.Popup
@ -145,8 +144,7 @@ private fun addMultiplayerServerOptions(
settings.save() settings.save()
} }
val screen = optionsPopup.screen serverIpTable.add(multiplayerServerTextField).minWidth(optionsPopup.stageToShowOn.width / 2).growX()
serverIpTable.add(multiplayerServerTextField).minWidth(screen.stage.width / 2).growX()
tab.add(serverIpTable).colspan(2).fillX().row() tab.add(serverIpTable).colspan(2).fillX().row()
tab.add("Reset to Dropbox".toTextButton().onClick { tab.add("Reset to Dropbox".toTextButton().onClick {
@ -156,7 +154,7 @@ private fun addMultiplayerServerOptions(
}).colspan(2).row() }).colspan(2).row()
tab.add(connectionToServerButton.onClick { tab.add(connectionToServerButton.onClick {
val popup = Popup(screen).apply { val popup = Popup(optionsPopup.stage).apply {
addGoodSizedLabel("Awaiting response...").row() addGoodSizedLabel("Awaiting response...").row()
} }
popup.open(true) popup.open(true)

View File

@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
import com.badlogic.gdx.utils.Array import com.badlogic.gdx.utils.Array
import com.unciv.MainMenuScreen import com.unciv.MainMenuScreen
import com.unciv.UncivGame
import com.unciv.logic.event.EventBus import com.unciv.logic.event.EventBus
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
import com.unciv.models.metadata.BaseRuleset import com.unciv.models.metadata.BaseRuleset
@ -133,20 +134,20 @@ class OptionsPopup(
/** Reload this Popup after major changes (resolution, tileset, language, font) */ /** Reload this Popup after major changes (resolution, tileset, language, font) */
private fun reloadWorldAndOptions() { private fun reloadWorldAndOptions() {
settings.save() settings.save()
if (screen is WorldScreen) { val worldScreen = UncivGame.Current.getWorldScreenIfActive()
screen.game.resetToWorldScreen(WorldScreen(screen.gameInfo, screen.viewingCiv)) if (worldScreen != null) {
} else if (screen is MainMenuScreen) { val newWorldScreen = WorldScreen(worldScreen.gameInfo, worldScreen.viewingCiv)
screen.game.setScreen(MainMenuScreen()) worldScreen.game.setScreen(newWorldScreen)
newWorldScreen.openOptionsPopup(tabs.activePage)
} }
(screen.game.screen as BaseScreen).openOptionsPopup(tabs.activePage)
} }
fun addCheckbox(table: Table, text: String, initialState: Boolean, updateWorld: Boolean = false, action: ((Boolean) -> Unit)) { fun addCheckbox(table: Table, text: String, initialState: Boolean, updateWorld: Boolean = false, action: ((Boolean) -> Unit)) {
val checkbox = text.toCheckBox(initialState) { val checkbox = text.toCheckBox(initialState) {
action(it) action(it)
settings.save() settings.save()
if (updateWorld && screen is WorldScreen) val worldScreen = UncivGame.Current.getWorldScreenIfActive()
screen.shouldUpdate = true if (updateWorld && worldScreen != null) worldScreen.shouldUpdate = true
} }
table.add(checkbox).colspan(2).left().row() table.add(checkbox).colspan(2).left().row()
} }

View File

@ -2,9 +2,11 @@ package com.unciv.ui.options
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.UncivGame
import com.unciv.models.UncivSound import com.unciv.models.UncivSound
import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.GameSettings
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.audio.MusicController
import com.unciv.ui.audio.MusicTrackChooserFlags import com.unciv.ui.audio.MusicTrackChooserFlags
import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
@ -24,17 +26,17 @@ fun soundTab(
defaults().pad(5f) defaults().pad(5f)
val settings = optionsPopup.settings val settings = optionsPopup.settings
val screen = optionsPopup.screen val music = UncivGame.Current.musicController
addSoundEffectsVolumeSlider(this, settings) addSoundEffectsVolumeSlider(this, settings)
if (screen.game.musicController.isMusicAvailable()) { if (UncivGame.Current.musicController.isMusicAvailable()) {
addMusicVolumeSlider(this, settings, screen) addMusicVolumeSlider(this, settings, music)
addMusicPauseSlider(this, settings, screen) addMusicPauseSlider(this, settings, music)
addMusicCurrentlyPlaying(this, screen) addMusicCurrentlyPlaying(this, music)
} }
if (!screen.game.musicController.isDefaultFileAvailable()) if (!UncivGame.Current.musicController.isDefaultFileAvailable())
addDownloadMusic(this, optionsPopup) addDownloadMusic(this, optionsPopup)
} }
@ -52,11 +54,10 @@ private fun addDownloadMusic(table: Table, optionsPopup: OptionsPopup) {
// So the whole game doesn't get stuck while downloading the file // So the whole game doesn't get stuck while downloading the file
launchCrashHandling("MusicDownload") { launchCrashHandling("MusicDownload") {
try { try {
val screen = optionsPopup.screen UncivGame.Current.musicController.downloadDefaultFile()
screen.game.musicController.downloadDefaultFile()
postCrashHandlingRunnable { postCrashHandlingRunnable {
optionsPopup.tabs.replacePage("Sound", soundTab(optionsPopup)) optionsPopup.tabs.replacePage("Sound", soundTab(optionsPopup))
screen.game.musicController.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault) UncivGame.Current.musicController.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault)
} }
} catch (ex: Exception) { } catch (ex: Exception) {
postCrashHandlingRunnable { postCrashHandlingRunnable {
@ -83,7 +84,7 @@ private fun addSoundEffectsVolumeSlider(table: Table, settings: GameSettings) {
table.add(soundEffectsVolumeSlider).pad(5f).row() table.add(soundEffectsVolumeSlider).pad(5f).row()
} }
private fun addMusicVolumeSlider(table: Table, settings: GameSettings, screen: BaseScreen) { private fun addMusicVolumeSlider(table: Table, settings: GameSettings, music: MusicController) {
table.add("Music volume".tr()).left().fillX() table.add("Music volume".tr()).left().fillX()
val musicVolumeSlider = UncivSlider( val musicVolumeSlider = UncivSlider(
@ -95,7 +96,6 @@ private fun addMusicVolumeSlider(table: Table, settings: GameSettings, screen: B
settings.musicVolume = it settings.musicVolume = it
settings.save() settings.save()
val music = screen.game.musicController
music.setVolume(it) music.setVolume(it)
if (!music.isPlaying()) if (!music.isPlaying())
music.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault) music.chooseTrack(flags = MusicTrackChooserFlags.setPlayDefault)
@ -103,9 +103,7 @@ private fun addMusicVolumeSlider(table: Table, settings: GameSettings, screen: B
table.add(musicVolumeSlider).pad(5f).row() table.add(musicVolumeSlider).pad(5f).row()
} }
private fun addMusicPauseSlider(table: Table, settings: GameSettings, screen: BaseScreen) { private fun addMusicPauseSlider(table: Table, settings: GameSettings, music: MusicController) {
val music = screen.game.musicController
// map to/from 0-1-2..10-12-14..30-35-40..60-75-90-105-120 // map to/from 0-1-2..10-12-14..30-35-40..60-75-90-105-120
fun posToLength(pos: Float): Float = when (pos) { fun posToLength(pos: Float): Float = when (pos) {
in 0f..10f -> pos in 0f..10f -> pos
@ -141,16 +139,16 @@ private fun addMusicPauseSlider(table: Table, settings: GameSettings, screen: Ba
table.add(pauseLengthSlider).pad(5f).row() table.add(pauseLengthSlider).pad(5f).row()
} }
private fun addMusicCurrentlyPlaying(table: Table, screen: BaseScreen) { private fun addMusicCurrentlyPlaying(table: Table, music: MusicController) {
val label = WrappableLabel("", table.width - 10f, Color(-0x2f5001), 16) val label = WrappableLabel("", table.width - 10f, Color(-0x2f5001), 16)
label.wrap = true label.wrap = true
table.add(label).padTop(20f).colspan(2).fillX().row() table.add(label).padTop(20f).colspan(2).fillX().row()
screen.game.musicController.onChange { music.onChange {
postCrashHandlingRunnable { postCrashHandlingRunnable {
label.setText("Currently playing: [$it]".tr()) label.setText("Currently playing: [$it]".tr())
} }
} }
label.onClick(UncivSound.Silent) { label.onClick(UncivSound.Silent) {
screen.game.musicController.chooseTrack(flags = MusicTrackChooserFlags.none) music.chooseTrack(flags = MusicTrackChooserFlags.none)
} }
} }

View File

@ -127,7 +127,6 @@ class DiplomacyOverviewTab (
table.touchable = Touchable.enabled table.touchable = Touchable.enabled
table.onClick { table.onClick {
if (civInfo.isDefeated() || viewingPlayer.isSpectator() || civInfo == viewingPlayer) return@onClick if (civInfo.isDefeated() || viewingPlayer.isSpectator() || civInfo == viewingPlayer) return@onClick
overviewScreen.dispose()
UncivGame.Current.setScreen(DiplomacyScreen(viewingPlayer, civInfo)) UncivGame.Current.setScreen(DiplomacyScreen(viewingPlayer, civInfo))
} }
return table return table

View File

@ -138,7 +138,7 @@ class StatsOverviewTab(
for (city in viewingPlayer.cities) { city.cityStats.update() } for (city in viewingPlayer.cities) { city.cityStats.update() }
update() update()
} }
slider.isDisabled = !UncivGame.Current.worldScreen.canChangeState slider.isDisabled = !UncivGame.Current.worldScreen!!.canChangeState
sliderTable.add(slider).padTop(15f) sliderTable.add(slider).padTop(15f)
add(sliderTable).colspan(2) add(sliderTable).colspan(2)

View File

@ -78,7 +78,7 @@ class UnitOverviewTab(
private fun showWorldScreenAt(position: Vector2, unit: MapUnit?) { private fun showWorldScreenAt(position: Vector2, unit: MapUnit?) {
val game = overviewScreen.game val game = overviewScreen.game
game.resetToWorldScreen() game.resetToWorldScreen()
game.worldScreen.mapHolder.setCenterPosition(position, forceSelectUnit = unit) game.worldScreen!!.mapHolder.setCenterPosition(position, forceSelectUnit = unit)
} }
private fun showWorldScreenAt(unit: MapUnit) = showWorldScreenAt(unit.currentTile.position, unit) private fun showWorldScreenAt(unit: MapUnit) = showWorldScreenAt(unit.currentTile.position, unit)
private fun showWorldScreenAt(tile: TileInfo) = showWorldScreenAt(tile.position, null) private fun showWorldScreenAt(tile: TileInfo) = showWorldScreenAt(tile.position, null)
@ -190,7 +190,7 @@ class UnitOverviewTab(
if (unit.promotions.canBePromoted()) if (unit.promotions.canBePromoted())
promotionsTable.add( promotionsTable.add(
ImageGetter.getImage("OtherIcons/Star").apply { ImageGetter.getImage("OtherIcons/Star").apply {
color = if (game.worldScreen.canChangeState && unit.currentMovement > 0f && unit.attacksThisTurn == 0) color = if (game.worldScreen!!.canChangeState && unit.currentMovement > 0f && unit.attacksThisTurn == 0)
Color.GOLDENROD Color.GOLDENROD
else Color.GOLDENROD.darken(0.25f) else Color.GOLDENROD.darken(0.25f)
} }
@ -198,7 +198,6 @@ class UnitOverviewTab(
promotionsTable.onClick { promotionsTable.onClick {
if (unit.promotions.canBePromoted() || unit.promotions.promotions.isNotEmpty()) { if (unit.promotions.canBePromoted() || unit.promotions.promotions.isNotEmpty()) {
game.setScreen(PromotionPickerScreen(unit)) game.setScreen(PromotionPickerScreen(unit))
overviewScreen.dispose()
} }
} }
add(promotionsTable) add(promotionsTable)

View File

@ -238,8 +238,11 @@ class WonderOverviewTab(
val locationLabel = locationText.toLabel() val locationLabel = locationText.toLabel()
if (wonder.location != null) if (wonder.location != null)
locationLabel.onClick{ locationLabel.onClick{
val worldScreen = UncivGame.Current.worldScreen
if (worldScreen != null) {
UncivGame.Current.resetToWorldScreen() UncivGame.Current.resetToWorldScreen()
UncivGame.Current.worldScreen.mapHolder.setCenterPosition(wonder.location.position) worldScreen.mapHolder.setCenterPosition(wonder.location.position)
}
} }
add(locationLabel).fillY() add(locationLabel).fillY()
} }

View File

@ -59,7 +59,6 @@ class ImprovementPickerScreen(
onAccept() onAccept()
} }
game.resetToWorldScreen() game.resetToWorldScreen()
dispose()
} }
init { init {

View File

@ -87,7 +87,6 @@ class ModManagementScreen(
game.settings.tileSet = tileSets.first() game.settings.tileSet = tileSets.first()
} }
game.setScreen(MainMenuScreen()) game.setScreen(MainMenuScreen())
dispose()
} }
closeButton.onClick(closeAction) closeButton.onClick(closeAction)
onBackButtonClicked(closeAction) onBackButtonClicked(closeAction)
@ -581,7 +580,6 @@ class ModManagementScreen(
override fun resize(width: Int, height: Int) { override fun resize(width: Int, height: Int) {
if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) { if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) {
game.setScreen(ModManagementScreen(installedModInfo, onlineModInfo)) game.setScreen(ModManagementScreen(installedModInfo, onlineModInfo))
dispose() // interrupt background loader - sorry, the resized new screen won't continue
} }
} }

View File

@ -73,7 +73,7 @@ class PickerPane(
/** Sets the text of the [rightSideButton] and enables it if it's the player's turn */ /** Sets the text of the [rightSideButton] and enables it if it's the player's turn */
fun pick(rightButtonText: String) { 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

@ -43,7 +43,6 @@ open class PickerScreen(disableScroll: Boolean = false) : BaseScreen() {
val closeAction = { val closeAction = {
if (previousScreen != null) game.setScreen(previousScreen) if (previousScreen != null) game.setScreen(previousScreen)
else game.resetToWorldScreen() else game.resetToWorldScreen()
dispose()
} }
pickerPane.closeButton.onClick(closeAction) pickerPane.closeButton.onClick(closeAction)
onBackButtonClicked(closeAction) onBackButtonClicked(closeAction)

View File

@ -58,7 +58,6 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
// If we've moved to another screen in the meantime (great person pick, victory screen) ignore this // If we've moved to another screen in the meantime (great person pick, victory screen) ignore this
if (game.screen !is PolicyPickerScreen || !policies.canAdoptPolicy()) { if (game.screen !is PolicyPickerScreen || !policies.canAdoptPolicy()) {
game.resetToWorldScreen() game.resetToWorldScreen()
dispose()
} else { } else {
val policyScreen = PolicyPickerScreen(worldScreen) val policyScreen = PolicyPickerScreen(worldScreen)
policyScreen.scrollPane.scrollPercentX = scrollPane.scrollPercentX policyScreen.scrollPane.scrollPercentX = scrollPane.scrollPercentX

View File

@ -30,8 +30,6 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() {
game.setScreen(PromotionPickerScreen(unit).setScrollY(scrollPane.scrollY)) game.setScreen(PromotionPickerScreen(unit).setScrollY(scrollPane.scrollY))
else else
game.resetToWorldScreen() game.resetToWorldScreen()
dispose()
game.worldScreen.shouldUpdate = true
} }
init { init {
@ -43,7 +41,7 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() {
acceptPromotion(selectedPromotion) acceptPromotion(selectedPromotion)
} }
val canBePromoted = unit.promotions.canBePromoted() val canBePromoted = unit.promotions.canBePromoted()
val canChangeState = game.worldScreen.canChangeState val canChangeState = game.worldScreen!!.canChangeState
val canPromoteNow = canBePromoted && canChangeState val canPromoteNow = canBePromoted && canChangeState
&& unit.currentMovement > 0 && unit.attacksThisTurn == 0 && unit.currentMovement > 0 && unit.attacksThisTurn == 0
rightSideButton.isEnabled = canPromoteNow rightSideButton.isEnabled = canPromoteNow

View File

@ -67,7 +67,6 @@ abstract class ReligionPickerScreenCommon(
rightSideButton.onClick(UncivSound.Choir) { rightSideButton.onClick(UncivSound.Choir) {
choosingCiv.religionManager.action() choosingCiv.religionManager.action()
UncivGame.Current.resetToWorldScreen() UncivGame.Current.resetToWorldScreen()
dispose()
} }
} }

View File

@ -88,8 +88,6 @@ class TechPickerScreen(
game.settings.addCompletedTutorialTask("Pick technology") game.settings.addCompletedTutorialTask("Pick technology")
game.resetToWorldScreen() game.resetToWorldScreen()
game.worldScreen.shouldUpdate = true
dispose()
} }
// per default show current/recent technology, // per default show current/recent technology,
@ -265,7 +263,7 @@ class TechPickerScreen(
return return
} }
if (!UncivGame.Current.worldScreen.canChangeState) { if (!UncivGame.Current.worldScreen!!.canChangeState) {
rightSideButton.disable() rightSideButton.disable()
return return
} }

View File

@ -2,6 +2,7 @@ package com.unciv.ui.popup
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Button import com.badlogic.gdx.scenes.scene2d.ui.Button
import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Cell
@ -27,7 +28,12 @@ import com.unciv.ui.utils.extensions.toTextButton
* Base class for all Popups, i.e. Tables that get rendered in the middle of a screen and on top of everything else * Base class for all Popups, i.e. Tables that get rendered in the middle of a screen and on top of everything else
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) { open class Popup(
val stageToShowOn: Stage
): Table(BaseScreen.skin) {
constructor(screen: BaseScreen) : this(screen.stage)
// This exists to differentiate the actual popup (the inner table) // This exists to differentiate the actual popup (the inner table)
// from the 'screen blocking' part of the popup (which covers the entire screen) // from the 'screen blocking' part of the popup (which covers the entire screen)
val innerTable = Table(BaseScreen.skin) val innerTable = Table(BaseScreen.skin)
@ -38,11 +44,15 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
*/ */
val keyPressDispatcher = KeyPressDispatcher(this.javaClass.simpleName) val keyPressDispatcher = KeyPressDispatcher(this.javaClass.simpleName)
val closeListeners = mutableListOf<() -> Unit>()
val scrollPane: AutoScrollPane
init { init {
// Set actor name for debugging // Set actor name for debugging
name = javaClass.simpleName name = javaClass.simpleName
val scrollPane = AutoScrollPane(innerTable, BaseScreen.skin) scrollPane = AutoScrollPane(innerTable, BaseScreen.skin)
background = ImageGetter.getBackground(Color.GRAY.cpy().apply { a=.5f }) background = ImageGetter.getBackground(Color.GRAY.cpy().apply { a=.5f })
innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().darken(0.5f)) innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().darken(0.5f))
@ -61,11 +71,11 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
* closed. Use [force] = true if you want to open this popup above the other one anyway. * closed. Use [force] = true if you want to open this popup above the other one anyway.
*/ */
fun open(force: Boolean = false) { fun open(force: Boolean = false) {
screen.stage.addActor(this) stageToShowOn.addActor(this)
innerTable.pack() innerTable.pack()
pack() pack()
center(screen.stage) center(stageToShowOn)
if (force || !screen.hasOpenPopups()) { if (force || !stageToShowOn.hasOpenPopups()) {
show() show()
} }
} }
@ -73,18 +83,19 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
/** Subroutine for [open] handles only visibility and [keyPressDispatcher] */ /** Subroutine for [open] handles only visibility and [keyPressDispatcher] */
private fun show() { private fun show() {
this.isVisible = true this.isVisible = true
val currentCount = screen.countOpenPopups() val currentCount = stageToShowOn.countOpenPopups()
// the lambda is for stacked key dispatcher precedence: // the lambda is for stacked key dispatcher precedence:
keyPressDispatcher.install(screen.stage) { screen.countOpenPopups() > currentCount } keyPressDispatcher.install(stageToShowOn) { stageToShowOn.countOpenPopups() > currentCount }
} }
/** /**
* Close this popup and - if any other popups are pending - display the next one. * Close this popup and - if any other popups are pending - display the next one.
*/ */
open fun close() { open fun close() {
for (listener in closeListeners) listener()
keyPressDispatcher.uninstall() keyPressDispatcher.uninstall()
remove() remove()
val nextPopup = screen.stage.actors.firstOrNull { it is Popup } val nextPopup = stageToShowOn.actors.firstOrNull { it is Popup }
if (nextPopup != null) (nextPopup as Popup).show() if (nextPopup != null) (nextPopup as Popup).show()
} }
@ -104,7 +115,7 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
val label = text.toLabel(fontSize = size) val label = text.toLabel(fontSize = size)
label.wrap = true label.wrap = true
label.setAlignment(Align.center) label.setAlignment(Align.center)
return add(label).width(screen.stage.width / 2) return add(label).width(stageToShowOn.width / 2)
} }
/** /**
@ -219,9 +230,9 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
* [FocusListener][com.badlogic.gdx.scenes.scene2d.utils.FocusListener] cancels the event. * [FocusListener][com.badlogic.gdx.scenes.scene2d.utils.FocusListener] cancels the event.
*/ */
var keyboardFocus: Actor? var keyboardFocus: Actor?
get() = screen.stage.keyboardFocus get() = stageToShowOn.keyboardFocus
set(value) { set(value) {
if (screen.stage.setKeyboardFocus(value)) if (stageToShowOn.setKeyboardFocus(value))
(value as? TextField)?.selectAll() (value as? TextField)?.selectAll()
} }
} }
@ -230,25 +241,22 @@ open class Popup(val screen: BaseScreen): Table(BaseScreen.skin) {
* Checks if there are visible [Popup]s. * Checks if there are visible [Popup]s.
* @return `true` if any were found. * @return `true` if any were found.
*/ */
fun BaseScreen.hasOpenPopups(): Boolean = stage.actors.any { it is Popup && it.isVisible } fun BaseScreen.hasOpenPopups(): Boolean = stage.hasOpenPopups()
private fun Stage.hasOpenPopups(): Boolean = actors.any { it is Popup && it.isVisible }
/** /**
* Counts number of visible[Popup]s. * Counts number of visible[Popup]s.
* *
* Used for key dispatcher precedence. * Used for key dispatcher precedence.
*/ */
fun BaseScreen.countOpenPopups() = stage.actors.count { it is Popup && it.isVisible } private fun Stage.countOpenPopups() = actors.count { it is Popup && it.isVisible }
/** Closes all [Popup]s. */ /** Closes all [Popup]s. */
fun BaseScreen.closeAllPopups() = popups.forEach { it.close() } fun BaseScreen.closeAllPopups() = stage.popups.forEach { it.close() }
/**
* Closes the topmost visible [Popup].
* @return The [name][Popup.name] of the closed [Popup] if any popup was closed and if it had a name.
*/
fun BaseScreen.closeOneVisiblePopup() = popups.lastOrNull { it.isVisible }?.apply { close() }?.name
/** @return A [List] of currently active or pending [Popup] screens. */ /** @return A [List] of currently active or pending [Popup] screens. */
val BaseScreen.popups: List<Popup> val BaseScreen.popups
get() = stage.actors.filterIsInstance<Popup>() get() = stage.popups
private val Stage.popups: List<Popup>
get() = actors.filterIsInstance<Popup>()

View File

@ -1,5 +1,6 @@
package com.unciv.ui.popup package com.unciv.ui.popup
import com.badlogic.gdx.scenes.scene2d.Stage
import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.BaseScreen
@ -10,7 +11,10 @@ import kotlinx.coroutines.delay
* This is an unobtrusive popup which will close itself after a given amount of time. * This is an unobtrusive popup which will close itself after a given amount of time.
* Default time is two seconds (in milliseconds) * Default time is two seconds (in milliseconds)
*/ */
class ToastPopup (message: String, screen: BaseScreen, val time: Long = 2000) : Popup(screen){ class ToastPopup (message: String, stage: Stage, val time: Long = 2000) : Popup(stage){
constructor(message: String, screen: BaseScreen, time: Long = 2000) : this(message, screen.stage, time)
init { init {
//Make this popup unobtrusive //Make this popup unobtrusive
setFillParent(false) setFillParent(false)
@ -20,7 +24,7 @@ class ToastPopup (message: String, screen: BaseScreen, val time: Long = 2000) :
open() open()
//move it to the top so its not in the middle of the screen //move it to the top so its not in the middle of the screen
//have to be done after open() because open() centers the popup //have to be done after open() because open() centers the popup
y = screen.stage.height - (height + 20f) y = stage.height - (height + 20f)
} }
private fun startTimer(){ private fun startTimer(){

View File

@ -1,6 +1,7 @@
package com.unciv.ui.popup package com.unciv.ui.popup
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
@ -16,10 +17,17 @@ import com.unciv.ui.utils.extensions.toLabel
*/ */
open class YesNoPopup( open class YesNoPopup(
question: String, question: String,
action: ()->Unit, stage: Stage,
screen: BaseScreen = UncivGame.Current.worldScreen, restoreDefault: () -> Unit = {},
restoreDefault: ()->Unit = {} action: () -> Unit
) : Popup(screen) { ) : Popup(stage) {
constructor(
question: String,
screen: BaseScreen,
restoreDefault: () -> Unit = {},
action: () -> Unit
) : this(question, screen.stage, restoreDefault, action)
/** The [Label][com.badlogic.gdx.scenes.scene2d.ui.Label] created for parameter `question` for optional layout tweaking */ /** The [Label][com.badlogic.gdx.scenes.scene2d.ui.Label] created for parameter `question` for optional layout tweaking */
private val promptLabel = question.toLabel() private val promptLabel = question.toLabel()
@ -34,12 +42,11 @@ open class YesNoPopup (
} }
/** Shortcut to open a [YesNoPopup] with the exit game question */ /** Shortcut to open a [YesNoPopup] with the exit game question */
class ExitGamePopup(screen: BaseScreen, force: Boolean = false) class ExitGamePopup(screen: BaseScreen, force: Boolean = false) : YesNoPopup(
: YesNoPopup(
question = "Do you want to exit the game?", question = "Do you want to exit the game?",
action = { Gdx.app.exit() },
screen = screen, screen = screen,
restoreDefault = { screen.game.musicController.resume() } restoreDefault = { screen.game.musicController.resume() },
action = { Gdx.app.exit() }
) { ) {
init { init {
screen.game.musicController.pause() screen.game.musicController.pause()

View File

@ -6,9 +6,11 @@ import com.unciv.UncivGame
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
import com.unciv.ui.crashhandling.launchCrashHandling import com.unciv.ui.crashhandling.launchCrashHandling
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.multiplayer.MultiplayerHelpers
import com.unciv.ui.popup.Popup import com.unciv.ui.popup.Popup
import com.unciv.ui.popup.ToastPopup import com.unciv.ui.popup.ToastPopup
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
import com.unciv.utils.Log
//todo reduce code duplication //todo reduce code duplication
@ -70,6 +72,7 @@ object QuickSave {
outOfMemory() outOfMemory()
return@launchCrashHandling return@launchCrashHandling
} catch (ex: Exception) { } catch (ex: Exception) {
Log.error("Could not autoload game", ex)
postCrashHandlingRunnable { postCrashHandlingRunnable {
loadingPopup.close() loadingPopup.close()
ToastPopup("Cannot resume game!", screen) ToastPopup("Cannot resume game!", screen)
@ -82,6 +85,13 @@ object QuickSave {
screen.game.onlineMultiplayer.loadGame(savedGame) screen.game.onlineMultiplayer.loadGame(savedGame)
} catch (oom: OutOfMemoryError) { } catch (oom: OutOfMemoryError) {
outOfMemory() outOfMemory()
} catch (ex: Exception) {
val message = MultiplayerHelpers.getLoadExceptionMessage(ex)
Log.error("Could not autoload game", ex)
postCrashHandlingRunnable {
loadingPopup.close()
ToastPopup(message, screen)
}
} }
} else { } else {
postCrashHandlingRunnable { /// ... and load it into the screen on main thread for GL context postCrashHandlingRunnable { /// ... and load it into the screen on main thread for GL context
@ -89,6 +99,10 @@ object QuickSave {
screen.game.loadGame(savedGame) screen.game.loadGame(savedGame)
} catch (oom: OutOfMemoryError) { } catch (oom: OutOfMemoryError) {
outOfMemory() outOfMemory()
} catch (ex: Exception) {
Log.error("Could not autoload game", ex)
loadingPopup.close()
ToastPopup("Cannot resume game!", screen)
} }
} }
} }

View File

@ -33,7 +33,7 @@ class SaveGameScreen(val gameInfo: GameInfo) : LoadOrSaveScreen("Current saves")
rightSideButton.setText("Save game".tr()) rightSideButton.setText("Save game".tr())
val saveAction = { val saveAction = {
if (game.gameSaver.getSave(gameNameTextField.text).exists()) if (game.gameSaver.getSave(gameNameTextField.text).exists())
YesNoPopup("Overwrite existing file?", { saveGame() }, this).open() YesNoPopup("Overwrite existing file?", this) { saveGame() }.open()
else saveGame() else saveGame()
} }
rightSideButton.onClick(saveAction) rightSideButton.onClick(saveAction)

View File

@ -172,7 +172,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
val shouldDisplayResource = val shouldDisplayResource =
if (tileGroup.showEntireMap) showResourcesAndImprovements if (tileGroup.showEntireMap) showResourcesAndImprovements
else showResourcesAndImprovements else showResourcesAndImprovements
&& tileGroup.tileInfo.hasViewableResource(UncivGame.Current.worldScreen.viewingCiv) && tileGroup.tileInfo.hasViewableResource(UncivGame.Current.worldScreen!!.viewingCiv)
tileGroup.resourceImage!!.isVisible = shouldDisplayResource tileGroup.resourceImage!!.isVisible = shouldDisplayResource
} }
} }

View File

@ -73,7 +73,7 @@ class DiplomacyScreen(
private val rightSideTable = Table() private val rightSideTable = Table()
private val closeButton = Constants.close.toTextButton() private val closeButton = Constants.close.toTextButton()
private fun isNotPlayersTurn() = !UncivGame.Current.worldScreen.canChangeState private fun isNotPlayersTurn() = !UncivGame.Current.worldScreen!!.canChangeState
init { init {
onBackButtonClicked { UncivGame.Current.resetToWorldScreen() } onBackButtonClicked { UncivGame.Current.resetToWorldScreen() }
@ -205,7 +205,7 @@ class DiplomacyScreen(
wrapper.addTooltip(name, 18f) wrapper.addTooltip(name, 18f)
wrapper.onClick { wrapper.onClick {
val pedia = CivilopediaScreen( val pedia = CivilopediaScreen(
UncivGame.Current.gameInfo.ruleSet, UncivGame.Current.gameInfo!!.ruleSet,
this, this,
link = "Resource/$name" link = "Resource/$name"
) )
@ -389,11 +389,11 @@ class DiplomacyScreen(
private fun getRevokeProtectionButton(otherCiv: CivilizationInfo): TextButton { private fun getRevokeProtectionButton(otherCiv: CivilizationInfo): TextButton {
val revokeProtectionButton = "Revoke Protection".toTextButton() val revokeProtectionButton = "Revoke Protection".toTextButton()
revokeProtectionButton.onClick { revokeProtectionButton.onClick {
YesNoPopup("Revoke protection for [${otherCiv.civName}]?", { YesNoPopup("Revoke protection for [${otherCiv.civName}]?", this) {
otherCiv.removeProtectorCiv(viewingCiv) otherCiv.removeProtectorCiv(viewingCiv)
updateLeftSideTable(otherCiv) updateLeftSideTable(otherCiv)
updateRightSide(otherCiv) updateRightSide(otherCiv)
}, this).open() }.open()
} }
if (isNotPlayersTurn() || !otherCiv.otherCivCanWithdrawProtection(viewingCiv)) revokeProtectionButton.disable() if (isNotPlayersTurn() || !otherCiv.otherCivCanWithdrawProtection(viewingCiv)) revokeProtectionButton.disable()
return revokeProtectionButton return revokeProtectionButton
@ -402,11 +402,11 @@ class DiplomacyScreen(
private fun getPledgeToProtectButton(otherCiv: CivilizationInfo): TextButton { private fun getPledgeToProtectButton(otherCiv: CivilizationInfo): TextButton {
val protectionButton = "Pledge to protect".toTextButton() val protectionButton = "Pledge to protect".toTextButton()
protectionButton.onClick { protectionButton.onClick {
YesNoPopup("Declare Protection of [${otherCiv.civName}]?", { YesNoPopup("Declare Protection of [${otherCiv.civName}]?", this) {
otherCiv.addProtectorCiv(viewingCiv) otherCiv.addProtectorCiv(viewingCiv)
updateLeftSideTable(otherCiv) updateLeftSideTable(otherCiv)
updateRightSide(otherCiv) updateRightSide(otherCiv)
}, this).open() }.open()
} }
if (isNotPlayersTurn() || !otherCiv.otherCivCanPledgeProtection(viewingCiv)) protectionButton.disable() if (isNotPlayersTurn() || !otherCiv.otherCivCanPledgeProtection(viewingCiv)) protectionButton.disable()
return protectionButton return protectionButton
@ -418,7 +418,7 @@ class DiplomacyScreen(
): TextButton { ): TextButton {
val peaceButton = "Negotiate Peace".toTextButton() val peaceButton = "Negotiate Peace".toTextButton()
peaceButton.onClick { peaceButton.onClick {
YesNoPopup("Peace with [${otherCiv.civName}]?", { YesNoPopup("Peace with [${otherCiv.civName}]?", this) {
val tradeLogic = TradeLogic(viewingCiv, otherCiv) val tradeLogic = TradeLogic(viewingCiv, otherCiv)
tradeLogic.currentTrade.ourOffers.add( tradeLogic.currentTrade.ourOffers.add(
TradeOffer( TradeOffer(
@ -435,7 +435,7 @@ class DiplomacyScreen(
tradeLogic.acceptTrade() tradeLogic.acceptTrade()
updateLeftSideTable(otherCiv) updateLeftSideTable(otherCiv)
updateRightSide(otherCiv) updateRightSide(otherCiv)
}, this).open() }.open()
} }
val cityStatesAlly = otherCiv.getAllyCiv() val cityStatesAlly = otherCiv.getAllyCiv()
val atWarWithItsAlly = viewingCiv.getKnownCivs() val atWarWithItsAlly = viewingCiv.getKnownCivs()
@ -761,11 +761,11 @@ class DiplomacyScreen(
): TextButton { ): TextButton {
val denounceButton = "Denounce ([30] turns)".toTextButton() val denounceButton = "Denounce ([30] turns)".toTextButton()
denounceButton.onClick { denounceButton.onClick {
YesNoPopup("Denounce [${otherCiv.civName}]?", { YesNoPopup("Denounce [${otherCiv.civName}]?", this) {
diplomacyManager.denounce() diplomacyManager.denounce()
updateLeftSideTable(otherCiv) updateLeftSideTable(otherCiv)
setRightSideFlavorText(otherCiv, "We will remember this.", "Very well.") setRightSideFlavorText(otherCiv, "We will remember this.", "Very well.")
}, this).open() }.open()
} }
if (isNotPlayersTurn()) denounceButton.disable() if (isNotPlayersTurn()) denounceButton.disable()
return denounceButton return denounceButton
@ -956,12 +956,12 @@ class DiplomacyScreen(
declareWarButton.setText(declareWarButton.text.toString() + " ($turnsToPeaceTreaty${Fonts.turn})") declareWarButton.setText(declareWarButton.text.toString() + " ($turnsToPeaceTreaty${Fonts.turn})")
} }
declareWarButton.onClick { declareWarButton.onClick {
YesNoPopup("Declare war on [${otherCiv.civName}]?", { YesNoPopup("Declare war on [${otherCiv.civName}]?", this) {
diplomacyManager.declareWar() diplomacyManager.declareWar()
setRightSideFlavorText(otherCiv, otherCiv.nation.attacked, "Very well.") setRightSideFlavorText(otherCiv, otherCiv.nation.attacked, "Very well.")
updateLeftSideTable(otherCiv) updateLeftSideTable(otherCiv)
UncivGame.Current.musicController.chooseTrack(otherCiv.civName, MusicMood.War, MusicTrackChooserFlags.setSpecific) UncivGame.Current.musicController.chooseTrack(otherCiv.civName, MusicMood.War, MusicTrackChooserFlags.setSpecific)
}, this).open() }.open()
} }
if (isNotPlayersTurn()) declareWarButton.disable() if (isNotPlayersTurn()) declareWarButton.disable()
return declareWarButton return declareWarButton
@ -996,8 +996,11 @@ class DiplomacyScreen(
private fun getGoToOnMapButton(civilization: CivilizationInfo): TextButton { private fun getGoToOnMapButton(civilization: CivilizationInfo): TextButton {
val goToOnMapButton = "Go to on map".toTextButton() val goToOnMapButton = "Go to on map".toTextButton()
goToOnMapButton.onClick { goToOnMapButton.onClick {
val worldScreen = UncivGame.Current.worldScreen
if (worldScreen != null) {
UncivGame.Current.resetToWorldScreen() UncivGame.Current.resetToWorldScreen()
UncivGame.Current.worldScreen.mapHolder.setCenterPosition(civilization.getCapital()!!.location, selectUnit = false) worldScreen.mapHolder.setCenterPosition(civilization.getCapital()!!.location, selectUnit = false)
}
} }
return goToOnMapButton return goToOnMapButton
} }

View File

@ -92,7 +92,7 @@ class OffersListScroll(
Luxury_Resource, Strategic_Resource -> Luxury_Resource, Strategic_Resource ->
ImageGetter.getResourceImage(offer.name, 30f) ImageGetter.getResourceImage(offer.name, 30f)
WarDeclaration -> WarDeclaration ->
ImageGetter.getNationIndicator(UncivGame.Current.gameInfo.ruleSet.nations[offer.name]!!, 30f) ImageGetter.getNationIndicator(UncivGame.Current.gameInfo!!.ruleSet.nations[offer.name]!!, 30f)
else -> null else -> null
} }
val tradeButton = IconTextButton(tradeLabel, tradeIcon).apply { val tradeButton = IconTextButton(tradeLabel, tradeIcon).apply {

View File

@ -7,16 +7,22 @@ import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.g2d.BitmapFont import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.scenes.scene2d.Stage import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.ui.* import com.badlogic.gdx.scenes.scene2d.ui.CheckBox
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.ui.TextField
import com.badlogic.gdx.scenes.scene2d.utils.Drawable import com.badlogic.gdx.scenes.scene2d.utils.Drawable
import com.badlogic.gdx.utils.viewport.ExtendViewport import com.badlogic.gdx.utils.viewport.ExtendViewport
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.models.Tutorial import com.unciv.models.Tutorial
import com.unciv.ui.UncivStage import com.unciv.ui.UncivStage
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.options.OptionsPopup
import com.unciv.ui.popup.hasOpenPopups import com.unciv.ui.popup.hasOpenPopups
import com.unciv.ui.tutorials.TutorialController import com.unciv.ui.tutorials.TutorialController
import com.unciv.ui.options.OptionsPopup import com.unciv.ui.utils.extensions.isNarrowerThan4to3
abstract class BaseScreen : Screen { abstract class BaseScreen : Screen {
@ -122,7 +128,7 @@ abstract class BaseScreen : Screen {
fun isCrampedPortrait() = isPortrait() && fun isCrampedPortrait() = isPortrait() &&
game.settings.resolution.split("x").map { it.toInt() }.last() <= 700 game.settings.resolution.split("x").map { it.toInt() }.last() <= 700
/** @return `true` if the screen is narrower than 4:3 landscape */ /** @return `true` if the screen is narrower than 4:3 landscape */
fun isNarrowerThan4to3() = stage.viewport.screenHeight * 4 > stage.viewport.screenWidth * 3 fun isNarrowerThan4to3() = stage.isNarrowerThan4to3()
fun openOptionsPopup(startingPage: Int = OptionsPopup.defaultPage, onClose: () -> Unit = {}) { fun openOptionsPopup(startingPage: Int = OptionsPopup.defaultPage, onClose: () -> Unit = {}) {
OptionsPopup(this, startingPage, onClose).open(force = true) OptionsPopup(this, startingPage, onClose).open(force = true)

View File

@ -289,7 +289,7 @@ open class TabbedPager(
//region Initialization //region Initialization
init { init {
val screen = (if (UncivGame.isCurrentInitialized()) UncivGame.Current.screen else null) as? BaseScreen val screen = (if (UncivGame.isCurrentInitialized()) UncivGame.Current.screen else null)
val (screenWidth, screenHeight) = (screen?.stage?.run { width to height }) ?: (Float.MAX_VALUE to Float.MAX_VALUE) val (screenWidth, screenHeight) = (screen?.stage?.run { width to height }) ?: (Float.MAX_VALUE to Float.MAX_VALUE)
dimW = DimensionMeasurement.from(minimumWidth, maximumWidth, screenWidth) dimW = DimensionMeasurement.from(minimumWidth, maximumWidth, screenWidth)
dimH = DimensionMeasurement.from(minimumHeight, maximumHeight, screenHeight) dimH = DimensionMeasurement.from(minimumHeight, maximumHeight, screenHeight)
@ -601,7 +601,7 @@ open class TabbedPager(
if (!UncivGame.isCurrentInitialized() || askPasswordLock || deferredSecretPages.isEmpty()) return if (!UncivGame.isCurrentInitialized() || askPasswordLock || deferredSecretPages.isEmpty()) return
askPasswordLock = true // race condition: Popup closes _first_, then deferredSecretPages is emptied -> parent shows and calls us again askPasswordLock = true // race condition: Popup closes _first_, then deferredSecretPages is emptied -> parent shows and calls us again
PassPopup(UncivGame.Current.screen as BaseScreen, { PassPopup(UncivGame.Current.screen!!, {
addDeferredSecrets() addDeferredSecrets()
}, { }, {
deferredSecretPages.clear() deferredSecretPages.clear()

View File

@ -229,3 +229,6 @@ fun WidgetGroup.packIfNeeded(): WidgetGroup {
if (needsLayout()) pack() if (needsLayout()) pack()
return this return this
} }
/** @return `true` if the screen is narrower than 4:3 landscape */
fun Stage.isNarrowerThan4to3() = viewport.screenHeight * 4 > viewport.screenWidth * 3

View File

@ -3,25 +3,24 @@ package com.unciv.ui.worldscreen
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.unciv.Constants import com.unciv.Constants
import com.unciv.logic.GameInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.ui.crashhandling.postCrashHandlingRunnable import com.unciv.ui.crashhandling.postCrashHandlingRunnable
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.extensions.onClick import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toLabel
class PlayerReadyScreen(gameInfo: GameInfo, currentPlayerCiv: CivilizationInfo) : BaseScreen(){ class PlayerReadyScreen(worldScreen: WorldScreen) : BaseScreen() {
init { init {
val table = Table() val table = Table()
table.touchable = Touchable.enabled table.touchable = Touchable.enabled
table.background= ImageGetter.getBackground(currentPlayerCiv.nation.getOuterColor()) val curCiv = worldScreen.viewingCiv
table.background = ImageGetter.getBackground(curCiv.nation.getOuterColor())
table.add("[$currentPlayerCiv] ready?".toLabel(currentPlayerCiv.nation.getInnerColor(), Constants.headingFontSize)) table.add("[$curCiv] ready?".toLabel(curCiv.nation.getInnerColor(), Constants.headingFontSize))
table.onClick { table.onClick {
postCrashHandlingRunnable { // To avoid ANRs on Android when the creation of the worldscreen takes more than 500ms postCrashHandlingRunnable { // To avoid ANRs on Android when the creation of the worldscreen takes more than 500ms
game.resetToWorldScreen(WorldScreen(gameInfo, currentPlayerCiv)) game.setScreen(worldScreen)
} }
} }
table.setFillParent(true) table.setFillParent(true)

View File

@ -216,7 +216,7 @@ class WorldMapHolder(
} }
private fun onTileRightClicked(unit: MapUnit, tile: TileInfo) { private fun onTileRightClicked(unit: MapUnit, tile: TileInfo) {
if (UncivGame.Current.gameInfo.currentPlayerCiv.isSpectator()) { if (UncivGame.Current.gameInfo!!.currentPlayerCiv.isSpectator()) {
return return
} }
removeUnitActionOverlay() removeUnitActionOverlay()

View File

@ -336,7 +336,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
try { try {
debug("loadLatestMultiplayerState current game: gameId: %s, turn: %s, curCiv: %s", debug("loadLatestMultiplayerState current game: gameId: %s, turn: %s, curCiv: %s",
game.worldScreen.gameInfo.gameId, game.worldScreen.gameInfo.turns, game.worldScreen.gameInfo.currentPlayer) gameInfo.gameId, gameInfo.turns, gameInfo.currentPlayer)
val latestGame = game.onlineMultiplayer.downloadGame(gameInfo.gameId) val latestGame = game.onlineMultiplayer.downloadGame(gameInfo.gameId)
debug("loadLatestMultiplayerState downloaded game: gameId: %s, turn: %s, curCiv: %s", debug("loadLatestMultiplayerState downloaded game: gameId: %s, turn: %s, curCiv: %s",
latestGame.gameId, latestGame.turns, latestGame.currentPlayer) latestGame.gameId, latestGame.turns, latestGame.currentPlayer)
@ -345,8 +345,8 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
} }
postCrashHandlingRunnable { postCrashHandlingRunnable {
loadingGamePopup.close() loadingGamePopup.close()
if (game.gameInfo.gameId == gameInfo.gameId) { // game could've been changed during download if (game.gameInfo!!.gameId == gameInfo.gameId) { // game could've been changed during download
createNewWorldScreen(latestGame) game.setScreen(createNewWorldScreen(latestGame))
} }
} }
} catch (ex: Throwable) { } catch (ex: Throwable) {
@ -602,7 +602,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
} }
private fun createNewWorldScreen(gameInfo: GameInfo, resize:Boolean=false) { private fun createNewWorldScreen(gameInfo: GameInfo, resize:Boolean=false): WorldScreen {
game.gameInfo = gameInfo game.gameInfo = gameInfo
val newWorldScreen = WorldScreen(gameInfo, gameInfo.getPlayerToViewAs()) val newWorldScreen = WorldScreen(gameInfo, gameInfo.getPlayerToViewAs())
@ -621,7 +621,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
newWorldScreen.selectedCiv = gameInfo.getCivilization(selectedCiv.civName) newWorldScreen.selectedCiv = gameInfo.getCivilization(selectedCiv.civName)
newWorldScreen.fogOfWar = fogOfWar newWorldScreen.fogOfWar = fogOfWar
game.resetToWorldScreen(newWorldScreen) return newWorldScreen
} }
fun nextTurn() { fun nextTurn() {
@ -669,16 +669,15 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
// create a new WorldScreen to show the new stuff we've changed, and switch out the current screen. // create a new WorldScreen to show the new stuff we've changed, and switch out the current screen.
// do this on main thread - it's the only one that has a GL context to create images from // do this on main thread - it's the only one that has a GL context to create images from
postCrashHandlingRunnable { postCrashHandlingRunnable {
val newWorldScreen = createNewWorldScreen(gameInfoClone)
if (gameInfoClone.currentPlayerCiv.civName != viewingCiv.civName if (gameInfoClone.currentPlayerCiv.civName != viewingCiv.civName
&& !gameInfoClone.gameParameters.isOnlineMultiplayer) && !gameInfoClone.gameParameters.isOnlineMultiplayer) {
game.setScreen(PlayerReadyScreen(gameInfoClone, gameInfoClone.getCurrentPlayerCivilization())) game.setScreen(PlayerReadyScreen(newWorldScreen))
else { } else {
createNewWorldScreen(gameInfoClone) game.setScreen(newWorldScreen)
} }
if (shouldAutoSave) { if (shouldAutoSave) {
val newWorldScreen = this@WorldScreen.game.worldScreen
newWorldScreen.waitingForAutosave = true newWorldScreen.waitingForAutosave = true
newWorldScreen.shouldUpdate = true newWorldScreen.shouldUpdate = true
game.gameSaver.autoSave(gameInfoClone) { game.gameSaver.autoSave(gameInfoClone) {
@ -821,7 +820,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
nextTurn() nextTurn()
} }
if (game.settings.confirmNextTurn) { if (game.settings.confirmNextTurn) {
YesNoPopup("Confirm next turn", action, this).open() YesNoPopup("Confirm next turn", this, action = action).open()
} else { } else {
action() action()
} }

View File

@ -26,7 +26,7 @@ class TileInfoTable(private val viewingCiv :CivilizationInfo) : Table(BaseScreen
if (tile != null && (UncivGame.Current.viewEntireMapForDebug || viewingCiv.exploredTiles.contains(tile.position)) ) { if (tile != null && (UncivGame.Current.viewEntireMapForDebug || viewingCiv.exploredTiles.contains(tile.position)) ) {
add(getStatsTable(tile)) add(getStatsTable(tile))
add( MarkupRenderer.render(tile.toMarkup(viewingCiv), padding = 0f, iconDisplay = IconDisplay.None) { add( MarkupRenderer.render(tile.toMarkup(viewingCiv), padding = 0f, iconDisplay = IconDisplay.None) {
UncivGame.Current.setScreen(CivilopediaScreen(viewingCiv.gameInfo.ruleSet, UncivGame.Current.worldScreen, link = it)) UncivGame.Current.setScreen(CivilopediaScreen(viewingCiv.gameInfo.ruleSet, UncivGame.Current.worldScreen!!, link = it))
} ).pad(5f).row() } ).pad(5f).row()
if (UncivGame.Current.viewEntireMapForDebug) if (UncivGame.Current.viewEntireMapForDebug)
add(tile.position.run { "(${x.toInt()},${y.toInt()})" }.toLabel()).colspan(2).pad(5f) add(tile.position.run { "(${x.toInt()},${y.toInt()})" }.toLabel()).colspan(2).pad(5f)

View File

@ -42,7 +42,7 @@ class MapOverlayToggleButton(
/** Toggle overlay. Called on click. */ /** Toggle overlay. Called on click. */
fun toggle() { fun toggle() {
setter(!getter()) setter(!getter())
UncivGame.Current.worldScreen.shouldUpdate = true UncivGame.Current.worldScreen!!.shouldUpdate = true
// Setting worldScreen.shouldUpdate implicitly causes this.update() to be called by the WorldScreen on the next update. // Setting worldScreen.shouldUpdate implicitly causes this.update() to be called by the WorldScreen on the next update.
} }

View File

@ -127,7 +127,7 @@ object UnitActions {
val disbandText = if (unit.currentTile.getOwner() == unit.civInfo) val disbandText = if (unit.currentTile.getOwner() == unit.civInfo)
"Disband this unit for [${unit.baseUnit.getDisbandGold(unit.civInfo)}] gold?".tr() "Disband this unit for [${unit.baseUnit.getDisbandGold(unit.civInfo)}] gold?".tr()
else "Do you really want to disband this unit?".tr() else "Do you really want to disband this unit?".tr()
YesNoPopup(disbandText, { unit.disband(); worldScreen.shouldUpdate = true }).open() YesNoPopup(disbandText, UncivGame.Current.worldScreen!!) { unit.disband(); worldScreen.shouldUpdate = true }.open()
} }
}.takeIf { unit.currentMovement > 0 }) }.takeIf { unit.currentMovement > 0 })
} }
@ -187,7 +187,7 @@ object UnitActions {
if (tile.ruleset.tileImprovements.containsKey("City center")) if (tile.ruleset.tileImprovements.containsKey("City center"))
tile.improvement = "City center" tile.improvement = "City center"
unit.destroy() unit.destroy()
UncivGame.Current.worldScreen.shouldUpdate = true UncivGame.Current.worldScreen!!.shouldUpdate = true
} }
if (unit.civInfo.playerType == PlayerType.AI) if (unit.civInfo.playerType == PlayerType.AI)
@ -204,7 +204,7 @@ object UnitActions {
else { else {
// ask if we would be breaking a promise // ask if we would be breaking a promise
val text = "Do you want to break your promise to [$leaders]?" val text = "Do you want to break your promise to [$leaders]?"
YesNoPopup(text, foundAction, UncivGame.Current.worldScreen).open(force = true) YesNoPopup(text, UncivGame.Current.worldScreen!!, action = foundAction).open(force = true)
} }
} }
) )
@ -275,7 +275,7 @@ object UnitActions {
else actionList += UnitAction(type = UnitActionType.Pillage) { else actionList += UnitAction(type = UnitActionType.Pillage) {
if (!worldScreen.hasOpenPopups()) { if (!worldScreen.hasOpenPopups()) {
val pillageText = "Are you sure you want to pillage this [${unit.currentTile.improvement}]?" val pillageText = "Are you sure you want to pillage this [${unit.currentTile.improvement}]?"
YesNoPopup(pillageText, { (pillageAction.action)(); worldScreen.shouldUpdate = true }).open() YesNoPopup(pillageText, UncivGame.Current.worldScreen!!) { (pillageAction.action)(); worldScreen.shouldUpdate = true }.open()
} }
} }
} }
@ -853,7 +853,7 @@ object UnitActions {
unit.destroy() // City states dont get GPs unit.destroy() // City states dont get GPs
else else
unit.gift(recipient) unit.gift(recipient)
UncivGame.Current.worldScreen.shouldUpdate = true UncivGame.Current.worldScreen!!.shouldUpdate = true
} }
return UnitAction(UnitActionType.GiftUnit, action = giftAction) return UnitAction(UnitActionType.GiftUnit, action = giftAction)

View File

@ -39,7 +39,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
actionButton.pack() actionButton.pack()
val action = { val action = {
unitAction.action?.invoke() unitAction.action?.invoke()
UncivGame.Current.worldScreen.shouldUpdate = true UncivGame.Current.worldScreen!!.shouldUpdate = true
} }
if (unitAction.action == null) actionButton.disable() if (unitAction.action == null) actionButton.disable()
else { else {

View File

@ -87,6 +87,7 @@ internal object DesktopLauncher {
try { try {
updateRpc(game) updateRpc(game)
} catch (ex: Exception) { } catch (ex: Exception) {
debug("Exception while updating Discord Rich Presence", ex)
} }
} }
} catch (ex: Throwable) { } catch (ex: Throwable) {
@ -98,10 +99,15 @@ internal object DesktopLauncher {
private fun updateRpc(game: UncivGame) { private fun updateRpc(game: UncivGame) {
if (!game.isInitialized) return if (!game.isInitialized) return
val presence = DiscordRichPresence() val presence = DiscordRichPresence()
val currentPlayerCiv = game.gameInfo.getCurrentPlayerCivilization()
presence.details = "${currentPlayerCiv.nation.leaderName} of ${currentPlayerCiv.nation.name}"
presence.largeImageKey = "logo" // The actual image is uploaded to the discord app / applications webpage presence.largeImageKey = "logo" // The actual image is uploaded to the discord app / applications webpage
val gameInfo = game.gameInfo
if (gameInfo != null) {
val currentPlayerCiv = gameInfo.getCurrentPlayerCivilization()
presence.details = "${currentPlayerCiv.nation.leaderName} of ${currentPlayerCiv.nation.name}"
presence.largeImageText = "Turn" + " " + currentPlayerCiv.gameInfo.turns presence.largeImageText = "Turn" + " " + currentPlayerCiv.gameInfo.turns
}
DiscordRPC.INSTANCE.Discord_UpdatePresence(presence) DiscordRPC.INSTANCE.Discord_UpdatePresence(presence)
} }
} }