diff --git a/android/assets/jsons/Civ V - Gods & Kings/Techs.json b/android/assets/jsons/Civ V - Gods & Kings/Techs.json index ad22e0a0ca..a4b96f76d1 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Techs.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Techs.json @@ -197,7 +197,7 @@ "name": "Guilds", "row": 7, "prerequisites": ["Currency"], - "uniques": ["Enables conversion of city production to gold"], + "uniques": ["Enables conversion of city production to [Gold]"], "quote": "'The merchants and the traders have come; their profits are pre-ordained...' - Sri Guru Granth Sahib" }, { @@ -226,7 +226,7 @@ "name": "Education", "row": 3, "prerequisites": ["Theology","Civil Service"], - "uniques": ["Enables conversion of city production to science","Enables Research agreements"], + "uniques": ["Enables conversion of city production to [Science]","Enables Research agreements"], "quote": "'Education is the best provision for old age.' - Aristotle" }, { diff --git a/android/assets/jsons/Civ V - Vanilla/Techs.json b/android/assets/jsons/Civ V - Vanilla/Techs.json index 989ad3a36e..fed4aa3e42 100644 --- a/android/assets/jsons/Civ V - Vanilla/Techs.json +++ b/android/assets/jsons/Civ V - Vanilla/Techs.json @@ -170,7 +170,7 @@ "name": "Currency", "row": 7, "prerequisites": ["Mathematics"], - "uniques": ["Enables conversion of city production to gold"], + "uniques": ["Enables conversion of city production to [Gold]"], "quote": "'Better is bread with a happy heart than wealth with vexation.' - Amenemope" }, { @@ -206,7 +206,7 @@ "name": "Education", "row": 3, "prerequisites": ["Theology","Civil Service"], - "uniques": ["Enables conversion of city production to science"], + "uniques": ["Enables conversion of city production to [Science]"], "quote": "'Education is the best provision for old age.' - Aristotle" }, { diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 7438bbabcf..2ae834f1e9 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1023,6 +1023,8 @@ Current points = Points per turn = Convert production to gold at a rate of 4 to 1 = Convert production to science at a rate of [rate] to 1 = +Convert production to [stat] at a rate of [rate] to 1 = +Production to [stat] conversion in cities changed by [relativeAmount]% = The city will not produce anything. = Worked by [cityName] = Lock = diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index 92f24e2253..b6d6b942d3 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -107,17 +107,22 @@ class CityStats(val cityInfo: CityInfo) { private fun getStatsFromProduction(production: Float): Stats { val stats = Stats() - when (cityInfo.cityConstructions.currentConstructionFromQueue) { - "Gold" -> stats.gold += production / 4 - "Science" -> stats.science += production * getScienceConversionRate() + if (cityInfo.cityConstructions.currentConstructionFromQueue in Stat.statsWithCivWideField.map { it.name }) { + val stat = Stat.valueOf(cityInfo.cityConstructions.currentConstructionFromQueue) + stats[stat] = production * getStatConversionRate(stat) } return stats } - fun getScienceConversionRate(): Float { + fun getStatConversionRate(stat: Stat): Float { var conversionRate = 1 / 4f - if (cityInfo.civInfo.hasUnique(UniqueType.ProductionToScienceConversionBonus)) + val conversionUnique = cityInfo.civInfo.getMatchingUniques(UniqueType.ProductionToCivWideStatConversionBonus).firstOrNull { it.params[0] == stat.name } + if (conversionUnique != null) { + conversionRate *= conversionUnique.params[1].toPercent() + } else if (stat == Stat.Science && cityInfo.civInfo.hasUnique(UniqueType.ProductionToScienceConversionBonus)) { + // backwards compatibility conversionRate *= 1.33f + } return conversionRate } diff --git a/core/src/com/unciv/logic/city/IConstruction.kt b/core/src/com/unciv/logic/city/IConstruction.kt index 9162c44610..b7f839f2aa 100644 --- a/core/src/com/unciv/logic/city/IConstruction.kt +++ b/core/src/com/unciv/logic/city/IConstruction.kt @@ -212,35 +212,19 @@ data class RejectionReasonInstance(val rejectionReason:RejectionReason, open class PerpetualConstruction(override var name: String, val description: String) : IConstruction { override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions) - open fun getProductionTooltip(cityInfo: CityInfo) : String - = "\r\n${(cityInfo.cityStats.currentCityStats.production / CONVERSION_RATE).roundToInt()}/${Fonts.turn}" - open fun getConversionRate(cityInfo: CityInfo) : Int - = CONVERSION_RATE + open fun getProductionTooltip(cityInfo: CityInfo) : String = "" companion object { - const val CONVERSION_RATE: Int = 4 - val science = object : PerpetualConstruction("Science", "Convert production to science at a rate of [rate] to 1") { - override fun isBuildable(cityConstructions: CityConstructions): Boolean { - return cityConstructions.cityInfo.civInfo.hasUnique(UniqueType.EnablesScienceProduction) - } - override fun getProductionTooltip(cityInfo: CityInfo): String { - return "\r\n${(cityInfo.cityStats.currentCityStats.production / getConversionRate(cityInfo)).roundToInt()}/${Fonts.turn}" - } - override fun getConversionRate(cityInfo: CityInfo) = (1/cityInfo.cityStats.getScienceConversionRate()).roundToInt() - } - val gold = object : PerpetualConstruction("Gold", "Convert production to gold at a rate of $CONVERSION_RATE to 1") { - override fun isBuildable(cityConstructions: CityConstructions): Boolean { - return cityConstructions.cityInfo.civInfo.hasUnique(UniqueType.EnablesGoldProduction) - } - } + val science = PerpetualStatConversion(Stat.Science) + val gold = PerpetualStatConversion(Stat.Gold) + val culture = PerpetualStatConversion(Stat.Culture) + val faith = PerpetualStatConversion(Stat.Faith) val idle = object : PerpetualConstruction("Nothing", "The city will not produce anything.") { override fun isBuildable(cityConstructions: CityConstructions): Boolean = true - - override fun getProductionTooltip(cityInfo: CityInfo): String = "" } val perpetualConstructionsMap: Map - = mapOf(science.name to science, gold.name to gold, idle.name to idle) + = mapOf(science.name to science, gold.name to gold, culture.name to culture, faith.name to faith, idle.name to idle) } override fun isBuildable(cityConstructions: CityConstructions): Boolean = @@ -251,3 +235,24 @@ open class PerpetualConstruction(override var name: String, val description: Str override fun requiresResource(resource: String) = false } + +open class PerpetualStatConversion(val stat: Stat) : + PerpetualConstruction(stat.name, "Convert production to [${stat.name}] at a rate of [rate] to 1") { + + override fun getProductionTooltip(cityInfo: CityInfo) : String + = "\r\n${(cityInfo.cityStats.currentCityStats.production / getConversionRate(cityInfo)).roundToInt()}/${Fonts.turn}" + fun getConversionRate(cityInfo: CityInfo) : Int = (1/cityInfo.cityStats.getStatConversionRate(stat)).roundToInt() + + override fun isBuildable(cityConstructions: CityConstructions): Boolean { + val hasProductionUnique = cityConstructions.cityInfo.civInfo.getMatchingUniques(UniqueType.EnablesCivWideStatProduction).any { it.params[0] == stat.name } + return when (stat) { + Stat.Science -> hasProductionUnique + || cityConstructions.cityInfo.civInfo.hasUnique(UniqueType.EnablesScienceProduction) // backwards compatibility + Stat.Gold -> hasProductionUnique + || cityConstructions.cityInfo.civInfo.hasUnique(UniqueType.EnablesGoldProduction) // backwards compatibility + Stat.Culture -> hasProductionUnique + Stat.Faith -> cityConstructions.cityInfo.civInfo.gameInfo.isReligionEnabled() && hasProductionUnique + else -> false + } + } +} diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt index ba0bd6e5fd..294d6ec855 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueParameterType.kt @@ -162,7 +162,7 @@ enum class UniqueParameterType( }, /** [UniqueType.DamageUnitsPlunder] and others near that one */ - PlunderableStatName("plunderableStat", "Gold", "All the following stats can be plundered: `Gold`, `Science`, `Culture`, `Faith`") { + CivWideStatName("civWideStat", "Gold", "All the following stats have civ-wide fields: `Gold`, `Science`, `Culture`, `Faith`") { private val knownValues = Stat.statsWithCivWideField.map { it.name }.toSet() override fun getErrorSeverity( parameterText: String, diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 28431e3100..c0f1214ff3 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -193,9 +193,11 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: BuyBuildingsByProductionCost("May buy [buildingFilter] buildings with [stat] for [amount] times their normal Production cost", UniqueTarget.FollowerBelief, UniqueTarget.Global), - // ToDo: Unify + @Deprecated("As of 4.1.14", ReplaceWith("Enables conversion of city production to [Gold]")) EnablesGoldProduction("Enables conversion of city production to gold", UniqueTarget.Global), + @Deprecated("s of 4.1.14", ReplaceWith("Enables conversion of city production to [Science]")) EnablesScienceProduction("Enables conversion of city production to science", UniqueTarget.Global), + EnablesCivWideStatProduction("Enables conversion of city production to [civWideStat]", UniqueTarget.Global), BuyItemsDiscount("[stat] cost of purchasing items in cities [relativeAmount]%", UniqueTarget.Global, UniqueTarget.FollowerBelief), BuyBuildingsDiscount("[stat] cost of purchasing [buildingFilter] buildings [relativeAmount]%", UniqueTarget.Global, UniqueTarget.FollowerBelief), @@ -227,7 +229,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: EnablesConstructionOfSpaceshipParts("Enables construction of Spaceship parts", UniqueTarget.Global), EnemyLandUnitsSpendExtraMovement("Enemy land units must spend 1 extra movement point when inside your territory (obsolete upon Dynamite)", UniqueTarget.Global), + @Deprecated("s of 4.1.14", ReplaceWith("Production to [Science] conversion in cities changed by [33]%")) ProductionToScienceConversionBonus("Production to science conversion in cities increased by 33%", UniqueTarget.Global), + ProductionToCivWideStatConversionBonus("Production to [civWideStat] conversion in cities changed by [relativeAmount]%", UniqueTarget.Global), // Misc national uniques NotifiedOfBarbarianEncampments("Notified of new Barbarian encampments", UniqueTarget.Global), @@ -490,10 +494,10 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: UnitUpgradeCost("[relativeAmount]% Gold cost of upgrading", UniqueTarget.Unit, UniqueTarget.Global), GreatPersonEarnedFaster("[greatPerson] is earned [relativeAmount]% faster", UniqueTarget.Unit, UniqueTarget.Global), - DamageUnitsPlunder("Earn [amount]% of the damage done to [combatantFilter] units as [plunderableStat]", UniqueTarget.Unit, UniqueTarget.Global), - CaptureCityPlunder("Upon capturing a city, receive [amount] times its [stat] production as [plunderableStat] immediately", UniqueTarget.Unit, UniqueTarget.Global), - KillUnitPlunder("Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [plunderableStat]", UniqueTarget.Unit, UniqueTarget.Global), - KillUnitPlunderNearCity("Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [plunderableStat] when killed within 4 tiles of a city following this religion", UniqueTarget.FollowerBelief), + DamageUnitsPlunder("Earn [amount]% of the damage done to [combatantFilter] units as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), + CaptureCityPlunder("Upon capturing a city, receive [amount] times its [stat] production as [civWideStat] immediately", UniqueTarget.Unit, UniqueTarget.Global), + KillUnitPlunder("Earn [amount]% of killed [mapUnitFilter] unit's [costOrStrength] as [civWideStat]", UniqueTarget.Unit, UniqueTarget.Global), + KillUnitPlunderNearCity("Earn [amount]% of [mapUnitFilter] unit's [costOrStrength] as [civWideStat] when killed within 4 tiles of a city following this religion", UniqueTarget.FollowerBelief), KillUnitCapture("May capture killed [mapUnitFilter] units", UniqueTarget.Unit), FlatXPGain("[amount] XP gained from combat", UniqueTarget.Unit, UniqueTarget.Global), diff --git a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt index b91f9e64cb..22a7d8ad13 100644 --- a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt @@ -444,6 +444,8 @@ class CityConstructionsTable(private val cityScreen: CityScreen) { is BaseUnit -> UncivSound.Promote PerpetualConstruction.gold -> UncivSound.Coin PerpetualConstruction.science -> UncivSound.Paper + PerpetualConstruction.culture -> UncivSound.Policy + PerpetualConstruction.faith -> UncivSound.Choir else -> UncivSound.Click } } diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt index e734a28c35..32250dad96 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionInfoTable.kt @@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.UncivGame import com.unciv.logic.city.IConstruction import com.unciv.logic.city.PerpetualConstruction +import com.unciv.logic.city.PerpetualStatConversion import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.IRulesetObject import com.unciv.models.ruleset.unit.BaseUnit @@ -63,7 +64,7 @@ class ConstructionInfoTable(val cityScreen: CityScreen): Table() { val description = when (construction) { is BaseUnit -> construction.getDescription(city) is Building -> construction.getDescription(city, true) - is PerpetualConstruction -> construction.description.replace("[rate]", "[${construction.getConversionRate(city)}]").tr() + is PerpetualStatConversion -> construction.description.replace("[rate]", "[${construction.getConversionRate(city)}]").tr() else -> "" // Should never happen }