Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a waiting command (#6884) #6896

Merged
merged 4 commits into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions core/src/com/unciv/logic/civilization/CivilizationInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ class CivilizationInfo {
*/
var attacksSinceTurnStart = ArrayList<HistoricalAttackMemory>()

/**
* Queue of all civilization units that have their actions possibly pending. Internally
* might include e.g. non-idle units, so must be filtered before being given to any outside code.
* (Should be small enough that using ArrayList is fine.)
*/
@Transient
private var dueUnits = mutableListOf<MapUnit>()
var hasMovedAutomatedUnits = false

@Transient
Expand Down Expand Up @@ -264,6 +271,7 @@ class CivilizationInfo {
toReturn.totalCultureForContests = totalCultureForContests
toReturn.totalFaithForContests = totalFaithForContests
toReturn.attacksSinceTurnStart = attacksSinceTurnStart.copy()
toReturn.dueUnits = dueUnits.toMutableList()
toReturn.hasMovedAutomatedUnits = hasMovedAutomatedUnits
return toReturn
}
Expand Down Expand Up @@ -453,6 +461,10 @@ class CivilizationInfo {
newList.add(mapUnit)
units = newList

// Make sure it is initialized.
getDueUnits()
dueUnits.add(mapUnit)
This conversation was marked as resolved.
Show resolved Hide resolved

if (updateCivInfo) {
// Not relevant when updating TileInfo transients, since some info of the civ itself isn't yet available,
// and in any case it'll be updated once civ info transients are
Expand All @@ -465,24 +477,43 @@ class CivilizationInfo {
val newList = ArrayList(units)
newList.remove(mapUnit)
units = newList
dueUnits.remove(mapUnit)
updateStatsForNextTurn() // unit upkeep
updateDetailedCivResources()
}

fun getIdleUnits() = getCivUnits().filter { it.isIdle() }

private fun getDueUnits() = getCivUnits().filter { it.due && it.isIdle() }
// Drop all units that are not really 'due' anymore. We do it here to avoid caring how and where it happened.
// Internal side effect: if 'dueUnits' has never been initialized (new game, load game), do it here.
fun getDueUnits(): List<MapUnit> {
if (dueUnits.none())
dueUnits.addAll(units)
return dueUnits.filter { it.due && it.isIdle() }
}

fun shouldGoToDueUnit() = UncivGame.Current.settings.checkForDueUnits && getDueUnits().any()

fun getNextDueUnit(): MapUnit? {
val dueUnits = getDueUnits()
if (dueUnits.any()) {
val unit = dueUnits.first()
unit.due = false
return unit
// Callers should consider if cycleThroughDueUnits() is not a better choice.
fun getNextDueUnit() = getDueUnits().firstOrNull()
Copy link
Collaborator

@Azzurite Azzurite May 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is unused now, can be removed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept because it was used before. But OK, removed in the latest commit.


fun cycleThroughDueUnits(unitToSkip: MapUnit?): MapUnit? {
var realDueUnits = getDueUnits();
if (realDueUnits.any()) {
var unit = realDueUnits.first();
// We shift the unit to the back of the queue. However, the caller may clear its 'due' state if it wants.
dueUnits.remove(unit);
dueUnits.add(unit);

if (unit == unitToSkip && realDueUnits.size > 1) {
unit = realDueUnits[1];
dueUnits.remove(unit);
dueUnits.add(unit);
}

return unit;
}
return null
else return null;
}
//endregion

Expand Down
2 changes: 2 additions & 0 deletions core/src/com/unciv/models/UnitAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ enum class UnitActionType(
{ ImageGetter.getImage("OtherIcons/DisbandUnit") }, KeyCharAndCode.DEL),
GiftUnit("Gift unit",
{ ImageGetter.getImage("OtherIcons/Present") }, UncivSound.Silent),
Wait("Wait",
null, 'z', UncivSound.Silent),
ShowAdditionalActions("Show more",
{ imageGetShowMore() }, KeyCharAndCode(Input.Keys.PAGE_DOWN)),
HideAdditionalActions("Back",
Expand Down
30 changes: 17 additions & 13 deletions core/src/com/unciv/ui/worldscreen/WorldScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
else
mapHolder.setCenterPosition(tileToCenterOn, immediately = true, selectUnit = true)


tutorialController.allTutorialsShowedCallback = { shouldUpdate = true }

onBackButtonClicked { backButtonAndESCHandler() }
Expand Down Expand Up @@ -727,6 +726,22 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
}
}

fun switchToNextUnit() {
// Try to select something new if we already have the next pending unit selected.
val nextDueUnit = viewingCiv.cycleThroughDueUnits(bottomUnitTable.selectedUnit)
if (nextDueUnit != null) {
mapHolder.setCenterPosition(
nextDueUnit.currentTile.position,
immediately = false,
selectUnit = false
)
bottomUnitTable.selectUnit(nextDueUnit)
shouldUpdate = true
// Unless 'wait' action is chosen, the unit will not be considered due anymore.
nextDueUnit.due = false
}
}

private fun updateNextTurnButton(isSomethingOpen: Boolean) {
nextTurnButton.update(isSomethingOpen, isPlayersTurn, waitingForAutosave, getNextTurnAction())
nextTurnButton.setPosition(stage.width - nextTurnButton.width - 10f, topBar.y - nextTurnButton.height - 10f)
Expand All @@ -741,18 +756,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Bas
NextTurnAction("Waiting for other players...",Color.GRAY) {}

viewingCiv.shouldGoToDueUnit() ->
NextTurnAction("Next unit", Color.LIGHT_GRAY) {
val nextDueUnit = viewingCiv.getNextDueUnit()
if (nextDueUnit != null) {
mapHolder.setCenterPosition(
nextDueUnit.currentTile.position,
immediately = false,
selectUnit = false
)
bottomUnitTable.selectUnit(nextDueUnit)
shouldUpdate = true
}
}
NextTurnAction("Next unit", Color.LIGHT_GRAY) { switchToNextUnit() }

viewingCiv.cities.any { it.cityConstructions.currentConstructionFromQueue == "" } ->
NextTurnAction("Pick construction", Color.CORAL) {
Expand Down
16 changes: 14 additions & 2 deletions core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ object UnitActions {
addTriggerUniqueActions(unit, actionList)
addAddInCapitalAction(unit, actionList, tile)


addToggleActionsAction(unit, actionList, unitTable)

addWaitAction(unit, actionList, worldScreen);

Copy link
Collaborator

@Azzurite Azzurite May 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be above addToggleActionsAction (what a name...) because that is basically our "Next Page" button, and a "Next Page" button does not make sense in the middle of a page, but should be at the bottom.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

return actionList
}

Expand Down Expand Up @@ -832,4 +833,15 @@ object UnitActions {
)
}

}
private fun addWaitAction(unit: MapUnit, actionList: ArrayList<UnitAction>, worldScreen: WorldScreen) {
if (!unit.isIdle()) return
if (worldScreen.viewingCiv.getDueUnits().filter { it != unit }.none()) return
actionList += UnitAction(
type = UnitActionType.Wait,
action = {
unit.due = true
worldScreen.switchToNextUnit()
}
)
}
}