From d0774db030758c6941a0e54bfe61991755ed4f1b Mon Sep 17 00:00:00 2001 From: Yair Morgenstern Date: Fri, 11 Dec 2020 14:24:09 +0200 Subject: [PATCH] Resolved #3408 - Unit maintenance cost reduction generalized, now works for Ottomans --- .../assets/jsons/Civ V - Vanilla/Nations.json | 4 +-- .../unciv/logic/battle/MapUnitCombatant.kt | 2 +- .../unciv/logic/civilization/CivInfoStats.kt | 27 ++++++++++++------- core/src/com/unciv/logic/map/MapUnit.kt | 24 ++++++++--------- core/src/com/unciv/logic/map/TileMap.kt | 2 +- core/src/com/unciv/models/ruleset/Unique.kt | 2 +- .../com/unciv/models/ruleset/unit/BaseUnit.kt | 5 ++-- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/android/assets/jsons/Civ V - Vanilla/Nations.json b/android/assets/jsons/Civ V - Vanilla/Nations.json index acc1b36e28..a10bdcdd06 100644 --- a/android/assets/jsons/Civ V - Vanilla/Nations.json +++ b/android/assets/jsons/Civ V - Vanilla/Nations.json @@ -337,7 +337,7 @@ "outerColor": [150,150,150], "innerColor": [60,60,60], "uniqueName": "Furor Teutonicus", - "uniques": ["67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment", "-25% land units maintenance"], + "uniques": ["67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment", "-[25]% [Land] unit maintenance costs"], "cities": ["Berlin","Hamburg","Munich","Cologne","Frankfurt","Essen","Dortmund","Stuttgart","Dusseldorf","Bremen", "Hannover","Duisburg","Leipzig","Dresden","Bonn","Bochum","Bielefeld","Karlsruhe","Gelsenkirchen","Wiesbaden", "Munster","Rostok","Chemnitz","Braunschweig","Halle","M׌nchengladbach","Kiel","Wuppertal","Freiburg","Hagen", @@ -366,7 +366,7 @@ "outerColor": [245,248,185], "innerColor": [18,84,30], "uniqueName": "Barbary Corsairs", - "uniques": ["Pay only one third the usual cost for naval unit maintenance", "50% chance of capturing defeated Barbarian naval units and earning 25 Gold"], + "uniques": ["-[66]% [Water] unit maintenance costs", "50% chance of capturing defeated Barbarian naval units and earning 25 Gold"], "cities": ["Istanbul","Edirne","Ankara","Bursa","Konya","Samsun","Gaziantep","Diyabakir","Izmir","Kayseri","Malatya", "Marsin","Antalya","Zonguldak","Denizli","Ordu","Mugia","Eskishehir","Inebolu","Sinop","Adana","Artuin", "Bodrum","Eregli","Silifke","Sivas","Amasya","Marmaris","Trabzon","Erzurum","Urfa","Izmit","Afyonkarhisar", diff --git a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt index 09bb3c6bf5..3194223623 100644 --- a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt +++ b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt @@ -14,7 +14,7 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant { override fun isDefeated(): Boolean = unit.health <= 0 override fun isInvisible(): Boolean = unit.isInvisible() override fun canAttack(): Boolean = unit.canAttack() - override fun matchesCategory(category:String) = unit.matchesCategory(category) + override fun matchesCategory(category:String) = unit.matchesFilter(category) override fun takeDamage(damage: Int) { unit.health -= damage diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index db66c4b5b1..a40eaad92c 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -1,6 +1,5 @@ package com.unciv.logic.civilization -import com.unciv.Constants import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.RoadStatus import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS @@ -15,29 +14,37 @@ import kotlin.math.pow /** CivInfo class was getting too crowded */ class CivInfoStats(val civInfo: CivilizationInfo){ - private fun getUnitUpkeep(): Int { + private fun getUnitMaintenance(): Int { val baseUnitCost = 0.5f val freeUnits = 3 var unitsToPayFor = civInfo.getCivUnits() - if(civInfo.hasUnique("Units in cities cost no Maintenance")) - // Only land military units can truly "garrison" + if (civInfo.hasUnique("Units in cities cost no Maintenance")) + // Only land military units can truly "garrison" unitsToPayFor = unitsToPayFor.filterNot { it.getTile().isCityCenter() && it.canGarrison() } + var numberOfUnitsToPayFor = max(0f, unitsToPayFor.count().toFloat() - freeUnits) - if(civInfo.hasUnique("-25% land units maintenance")){ + + // Deprecated and generalized as of 3.11.20 - here for mod transition period + if (civInfo.hasUnique("-25% land units maintenance")) { val numberOfUnitsWithDiscount = min(numberOfUnitsToPayFor, unitsToPayFor.count { it.type.isLandUnit() }.toFloat()) numberOfUnitsToPayFor -= 0.25f * numberOfUnitsWithDiscount } + for (unique in civInfo.getMatchingUniques("-[]% [] unit maintenance costs")) { + val numberOfUnitsWithDiscount = min(numberOfUnitsToPayFor, unitsToPayFor.count { it.matchesFilter(unique.params[1]) }.toFloat()) + numberOfUnitsToPayFor -= numberOfUnitsWithDiscount * (1 - unique.params[0].toFloat() / 100) + } + val turnLimit = BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier val gameProgress = civInfo.gameInfo.turns / turnLimit // as game progresses Maintenance cost rises - var cost = baseUnitCost*numberOfUnitsToPayFor*(1+gameProgress) - cost = cost.pow(1+gameProgress/3) // Why 3? To spread 1 to 1.33 - if(!civInfo.isPlayerCivilization()) + 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 - if(civInfo.hasUnique("-33% unit upkeep costs")) cost *= 0.66f + if (civInfo.hasUnique("-33% unit upkeep costs")) cost *= 0.66f return cost.toInt() } @@ -100,7 +107,7 @@ class CivInfoStats(val civInfo: CivilizationInfo){ } statMap["Transportation upkeep"] = Stats().apply { gold=- getTransportationUpkeep().toFloat()} - statMap["Unit upkeep"] = Stats().apply { gold=- getUnitUpkeep().toFloat()} + statMap["Unit upkeep"] = Stats().apply { gold=- getUnitMaintenance().toFloat()} if (civInfo.hasUnique("50% of excess happiness added to culture towards policies")) { val happiness = civInfo.getHappiness() diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 4f66f1f58c..e8dd8dccb5 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -109,7 +109,7 @@ class MapUnit { movement += 2 for (unique in civInfo.getMatchingUniques("+[] Movement for all [] units")) - if (matchesCategory(unique.params[1])) + if (matchesFilter(unique.params[1])) movement += unique.params[0].toInt() if (civInfo.goldenAges.isGoldenAge() && @@ -719,17 +719,17 @@ class MapUnit { } } - fun matchesCategory(category: String): Boolean { - if (category == type.name) return true - if (category == name) return true - if ((category == "Wounded" || category == "wounded units") && health < 100) return true - if ((category == "Land" || category == "land units") && type.isLandUnit()) return true - if ((category == "Water" || category == "water units") && type.isWaterUnit()) return true - if ((category == "Air" || category == "air units") && type.isAirUnit()) return true - if (category == "non-air" && !type.isAirUnit()) return true - if ((category == "military" || category == "military units") && type.isMilitary()) return true - if (hasUnique(category)) return true - if ((category == "Barbarians" || category == "Barbarian") && civInfo.isBarbarian()) return true + fun matchesFilter(filter: String): Boolean { + if (filter == type.name) return true + if (filter == name) return true + if ((filter == "Wounded" || filter == "wounded units") && health < 100) return true + if ((filter == "Land" || filter == "land units") && type.isLandUnit()) return true + if ((filter == "Water" || filter == "water units") && type.isWaterUnit()) return true + if ((filter == "Air" || filter == "air units") && type.isAirUnit()) return true + if (filter == "non-air" && !type.isAirUnit()) return true + if ((filter == "military" || filter == "military units") && type.isMilitary()) return true + if (hasUnique(filter)) return true + if ((filter == "Barbarians" || filter == "Barbarian") && civInfo.isBarbarian()) return true return false } diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 50fc7dca74..f4bac9a85b 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -169,7 +169,7 @@ class TileMap { unit.promotions.addPromotion(promotion, true) for (unique in civInfo.getMatchingUniques("[] units gain the [] promotion")) { - if (unit.matchesCategory(unique.params[0])) { + if (unit.matchesFilter(unique.params[0])) { unit.promotions.addPromotion(unique.params[1], true) } } diff --git a/core/src/com/unciv/models/ruleset/Unique.kt b/core/src/com/unciv/models/ruleset/Unique.kt index eb19be9d07..6ec7d6043a 100644 --- a/core/src/com/unciv/models/ruleset/Unique.kt +++ b/core/src/com/unciv/models/ruleset/Unique.kt @@ -83,7 +83,7 @@ object UniqueTriggerActivation { val filter = unique.params[0] val promotion = unique.params[1] for (unit in civInfo.getCivUnits()) - if (unit.matchesCategory(filter) + if (unit.matchesFilter(filter) || (civInfo.gameInfo.ruleSet.unitPromotions.values.any { it.name == promotion && unit.type.name in it.unitTypes })) unit.promotions.addPromotion(promotion, isFree = true)} diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index b7a2c34a2c..2fa65560b8 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -5,7 +5,6 @@ import com.unciv.logic.city.CityConstructions import com.unciv.logic.city.IConstruction import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.MapUnit -import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Unique import com.unciv.models.translations.Translations @@ -179,7 +178,7 @@ class BaseUnit : INamed, IConstruction { for (unique in construction.cityInfo.cityConstructions.builtBuildingUniqueMap.getUniques("New [] units start with [] Experience in this city") + civInfo.getMatchingUniques("New [] units start with [] Experience")) { - if (unit.matchesCategory(unique.params[0])) + if (unit.matchesFilter(unique.params[0])) XP += unique.params[1].toInt() } unit.promotions.XP = XP @@ -188,7 +187,7 @@ class BaseUnit : INamed, IConstruction { val filter = unique.params[0] val promotion = unique.params[1] - if (unit.matchesCategory(filter) || (filter == "relevant" && civInfo.gameInfo.ruleSet.unitPromotions.values.any { unit.type.toString() in it.unitTypes && it.name == promotion })) + if (unit.matchesFilter(filter) || (filter == "relevant" && civInfo.gameInfo.ruleSet.unitPromotions.values.any { unit.type.toString() in it.unitTypes && it.name == promotion })) unit.promotions.addPromotion(promotion, isFree = true) }