From 83b62f8c0a79249d0d5bd53c73e5a5ccd4ab7968 Mon Sep 17 00:00:00 2001 From: itanasi <44038014+itanasi@users.noreply.github.com> Date: Tue, 11 Feb 2025 06:23:32 -0800 Subject: [PATCH] Merge up to latest master (#12927) --- .../UnitActionIcons/Skip.png | Bin 0 -> 5884 bytes .../UnitActionIcons/Wait.png | Bin 896 -> 0 bytes android/Images.Icons/OtherIcons/Skip.png | Bin 0 -> 9451 bytes android/Images.Icons/OtherIcons/Wait.png | Bin 896 -> 0 bytes android/assets/jsons/Tutorials.json | 20 +++--- .../jsons/translations/template.properties | 6 +- .../com/unciv/logic/simulation/Simulation.kt | 4 +- core/src/com/unciv/models/UnitAction.kt | 4 +- .../com/unciv/models/metadata/GameSettings.kt | 1 + .../ui/components/input/KeyboardBinding.kt | 3 +- .../unciv/ui/popups/options/GameplayTab.kt | 1 + .../ui/screens/worldscreen/WorldScreen.kt | 9 ++- .../worldscreen/status/NextTurnButton.kt | 5 ++ .../worldscreen/status/SmallUnitButton.kt | 55 +++++++++++++++ .../worldscreen/status/StatusButtons.kt | 66 +++++++++--------- .../worldscreen/unit/actions/UnitActions.kt | 9 +-- .../unit/presenter/SummaryPresenter.kt | 2 +- docs/Credits.md | 2 +- 18 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 android/Images.ConstructionIcons/UnitActionIcons/Skip.png delete mode 100644 android/Images.ConstructionIcons/UnitActionIcons/Wait.png create mode 100644 android/Images.Icons/OtherIcons/Skip.png delete mode 100644 android/Images.Icons/OtherIcons/Wait.png create mode 100644 core/src/com/unciv/ui/screens/worldscreen/status/SmallUnitButton.kt diff --git a/android/Images.ConstructionIcons/UnitActionIcons/Skip.png b/android/Images.ConstructionIcons/UnitActionIcons/Skip.png new file mode 100644 index 0000000000000000000000000000000000000000..f5e3777cdabd7efcdfc6160fe3c7f303885882e8 GIT binary patch literal 5884 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 diff --git a/android/Images.Icons/OtherIcons/Skip.png b/android/Images.Icons/OtherIcons/Skip.png new file mode 100644 index 0000000000000000000000000000000000000000..398b0d124d2b68cdc213e1d53a0e5c2e17410e78 GIT binary patch literal 9451 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 diff --git a/android/assets/jsons/Tutorials.json b/android/assets/jsons/Tutorials.json index adf3001c54..1219900131 100644 --- a/android/assets/jsons/Tutorials.json +++ b/android/assets/jsons/Tutorials.json @@ -27,7 +27,7 @@ {"text": "Cities will house Citizens, which can work tiles up to 3 tiles away from the city. This means you don’t have to settle cities right on or next to good tiles. Let’s say, for example, that you want access to some Iron – but the resource is in a desert area. You don’t have to settle your city in the desert. You can settle a few tiles away in more prosperous lands. Your city will grow and eventually gain access to the resource. You only need to settle right on top of resources if you need them immediately."}, {}, {"text": "The first thing coming out of your city depends on the strategy you want to follow, but the 'classic' build order is to build first two Scouts, then a Shrine, and three Settlers, and adopt Tradition, to explore the map quickly (Scouts ignore terrain cost), and to get an early Pantheon (if you're playing with religion enabled)."}, - {"text": "But feel free to experiment with your own build orders!", "color": "#fa0"}, + {"text": "But feel free to experiment with your own build orders!", "color": "#fa0"} ] }, { @@ -129,7 +129,7 @@ {"text":"This greatly improves the speed you can get Units around the map."}, {"text":"Until you research the technology that removes it, Roads do not cross Rivers"}, {"text":"Connecting your cities to the capital by Roads and/or Railroads will generate Gold via the Trade Route.","link":"Tutorials/Trade Route"}, - {"text":"However, since each Road and Railroad have a Maintenance Cost, it may be more economical to wait until the cities grow and only place where needed."}, + {"text":"However, since each Road and Railroad have a Maintenance Cost, it may be more economical to wait until the cities grow and only place where needed."} ] }, { @@ -233,7 +233,11 @@ { "name": "Idle Units", "steps": [ - "If you don't want to move a unit this turn, you can skip it by clicking 'Next unit' again, or command the unit to 'Wait'.\nIf you won't be moving it for a while, you can have the unit enter Fortify or Sleep mode - \n units in Fortify or Sleep are not considered idle units.\nIf you want to disable the 'Next unit' feature entirely, you can toggle it in Menu -> Check for idle units." + "Clicking 'Next unit' moves to the next idle unit in the queue (as listed in Overview -> Units). After issuing an order to an unit, if 'Auto Unit Cycle' in Options -> Gameplay is enabled, you will automatically select the next idle unit.", + "If you don't want to move a unit this turn, you can skip it by clicking 'Next unit' again, or command the unit to 'Skip turn'.", + "If you want to disable the 'Next unit' feature entirely, you can toggle it in Options -> Gameplay -> Check for idle units.", + "If you'd rather 'Next unit' cycle the units and not mark them as Done, you can change it in the Options -> Gameplay menu.", + "You can also cycle through the idle units using the left and right triangles on the Unit Table in the lower left of the screen. Or by default using the Cycle button next to the 'Next Unit' button." ] }, { @@ -348,7 +352,7 @@ "⑥: Unit Action Buttons - while a unit is selected its possible actions appear here.", "⑦: The unit/city info pane - shows information about a selected unit or city.", "⑧: The name (and unit icon) of the selected unit or city, with current health if wounded. Clicking a unit name or icon will open its civilopedia entry.", - "⑨: The arrow buttons allow jumping to the next/previous unit.", + "⑨: The arrow buttons allow jumping to the next/previous idle unit.", "⑩: For a selected unit, its promotions appear here, and clicking leads to the promotions screen for that unit.", "⑪: Remaining/per turn movement points, strength and experience / XP needed for promotion. For cities, you get its combat strength.", "⑫: This button closes the selected unit/city info pane.", @@ -494,7 +498,7 @@ {"text":"The Intercepting Unit rolls to see if it hits. Whether it hits or not costs an Attack, and most units (without Promotions) can only Attack Once per Nation's Turn. It does NOT cost Movement Points, but Air Units that have used their Movement cannot Intercept between turns."}, {"text":"If the Intercepting Unit Hits, it deals damage according to the Combat Strength calculation to the Attacking Air Unit, potentially with any Strength Bonuses that apply to Interception. It does not receive damage from the Attacking Air Unit."}, {"text":"After Interception resolves, the Attacking Air Unit and the Defending Unit in the targeted tile do Combat as normal, with damage dealt to both sides."}, - {"text":"To help deal with Interceptions, see Air Sweeps.","link": "Tutorials/Air Sweeps"}, + {"text":"To help deal with Interceptions, see Air Sweeps.","link": "Tutorials/Air Sweeps"} ] }, { @@ -545,7 +549,7 @@ {"text":"Spies at a higher rank have a higher chance of success. The max rank a spy can reach is rank 3. After a spy is killed it will revive after a certain amount of turns back at rank 1."}, {"text":"Building buildings like the constabulary and police station will reduce the technology steal rate of spies in that city."}, {}, - {"text":"Espionage is available using the Gods and Kings ruleset. To enable it in a new game click advanced settings, then click on the Enable Espionage option."}, + {"text":"Espionage is available using the Gods and Kings ruleset. To enable it in a new game click advanced settings, then click on the Enable Espionage option."} ] }, { @@ -671,7 +675,7 @@ {}, {"text":"Tile improvements\nIn Civilzation V, workers start working on an improvement-under-construction at the beginning of movement. Unciv changes this, to allow players to assign workers to tiles, and then reconsider and change improvement or move them elsewhere."}, {}, - {"text":"Forest and Jungle Visibility\nIn Unciv, forests and jungles are visible 1 tile outside visibility range. In Civilization V, this is the behaviour of hills and mountains, but not of forests and jungles, yet jungle and forest can block hills, and hill + forest can block mountain, indicating they're on the same elevation. This is considered to be a bug in the otherwise well-structured visibility logic in Civilization V."}, + {"text":"Forest and Jungle Visibility\nIn Unciv, forests and jungles are visible 1 tile outside visibility range. In Civilization V, this is the behaviour of hills and mountains, but not of forests and jungles, yet jungle and forest can block hills, and hill + forest can block mountain, indicating they're on the same elevation. This is considered to be a bug in the otherwise well-structured visibility logic in Civilization V."} ] }, { @@ -679,7 +683,7 @@ "civilopediaText": [ {"text": "Founding Cities\nThe Settler is a unit that can found a new city. You can build a Settler unit in a city with at least 2 population, and then move them to a good location to found a new city. This will usually be your main way of acquiring more cities."}, {}, - {"text": "Food conversion to Production\nDuring the construction of a Settler, the city will not grow. Instead, the 1st, 2nd, 4th, and from there on every 4th, excess Food (Growth) is converted into Production, with the rest of the excess Food being lost."}, + {"text": "Food conversion to Production\nDuring the construction of a Settler, the city will not grow. Instead, the 1st, 2nd, 4th, and from there on every 4th, excess Food (Growth) is converted into Production, with the rest of the excess Food being lost."} ] } ] diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 82f81abeda..cf0ca43da9 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1177,7 +1177,8 @@ turn = Next unit = [amount] units idle = [idleCount] idle = -[waitingCount] waiting = +[skipCount] skipping = +Cycle = Fog of War = Pick a policy = Move Spies = @@ -1227,7 +1228,8 @@ Pillage = Pillage [improvement] = [improvement] (Pillaged!) = Repair [improvement] - [turns] = -Wait = +Skip = +Skip turn = Are you sure you want to pillage this [improvement]? = We have looted [amount] from a [improvement] = We have looted [amount] from a [improvement] which has been sent to [cityName] = diff --git a/core/src/com/unciv/logic/simulation/Simulation.kt b/core/src/com/unciv/logic/simulation/Simulation.kt index 389d360ce9..a0339f3d4f 100644 --- a/core/src/com/unciv/logic/simulation/Simulation.kt +++ b/core/src/com/unciv/logic/simulation/Simulation.kt @@ -165,8 +165,8 @@ class Simulation( val numSteps = max(steps.size, 1) val expWinRate = 1f / majorCivs - val winRate = numWins[civ]!!.value * 100 / numSteps - if (winRate == 0) continue + if (numWins[civ]!!.value == 0) continue + val winRate = String.format("%.1f", numWins[civ]!!.value * 100f / numSteps) outString += "\n$civ:\n" outString += "$winRate% total win rate \n" diff --git a/core/src/com/unciv/models/UnitAction.kt b/core/src/com/unciv/models/UnitAction.kt index 54e56c4663..a61f33504d 100644 --- a/core/src/com/unciv/models/UnitAction.kt +++ b/core/src/com/unciv/models/UnitAction.kt @@ -180,8 +180,8 @@ enum class UnitActionType( { ImageGetter.getUnitActionPortrait("DisbandUnit") }, false, defaultPage = 1), GiftUnit("Gift unit", { ImageGetter.getUnitActionPortrait("Present") }, UncivSound.Silent, defaultPage = 1), - Wait("Wait", - { ImageGetter.getUnitActionPortrait("Wait") }, UncivSound.Silent), + Skip("Skip turn", + { ImageGetter.getUnitActionPortrait("Skip") }, UncivSound.Silent, defaultPage = 0), ShowAdditionalActions("Show more", { ImageGetter.getUnitActionPortrait("ShowMore") }, false), HideAdditionalActions("Back", diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index 0c4b680683..5d6ffac701 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -39,6 +39,7 @@ class GameSettings { var checkForDueUnits: Boolean = true var checkForDueUnitsCycles: Boolean = false var autoUnitCycle: Boolean = true + var smallUnitButton: Boolean = true var singleTapMove: Boolean = false var longTapMove: Boolean = true var language: String = Constants.english diff --git a/core/src/com/unciv/ui/components/input/KeyboardBinding.kt b/core/src/com/unciv/ui/components/input/KeyboardBinding.kt index 623a50678a..e66307e0f3 100644 --- a/core/src/com/unciv/ui/components/input/KeyboardBinding.kt +++ b/core/src/com/unciv/ui/components/input/KeyboardBinding.kt @@ -50,6 +50,7 @@ enum class KeyboardBinding( DeveloperConsole(Category.WorldScreen, '`'), PrevIdleButton(Category.WorldScreen, "Idle Prev",','), NextIdleButton(Category.WorldScreen, "Idle Next", '.'), + Cycle(Category.WorldScreen, ';'), /* * These try to be faithful to default Civ5 key bindings as found in several places online @@ -136,7 +137,7 @@ enum class KeyboardBinding( EnhanceReligion(Category.UnitActions,"Enhance a Religion", 'g'), DisbandUnit(Category.UnitActions,"Disband unit", KeyCharAndCode.DEL), GiftUnit(Category.UnitActions,"Gift unit", KeyCharAndCode.UNKNOWN), - Wait(Category.UnitActions, 'z'), + Skip(Category.UnitActions, 'z'), ShowAdditionalActions(Category.UnitActions,"Show more", Input.Keys.PAGE_DOWN), HideAdditionalActions(Category.UnitActions,"Back", Input.Keys.PAGE_UP), AddInCapital(Category.UnitActions, "Add in capital", 'g'), diff --git a/core/src/com/unciv/ui/popups/options/GameplayTab.kt b/core/src/com/unciv/ui/popups/options/GameplayTab.kt index 5969f593a2..60647e8b20 100644 --- a/core/src/com/unciv/ui/popups/options/GameplayTab.kt +++ b/core/src/com/unciv/ui/popups/options/GameplayTab.kt @@ -16,6 +16,7 @@ fun gameplayTab( optionsPopup.addCheckbox(this, "Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it } optionsPopup.addCheckbox(this, "'Next unit' button cycles idle units", settings.checkForDueUnitsCycles, true) { settings.checkForDueUnitsCycles = it } + optionsPopup.addCheckbox(this, "Show Small Skip/Cycle Unit Button", settings.smallUnitButton, true) { settings.smallUnitButton = it } optionsPopup.addCheckbox(this, "Auto Unit Cycle", settings.autoUnitCycle, true) { settings.autoUnitCycle = it } optionsPopup.addCheckbox(this, "Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it } optionsPopup.addCheckbox(this, "Move units with a long tap", settings.longTapMove) { settings.longTapMove = it } diff --git a/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt index 6ddffbf9ab..5cc55456d1 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt @@ -57,6 +57,7 @@ import com.unciv.ui.screens.worldscreen.status.MultiplayerStatusButton import com.unciv.ui.screens.worldscreen.status.NextTurnButton import com.unciv.ui.screens.worldscreen.status.NextTurnProgress import com.unciv.ui.screens.worldscreen.status.StatusButtons +import com.unciv.ui.screens.worldscreen.status.SmallUnitButton import com.unciv.ui.screens.worldscreen.topbar.WorldScreenTopBar import com.unciv.ui.screens.worldscreen.unit.AutoPlay import com.unciv.ui.screens.worldscreen.unit.UnitTable @@ -121,6 +122,7 @@ class WorldScreen( internal val notificationsScroll = NotificationsScroll(this) internal val nextTurnButton = NextTurnButton(this) private val statusButtons = StatusButtons(nextTurnButton) + internal val smallUnitButton = SmallUnitButton(this, statusButtons) private val tutorialTaskTable = Table().apply { background = skinStrings.getUiBackground("WorldScreen/TutorialTaskTable", tintColor = skinStrings.skinConfig.baseColor.darken(0.5f)) } @@ -669,13 +671,10 @@ class WorldScreen( updateAutoPlayStatusButton() updateMultiplayerStatusButton() - statusButtons.wrap(false) - statusButtons.pack() + statusButtons.update(false) val maxWidth = stage.width - techPolicyAndDiplomacy.width - 25f if(statusButtons.width > maxWidth) { - statusButtons.width = maxWidth - statusButtons.wrap() - statusButtons.pack() + statusButtons.update(true) } statusButtons.setPosition(stage.width - statusButtons.width - 10f, topBar.y - statusButtons.height - 10f) } diff --git a/core/src/com/unciv/ui/screens/worldscreen/status/NextTurnButton.kt b/core/src/com/unciv/ui/screens/worldscreen/status/NextTurnButton.kt index 7fa804e87d..ee9c523808 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/status/NextTurnButton.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/status/NextTurnButton.kt @@ -52,6 +52,8 @@ class NextTurnButton( || (!worldScreen.hasOpenPopups() && worldScreen.isPlayersTurn && !worldScreen.waitingForAutosave && !worldScreen.isNextTurnUpdateRunning()) if (isEnabled) addTooltip(KeyboardBinding.NextTurn) else addTooltip("") + + worldScreen.smallUnitButton.update() } internal fun updateButton(nextTurnAction: NextTurnAction) { @@ -76,4 +78,7 @@ class NextTurnButton( private fun getNextTurnAction(worldScreen: WorldScreen) = // Guaranteed to return a non-null NextTurnAction because the last isChoice always returns true NextTurnAction.entries.first { it.isChoice(worldScreen) } + + fun isNextUnitAction(): Boolean = nextTurnAction == NextTurnAction.NextUnit + } diff --git a/core/src/com/unciv/ui/screens/worldscreen/status/SmallUnitButton.kt b/core/src/com/unciv/ui/screens/worldscreen/status/SmallUnitButton.kt new file mode 100644 index 0000000000..7a9c07bcb6 --- /dev/null +++ b/core/src/com/unciv/ui/screens/worldscreen/status/SmallUnitButton.kt @@ -0,0 +1,55 @@ +package com.unciv.ui.screens.worldscreen.status + +import com.unciv.models.translations.tr +import com.unciv.ui.components.UncivTooltip.Companion.addTooltip +import com.unciv.ui.components.extensions.isEnabled +import com.unciv.ui.components.extensions.setSize +import com.unciv.ui.components.input.KeyboardBinding +import com.unciv.ui.components.input.keyShortcuts +import com.unciv.ui.components.input.onActivation +import com.unciv.ui.images.IconTextButton +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.screens.worldscreen.WorldScreen + +const val nextLabel = "Cycle" +const val skipLabel = "Skip" + +class SmallUnitButton( + private val worldScreen: WorldScreen, + private val statusButtons: StatusButtons +) : IconTextButton("", null, fontColor = NextTurnAction.NextUnit.color) { + + private var isSkip = worldScreen.game.settings.checkForDueUnitsCycles + + init { + onActivation { + worldScreen.switchToNextUnit(resetDue = isSkip) + } + } + + fun update() { + keyShortcuts.clear() + isSkip = worldScreen.game.settings.checkForDueUnitsCycles // refresh value + if(isSkip) { + label.setText(skipLabel.tr()) + iconCell.setActor(ImageGetter.getImage("OtherIcons/Skip").apply { setSize(20f) }) + //keyShortcuts.add(KeyboardBinding.Skip) // don't double binding + addTooltip(KeyboardBinding.Skip) + } else { + label.setText(nextLabel.tr()) + iconCell.setActor(ImageGetter.getImage("OtherIcons/Loading").apply { setSize(20f) }) + keyShortcuts.add(KeyboardBinding.Cycle) + addTooltip(KeyboardBinding.Cycle) + } + val nextTurnButton = statusButtons.nextTurnButton + val visible = worldScreen.game.settings.smallUnitButton + && nextTurnButton.isVisible + && nextTurnButton.isNextUnitAction() + && worldScreen.bottomUnitTable.selectedUnit != null + statusButtons.smallUnitButton = if (visible) this else null + isEnabled = visible && nextTurnButton.isEnabled + && worldScreen.bottomUnitTable.selectedUnit?.run { due && isIdle() } == true + pack() + } + +} diff --git a/core/src/com/unciv/ui/screens/worldscreen/status/StatusButtons.kt b/core/src/com/unciv/ui/screens/worldscreen/status/StatusButtons.kt index d925387869..072d311e9e 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/status/StatusButtons.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/status/StatusButtons.kt @@ -1,44 +1,44 @@ package com.unciv.ui.screens.worldscreen.status -import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup +import com.badlogic.gdx.scenes.scene2d.ui.Table 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() - field = button - if (button != null) { - addActorAt(0, button) - } - } + val nextTurnButton: NextTurnButton +) : Table(), Disposable { + var autoPlayStatusButton: AutoPlayStatusButton? = null + var multiplayerStatusButton: MultiplayerStatusButton? = null + var smallUnitButton: SmallUnitButton? = null + private val padXSpace = 10f + private val padYSpace = 5f - init { - space(10f) - right() - wrapReverse() - wrapSpace(10f) - rowRight() - if (autoPlayStatusButton != null) { - addActor(autoPlayStatusButton) + add(nextTurnButton) + } + + fun update(verticalWrap: Boolean) { + clear() + if(verticalWrap) { + add(nextTurnButton) + smallUnitButton?.let { + row() + add(it).padTop(padYSpace).right() + } + autoPlayStatusButton?.let { + row() + add(it).padTop(padYSpace).right() + } + multiplayerStatusButton?.let { + row() + add(it).padTop(padYSpace).right() + } + } else { + multiplayerStatusButton?.let { add(it).padRight(padXSpace).top() } + autoPlayStatusButton?.let { add(it).padRight(padXSpace).top() } + smallUnitButton?.let { add(it).padRight(padXSpace).top() } + add(nextTurnButton) } - if (multiplayerStatusButton != null) { - addActor(multiplayerStatusButton) - } - addActor(nextTurnButton) + pack() } override fun dispose() { diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt index 768e171d0e..4eb443b106 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActions.kt @@ -155,7 +155,7 @@ object UnitActions { addExplorationActions(unit) - addWaitAction(unit) + addSkipAction(unit) // From here we have actions defaulting to the second page if (unit.isMoving()) { @@ -377,10 +377,11 @@ object UnitActions { )) } - private suspend fun SequenceScope.addWaitAction(unit: MapUnit) { + // Skip one turn: marks a unit as due=false and doesn't cycle back in the queue + private suspend fun SequenceScope.addSkipAction(unit: MapUnit) { yield(UnitAction( - type = UnitActionType.Wait, - useFrequency = 65f, // Preferably have this on the first page + type = UnitActionType.Skip, + useFrequency = 0f, // Last on first page (defaultPage=0) action = { unit.due = !unit.due // If it's on, skips to next unit due to worldScreen.switchToNextUnit() in activateAction diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/presenter/SummaryPresenter.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/presenter/SummaryPresenter.kt index caceb96189..7f3aaca1a6 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/presenter/SummaryPresenter.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/presenter/SummaryPresenter.kt @@ -23,7 +23,7 @@ class SummaryPresenter(private val unitTable: UnitTable) : UnitTable.Presenter { val subText = mutableListOf().apply { if (idleCount > 0) add("[$idleCount] idle".tr()) - if (waitingCount > 0) add("[$waitingCount] waiting".tr()) + if (waitingCount > 0) add("[$waitingCount] skipping".tr()) }.joinToString(", ") if(subText!="") { diff --git a/docs/Credits.md b/docs/Credits.md index ae2da30247..7a24aa2426 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -710,7 +710,7 @@ HexaRealm tileset images by legacymtgsalvationuser69544 [here](https://github.co - [City](https://thenounproject.com/icon/city-571332) By Felix Westphal - [Fire](https://thenounproject.com/icon/96564) By Lloyd Humphreys for "city being razed" icon - [Sleep](https://thenounproject.com/icon/sleep-1760085) By Saeful Muslim for unit "sleep" action and status -- [Clockwise](https://thenounproject.com/icon/clockwise-184528/) By Universal Icons (Louis Dawson) for "Wait" icon. The original work has been slightly modified. +- [Skip](https://www.flaticon.com/free-icon/jump_3976216) by Freq Wazza for Skip icon - [Banner](https://thenounproject.com/term/banner/866282/) By Emir Palavan for embarked units - [Arrow](https://thenounproject.com/icon/arrow-2032227/) By uzeir syarief for moving between idle units, expanders, etc. - [Exchange](https://thenounproject.com/icon/exchange-17858) By Mike Rowe for switching tiles between cities