From b72a2c3ebbed5f12d47768000db82b64e61c7b4e Mon Sep 17 00:00:00 2001 From: itanasi <44038014+itanasi@users.noreply.github.com> Date: Mon, 22 Nov 2021 08:21:34 -0800 Subject: [PATCH] Make Guided Missile Free (and Maintenance overhaul) (#5698) * Add new UniqueType.NoMaintenance to support Guided Missile * revert gradle Add UnitMaintenanceDiscount Rename UnitMaintenanceDiscount->UnitMaintenanceDiscountGlobal Rework maintenance equation to account for overlapping reductions Add maintenance variable to MapUnit * Add square brackets in string (apparently didn't check in?) More robust uniques check code so not assuming only one matching unique Use toPercent() * Proper toPercent() math Co-authored-by: temurakami --- .../jsons/Civ V - Gods & Kings/Units.json | 1 + .../assets/jsons/Civ V - Vanilla/Units.json | 1 + .../unciv/logic/civilization/CivInfoStats.kt | 30 ++++++++++++------- core/src/com/unciv/logic/map/MapUnit.kt | 3 ++ .../unciv/models/ruleset/unique/UniqueType.kt | 4 ++- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/android/assets/jsons/Civ V - Gods & Kings/Units.json b/android/assets/jsons/Civ V - Gods & Kings/Units.json index b73f8d867c..9aae3ac322 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Units.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Units.json @@ -1474,6 +1474,7 @@ "range": 8, "cost": 150, "requiredTech": "Advanced Ballistics", + "uniques": ["[-100]% maintenance costs"], "attackSound": "missile" }, { diff --git a/android/assets/jsons/Civ V - Vanilla/Units.json b/android/assets/jsons/Civ V - Vanilla/Units.json index 1f7fc31e7b..04e7ab615d 100644 --- a/android/assets/jsons/Civ V - Vanilla/Units.json +++ b/android/assets/jsons/Civ V - Vanilla/Units.json @@ -1147,6 +1147,7 @@ "range": 8, "cost": 150, "requiredTech": "Satellites", + "uniques": ["[-100]% maintenance costs"], "attackSound": "missile" }, { diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index 4a9dd3353e..46a539397e 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -32,17 +32,27 @@ class CivInfoStats(val civInfo: CivilizationInfo) { unitsToPayFor = unitsToPayFor.filterNot { it.getTile().isCityCenter() && it.canGarrison() } - - - var numberOfUnitsToPayFor = max(0f, unitsToPayFor.count().toFloat() - freeUnits) - - for (unique in civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscount, StateForConditionals(civInfo))) { - val numberOfUnitsWithDiscount = min( - numberOfUnitsToPayFor, - unitsToPayFor.count { it.matchesFilter(unique.params[1]) }.toFloat() - ) - numberOfUnitsToPayFor += numberOfUnitsWithDiscount * unique.params[0].toFloat() / 100f + // Handle unit maintenance discounts + // Have to capture global and per-unit + // Free Garrison already removed above from sequence + // Initialize maintenance cost per unit, default 1 aka 100% + // Note all discounts are in the form of -X%, such as -25 for 25% reduction + for (unit in unitsToPayFor){ + unit.maintenance = 1f + for (unique in unit.getMatchingUniques(UniqueType.UnitMaintenanceDiscount)){ + unit.maintenance *= unique.params[0].toPercent() + } } + // Apply global discounts + for (unique in civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscountGlobal, StateForConditionals(civInfo))) { + for (unit in unitsToPayFor.filter{it.matchesFilter(unique.params[1])}){ + unit.maintenance *= unique.params[0].toPercent() + } + } + // Sort by descending maintenance, then drop most expensive X units to make them free + // If more free than units left, returns empty sequence + unitsToPayFor = unitsToPayFor.sortedByDescending { it.maintenance }.drop(freeUnits) + val numberOfUnitsToPayFor = max(0.0, unitsToPayFor.sumOf { it.maintenance.toDouble() }).toFloat() val turnLimit = BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 4aab83b398..49bf2e94f9 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -42,6 +42,9 @@ class MapUnit { @Transient val movement = UnitMovementAlgorithms(this) + @Transient + var maintenance = 1f + @Transient var isDestroyed = false diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index d7beaf29e3..12c6439fe7 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -137,7 +137,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: /////// Other global uniques FreeUnits("[amount] units cost no maintenance", UniqueTarget.Global), - UnitMaintenanceDiscount("[amount]% maintenance costs for [mapUnitFilter] units", UniqueTarget.Global), + UnitMaintenanceDiscountGlobal("[amount]% maintenance costs for [mapUnitFilter] units", UniqueTarget.Global), @Deprecated("As of 3.16.16 - removed as of 3.17.11", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.ERROR) DecreasedUnitMaintenanceCostsByFilter("-[amount]% [mapUnitFilter] unit maintenance costs", UniqueTarget.Global), @Deprecated("As of 3.16.16 - removed as of 3.17.11", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.ERROR) @@ -286,6 +286,8 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags: CarryExtraAirUnits("Can carry [amount] extra [mapUnitFilter] units", UniqueTarget.Unit), CannotBeCarriedBy("Cannot be carried by [mapUnitFilter] units", UniqueTarget.Unit), + UnitMaintenanceDiscount("[amount]% maintenance costs", UniqueTarget.Unit), + // The following block gets cached in MapUnit for faster getMovementCostBetweenAdjacentTiles DoubleMovementOnTerrain("Double movement in [terrainFilter]", UniqueTarget.Unit), @Deprecated("As of 3.17.1 - removed as of 3.17.13", ReplaceWith("Double movement in [terrainFilter]"), DeprecationLevel.ERROR)