From c40b6159dff18518c39955f6a0895cae3a86cd70 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Sat, 4 Mar 2023 18:20:23 +0100 Subject: [PATCH] Better Religion info and some moddability (#8807) * Make maximum number of religions moddable * Explain remaining religion count in Empire Overview --- .../jsons/translations/German.properties | 7 ++- .../jsons/translations/template.properties | 7 ++- .../civilization/managers/ReligionManager.kt | 38 +++++++++--- core/src/com/unciv/models/ModConstants.kt | 6 ++ .../overviewscreen/ReligionOverviewTable.kt | 20 +++++- docs/Other/Miscellaneous-JSON-files.md | 62 ++++++++++--------- 6 files changed, 96 insertions(+), 44 deletions(-) diff --git a/android/assets/jsons/translations/German.properties b/android/assets/jsons/translations/German.properties index 969a045765..42a133bed2 100644 --- a/android/assets/jsons/translations/German.properties +++ b/android/assets/jsons/translations/German.properties @@ -1520,7 +1520,12 @@ Followers of this religion: = Anhänger dieser Religion: Click an icon to see the stats of this religion = Klicke auf ein Icon, um die Statistiken dieser Religion anzuzeigen Religion: Off = Religion: Aus Minimal Faith required for\nthe next [Great Prophet]: = Mindest-Glaubenspunkte für\nden nächsten [Great Prophet]: -Religions to be founded: = Noch zu gründende Religionen: +Religions to be founded: [amount] = Noch zu gründende Religionen: [amount] +Available religion symbols = Verfügbare Religions-Symbole +Number of civilizations * [amount] + [amount2] = Maximum nach ([amount]*Zivilisationen)+[amount2] +Religions already founded = Bereits gegründete Religionen +Available founder beliefs = Verfügbare Gründer-Glaubenssätze +Available follower beliefs = Verfügbare Anhänger-Glaubenssätze Religious status: = Religions-Status: None = Keine diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 38957edc28..4f27aea02f 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1521,7 +1521,12 @@ Followers of this religion: = Click an icon to see the stats of this religion = Religion: Off = Minimal Faith required for\nthe next [Great Prophet]: = -Religions to be founded: = +Religions to be founded: [amount] = +Available religion symbols = +Number of civilizations * [amount] + [amount2] = +Religions already founded = +Available founder beliefs = +Available follower beliefs = Religious status: = None = diff --git a/core/src/com/unciv/logic/civilization/managers/ReligionManager.kt b/core/src/com/unciv/logic/civilization/managers/ReligionManager.kt index c332de79c4..fd92dcb07c 100644 --- a/core/src/com/unciv/logic/civilization/managers/ReligionManager.kt +++ b/core/src/com/unciv/logic/civilization/managers/ReligionManager.kt @@ -186,20 +186,24 @@ class ReligionManager : IsPartOfGameInfoSerialization { } } - private fun maxNumberOfReligions() = min( - civInfo.gameInfo.ruleset.religions.size, - civInfo.gameInfo.civilizations.count { it.isMajorCiv() } / 2 + 1 - ) + private fun maxNumberOfReligions(): Int { + val gameInfo = civInfo.gameInfo + val ruleset = gameInfo.ruleset + val multiplier = ruleset.modOptions.constants.religionLimitMultiplier + val base = ruleset.modOptions.constants.religionLimitBase + val civCount = gameInfo.civilizations.count { it.isMajorCiv() } + return min(ruleset.religions.size, base + (civCount * multiplier).toInt()) + } + + /** Calculates the number of religions that are already founded */ + private fun foundedReligionsCount() = civInfo.gameInfo.civilizations.count { + it.religionManager.religion != null && it.religionManager.religionState >= ReligionState.Religion + } /** Calculates the amount of religions that can still be founded */ fun remainingFoundableReligions(): Int { - val gameInfo = civInfo.gameInfo - val foundedReligionsCount = gameInfo.civilizations.count { - it.religionManager.religion != null && it.religionManager.religionState >= ReligionState.Religion - } - // count the number of foundable religions left given defined ruleset religions and number of civs in game - val maxNumberOfAdditionalReligions = maxNumberOfReligions() - foundedReligionsCount + val maxNumberOfAdditionalReligions = maxNumberOfReligions() - foundedReligionsCount() val availableBeliefsToFound = min( numberOfBeliefsAvailable(BeliefType.Follower), @@ -209,6 +213,20 @@ class ReligionManager : IsPartOfGameInfoSerialization { return min(maxNumberOfAdditionalReligions, availableBeliefsToFound) } + /** Get info breaking down the reasons behind the result of [remainingFoundableReligions] */ + fun remainingFoundableReligionsBreakdown() = sequence { + val gameInfo = civInfo.gameInfo + val ruleset = gameInfo.ruleset + val multiplier = ruleset.modOptions.constants.religionLimitMultiplier + val base = ruleset.modOptions.constants.religionLimitBase + val civCount = gameInfo.civilizations.count { it.isMajorCiv() } + yield("Available religion symbols" to ruleset.religions.size) + yield("Number of civilizations * [$multiplier] + [$base]" to base + (civCount * multiplier).toInt()) + yield("Religions already founded" to foundedReligionsCount()) + yield("Available founder beliefs" to numberOfBeliefsAvailable(BeliefType.Founder)) + yield("Available follower beliefs" to numberOfBeliefsAvailable(BeliefType.Follower)) + } + fun numberOfBeliefsAvailable(type: BeliefType): Int { val gameInfo = civInfo.gameInfo val numberOfBeliefs = if (type == BeliefType.Any) gameInfo.ruleset.beliefs.values.count() diff --git a/core/src/com/unciv/models/ModConstants.kt b/core/src/com/unciv/models/ModConstants.kt index dca97c58b7..0be0b24178 100644 --- a/core/src/com/unciv/models/ModConstants.kt +++ b/core/src/com/unciv/models/ModConstants.kt @@ -62,6 +62,10 @@ class ModConstants { var minRiverLength = 5 var maxRiverLength = 666 // Do not set to less than the maximal map radius + // Factors in formula for Maximum Number of foundable Religions + var religionLimitBase = 1 + var religionLimitMultiplier = 0.5f + fun merge(other: ModConstants) { if (other.maxXPfromBarbarians != defaults.maxXPfromBarbarians) maxXPfromBarbarians = other.maxXPfromBarbarians if (other.cityStrengthBase != defaults.cityStrengthBase) cityStrengthBase = other.cityStrengthBase @@ -82,6 +86,8 @@ class ModConstants { if (other.riverCountMultiplier != defaults.riverCountMultiplier) riverCountMultiplier = other.riverCountMultiplier if (other.minRiverLength != defaults.minRiverLength) minRiverLength = other.minRiverLength if (other.maxRiverLength != defaults.maxRiverLength) maxRiverLength = other.maxRiverLength + if (other.religionLimitBase != defaults.religionLimitBase) religionLimitBase = other.religionLimitBase + if (other.religionLimitMultiplier != defaults.religionLimitMultiplier) religionLimitMultiplier = other.religionLimitMultiplier } companion object { diff --git a/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt b/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt index 0c3e6f18d0..02122e946b 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt @@ -12,6 +12,7 @@ import com.unciv.models.Religion import com.unciv.models.ruleset.Belief import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.tr +import com.unciv.ui.components.ExpanderTab import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen import com.unciv.ui.screens.civilopediascreen.MarkupRenderer import com.unciv.ui.images.ImageGetter @@ -66,6 +67,22 @@ class ReligionOverviewTab( } private fun Table.addCivSpecificStats() { + // This is not Civ-specific, but -oh well- still fits + val remaining = viewingPlayer.religionManager.remainingFoundableReligions() + val minWidth = max(religionButtonLabel.prefWidth, overviewScreen.stage.width / 3) + val headerText = "Religions to be founded: [$remaining]" + val religionCountExpander = ExpanderTab( + headerText, fontSize = 18, headerPad = 5f, + startsOutOpened = false, defaultPad = 0f, expanderWidth = minWidth + ) { + it.defaults().padTop(10f) + for ((text, num) in viewingPlayer.religionManager.remainingFoundableReligionsBreakdown()) { + it.add(text.toLabel()) + it.add(num.toString().toLabel(alignment = Align.right)).right().row() + } + } + add(religionCountExpander).colspan(2).growX().row() + if (viewingPlayer.religionManager.canGenerateProphet()) { add("Minimal Faith required for\nthe next [great prophet equivalent]:" .fillPlaceholders(viewingPlayer.religionManager.getGreatProphetEquivalent()!!) @@ -77,9 +94,6 @@ class ReligionOverviewTab( ).right().row() } - add("Religions to be founded:".toLabel()) - add((viewingPlayer.religionManager.remainingFoundableReligions()).toLabel()).right().row() - add("Religious status:".toLabel()).left() add(viewingPlayer.religionManager.religionState.toString().toLabel()).right().row() } diff --git a/docs/Other/Miscellaneous-JSON-files.md b/docs/Other/Miscellaneous-JSON-files.md index a0e120d2d9..de55ae8138 100644 --- a/docs/Other/Miscellaneous-JSON-files.md +++ b/docs/Other/Miscellaneous-JSON-files.md @@ -129,52 +129,56 @@ Stored in ModOptions.constants, this is a collection of constants used internall This is the only structure that is _merged_ field by field from mods, not overwritten, so you can change XP from Barbarians in one mod and city distance in another. In case of conflicts, there is no guarantee which mod wins, only that _default_ values are ignored. -| Attribute | Type | Default | Notes | -| --------- | ---- | -------- | ----- | -| maxXPfromBarbarians | Int | 30 | [^A] | -| cityStrengthBase| Float | 8.0 | [^B] | -| cityStrengthPerPop| Float | 0.4 | [^B] | -| cityStrengthFromTechsMultiplier| Float | 5.5 | [^B] | -| cityStrengthFromTechsExponent| Float | 2.8 | [^B] | -| cityStrengthFromTechsFullMultiplier| Float | 1.0 | [^B] | -| cityStrengthFromGarrison| Float | 0.2 | [^B] | -| unitSupplyPerPopulation| Float | 0.5 | [^C] | -| minimalCityDistance| Int | 3 | [^D] | -| minimalCityDistanceOnDifferentContinents| Int | 2 | [^D] | -| unitUpgradeCost | Object | see below | [^J] | -| naturalWonderCountMultiplier| Float | 0.124 | [^E] | -| naturalWonderCountAddedConstant| Float | 0.1 | [^E] | -| ancientRuinCountMultiplier| Float | 0.02 | [^F] | -| maxLakeSize| Int | 10 | [^H] | -| riverCountMultiplier| Float | 0.01 | [^I] | -| minRiverLength| Int | 5 | [^I] | -| maxRiverLength| Int | 666 | [^I] | +| Attribute | Type | Default | Notes | +|------------------------------------------|--------|-----------|-------| +| maxXPfromBarbarians | Int | 30 | [^A] | +| cityStrengthBase | Float | 8.0 | [^B] | +| cityStrengthPerPop | Float | 0.4 | [^B] | +| cityStrengthFromTechsMultiplier | Float | 5.5 | [^B] | +| cityStrengthFromTechsExponent | Float | 2.8 | [^B] | +| cityStrengthFromTechsFullMultiplier | Float | 1.0 | [^B] | +| cityStrengthFromGarrison | Float | 0.2 | [^B] | +| unitSupplyPerPopulation | Float | 0.5 | [^C] | +| minimalCityDistance | Int | 3 | [^D] | +| minimalCityDistanceOnDifferentContinents | Int | 2 | [^D] | +| unitUpgradeCost | Object | see below | [^J] | +| naturalWonderCountMultiplier | Float | 0.124 | [^E] | +| naturalWonderCountAddedConstant | Float | 0.1 | [^E] | +| ancientRuinCountMultiplier | Float | 0.02 | [^F] | +| maxLakeSize | Int | 10 | [^H] | +| riverCountMultiplier | Float | 0.01 | [^I] | +| minRiverLength | Int | 5 | [^I] | +| maxRiverLength | Int | 666 | [^I] | +| religionLimitBase | Int | 1 | [^K] | +| religionLimitMultiplier | Float | 0.5 | [^K] | + Legend: -- [^A]: Max amount of experience that can be gained from combat with barbarians -- [^B]: Formula for city Strength: +- [^A]: Max amount of experience that can be gained from combat with barbarians +- [^B]: Formula for city Strength: Strength = baseStrength + strengthPerPop + strengthFromTiles + ((%techs * multiplier) ^ exponent) * fullMultiplier + (garrisonBonus * garrisonUnitStrength * garrisonUnitHealth/100) + defensiveBuildingStrength where %techs is the percentage of techs in the tech tree that are complete If no techs exist in this ruleset, %techs = 0.5 (=50%) -- [^C]: Formula for Unit Supply: +- [^C]: Formula for Unit Supply: Supply = unitSupplyBase (difficulties.json) unitSupplyPerCity * amountOfCities + (difficulties.json) unitSupplyPerPopulation * amountOfPopulationInAllCities unitSupplyBase and unitSupplyPerCity can be found in difficulties.json unitSupplyBase, unitSupplyPerCity and unitSupplyPerPopulation can also be increased through uniques -- [^D]: The minimal distance that must be between any two cities, not counting the tiles cities are on +- [^D]: The minimal distance that must be between any two cities, not counting the tiles cities are on The number is the amount of tiles between two cities, not counting the tiles the cities are on. e.g. "C__C", where "C" is a tile with a city and "_" is a tile without a city, has a distance of 2. First constant is for cities on the same landmass, the second is for cities on different continents. -- [^E]: NaturalWonderGenerator uses these to determine the number of Natural Wonders to spawn for a given map size. The number scales linearly with map radius: #wonders = radius * naturalWonderCountMultiplier + naturalWonderCountAddedConstant. The defaults effectively mean Tiny - 1, Small - 2, Medium - 3, Large - 4, Huge - 5, Custom radius >=109 - all G&K wonders. -- [^F]: MapGenerator.spreadAncientRuins: number of ruins = suitable tile count * this -- [^H]: MapGenerator.spawnLakesAndCoasts: Water bodies up to this tile count become Lakes -- [^I]: RiverGenerator: river frequency and length bounds -- [^J]: A [UnitUpgradeCost](#UnitUpgradeCost) sub-structure. +- [^E]: NaturalWonderGenerator uses these to determine the number of Natural Wonders to spawn for a given map size. The number scales linearly with map radius: #wonders = radius * naturalWonderCountMultiplier + naturalWonderCountAddedConstant. The defaults effectively mean Tiny - 1, Small - 2, Medium - 3, Large - 4, Huge - 5, Custom radius >=109 - all G&K wonders. +- [^F]: MapGenerator.spreadAncientRuins: number of ruins = suitable tile count * this +- [^H]: MapGenerator.spawnLakesAndCoasts: Water bodies up to this tile count become Lakes +- [^I]: RiverGenerator: river frequency and length bounds +- [^J]: A [UnitUpgradeCost](#UnitUpgradeCost) sub-structure. +- [^K]: Maximum foundable Religions = religionLimitBase + floor(MajorCivCount * religionLimitMultiplier) #### UnitUpgradeCost