diff --git a/android/assets/jsons/Civ V - Vanilla/Beliefs.json b/android/assets/jsons/Civ V - Vanilla/Beliefs.json index 5ae66902ae..c54d7e2acf 100644 --- a/android/assets/jsons/Civ V - Vanilla/Beliefs.json +++ b/android/assets/jsons/Civ V - Vanilla/Beliefs.json @@ -175,5 +175,37 @@ "name": "Swords into Ploughshares", "type": "Follower", "uniques": ["[+15]% growth [in this city] when not at war"] - } + }, +///////////////////////////////////////// Founder beliefs ////////////////////////////////////////// + + { + "name": "Ceremonial Burial", + "type": "Founder", + "uniques": ["[+1 Happiness] for each global city following this religion"] + }, + { + "name": "Church Property", + "type": "Founder", + "uniques": ["[+2 Gold] for each global city following this religion"] + }, + { + "name": "Initiation Rites", + "type": "Founder", + "uniques": ["[+100 Gold] when a city adopts this religion for the first time (modified by game speed)"] + }, + // Missing: Interfaith Dialogue (requires followers) + { + "name": "Papal Primacy", + "type": "Founder", + "uniques": ["Resting point for influence with City-States following this religion [+15]"] + }, + // Missing: Peace Loving (requires followers) + { + "name": "Pilgrimage", + "type": "Founder", + "uniques": ["[+2 Faith] for each global city following this religion"] + }, + // Missing: Tithe (requires followers) + // Missing: World Churhc (requires followers) ] + diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 219ef27937..a0819088f3 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -530,7 +530,11 @@ Our [name] took [tileDamage] tile damage = [civName] has adopted the [policyName] policy = An unknown civilization has adopted the [policyName] policy = Our influence with City-States has started dropping faster! = - +You gained [Stats] as your religion was spread to [cityName] = +You gained [Stats] as your religion was spread to an unknown city = +Your city [cityName] was converted to [religionName]! = + + # World Screen UI Working... = @@ -1152,4 +1156,4 @@ in all cities with a garrison = Only available after [] turns = This Unit upgrades for free = - +[stats] when a city adopts this religion for the first time = diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 1abd571bf4..43d04e6d3d 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -92,11 +92,9 @@ class CityInfo { val startingEra = civInfo.gameInfo.gameParameters.startingEra addStartingBuildings(civInfo, startingEra) - - + expansion.reset() - tryUpdateRoadStatus() val tile = getCenterTile() @@ -106,6 +104,10 @@ class CityInfo { tile.improvement = null tile.improvementInProgress = null + if (civInfo.religionManager.religion != null && civInfo.religionManager.religion!!.isPantheon()) { + religion.addPressure(civInfo.religionManager.religion!!.name, 100) + } + val ruleset = civInfo.gameInfo.ruleSet workedTiles = hashSetOf() //reassign 1st working tile if (startingEra in ruleset.eras) @@ -204,6 +206,7 @@ class CityInfo { toReturn.population = population.clone() toReturn.cityConstructions = cityConstructions.clone() toReturn.expansion = expansion.clone() + toReturn.religion = religion.clone() toReturn.tiles = tiles toReturn.workedTiles = workedTiles toReturn.lockedTiles = lockedTiles @@ -214,7 +217,6 @@ class CityInfo { toReturn.turnAcquired = turnAcquired toReturn.isPuppet = isPuppet toReturn.isOriginalCapital = isOriginalCapital - toReturn.religion = CityInfoReligionManager().apply { putAll(religion) } return toReturn } @@ -431,7 +433,7 @@ class CityInfo { cityStats.cityInfo = this cityConstructions.cityInfo = this cityConstructions.setTransients() - religion.cityInfo = this + religion.setTransients(this) } fun startTurn() { diff --git a/core/src/com/unciv/logic/city/CityReligion.kt b/core/src/com/unciv/logic/city/CityReligion.kt index f94db989b9..d173887da5 100644 --- a/core/src/com/unciv/logic/city/CityReligion.kt +++ b/core/src/com/unciv/logic/city/CityReligion.kt @@ -1,13 +1,33 @@ package com.unciv.logic.city +import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.civilization.NotificationIcon import com.unciv.models.Counter import com.unciv.models.ruleset.Unique +import com.unciv.models.stats.Stats import kotlin.math.roundToInt -class CityInfoReligionManager: Counter() { +class CityInfoReligionManager { @Transient lateinit var cityInfo: CityInfo + + // This needs to be kept track of for the + // "[Stats] when a city adopts this religion for the first time" unique + val religionsAtSomePointAdopted: HashSet = hashSetOf() + private val pressures: Counter = Counter() + + fun clone(): CityInfoReligionManager { + val toReturn = CityInfoReligionManager() + toReturn.religionsAtSomePointAdopted.addAll(religionsAtSomePointAdopted) + toReturn.pressures.putAll(pressures) + return toReturn + } + + fun setTransients(cityInfo: CityInfo) { + this.cityInfo = cityInfo + } + fun getUniques(): Sequence { val majorityReligion = getMajorityReligion() if (majorityReligion == null) return sequenceOf() @@ -18,12 +38,45 @@ class CityInfoReligionManager: Counter() { return getUniques().filter { it.placeholderText == unique } } + fun clearAllPressures() { + pressures.clear() + } + + fun addPressure(religionName: String, amount: Int) { + val oldMajorityReligion = getMajorityReligion() + pressures.add(religionName, amount) + val newMajorityReligion = getMajorityReligion() + if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) { + triggerReligionAdoption(newMajorityReligion) + } + } + + private fun triggerReligionAdoption(newMajorityReligion: String) { + cityInfo.civInfo.addNotification("Your city [${cityInfo.name}] was converted to [$newMajorityReligion]!", cityInfo.location, NotificationIcon.Faith) + if (newMajorityReligion in religionsAtSomePointAdopted) return + + val religionOwningCiv = cityInfo.civInfo.gameInfo.getCivilization(cityInfo.civInfo.gameInfo.religions[newMajorityReligion]!!.foundingCivName) + for (unique in cityInfo.civInfo.gameInfo.religions[newMajorityReligion]!!.getFounderUniques()) { + val statsGranted = when (unique.placeholderText) { + "[] when a city adopts this religion for the first time (modified by game speed)" -> unique.stats.times(cityInfo.civInfo.gameInfo.gameParameters.gameSpeed.modifier) + "[] when a city adopts this religion for the first time" -> unique.stats + else -> continue + } + religionOwningCiv.addStats(statsGranted) + if (cityInfo.location in religionOwningCiv.exploredTiles) + religionOwningCiv.addNotification("You gained [$statsGranted] as your religion was spread to [${cityInfo.name}]", cityInfo.location, NotificationIcon.Faith) + else + religionOwningCiv.addNotification("You gained [$statsGranted] as your religion was spread to an unknown city", NotificationIcon.Faith) + } + religionsAtSomePointAdopted.add(newMajorityReligion) + } + fun getNumberOfFollowers(): Counter { - val totalInfluence = values.sum() + val totalInfluence = pressures.values.sum() val population = cityInfo.population.population if (totalInfluence > 100 * population) { val toReturn = Counter() - for ((key, value) in this) + for ((key, value) in pressures) if (value > 100) toReturn.add(key, value / 100) return toReturn @@ -31,7 +84,7 @@ class CityInfoReligionManager: Counter() { val toReturn = Counter() - for ((key, value) in this) { + for ((key, value) in pressures) { val percentage = value.toFloat() / totalInfluence val relativePopulation = (percentage * population).roundToInt() toReturn.add(key, relativePopulation) @@ -57,7 +110,11 @@ class CityInfoReligionManager: Counter() { for (city in allCitiesWithin10Tiles) { val majorityReligionOfCity = city.religion.getMajorityReligion() if (majorityReligionOfCity == null) continue - else add(majorityReligionOfCity, 6) // todo - when holy cities are implemented, *5 + else addPressure( + majorityReligionOfCity, + if (city.isHolyCity()) 30 + else 6 + ) } } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index aa05c86fc5..d62f809b8c 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -108,6 +108,18 @@ class CivInfoStats(val civInfo: CivilizationInfo) { statMap["Transportation upkeep"] = Stats().apply { gold = -getTransportationUpkeep().toFloat() } statMap["Unit upkeep"] = Stats().apply { gold = -getUnitMaintenance().toFloat() } + if (civInfo.religionManager.religion != null) { + for (unique in civInfo.religionManager.religion!!.getFounderBeliefs().flatMap { it.uniqueObjects }) { + if (unique.placeholderText == "[] for each global city following this religion") { + statMap.add( + "Religion", + unique.stats.times(civInfo.religionManager.numberOfCitiesFollowingThisReligion().toFloat()) + ) + } + } + } + + if (civInfo.hasUnique("50% of excess happiness added to culture towards policies")) { val happiness = civInfo.getHappiness() if (happiness > 0) statMap.add("Policies", Stats().apply { culture = happiness / 2f }) @@ -185,6 +197,19 @@ class CivInfoStats(val civInfo: CivilizationInfo) { statMap["Natural Wonders"] = happinessPerNaturalWonder * civInfo.naturalWonders.size + if (civInfo.religionManager.religion != null) { + statMap["Religion"] = 0f + for (unique in civInfo.religionManager.religion!!.getFounderBeliefs().flatMap { it.uniqueObjects }) { + if (unique.placeholderText == "[] for each global city following this religion") { + statMap["Religion"] = + statMap["Religion"]!! + + unique.stats.happiness * civInfo.religionManager.numberOfCitiesFollowingThisReligion().toFloat() + } + } + if (statMap["Religion"] == 0f) + statMap.remove("Religion") + } + //From city-states for (otherCiv in civInfo.getKnownCivs()) { if (otherCiv.isCityState() && otherCiv.cityStateType == CityStateType.Mercantile diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index f19d2a70de..44b45cd0f1 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -262,7 +262,9 @@ class CivilizationInfo { } + policies.policyUniques.getUniques(uniqueTemplate) + tech.techUniques.getUniques(uniqueTemplate) + - temporaryUniques.filter { it.first.placeholderText == uniqueTemplate }.map { it.first } + temporaryUniques.filter { it.first.placeholderText == uniqueTemplate }.map { it.first } + + if (religionManager.religion != null) religionManager.religion!!.getFounderUniques().asSequence() + else sequenceOf() } //region Units @@ -712,6 +714,13 @@ class CivilizationInfo { } } + /** Rounds each of the stats down to the nearest integer */ + fun addStats(stats: Stats) { + for (stat in stats.toHashMap()) { + addStat(stat.key, stat.value.toInt()) + } + } + fun getStatReserve(stat: Stat): Int { return when (stat) { Stat.Culture -> policies.storedCulture diff --git a/core/src/com/unciv/logic/civilization/ReligionManager.kt b/core/src/com/unciv/logic/civilization/ReligionManager.kt index a159329b8a..7420ebd0bc 100644 --- a/core/src/com/unciv/logic/civilization/ReligionManager.kt +++ b/core/src/com/unciv/logic/civilization/ReligionManager.kt @@ -87,8 +87,9 @@ class ReligionManager { religion = Religion(belief.name, civInfo.gameInfo, civInfo.civName) religion!!.followerBeliefs.add(belief.name) civInfo.gameInfo.religions[belief.name] = religion!! - // This should later be changed when religions can have multiple beliefs - civInfo.getCapital().religion[belief.name] = 100 // Capital is religious, other cities are not + // ToDo: This should later be changed when religions can have multiple beliefs + civInfo.getCapital().religion.clearAllPressures() + civInfo.getCapital().religion.addPressure(belief.name, 100) // Capital is religious, other cities are not religionState = ReligionState.Pantheon } @@ -102,6 +103,7 @@ class ReligionManager { private fun canGenerateProphet(): Boolean { if (religion == null || religionState == ReligionState.None) return false // First get a pantheon, then we'll talk about a real religion if (storedFaith < faithForNextGreatProphet()) return false + if (!civInfo.isMajorCiv()) return false // In the base game, great prophets shouldn't generate anymore starting from the industrial era // This is difficult to implement in the current codebase, probably requires an additional variable in eras.json return true @@ -123,53 +125,60 @@ class ReligionManager { } } - fun mayUseGreatProphetAtAll(prophet: MapUnit): Boolean { + fun mayFoundReligionAtAll(prophet: MapUnit): Boolean { if (religion == null) return false // First found a pantheon if (religion!!.isMajorReligion()) return false // Already created a major religion if (prophet.abilityUsedCount["Religion Spread"] != 0) return false // Already used its power for other things + if (!civInfo.isMajorCiv()) return false // Only major civs may use religion val foundedReligionsCount = civInfo.gameInfo.civilizations.count { it.religionManager.religion != null && it.religionManager.religion!!.isMajorReligion() } if (foundedReligionsCount >= civInfo.gameInfo.civilizations.count { it.isMajorCiv() } / 2 + 1) - return false // Too bad, too many religions have already been founded. + return false // Too bad, too many religions have already been founded if (foundedReligionsCount >= civInfo.gameInfo.ruleSet.religions.count()) - return false - // Mod maker did not provide enough religions for the amount of civs present + return false // Mod maker did not provide enough religions for the amount of civs present + + if (foundedReligionsCount >= civInfo.gameInfo.ruleSet.beliefs.values.count { it.type == BeliefType.Follower }) + return false // Mod maker did not provide enough follower beliefs + + if (foundedReligionsCount >= civInfo.gameInfo.ruleSet.beliefs.values.count { it.type == BeliefType.Founder }) + return false // Mod maker did not provide enough founder beliefs return true } - fun mayUseGreatProphetNow(prophet: MapUnit): Boolean { - if (!mayUseGreatProphetAtAll(prophet)) return false + fun mayFoundReligionNow(prophet: MapUnit): Boolean { + if (!mayFoundReligionAtAll(prophet)) return false if (!prophet.getTile().isCityCenter()) return false return true } fun useGreatProphet(prophet: MapUnit) { - if (!mayUseGreatProphetNow(prophet)) return // How did you do this? + if (!mayFoundReligionNow(prophet)) return // How did you do this? religionState = ReligionState.FoundingReligion foundingCityId = prophet.getTile().getCity()!!.id } - fun foundReligion(iconName: String, name: String, founderBelief: String, followerBeliefs: List) { + fun foundReligion(iconName: String, name: String, founderBelief: List, followerBeliefs: List) { val newReligion = Religion(name, civInfo.gameInfo, civInfo.civName) newReligion.iconName = iconName if (religion != null) { newReligion.followerBeliefs.addAll(religion!!.followerBeliefs) } newReligion.followerBeliefs.addAll(followerBeliefs) - newReligion.founderBeliefs.add(founderBelief) + newReligion.founderBeliefs.addAll(founderBelief) newReligion.holyCityId = foundingCityId religion = newReligion civInfo.gameInfo.religions[name] = newReligion religionState = ReligionState.Religion val holyCity = civInfo.cities.firstOrNull { it.id == newReligion.holyCityId }!! - holyCity.religion.clear() - holyCity.religion[name] = 100 + // ToDo: check this when implementing followers + holyCity.religion.clearAllPressures() + holyCity.religion.addPressure(name, 100) foundingCityId = null } diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index ebecb9cc6f..299c3dc63a 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -193,8 +193,14 @@ class DiplomacyManager() { // To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different. fun getCityStateInfluenceRestingPoint(): Float { var restingPoint = 0f + for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []")) restingPoint += unique.params[0].toInt() + + for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States following this religion []")) + if (otherCiv().religionManager.religion?.name == civInfo.getCapital().religion.getMajorityReligion()) + restingPoint += unique.params[0].toInt() + if (diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5 return restingPoint } diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index 28163dfd65..43391daf6a 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -42,7 +42,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { return counter } - var greatPersonPoints= Counter() + var greatPersonPoints = Counter() /** Extra cost percentage when purchasing */ override var hurryCostModifier = 0 diff --git a/core/src/com/unciv/ui/pickerscreens/FoundReligionPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/FoundReligionPickerScreen.kt index ef0987be20..7b932456db 100644 --- a/core/src/com/unciv/ui/pickerscreens/FoundReligionPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/FoundReligionPickerScreen.kt @@ -46,14 +46,13 @@ class FoundReligionPickerScreen ( middlePanes.add(ScrollPane(rightBeliefsToChoose)) topTable.add(topReligionIcons).row() - // commented out, as the middle panes will always be empty for now, and this will create a random line otherwise topTable.addSeparator() topTable.add(middlePanes) rightSideButton.label = "Choose a religion".toLabel() rightSideButton.onClick(UncivSound.Choir) { choosingCiv.religionManager.foundReligion( - iconName!!, religionName!!, "" /**chosenFollowerBeliefs.map {it!!.name} */, chosenFollowerBeliefs.map { it!!.name} + iconName!!, religionName!!, chosenFounderBeliefs.map {it!!.name}, chosenFollowerBeliefs.map { it!!.name} ) UncivGame.Current.setWorldScreen() } @@ -61,8 +60,8 @@ class FoundReligionPickerScreen ( private fun checkAndEnableRightSideButton() { if (religionName == null) return - println(chosenFollowerBeliefs) if (chosenFollowerBeliefs.any { it == null }) return + if (chosenFounderBeliefs.any { it == null }) return // check if founder belief chosen rightSideButton.enable() } @@ -113,21 +112,32 @@ class FoundReligionPickerScreen ( for (newFollowerBelief in chosenFollowerBeliefs.withIndex()) { val newFollowerBeliefButton = - if (newFollowerBelief.value == null) emptyBeliefButton("Follower") + if (newFollowerBelief.value == null) emptyBeliefButton(BeliefType.Follower) else convertBeliefToButton(newFollowerBelief.value!!) leftChosenBeliefs.add(newFollowerBeliefButton).pad(10f).row() newFollowerBeliefButton.onClick { - loadRightTable("Follower", newFollowerBelief.index) + loadRightTable(BeliefType.Follower, newFollowerBelief.index) + } + } + + for (newFounderBelief in chosenFounderBeliefs.withIndex()) { + val newFounderBeliefButton = + if (newFounderBelief.value == null) emptyBeliefButton(BeliefType.Founder) + else convertBeliefToButton(newFounderBelief.value!!) + + leftChosenBeliefs.add(newFounderBeliefButton).pad(10f).row() + newFounderBeliefButton.onClick { + loadRightTable(BeliefType.Founder, newFounderBelief.index) } } } - private fun loadRightTable(beliefType: String, leftButtonIndex: Int) { + private fun loadRightTable(beliefType: BeliefType, leftButtonIndex: Int) { rightBeliefsToChoose.clear() val availableBeliefs = gameInfo.ruleSet.beliefs.values .filter { - it.type.name == beliefType + it.type == beliefType && gameInfo.religions.values.none { religion -> religion.hasBelief(it.name) } @@ -136,8 +146,8 @@ class FoundReligionPickerScreen ( for (belief in availableBeliefs) { val beliefButton = convertBeliefToButton(belief) beliefButton.onClick { - if (beliefType == BeliefType.Follower.name) chosenFollowerBeliefs[leftButtonIndex] = belief - else if (beliefType == BeliefType.Founder.name) chosenFounderBeliefs[leftButtonIndex] = belief + if (beliefType == BeliefType.Follower) chosenFollowerBeliefs[leftButtonIndex] = belief + else if (beliefType == BeliefType.Founder) chosenFounderBeliefs[leftButtonIndex] = belief updateLeftTable() checkAndEnableRightSideButton() } @@ -153,9 +163,9 @@ class FoundReligionPickerScreen ( return Button(contentsTable, skin) } - private fun emptyBeliefButton(beliefType: String): Button { + private fun emptyBeliefButton(beliefType: BeliefType): Button { val contentsTable = Table() - contentsTable.add("Choose a [$beliefType] belief!".toLabel()) + contentsTable.add("Choose a [${beliefType.name}] belief!".toLabel()) return Button(contentsTable, skin) } } diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 47040fccb0..6bb753913b 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -450,34 +450,37 @@ object UnitActions { private fun addFoundReligionAction(unit: MapUnit, actionList: ArrayList, tile: TileInfo) { if (!unit.hasUnique("May found a religion")) return // should later also include enhance religion - if (!unit.civInfo.religionManager.mayUseGreatProphetAtAll(unit)) return + if (!unit.civInfo.religionManager.mayFoundReligionAtAll(unit)) return actionList += UnitAction(UnitActionType.FoundReligion, action = { addGoldPerGreatPersonUsage(unit.civInfo) unit.civInfo.religionManager.useGreatProphet(unit) unit.destroy() - }.takeIf { unit.civInfo.religionManager.mayUseGreatProphetNow(unit) } + }.takeIf { unit.civInfo.religionManager.mayFoundReligionNow(unit) } ) } private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList, tile: TileInfo) { if (!unit.hasUnique("Can spread religion [] times")) return - if (unit.religion == null) return + if (unit.religion == null || unit.civInfo.gameInfo.religions[unit.religion]!!.isPantheon()) return val maxReligionSpreads = unit.maxReligionSpreads() if (!unit.abilityUsedCount.containsKey("Religion Spread")) return // This should be impossible anyways, but just in case if (maxReligionSpreads <= unit.abilityUsedCount["Religion Spread"]!!) return val city = tile.getCity() + if (city == null) return actionList += UnitAction(UnitActionType.SpreadReligion, title = "Spread [${unit.religion!!}]", action = { unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1 - city!!.religion[unit.religion!!] = 100 + // ToDo: implement followers + city.religion.clearAllPressures() + city.religion.addPressure(unit.religion!!, 100) unit.currentMovement = 0f if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) { addGoldPerGreatPersonUsage(unit.civInfo) unit.destroy() } - }.takeIf { unit.currentMovement > 0 && city != null && city.civInfo == unit.civInfo } // For now you can only convert your own cities + }.takeIf { unit.currentMovement > 0 } ) }