From da85856fe38f70d758086b69b4be6406263ef672 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Fri, 22 Aug 2025 12:37:26 +0300 Subject: [PATCH] chore(purity): UnitOverview and UnitPromotions --- build.gradle.kts | 4 +++- core/src/com/unciv/logic/map/mapunit/MapUnit.kt | 3 ++- .../com/unciv/logic/map/mapunit/UnitPromotions.kt | 15 +++++++++++---- core/src/com/unciv/models/Religion.kt | 2 +- .../ui/screens/overviewscreen/UnitOverviewTab.kt | 2 +- .../overviewscreen/UnitOverviewTabColumn.kt | 6 ++++-- .../overviewscreen/UnitOverviewTabHelpers.kt | 4 ++++ 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fad199546a..bbf3ac27d4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -68,7 +68,9 @@ allprojects { "kotlin.collections.shuffled", ) wellKnownPureClasses = setOf( - "java.lang.StackTraceElement" // moved + "java.lang.StackTraceElement", // moved + "java.text.DecimalFormat", + "java.lang.Math", ) wellKnownInternalStateClasses = setOf( "com.badlogic.gdx.math.Vector2", diff --git a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt index 637e7bf05c..b9fd2a85a0 100644 --- a/core/src/com/unciv/logic/map/mapunit/MapUnit.kt +++ b/core/src/com/unciv/logic/map/mapunit/MapUnit.kt @@ -183,6 +183,7 @@ class MapUnit : IsPartOfGameInfoSerialization { * Note this is translated after being returned from this function, so let's pay * attention to combined names (renamed units, religion). */ + @Readonly fun displayName(): String { val baseName = if (instanceName == null) "[$name]" @@ -231,7 +232,7 @@ class MapUnit : IsPartOfGameInfoSerialization { val type: UnitType get() = baseUnit.type - fun getMovementString(): String = + @Readonly fun getMovementString(): String = (DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + getMaxMovement()).tr() diff --git a/core/src/com/unciv/logic/map/mapunit/UnitPromotions.kt b/core/src/com/unciv/logic/map/mapunit/UnitPromotions.kt index bd2f2c53f0..7d13240b66 100644 --- a/core/src/com/unciv/logic/map/mapunit/UnitPromotions.kt +++ b/core/src/com/unciv/logic/map/mapunit/UnitPromotions.kt @@ -34,6 +34,7 @@ class UnitPromotions : IsPartOfGameInfoSerialization { * @param sorted if `true` return the promotions in json order (`false` gives hashset order) for display. * @return a Sequence of this unit's promotions */ + @Readonly fun getPromotions(sorted: Boolean = false): Sequence = sequence { if (promotions.isEmpty()) return@sequence val unitPromotions = unit.civ.gameInfo.ruleset.unitPromotions @@ -51,14 +52,17 @@ class UnitPromotions : IsPartOfGameInfoSerialization { } /** @return the XP points needed to "buy" the next promotion. 10, 30, 60, 100, 150,... */ - fun xpForNextPromotion(): Int = Math.round(baseXpForPromotionNumber(numberOfPromotions + 1) * promotionCostModifier()) + @Readonly fun xpForNextPromotion(): Int = Math.round(baseXpForPromotionNumber(numberOfPromotions + 1) * promotionCostModifier()) /** @return the XP points needed to "buy" the next [count] promotions. */ + @Readonly fun xpForNextNPromotions(count: Int) = (1..count).sumOf { - baseXpForPromotionNumber(numberOfPromotions+it)} * promotionCostModifier() + baseXpForPromotionNumber(numberOfPromotions+it)} * promotionCostModifier() + @Readonly private fun baseXpForPromotionNumber(numberOfPromotions: Int) = (numberOfPromotions) * 10 - + + @Readonly private fun promotionCostModifier(): Float { var totalPromotionCostModifier = 1f for (unique in unit.civ.getMatchingUniques(UniqueType.XPForPromotionModifier)) { @@ -69,8 +73,9 @@ class UnitPromotions : IsPartOfGameInfoSerialization { } /** @return Total XP including that already "spent" on promotions */ - fun totalXpProduced() = XP + (numberOfPromotions * (numberOfPromotions + 1)) * 5 + @Readonly fun totalXpProduced() = XP + (numberOfPromotions * (numberOfPromotions + 1)) * 5 + @Readonly fun canBePromoted(): Boolean { if (XP < xpForNextPromotion()) return false if (getAvailablePromotions().none()) return false @@ -134,10 +139,12 @@ class UnitPromotions : IsPartOfGameInfoSerialization { /** Gets all promotions this unit could currently "buy" with enough [XP] * Checks unit type, already acquired promotions, prerequisites and incompatibility uniques. */ + @Readonly fun getAvailablePromotions(): Sequence { return unit.civ.gameInfo.ruleset.unitPromotions.values.asSequence().filter { isAvailable(it) } } + @Readonly private fun isAvailable(promotion: Promotion): Boolean { if (promotion.name in promotions) return false if (unit.type.name !in promotion.unitTypes) return false diff --git a/core/src/com/unciv/models/Religion.kt b/core/src/com/unciv/models/Religion.kt index 65888b4f20..1fe2948971 100644 --- a/core/src/com/unciv/models/Religion.kt +++ b/core/src/com/unciv/models/Religion.kt @@ -102,7 +102,7 @@ class Religion() : INamed, IsPartOfGameInfoSerialization { .filter { it.type == beliefType } } - fun getAllBeliefsOrdered(): Sequence { + @Readonly fun getAllBeliefsOrdered(): Sequence { return mapToExistingBeliefs(followerBeliefs).filter { it.type == BeliefType.Pantheon } + mapToExistingBeliefs(founderBeliefs).filter { it.type == BeliefType.Founder } + mapToExistingBeliefs(followerBeliefs).filter { it.type == BeliefType.Follower } + diff --git a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt index d02a8239c7..8c2ef1d628 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt @@ -59,7 +59,7 @@ class UnitOverviewTab( //todo the comments and todo below are copied verbatim from CityOverviewTab - synergies? private val grid = SortableGrid( - columns = UnitOverviewTabColumn.values().asIterable(), + columns = UnitOverviewTabColumn.entries.asIterable(), data = viewingPlayer.units.getCivUnits().asIterable(), actionContext = this, sortState = persistableData, diff --git a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabColumn.kt b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabColumn.kt index aa5b600a96..29b34f79c0 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabColumn.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabColumn.kt @@ -17,6 +17,7 @@ import com.unciv.ui.components.widgets.UnitIconGroup import com.unciv.ui.images.IconTextButton import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.pickerscreens.UnitRenamePopup +import yairm210.purity.annotations.Readonly //todo Extending getEntryValue here to have a second String-based "channel" - could go into SortableGrid, possibly by defining a DataType per column??? @@ -91,6 +92,7 @@ enum class UnitOverviewTabColumn( label.onClick { showWorldScreenAt(closestCityTile) } return label } + @Readonly private fun getClosestCityTile(item: MapUnit) = item.getTile() .getTilesInDistance(3).firstOrNull { it.isCityCenter() } }, @@ -134,11 +136,11 @@ enum class UnitOverviewTabColumn( override val defaultSort get() = SortableGrid.SortDirection.Ascending //endregion - open fun getEntryString(item: MapUnit): String? = getEntryValue(item).takeIf { it > 0 }?.tr() + @Readonly open fun getEntryString(item: MapUnit): String? = getEntryValue(item).takeIf { it > 0 }?.tr() //region Overridden superclass methods override fun getHeaderActor(iconSize: Float) = (headerLabel ?: name).toLabel() - override fun getEntryValue(item: MapUnit) = 0 + @Readonly override fun getEntryValue(item: MapUnit) = 0 override fun getEntryActor(item: MapUnit, iconSize: Float, actionContext: UnitOverviewTab): Actor? = getEntryString(item)?.toLabel(alignment = Align.center) override fun getComparator() = if (isNumeric) super.getComparator() diff --git a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabHelpers.kt b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabHelpers.kt index 011248e009..e64d0ddabd 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabHelpers.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTabHelpers.kt @@ -20,6 +20,7 @@ import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.UnitUpgradeMenu import com.unciv.ui.screens.pickerscreens.PromotionPickerScreen import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade +import yairm210.purity.annotations.Readonly /** * Helper library for [UnitOverviewTabColumn] @@ -43,6 +44,7 @@ open class UnitOverviewTabHelpers { protected fun showWorldScreenAt(unit: MapUnit) = showWorldScreenAt(unit.currentTile.position, unit) protected fun showWorldScreenAt(tile: Tile) = showWorldScreenAt(tile.position, null) + @Readonly private fun getWorkerActionText(unit: MapUnit): String? = when { // See UnitTurnManager.endTurn, if..workOnImprovement or UnitGroup.getActionImage: similar logic !unit.cache.hasUniqueToBuildImprovements -> null @@ -52,6 +54,7 @@ open class UnitOverviewTabHelpers { else -> unit.currentTile.improvementInProgress } + @Readonly protected fun getActionText(unit: MapUnit): String? { val workerText by lazy { getWorkerActionText(unit) } return when { @@ -88,6 +91,7 @@ open class UnitOverviewTabHelpers { return table } + @Readonly @Suppress("purity") // Calls action protected fun getUpgradeSortString(unit: MapUnit): String? { val upgrade = UnitActionsUpgrade.getUpgradeActionAnywhere(unit).firstOrNull() ?: return null