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 <spellman23@gmail.com>
This commit is contained in:
itanasi 2021-11-22 08:21:34 -08:00 committed by GitHub
parent 14c4f2d570
commit b72a2c3ebb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 28 additions and 11 deletions

View File

@ -1474,6 +1474,7 @@
"range": 8, "range": 8,
"cost": 150, "cost": 150,
"requiredTech": "Advanced Ballistics", "requiredTech": "Advanced Ballistics",
"uniques": ["[-100]% maintenance costs"],
"attackSound": "missile" "attackSound": "missile"
}, },
{ {

View File

@ -1147,6 +1147,7 @@
"range": 8, "range": 8,
"cost": 150, "cost": 150,
"requiredTech": "Satellites", "requiredTech": "Satellites",
"uniques": ["[-100]% maintenance costs"],
"attackSound": "missile" "attackSound": "missile"
}, },
{ {

View File

@ -32,17 +32,27 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
unitsToPayFor = unitsToPayFor.filterNot { unitsToPayFor = unitsToPayFor.filterNot {
it.getTile().isCityCenter() && it.canGarrison() it.getTile().isCityCenter() && it.canGarrison()
} }
// Handle unit maintenance discounts
// Have to capture global and per-unit
var numberOfUnitsToPayFor = max(0f, unitsToPayFor.count().toFloat() - freeUnits) // Free Garrison already removed above from sequence
// Initialize maintenance cost per unit, default 1 aka 100%
for (unique in civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscount, StateForConditionals(civInfo))) { // Note all discounts are in the form of -X%, such as -25 for 25% reduction
val numberOfUnitsWithDiscount = min( for (unit in unitsToPayFor){
numberOfUnitsToPayFor, unit.maintenance = 1f
unitsToPayFor.count { it.matchesFilter(unique.params[1]) }.toFloat() for (unique in unit.getMatchingUniques(UniqueType.UnitMaintenanceDiscount)){
) unit.maintenance *= unique.params[0].toPercent()
numberOfUnitsToPayFor += numberOfUnitsWithDiscount * unique.params[0].toFloat() / 100f }
} }
// 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 = val turnLimit =
BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier

View File

@ -42,6 +42,9 @@ class MapUnit {
@Transient @Transient
val movement = UnitMovementAlgorithms(this) val movement = UnitMovementAlgorithms(this)
@Transient
var maintenance = 1f
@Transient @Transient
var isDestroyed = false var isDestroyed = false

View File

@ -137,7 +137,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
/////// Other global uniques /////// Other global uniques
FreeUnits("[amount] units cost no maintenance", UniqueTarget.Global), 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) @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), 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) @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), CarryExtraAirUnits("Can carry [amount] extra [mapUnitFilter] units", UniqueTarget.Unit),
CannotBeCarriedBy("Cannot be carried by [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 // The following block gets cached in MapUnit for faster getMovementCostBetweenAdjacentTiles
DoubleMovementOnTerrain("Double movement in [terrainFilter]", UniqueTarget.Unit), 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) @Deprecated("As of 3.17.1 - removed as of 3.17.13", ReplaceWith("Double movement in [terrainFilter]"), DeprecationLevel.ERROR)