Fixed a bug where all global unit discounts would always apply, despite only being for certain units (#5879)

This commit is contained in:
Xander Lenstra
2021-12-31 10:07:59 +01:00
committed by GitHub
parent dcbb0df4f9
commit ee65adb5e4
8 changed files with 25 additions and 29 deletions

View File

@ -28,27 +28,21 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
var unitsToPayFor = civInfo.getCivUnits()
if (civInfo.hasUnique("Units in cities cost no Maintenance"))
// Only land military units can truly "garrison"
unitsToPayFor = unitsToPayFor.filterNot {
it.getTile().isCityCenter() && it.canGarrison()
}
// Handle unit maintenance discounts
// Have to capture global and per-unit
// Free Garrison already removed above from sequence
// Initialize base maintenance cost empire-wide, default 1 aka 100%
// Then calculate per-unit discounrts
// To try and avoid concurrent modifications leading to crashes,
// we calculate the costs of one unit at a time.
// Each unit starts with 1f aka 100% of cost, and then the discout is addded.
// Note all discounts are in the form of -X%, such as -25 for 25% reduction
var civWideMaintenance = 1f
// Calculate global discounts
for (unique in civInfo.getMatchingUniques(UniqueType.UnitMaintenanceDiscountGlobal, StateForConditionals(civInfo))) {
civWideMaintenance *= unique.params[0].toPercent()
}
val costsToPay = ArrayList<Float>()
for (unit in unitsToPayFor) {
var unitMaintenance = civWideMaintenance
for (unique in unit.getMatchingUniques(UniqueType.UnitMaintenanceDiscount)){
val stateForConditionals = StateForConditionals(civInfo=civInfo, unit=unit)
var unitMaintenance = 1f
for (unique in unit.getMatchingUniques(UniqueType.UnitMaintenanceDiscount, stateForConditionals, true)){
unitMaintenance *= unique.params[0].toPercent()
}
costsToPay.add(unitMaintenance)
@ -59,16 +53,16 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
costsToPay.sortDescending()
val numberOfUnitsToPayFor = max(0.0, costsToPay.asSequence().drop(freeUnits).sumOf { it.toDouble() } ).toFloat()
val turnLimit =
BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier
val gameProgress =
min(civInfo.gameInfo.turns / turnLimit, 1f) // as game progresses Maintenance cost rises
// as game progresses Maintenance cost rises
val turnLimit = BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier
val gameProgress = min(civInfo.gameInfo.turns / turnLimit, 1f)
var cost = baseUnitCost * numberOfUnitsToPayFor * (1 + gameProgress)
cost = cost.pow(1 + gameProgress / 3) // Why 3? To spread 1 to 1.33
if (!civInfo.isPlayerCivilization())
cost *= civInfo.gameInfo.getDifficulty().aiUnitMaintenanceModifier
return cost.toInt()
}

View File

@ -553,6 +553,7 @@ class MapUnit {
return getMatchingUniques("All adjacent units heal [] HP when healing").sumOf { it.params[0].toInt() }
}
// Only military land units can truly "garrison"
fun canGarrison() = baseUnit.isMilitary() && baseUnit.isLandUnit()
fun isGreatPerson() = baseUnit.isGreatPerson()

View File

@ -130,7 +130,6 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
/////// Other global uniques
FreeUnits("[amount] units cost no maintenance", UniqueTarget.Global),
UnitMaintenanceDiscountGlobal("[amount]% maintenance costs for [mapUnitFilter] units", UniqueTarget.Global),
ConsumesResources("Consumes [amount] [resource]", UniqueTarget.Improvement, UniqueTarget.Building, UniqueTarget.Unit),
ProvidesResources("Provides [amount] [resource]", UniqueTarget.Improvement, UniqueTarget.Building),
@ -568,6 +567,9 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget, val flags:
BonuxXPGain("[amount]% Bonus XP gain", UniqueTarget.Unit),
@Deprecated("As of 3.18.12", ReplaceWith("[amount]% XP gained from combat <for [mapUnitFilter] units>"))
BonusXPGainForUnits("[mapUnitFilter] units gain [amount]% more Experience from combat", UniqueTarget.Global),
@Deprecated("As of 3.18.14", ReplaceWith("[amount]% maintenance costs <for [mapUnitFilter] units>"))
UnitMaintenanceDiscountGlobal("[amount]% maintenance costs for [mapUnitFilter] units", UniqueTarget.Global),
// endregion