Initial AutoPlay implementation (#10315)

* AutoPlay initial hack

* Removed extra changes

* Added canceling AutoPlay and its own button

* Victory screen showing up stops AutoPlay

* Removed AutomateTurn for the spectator

* Right Clicking AutoPlay Button starts AutoPlay immediately

* Renamed NextTurnMenu to AutoPlayMenu

* AutoPlay can now only begin on the players turn

* Added specific unit actions AutoPlay

* AutoPlay stops on VictoryScreen and GreatPersonPickerScreen

* AutoPlay now stops when loading a new game

* Hovering the mouse over the AutoPlayStatusButton now stops AutoPlay

* Removed temporary right click NextTurnButton functionality

* Removed multi-turn AutoPlay from multiplayer games

* Loading a multiplayer game now stops AutoPlay

* AutoPlayStatusButton persists over reloading WorldScreen

* Victory popup now stops autoplay

* AutoPlay now automatically picks great person

* Full AutoPlay now captures cities

* Added settings.isAutoPlaying and fixed bug with closing game in the middle of AutoPlaying a turn

* AutoPlay now correctly stops when a victory screen is shown

* AutoPlay now automates city constructions without autoAssignCityProduction being on

* Reordered NextTurnAction

* Removed extra condition for displaying AutoPlay text on next turn button

* Moved AutoPlay settings to new tab

* Changed AutoPlay slider

* Refactored Settings to have AutoPlay to be in a new subclass

* Added an show AutoPlay button setting, commented out unimplemented settings

* Opening the exit game window stops autoPlay

* Made cyclopedia entry

* Added translations

* AutoPlayStatusButton now ends with a new line

* Commented out extra code and removed extra import statements

* Fixed UncivSlider Change

* Fixed merge conflicts

* Settlers no longer stuck in endless loops wanting to found cities on tiles they can't reach @tuvus

* Support for Leader voices (#10395)

* Prepare Leader Voices: Framework

* Leader Voices: Hooks and corresponding text field comments

* Leader Voices: wiki

* Leader Voices: oops, comments

* Decouple voice play calls to make global modification easier

* Move voices to own folder and give them a separate volume setting

* Oops, template needed too

* Oops, wiki needed too

* Resolved #10366 - City centers don't provide resources you don't have tech to extract

* Add a TriggerUponDiscoveringTile unique type (#10523)

* Add a TriggerUponDiscoveringTile unique type

* Add a check for trigger presence

* Add gain stat modified by speed and improvement speed by filter uniques (#10443)

* Add gain stat modified by speed and improvement speed by filter uniques

* Fix rulesets

* Remove nonfunctional leftover resource text

* Reword improvement unqiue as suggested

* Add the SellBuilding Unique (#10514)

* Restored the SellBuilding Unique

* Rephrased SellBuilding unique

* Version rollout (#10530)

* Bump version and create initial changelog entry

* Update Brazilian_Portuguese.properties (#10528)

* Update French.properties (#10524)

* Update Italian.properties (#10522)

* Update Polish.properties (#10521)

* Update Polish.properties

* Added Fastlane_short_description

* Update Malay.properties (#10520)

Translated line 33 to line 325.
Not at all finished.
This time though I didn't mess up.

---------

Co-authored-by: yairm210 <yairm210@users.noreply.github.com>
Co-authored-by: Vitor Gabriel <59321138+Ranbut@users.noreply.github.com>
Co-authored-by: Ouaz <Ouaz@users.noreply.github.com>
Co-authored-by: Giuseppe D'Addio <41149920+Smashfanful@users.noreply.github.com>
Co-authored-by: Lesiakower <125187776+Lesiakower@users.noreply.github.com>
Co-authored-by: Mikhail <151419244+MetaFBMI@users.noreply.github.com>

* Better performance for 'best tile to found city' (minimized canReach calls) @tuvus

* 4.9.0

* [Translation] Add back "general" unit types (#10526)

* Add back "general" unit types

These entries have been removed from translation files, making them untranslated in-game (in Civilopedia articles)

* Revert changes in template.properties

* Fix missing unit type translations

Fix by @SomeTroglodyte

* Changed some parts of GameSettings back to master.

* Changed right clicking to call startAutoPlay instead of setting it itself

* Fixed some !isHuman() conditions to also include full AutoPlay and refactored some other AutoPlay code

---------

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
Co-authored-by: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com>
Co-authored-by: Sergey <serdav74@inbox.ru>
Co-authored-by: SeventhM <127357473+SeventhM@users.noreply.github.com>
Co-authored-by: PLynx <pawelrys2011@gmail.com>
Co-authored-by: yairm210 <yairm210@users.noreply.github.com>
Co-authored-by: Vitor Gabriel <59321138+Ranbut@users.noreply.github.com>
Co-authored-by: Ouaz <Ouaz@users.noreply.github.com>
Co-authored-by: Giuseppe D'Addio <41149920+Smashfanful@users.noreply.github.com>
Co-authored-by: Lesiakower <125187776+Lesiakower@users.noreply.github.com>
Co-authored-by: Mikhail <151419244+MetaFBMI@users.noreply.github.com>
This commit is contained in:
Oskar Niesen 2023-11-28 06:37:21 -06:00 committed by GitHub
parent 03698e47ef
commit 4b261a9257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 375 additions and 21 deletions

View File

@ -284,6 +284,17 @@
"What you don't see: The phone/tablet's back button will pop the question whether you wish to leave Unciv and go back to Real Life. On desktop versions, you can use the ESC key."
]
},
{
"name": "AutoPlay",
"steps": ["When at later stages of the game, you might have a lot of units but only a little to do. To help you we have implemented an AutoPlay feature that lets you use the AI to play part or all of your turn.",
"To enable AutoPlay, go to options and open the AutoPlay tab and press \"Show AutoPlay button\".",
"Clicking on the AutoPlay button opens a popup menue for choosing to AutoPlay parts or all of your turn.",
"Clicking Start AutoPlay in the pop-up menue or long pressing the AutoPlay button begins the multi-turn AutoPlay. This will play your next turns as if you were an AI.",
"To cancel multi-turn AutoPlay you can press the AutoPlay button, next turn button or open the options menue.",
"Multi-turn AutoPlay is not advised on harder difficulty levels as your AI will not play better against an AI with modifiers.",
"Multi-turn AutoPlay for multiplayer is not yet supported."
]
},
{
"name": "Faith",
"steps": [

View File

@ -857,6 +857,16 @@ Hide =
HIGHLY EXPERIMENTAL - YOU HAVE BEEN WARNED! =
You need to restart the game for this change to take effect. =
# AutoPlay
AutoPlay =
Show AutoPlay button =
Multi-turn AutoPlay amount =
Start AutoPlay =
AutoPlay End Turn =
AutoPlay Military Once =
AutoPlay Civilians Once =
AutoPlay Economy Once =
# Notifications

View File

@ -292,6 +292,7 @@ open class UncivGame(val isConsoleMode: Boolean = false) : Game(), PlatformSpeci
fun popScreen(): BaseScreen? {
if (screenStack.size == 1) {
musicController.pause()
UncivGame.Current.settings.autoPlay.stopAutoPlay()
ConfirmPopup(
screen = screenStack.last(),
question = "Do you want to exit the game?",

View File

@ -339,7 +339,7 @@ object NextTurnAutomation {
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
}
private fun getUnitPriority(unit: MapUnit, isAtWar: Boolean): Int {
fun getUnitPriority(unit: MapUnit, isAtWar: Boolean): Int {
if (unit.isCivilian() && !unit.isGreatPersonOfType("War")) return 1 // Civilian
if (unit.baseUnit.isAirUnit()) return 2
val distance = if (!isAtWar) 0 else unit.civ.threatManager.getDistanceToClosestEnemyUnit(unit.getTile(),6)
@ -356,7 +356,7 @@ object NextTurnAutomation {
for (city in civInfo.cities) UnitAutomation.tryBombardEnemy(city)
}
private fun automateCities(civInfo: Civilization) {
fun automateCities(civInfo: Civilization) {
val ownMilitaryStrength = civInfo.getStatForRanking(RankingType.Force)
val sumOfEnemiesMilitaryStrength =
civInfo.gameInfo.civilizations

View File

@ -125,8 +125,8 @@ object UnitAutomation {
}
internal fun tryUpgradeUnit(unit: MapUnit): Boolean {
val isHuman = unit.civ.isHuman()
if (!UncivGame.Current.settings.automatedUnitsCanUpgrade && isHuman) return false
if (unit.civ.isHuman() && (!UncivGame.Current.settings.automatedUnitsCanUpgrade
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) return false
if (unit.baseUnit.upgradesTo == null) return false
val upgradedUnit = unit.upgrade.getUnitToUpgradeTo()
if (!upgradedUnit.isBuildable(unit.civ)) return false // for resource reasons, usually

View File

@ -50,7 +50,8 @@ class WorkerAutomation(
private val bestRoadAvailable: RoadStatus =
cloningSource?.bestRoadAvailable ?:
//Player can choose not to auto-build roads & railroads.
if (civInfo.isHuman() && !UncivGame.Current.settings.autoBuildingRoads)
if (civInfo.isHuman() && (!UncivGame.Current.settings.autoBuildingRoads
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()))
RoadStatus.None
else civInfo.tech.getBestRoadAvailable()
@ -340,11 +341,12 @@ class WorkerAutomation(
//If the tile is a junk improvement or a fort placed in a bad location.
val junkImprovement = tile.getTileImprovement()?.hasUnique(UniqueType.AutomatedWorkersWillReplace) == true
|| (tile.improvement == Constants.fort && !evaluateFortSuroundings(tile, false) && !civInfo.isHuman())
|| (tile.improvement == Constants.fort && !evaluateFortSuroundings(tile, false)
&& (!civInfo.isHuman() || UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()))
if (tile.improvement != null && !junkImprovement
&& !UncivGame.Current.settings.automatedWorkersReplaceImprovements
&& unit.civ.isHuman())
&& unit.civ.isHuman() && !UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())
return false
if (tile.improvement == null || junkImprovement) {

View File

@ -2,6 +2,7 @@ package com.unciv.logic.battle
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.GUI
import com.unciv.UncivGame
import com.unciv.logic.automation.civilization.NextTurnAutomation
import com.unciv.logic.city.City
@ -535,7 +536,7 @@ object Battle {
city.puppetCity(attackerCiv)
//Although in Civ5 Venice is unable to re-annex their capital, that seems a bit silly. No check for May not annex cities here.
city.annexCity()
} else if (attackerCiv.isHuman()) {
} else if (attackerCiv.isHuman() && !(UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) {
// we're not taking our former capital
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.id))
} else automateCityConquer(attackerCiv, city)

View File

@ -697,7 +697,8 @@ class CityConstructions : IsPartOfGameInfoSerialization {
val isCurrentPlayersTurn = city.civ.gameInfo.isUsersTurn()
|| !city.civ.gameInfo.gameParameters.isOnlineMultiplayer
if ((UncivGame.Current.settings.autoAssignCityProduction && isCurrentPlayersTurn) // only automate if the active human player has the setting to automate production
if ((isCurrentPlayersTurn && (UncivGame.Current.settings.autoAssignCityProduction
|| UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI())) // only automate if the active human player has the setting to automate production
|| !city.civ.isHuman() || city.isPuppet) {
ConstructionAutomation(this).chooseNextConstruction()
}

View File

@ -156,7 +156,7 @@ class DiplomacyFunctions(val civInfo: Civilization) {
if (diplomacyManager != null && (diplomacyManager.hasOpenBorders || diplomacyManager.diplomaticStatus == DiplomaticStatus.War))
return true
// Players can always pass through city-state tiles
if (civInfo.isHuman() && otherCiv.isCityState()) return true
if ((civInfo.isHuman() && !UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) && otherCiv.isCityState()) return true
return false
}

View File

@ -244,6 +244,7 @@ class OnlineMultiplayer {
} else if (onlinePreview != null && hasNewerGameState(preview, onlinePreview)) {
onlineGame.doManualUpdate(preview)
}
UncivGame.Current.settings.autoPlay.stopAutoPlay()
UncivGame.Current.loadGame(gameInfo)
}

View File

@ -91,6 +91,8 @@ class GameSettings {
var androidHideSystemUi = true
var multiplayer = GameSettingsMultiplayer()
var autoPlay = GameSettingsAutoPlay()
var enableEspionageOption = false
@ -322,6 +324,35 @@ class GameSettings {
}
}
class GameSettingsAutoPlay {
var showAutoPlayButton: Boolean = false
var autoPlayMaxTurns = 10
var fullAutoPlayAI: Boolean = true
var autoPlayMilitary: Boolean = true
var autoPlayCivilian: Boolean = true
var autoPlayEconomy: Boolean = true
var autoPlayTechnology: Boolean = true
var autoPlayPolicies: Boolean = true
var autoPlayReligion: Boolean = true
var autoPlayDiplomacy: Boolean = true
var turnsToAutoPlay: Int = 0
var autoPlayTurnInProgress: Boolean = false
fun startAutoPlay() {
turnsToAutoPlay = autoPlayMaxTurns
}
fun stopAutoPlay() {
turnsToAutoPlay = 0
autoPlayTurnInProgress = false
}
fun isAutoPlaying(): Boolean = turnsToAutoPlay > 0
fun isAutoPlayingAndFullAI():Boolean = isAutoPlaying() && fullAutoPlayAI
}
@Suppress("SuspiciousCallableReferenceInLambda") // By @Azzurite, safe as long as that warning below is followed
enum class GameSetting(
val kClass: KClass<*>,

View File

@ -209,7 +209,7 @@ object UniqueTriggerActivation {
val greatPeople = civInfo.greatPeople.getGreatPeople()
if (unique.type == UniqueType.MayanGainGreatPerson && civInfo.greatPeople.longCountGPPool.isEmpty())
civInfo.greatPeople.longCountGPPool = greatPeople.map { it.name }.toHashSet()
if (civInfo.isHuman()) {
if (civInfo.isHuman() && !UncivGame.Current.settings.autoPlay.isAutoPlayingAndFullAI()) {
civInfo.greatPeople.freeGreatPeople++
// Anyone an idea for a good icon?
if (unique.type == UniqueType.MayanGainGreatPerson) {

View File

@ -0,0 +1,91 @@
package com.unciv.ui.popups.options
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.models.metadata.GameSettings
import com.unciv.ui.components.widgets.UncivSlider
import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.screens.basescreen.BaseScreen
fun autoPlayTab(
optionsPopup: OptionsPopup
): Table = Table(BaseScreen.skin).apply {
pad(10f)
defaults().pad(5f)
val settings = optionsPopup.settings
// fun addAutoPlaySections() {
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Military",
// settings.autoPlay.autoPlayMilitary, false
// ) { settings.autoPlay.autoPlayMilitary = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Civilian",
// settings.autoPlay.autoPlayCivilian, false
// ) { settings.autoPlay.autoPlayCivilian = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Economy",
// settings.autoPlay.autoPlayEconomy, false
// ) { settings.autoPlay.autoPlayEconomy = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Diplomacy",
// settings.autoPlay.autoPlayDiplomacy, false
// ) { settings.autoPlay.autoPlayDiplomacy = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Technology",
// settings.autoPlay.autoPlayTechnology, false
// ) { settings.autoPlay.autoPlayTechnology = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Policies",
// settings.autoPlay.autoPlayPolicies, false
// ) { settings.autoPlay.autoPlayPolicies = it }
// optionsPopup.addCheckbox(
// this,
// "AutoPlay Religion",
// settings.autoPlay.autoPlayReligion, false
// ) { settings.autoPlay.autoPlayReligion = it }
// }
optionsPopup.addCheckbox(
this,
"Show AutoPlay button",
settings.autoPlay.showAutoPlayButton, true
) { settings.autoPlay.showAutoPlayButton = it
settings.autoPlay.stopAutoPlay() }
addAutoPlayMaxTurnsSlider(this, settings, optionsPopup.selectBoxMinWidth)
// optionsPopup.addCheckbox(
// this,
// "Full AutoPlay AI",
// settings.autoPlay.fullAutoPlayAI, false
// ) { settings.autoPlay.fullAutoPlayAI = it
// if (!it) addAutoPlaySections()
// else optionsPopup.tabs.replacePage(optionsPopup.tabs.activePage, autoPlayTab(optionsPopup))
// }
// if (!settings.autoPlay.fullAutoPlayAI)
// addAutoPlaySections()
}
private fun addAutoPlayMaxTurnsSlider(
table: Table,
settings: GameSettings,
selectBoxMinWidth: Float
) {
table.add("Multi-turn AutoPlay amount".toLabel()).left().fillX()
val minimapSlider = UncivSlider(
1f, 200f, 1f,
initial = settings.autoPlay.autoPlayMaxTurns.toFloat()
) {
val turns = it.toInt()
settings.autoPlay.autoPlayMaxTurns = turns
}
table.add(minimapSlider).minWidth(selectBoxMinWidth).pad(10f).row()
}

View File

@ -10,7 +10,7 @@ import com.unciv.ui.screens.basescreen.BaseScreen
fun gameplayTab(
optionsPopup: OptionsPopup
) = Table(BaseScreen.skin).apply {
): Table = Table(BaseScreen.skin).apply {
pad(10f)
defaults().pad(5f)

View File

@ -88,6 +88,11 @@ class OptionsPopup(
gameplayTab(this),
ImageGetter.getImage("OtherIcons/Options"), 24f
)
tabs.addPage(
"AutoPlay",
autoPlayTab(this),
ImageGetter.getImage("OtherIcons/NationSwap"), 24f
)
tabs.addPage(
"Language",
LanguageTab(this, ::reloadWorldAndOptions),

View File

@ -14,6 +14,7 @@ class GreatPersonPickerScreen(val civInfo:Civilization) : PickerScreen() {
private var theChosenOne: BaseUnit? = null
init {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
closeButton.isVisible = false
rightSideButton.setText("Choose a free great person".tr())

View File

@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.utils.SerializationException
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.MissingModsException
import com.unciv.logic.UncivShowableException
import com.unciv.logic.files.PlatformSaverLoader
@ -121,6 +122,7 @@ class LoadGameScreen : LoadOrSaveScreen() {
}
private fun onLoadGame() {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
if (selectedSave == null) return
val loadingPopup = LoadingPopup(this)
Concurrency.run(loadGame) {

View File

@ -35,6 +35,7 @@ object QuickSave {
}
fun load(screen: WorldScreen) {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
val files = UncivGame.Current.files
val toast = ToastPopup("Quickloading...", screen)
Concurrency.run("QuickLoadGame") {
@ -57,6 +58,7 @@ object QuickSave {
}
fun autoLoadGame(screen: MainMenuScreen) {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
val loadingPopup = LoadingPopup(screen)
Concurrency.run("autoLoadGame") {
// Load game from file to class on separate thread to avoid ANR...

View File

@ -85,6 +85,7 @@ class VictoryScreen(
}
init {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
//**************** Set up the tabs ****************
splitPane.setFirstWidget(tabs)
val iconSize = Constants.headingFontSize.toFloat()
@ -158,6 +159,7 @@ class VictoryScreen(
displayWonOrLost("[$winningCiv] has won a [$victoryType] Victory!", victory.defeatString)
music.chooseTrack(playerCiv.civName, MusicMood.Defeat, EnumSet.of(MusicTrackChooserFlags.SuffixMustMatch))
}
UncivGame.Current.settings.autoPlay.stopAutoPlay()
}
private fun displayWonOrLost(vararg descriptions: String) {

View File

@ -11,6 +11,7 @@ import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException
import com.unciv.logic.civilization.AlertType
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.PlayerType
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
@ -58,6 +59,7 @@ import com.unciv.ui.screens.worldscreen.bottombar.BattleTable
import com.unciv.ui.screens.worldscreen.bottombar.TileInfoTable
import com.unciv.ui.screens.worldscreen.mainmenu.WorldScreenMusicPopup
import com.unciv.ui.screens.worldscreen.minimap.MinimapHolder
import com.unciv.ui.screens.worldscreen.status.AutoPlayStatusButton
import com.unciv.ui.screens.worldscreen.status.MultiplayerStatusButton
import com.unciv.ui.screens.worldscreen.status.NextTurnButton
import com.unciv.ui.screens.worldscreen.status.NextTurnProgress
@ -92,7 +94,7 @@ class WorldScreen(
/** Indicates it's the player's ([viewingCiv]) turn */
var isPlayersTurn = viewingCiv.isCurrentPlayer()
internal set // only this class is allowed to make changes
/** Selected civilization, used in spectator and replay mode, equals viewingCiv in ordinary games */
var selectedCiv = viewingCiv
@ -412,7 +414,13 @@ class WorldScreen(
fogOfWarButton.isEnabled = !selectedCiv.isSpectator()
fogOfWarButton.setPosition(10f, topBar.y - fogOfWarButton.height - 10f)
if (!hasOpenPopups() && isPlayersTurn) {
// If the game has ended, lets stop AutoPlay
if (game.settings.autoPlay.isAutoPlaying()
&& !gameInfo.oneMoreTurnMode && (viewingCiv.isDefeated() || gameInfo.checkForVictory())) {
game.settings.autoPlay.stopAutoPlay()
}
if (!hasOpenPopups() && !game.settings.autoPlay.isAutoPlaying() && isPlayersTurn) {
when {
viewingCiv.shouldShowDiplomaticVotingResults() ->
UncivGame.Current.pushScreen(DiplomaticVoteResultScreen(gameInfo.diplomaticVictoryVotesCast, viewingCiv))
@ -694,6 +702,7 @@ class WorldScreen(
private fun updateGameplayButtons() {
nextTurnButton.update()
updateAutoPlayStatusButton()
updateMultiplayerStatusButton()
statusButtons.wrap(false)
@ -707,6 +716,18 @@ class WorldScreen(
statusButtons.setPosition(stage.width - statusButtons.width - 10f, topBar.y - statusButtons.height - 10f)
}
private fun updateAutoPlayStatusButton() {
if (statusButtons.autoPlayStatusButton == null) {
if (game.settings.autoPlay.showAutoPlayButton)
statusButtons.autoPlayStatusButton = AutoPlayStatusButton(this, nextTurnButton)
} else {
if (!game.settings.autoPlay.showAutoPlayButton) {
statusButtons.autoPlayStatusButton = null
game.settings.autoPlay.stopAutoPlay()
}
}
}
private fun updateMultiplayerStatusButton() {
if (gameInfo.gameParameters.isOnlineMultiplayer || game.settings.multiplayer.statusButtonInSinglePlayer) {
if (statusButtons.multiplayerStatusButton != null) return

View File

@ -1,5 +1,6 @@
package com.unciv.ui.screens.worldscreen.mainmenu
import com.unciv.UncivGame
import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.ui.components.input.onLongPress
import com.unciv.ui.popups.Popup
@ -10,6 +11,7 @@ import com.unciv.ui.screens.worldscreen.WorldScreen
class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen, scrollable = Scrollability.All) {
init {
UncivGame.Current.settings.autoPlay.stopAutoPlay()
defaults().fillX()
addButton("Main menu") {

View File

@ -0,0 +1,81 @@
package com.unciv.ui.popups
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.GUI
import com.unciv.logic.automation.civilization.NextTurnAutomation
import com.unciv.logic.automation.unit.UnitAutomation
import com.unciv.logic.civilization.managers.TurnManager
import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.ui.screens.worldscreen.status.NextTurnButton
//todo Check move/top/end for "place one improvement" buildings
//todo Check add/remove-all for "place one improvement" buildings
/**
* Adds a number of options
*/
class AutoPlayMenu(
stage: Stage,
positionNextTo: Actor,
private val nextTurnButton: NextTurnButton,
private val worldScreen: WorldScreen
) : AnimatedMenuPopup(stage, getActorTopRight(positionNextTo)) {
private val settings = GUI.getSettings()
init {
closeListeners.add {
}
}
override fun createContentTable(): Table? {
val table = super.createContentTable()!!
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer)
table.add(getButton("Start AutoPlay", KeyboardBinding.RaisePriority, ::autoPlay)).row()
table.add(getButton("AutoPlay End Turn", KeyboardBinding.RaisePriority, ::autoPlayEndTurn)).row()
table.add(getButton("AutoPlay Military Once", KeyboardBinding.RaisePriority, ::autoPlayMilitary)).row()
table.add(getButton("AutoPlay Civilians Once", KeyboardBinding.RaisePriority, ::autoPlayCivilian)).row()
table.add(getButton("AutoPlay Economy Once", KeyboardBinding.RaisePriority, ::autoPlayEconomy)).row()
return table.takeUnless { it.cells.isEmpty }
}
private fun autoPlayEndTurn() {
TurnManager(worldScreen.viewingCiv).automateTurn()
worldScreen.nextTurn()
}
private fun autoPlay() {
settings.autoPlay.startAutoPlay()
nextTurnButton.update()
}
private fun autoPlayMilitary() {
val civInfo = worldScreen.viewingCiv
val isAtWar = civInfo.isAtWar()
val sortedUnits = civInfo.units.getCivUnits().filter { it.isMilitary() }.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
for (city in civInfo.cities) UnitAutomation.tryBombardEnemy(city)
worldScreen.shouldUpdate = true
worldScreen.render(0f)
}
private fun autoPlayCivilian() {
val civInfo = worldScreen.viewingCiv
val isAtWar = civInfo.isAtWar()
val sortedUnits = civInfo.units.getCivUnits().filter { it.isCivilian() }.sortedBy { unit -> NextTurnAutomation.getUnitPriority(unit, isAtWar) }
for (unit in sortedUnits) UnitAutomation.automateUnitMoves(unit)
worldScreen.shouldUpdate = true
worldScreen.render(0f)
}
private fun autoPlayEconomy() {
val civInfo = worldScreen.viewingCiv
NextTurnAutomation.automateCities(civInfo)
worldScreen.shouldUpdate = true
worldScreen.render(0f)
}
}

View File

@ -0,0 +1,54 @@
package com.unciv.ui.screens.worldscreen.status
import com.badlogic.gdx.scenes.scene2d.ui.Button
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Stack
import com.badlogic.gdx.utils.Disposable
import com.unciv.GUI
import com.unciv.ui.components.extensions.setSize
import com.unciv.ui.components.input.onClick
import com.unciv.ui.components.input.onRightClick
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popups.AutoPlayMenu
import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.screens.worldscreen.WorldScreen
class AutoPlayStatusButton(
val worldScreen: WorldScreen,
nextTurnButton: NextTurnButton
) : Button(BaseScreen.skin), Disposable {
private val autoPlayImage = createAutoplayImage()
init {
add(Stack(autoPlayImage)).pad(5f)
val settings = GUI.getSettings()
onClick {
if (settings.autoPlay.isAutoPlaying())
settings.autoPlay.stopAutoPlay()
else if (worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv)
AutoPlayMenu(stage,this, nextTurnButton, worldScreen)
}
onRightClick {
if (!worldScreen.gameInfo.gameParameters.isOnlineMultiplayer
&& worldScreen.viewingCiv == worldScreen.gameInfo.currentPlayerCiv) {
settings.autoPlay.startAutoPlay()
nextTurnButton.update()
}
}
}
private fun createAutoplayImage(): Image {
val img = ImageGetter.getImage("OtherIcons/NationSwap")
img.setSize(40f)
return img
}
override fun dispose() {
val settings = GUI.getSettings()
if (isPressed && settings.autoPlay.isAutoPlaying()) {
settings.autoPlay.stopAutoPlay()
}
}
}

View File

@ -2,6 +2,7 @@ package com.unciv.ui.screens.worldscreen.status
import com.badlogic.gdx.graphics.Color
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.civilization.managers.ReligionManager
import com.unciv.logic.civilization.managers.ReligionState
import com.unciv.models.Counter
@ -24,6 +25,12 @@ enum class NextTurnAction(protected val text: String, val color: Color) {
override val icon get() = null
override fun isChoice(worldScreen: WorldScreen) = false
},
AutoPlay("AutoPlay", Color.WHITE) {
override fun isChoice(worldScreen: WorldScreen) =
UncivGame.Current.settings.autoPlay.isAutoPlaying()
override fun action(worldScreen: WorldScreen) =
UncivGame.Current.settings.autoPlay.stopAutoPlay()
},
Working(Constants.working, Color.GRAY) {
override fun isChoice(worldScreen: WorldScreen) =
worldScreen.isNextTurnUpdateRunning()
@ -120,7 +127,7 @@ enum class NextTurnAction(protected val text: String, val color: Color) {
},
;
open val icon: String? get() = "NotificationIcons/$name"
open val icon: String? get() = if (text != "AutoPlay") "NotificationIcons/$name" else "NotificationIcons/Working"
open fun getText(worldScreen: WorldScreen) = text
abstract fun isChoice(worldScreen: WorldScreen): Boolean
open fun action(worldScreen: WorldScreen) {}

View File

@ -1,5 +1,7 @@
package com.unciv.ui.screens.worldscreen.status
import com.unciv.GUI
import com.unciv.logic.civilization.managers.TurnManager
import com.unciv.models.translations.tr
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
import com.unciv.ui.components.extensions.isEnabled
@ -16,7 +18,6 @@ class NextTurnButton(
private val worldScreen: WorldScreen
) : IconTextButton("", null, 30) {
private var nextTurnAction = NextTurnAction.Default
init {
// label.setFontSize(30)
labelCell.pad(10f)
@ -30,10 +31,20 @@ class NextTurnButton(
fun update() {
nextTurnAction = getNextTurnAction(worldScreen)
updateButton(nextTurnAction)
isEnabled = !worldScreen.hasOpenPopups() && worldScreen.isPlayersTurn
&& !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning()
val settings = GUI.getSettings()
if (!settings.autoPlay.autoPlayTurnInProgress && settings.autoPlay.isAutoPlaying()
&& worldScreen.isPlayersTurn && !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning()) {
settings.autoPlay.autoPlayTurnInProgress = true
if (!worldScreen.viewingCiv.isSpectator())
TurnManager(worldScreen.viewingCiv).automateTurn()
worldScreen.nextTurn()
settings.autoPlay.turnsToAutoPlay--
settings.autoPlay.autoPlayTurnInProgress = false
}
isEnabled = nextTurnAction.getText (worldScreen) == "AutoPlay"
|| (!worldScreen.hasOpenPopups() && worldScreen.isPlayersTurn
&& !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning())
if (isEnabled) addTooltip(KeyboardBinding.NextTurn) else addTooltip("")
}

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.GUI
import com.unciv.UncivGame
import com.unciv.models.metadata.GameParameters
import com.unciv.ui.components.extensions.disable
import com.unciv.ui.images.ImageGetter
@ -97,7 +98,9 @@ class NextTurnProgress(
// On first update the button text is not yet updated. To stabilize geometry, do it now
if (progress == 0) nextTurnButton?.apply {
disable()
updateButton(NextTurnAction.Working)
if (UncivGame.Current.settings.autoPlay.isAutoPlaying())
updateButton(NextTurnAction.AutoPlay)
else updateButton(NextTurnAction.Working)
barWidth = width - removeHorizontalPad -
(background.leftWidth + background.rightWidth) // "cut off" the rounded parts of the button
this@NextTurnProgress.setPosition((width - barWidth) / 2, barYPos)

View File

@ -5,8 +5,17 @@ import com.badlogic.gdx.utils.Disposable
class StatusButtons(
nextTurnButton: NextTurnButton,
autoPlayStatusButton: AutoPlayStatusButton? = null,
multiplayerStatusButton: MultiplayerStatusButton? = null
) : HorizontalGroup(), Disposable {
var autoPlayStatusButton: AutoPlayStatusButton? = autoPlayStatusButton
set(button) {
autoPlayStatusButton?.remove()
field = button
if (button != null) {
addActorAt(0, button)
}
}
var multiplayerStatusButton: MultiplayerStatusButton? = multiplayerStatusButton
set(button) {
multiplayerStatusButton?.remove()
@ -15,6 +24,7 @@ class StatusButtons(
addActorAt(0, button)
}
}
init {
space(10f)
@ -22,6 +32,9 @@ class StatusButtons(
wrapReverse()
wrapSpace(10f)
rowRight()
if (autoPlayStatusButton != null) {
addActor(autoPlayStatusButton)
}
if (multiplayerStatusButton != null) {
addActor(multiplayerStatusButton)
}
@ -29,6 +42,7 @@ class StatusButtons(
}
override fun dispose() {
autoPlayStatusButton?.dispose()
multiplayerStatusButton?.dispose()
}
}