From 8047278d80b07acbbf31d34b0c6c6d166352884e Mon Sep 17 00:00:00 2001 From: alexban011 Date: Sat, 25 Jun 2022 14:40:42 +0300 Subject: [PATCH] Add Notifications Log (#7122) --- android/Images/OtherIcons/Notifications.png | Bin 0 -> 53314 bytes .../jsons/translations/template.properties | 4 + .../logic/civilization/CivilizationInfo.kt | 19 ++++- .../unciv/logic/civilization/Notification.kt | 20 +++++ .../com/unciv/models/metadata/GameSettings.kt | 2 + core/src/com/unciv/ui/options/GameplayTab.kt | 19 +++++ .../EmpireOverviewCategories.kt | 8 +- .../NotificationsOverviewTable.kt | 80 ++++++++++++++++++ .../ui/worldscreen/NotificationsScroll.kt | 13 +-- 9 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 android/Images/OtherIcons/Notifications.png create mode 100644 core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt diff --git a/android/Images/OtherIcons/Notifications.png b/android/Images/OtherIcons/Notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..b28e9b4154f0d0399fb0a2ff1cb246d61e7b280e GIT binary patch literal 53314 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 z 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

?S}<|q7w+)V5bHB#D+uXKpSDeEf2L{#e4Z=8K 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 var proximity = HashMap() - var notifications = ArrayList() val popupAlerts = ArrayList() private var allyCivName: String? = null var naturalWonders = ArrayList() + var notifications = ArrayList() + + var notificationsLog = ArrayList() + class NotificationsLog(val turn: Int = 0) { + var notifications = ArrayList() + } + /** for trades here, ourOffers is the current civ's offers, and theirOffers is what the requesting civ offers */ val tradeRequests = ArrayList() @@ -267,6 +273,7 @@ class CivilizationInfo { toReturn.exploredTiles.addAll(gameInfo.tileMap.values.asSequence().map { it.position }.filter { it in exploredTiles }) toReturn.lastSeenImprovement.putAll(lastSeenImprovement) toReturn.notifications.addAll(notifications) + toReturn.notificationsLog.addAll(notificationsLog) toReturn.citiesCreated = citiesCreated toReturn.popupAlerts.addAll(popupAlerts) toReturn.tradeRequests.addAll(tradeRequests) @@ -912,6 +919,16 @@ class CivilizationInfo { } fun endTurn() { + val notificationsThisTurn = NotificationsLog(gameInfo.turns) + notificationsThisTurn.notifications.addAll(notifications) + + while (notificationsLog.size >= UncivGame.Current.settings.notificationsLogMaxTurns) { + notificationsLog.removeFirst() + } + + if (notificationsThisTurn.notifications.isNotEmpty()) + notificationsLog.add(notificationsThisTurn) + notifications.clear() updateStatsForNextTurn() val nextTurnStats = statsForNextTurn diff --git a/core/src/com/unciv/logic/civilization/Notification.kt b/core/src/com/unciv/logic/civilization/Notification.kt index c0c5bc9e59..0954647c32 100644 --- a/core/src/com/unciv/logic/civilization/Notification.kt +++ b/core/src/com/unciv/logic/civilization/Notification.kt @@ -1,7 +1,11 @@ package com.unciv.logic.civilization import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.unciv.models.ruleset.Ruleset import com.unciv.ui.cityscreen.CityScreen +import com.unciv.ui.images.ImageGetter import com.unciv.ui.pickerscreens.TechPickerScreen import com.unciv.ui.trade.DiplomacyScreen import com.unciv.ui.utils.MayaCalendar @@ -48,6 +52,22 @@ open class Notification() { this.icons = notificationIcons this.action = action } + + fun addNotificationIcons(ruleset: Ruleset, iconSize: Float, table: Table) { + if (icons.isEmpty()) return + for (icon in icons.reversed()) { + val image: Actor = when { + ruleset.technologies.containsKey(icon) -> ImageGetter.getTechIcon(icon) + ruleset.nations.containsKey(icon) -> ImageGetter.getNationIndicator( + ruleset.nations[icon]!!, + iconSize + ) + ruleset.units.containsKey(icon) -> ImageGetter.getUnitIcon(icon) + else -> ImageGetter.getImage(icon) + } + table.add(image).size(iconSize).padRight(5f) + } + } } /** defines what to do if the user clicks on a notification */ diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index d1c9e543dd..c8b32a0877 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -56,6 +56,8 @@ class GameSettings { var useDemographics: Boolean = false var showZoomButtons: Boolean = false + var notificationsLogMaxTurns = 5 + var androidCutout: Boolean = false var multiplayer = GameSettingsMultiplayer() diff --git a/core/src/com/unciv/ui/options/GameplayTab.kt b/core/src/com/unciv/ui/options/GameplayTab.kt index 664cda750f..49b536ca63 100644 --- a/core/src/com/unciv/ui/options/GameplayTab.kt +++ b/core/src/com/unciv/ui/options/GameplayTab.kt @@ -3,7 +3,10 @@ package com.unciv.ui.options import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.UncivGame import com.unciv.logic.civilization.PlayerType +import com.unciv.models.metadata.GameSettings import com.unciv.ui.utils.BaseScreen +import com.unciv.ui.utils.UncivSlider +import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.worldscreen.WorldScreen fun gameplayTab( @@ -35,4 +38,20 @@ fun gameplayTab( ) { settings.automatedWorkersReplaceImprovements = it } optionsPopup.addCheckbox(this, "Order trade offers by amount", settings.orderTradeOffersByAmount) { settings.orderTradeOffersByAmount = it } optionsPopup.addCheckbox(this, "Ask for confirmation when pressing next turn", settings.confirmNextTurn) { settings.confirmNextTurn = it } + + addNotificationLogMaxTurnsSlider(this, settings, UncivGame.Current.worldScreen, optionsPopup.selectBoxMinWidth) +} + +private fun addNotificationLogMaxTurnsSlider(table: Table, settings: GameSettings, screen: BaseScreen?, selectBoxMinWidth: Float) { + table.add("Notifications log max turns".toLabel()).left().fillX() + + val minimapSlider = UncivSlider( + 3f, 15f, 1f, + initial = settings.notificationsLogMaxTurns.toFloat() + ) { + val turns = it.toInt() + settings.notificationsLogMaxTurns = turns + settings.save() + } + table.add(minimapSlider).minWidth(selectBoxMinWidth).pad(10f).row() } diff --git a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt index 5292275a7e..8b0d4b8fa7 100644 --- a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt +++ b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewCategories.kt @@ -1,6 +1,7 @@ package com.unciv.ui.overviewscreen import com.badlogic.gdx.utils.Align +import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.ui.utils.KeyCharAndCode import com.unciv.ui.overviewscreen.EmpireOverviewTab.EmpireOverviewTabPersistableData @@ -14,7 +15,7 @@ private fun Boolean.toState(): EmpireOverviewTabState = if (this) EmpireOverview /** This controls which Tabs for the [EmpireOverviewScreen] exist and their order. * * To add a Tab, build a new [EmpireOverviewTab] subclass and fill out a new entry here, that's all. - * Note the enum value's name is used as Tab caption, so if you ever need a non-alphanumeric caption please redesign to include a property for the caption. + * Note the enum value's name is used as Tab caption, so if you ever need a non-alphanumeric caption please redesign to include a property for the caption. */ enum class EmpireOverviewCategories( val iconName: String, @@ -59,7 +60,10 @@ enum class EmpireOverviewCategories( fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, _: EmpireOverviewTabPersistableData?) = WonderOverviewTab(viewingPlayer, overviewScreen), fun (viewingPlayer: CivilizationInfo) = (viewingPlayer.naturalWonders.isEmpty() && viewingPlayer.cities.isEmpty()).toState()), - ; + Notifications("OtherIcons/Notifications", 'N', Align.top, + fun (viewingPlayer: CivilizationInfo, overviewScreen: EmpireOverviewScreen, _: EmpireOverviewTabPersistableData?) + = NotificationsOverviewTable(worldScreen = UncivGame.Current.worldScreen!!, viewingPlayer, overviewScreen), + fun (_: CivilizationInfo) = EmpireOverviewTabState.Normal); constructor(iconName: String, shortcutChar: Char, scrollAlign: Int, factory: FactoryType, stateTester: StateTesterType = { _ -> EmpireOverviewTabState.Normal }) : this(iconName, KeyCharAndCode(shortcutChar), scrollAlign, factory, stateTester) diff --git a/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt new file mode 100644 index 0000000000..788547ead9 --- /dev/null +++ b/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt @@ -0,0 +1,80 @@ +package com.unciv.ui.overviewscreen + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.Touchable +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.unciv.UncivGame +import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.civilization.Notification +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.utils.BaseScreen +import com.unciv.ui.utils.WrappableLabel +import com.unciv.ui.utils.extensions.onClick +import com.unciv.ui.worldscreen.WorldScreen + +class NotificationsOverviewTable( + val worldScreen: WorldScreen, + viewingPlayer: CivilizationInfo, + overviewScreen: EmpireOverviewScreen +) : EmpireOverviewTab(viewingPlayer, overviewScreen) { + + val notificationLog = viewingPlayer.notificationsLog + + private val notificationTable = Table(BaseScreen.skin) + + val scaleFactor = 0.3f + val inverseScaleFactor = 1f / scaleFactor + private val maxWidthOfStage = 0.333f + private val maxEntryWidth = worldScreen.stage.width * maxWidthOfStage * inverseScaleFactor + + val iconSize = 20f + + init { + val tablePadding = 30f + defaults().pad(tablePadding).top() + + generateNotificationTable() + + add(notificationTable) + } + + private fun generateNotificationTable() { + if (viewingPlayer.notifications.isNotEmpty()) + notificationTable.add(notificationsArrayTable("Current", viewingPlayer.notifications)).row() + + for (notification in notificationLog.asReversed()) { + notificationTable.add(notificationsArrayTable(notification.turn.toString(), notification.notifications)) + notificationTable.padTop(20f).row() + } + } + + private fun notificationsArrayTable(index: String, notifications: ArrayList): Table { + val turnTable = Table(BaseScreen.skin) + if (index != "Current") + turnTable.add("Turn [$index]").row() + else + turnTable.add("Current turn").row() + + for (notification in notifications) { + val notificationTable = Table(BaseScreen.skin) + + val labelWidth = maxEntryWidth * notification.icons.size - 10f + val label = WrappableLabel(notification.text, labelWidth, Color.BLACK, 20) + + notificationTable.add(label) + notificationTable.background = ImageGetter.getRoundedEdgeRectangle() + notificationTable.touchable = Touchable.enabled + notificationTable.onClick { + UncivGame.Current.resetToWorldScreen() + notification.action?.execute(worldScreen) + } + + notification.addNotificationIcons(worldScreen.gameInfo.ruleSet, iconSize, notificationTable) + + turnTable.add(notificationTable).padTop(5f) + turnTable.padTop(20f).row() + } + turnTable.padTop(20f).row() + return turnTable + } +} diff --git a/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt b/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt index 253e608451..44f9c13ace 100644 --- a/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt +++ b/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt @@ -78,18 +78,7 @@ class NotificationsScroll( listItem.add(label).padRight(10f) } - if (notification.icons.isNotEmpty()) { - val ruleset = worldScreen.gameInfo.ruleSet - for (icon in notification.icons.reversed()) { - val image: Actor = when { - ruleset.technologies.containsKey(icon) -> ImageGetter.getTechIcon(icon) - ruleset.nations.containsKey(icon) -> ImageGetter.getNationIndicator(ruleset.nations[icon]!!, iconSize) - ruleset.units.containsKey(icon) -> ImageGetter.getUnitIcon(icon) - else -> ImageGetter.getImage(icon) - } - listItem.add(image).size(iconSize).padRight(5f) - } - } + notification.addNotificationIcons(worldScreen.gameInfo.ruleSet, iconSize, listItem) // using a large click area with no gap in between each message item. // this avoids accidentally clicking in between the messages, resulting in a map click