Implemented religious pressure (#4863)

* Implemented religious pressure: cities now can have more than one religion in them and religions spread between nearby cities over time.

* Implemented proposed changes

* Implemented requested changes & minor changes I forgot to include last time

* All pantheons not founded by you are now removed when you gain a new city (found this somewhere in the source code of the original, don't know if it's documented anywhere online)
This commit is contained in:
Xander Lenstra 2021-08-15 17:53:01 +02:00 committed by GitHub
parent 344ff85eea
commit 5d249ee673
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 690 additions and 548 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1500,8 +1500,10 @@
"name": "Great Prophet",
"unitType": "Civilian",
"uniques": ["Can construct [Holy site] if it hasn't spread religion yet", "Can spread religion [4] times",
"May found a religion", "Great Person - [Faith]", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
"movement": 2
"May found a religion", "May enter foreign tiles without open borders", "[-1] Visibility Range",
"Great Person - [Faith]", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
"movement": 2,
"religiousStrength": 1000
},
{
"name": "Great General",
@ -1525,9 +1527,11 @@
{
"name": "Missionary",
"unitType": "Civilian",
"uniques": ["Can spread religion [2] times", "Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
"Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
"movement": 4
"uniques": ["Can spread religion [2] times", "May enter foreign tiles without open borders, but loses [250] religious strength each turn it ends there",
"Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
"[-1] Visibility Range", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
"movement": 4,
"religiousStrength": 1000
}
/* Spaceship Parts */

View File

@ -533,6 +533,7 @@ 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]! =
Your [unitName] lost its faith after spending too long inside enemy territory! =
# World Screen UI

View File

@ -63,6 +63,9 @@ object Constants {
const val unitActionParadrop = "Paradrop"
const val futureTech = "Future Tech"
// Easter egg name. Hopefully is to hopefully avoid conflicts when later players can name their own religions.
// This religion name should never be displayed.
const val noReligionName = "The religion of TheLegend27"
const val cancelImprovementOrder = "Cancel improvement order"
const val tutorialPopupNamePrefix = "Tutorial: "

View File

@ -91,7 +91,7 @@ class GameInfo {
fun getCurrentPlayerCivilization() = currentPlayerCiv
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
fun getDifficulty() = difficultyObject
fun getCities() = civilizations.flatMap { it.cities }
fun getCities() = civilizations.asSequence().flatMap { it.cities }
fun getAliveCityStates() = civilizations.filter { it.isAlive() && it.isCityState() }
fun getAliveMajorCivs() = civilizations.filter { it.isAlive() && it.isMajorCiv() }
//endregion

View File

@ -485,7 +485,8 @@ class CityInfo {
}
} else population.nextTurn(foodForNextTurn())
// if (civInfo.gameInfo.hasReligionEnabled()) religion.getAffectedBySurroundingCities()
// This should go after the population change, as that might impact the amount of followers in this city
if (civInfo.gameInfo.hasReligionEnabled()) religion.endTurn()
if (this in civInfo.cities) { // city was not destroyed
health = min(health + 20, getMaxHealth())
@ -652,7 +653,7 @@ class CityInfo {
}
fun isHolyCity(): Boolean {
return civInfo.gameInfo.religions.values.any { it.holyCityId == id }
return religion.religionThisIsTheHolyCityOf != null
}
fun canBeDestroyed(): Boolean {

View File

@ -215,6 +215,8 @@ class CityInfoConquestFunctions(val city: CityInfo){
cityConstructions.addBuilding(civEquivalentBuilding.name)
}
}
religion.removeUnknownPantheons()
tryUpdateRoadStatus()
}

View File

@ -1,11 +1,10 @@
package com.unciv.logic.city
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.Constants
import com.unciv.logic.civilization.NotificationIcon
import com.unciv.models.Counter
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.Unique
import com.unciv.models.stats.Stats
import kotlin.math.roundToInt
class CityInfoReligionManager {
@Transient
@ -16,16 +15,41 @@ class CityInfoReligionManager {
val religionsAtSomePointAdopted: HashSet<String> = hashSetOf()
private val pressures: Counter<String> = Counter()
// `getNumberOfFollowers()` was called a surprisingly large amount of time, so caching it feels useful
@Transient
private val followers: Counter<String> = Counter()
private val pressureFromAdjacentCities: Int by lazy {
when (cityInfo.civInfo.gameInfo.gameParameters.gameSpeed) {
GameSpeed.Quick -> 9
GameSpeed.Standard -> 6
GameSpeed.Epic -> 4
GameSpeed.Marathon -> 2
}
}
var religionThisIsTheHolyCityOf: String? = null
init {
clearAllPressures()
}
fun clone(): CityInfoReligionManager {
val toReturn = CityInfoReligionManager()
toReturn.religionsAtSomePointAdopted.addAll(religionsAtSomePointAdopted)
toReturn.pressures.putAll(pressures)
toReturn.followers.putAll(followers)
toReturn.religionThisIsTheHolyCityOf = religionThisIsTheHolyCityOf
return toReturn
}
fun setTransients(cityInfo: CityInfo) {
this.cityInfo = cityInfo
updateNumberOfFollowers()
}
fun endTurn() {
getAffectedBySurroundingCities()
}
fun getUniques(): Sequence<Unique> {
@ -40,14 +64,31 @@ class CityInfoReligionManager {
fun clearAllPressures() {
pressures.clear()
// We add pressure for following no religion
// Basically used as a failsafe so that there is always some religion,
// and we don't suddenly divide by 0 somewhere
// Should be removed when updating the followers so it never becomes the majority religion,
// `null` is used for that instead.
pressures.add(Constants.noReligionName, 100)
}
fun addPressure(religionName: String, amount: Int) {
val oldMajorityReligion = getMajorityReligion()
fun addPressure(religionName: String, amount: Int, shouldUpdateFollowers: Boolean = true) {
pressures.add(religionName, amount)
val newMajorityReligion = getMajorityReligion()
if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) {
triggerReligionAdoption(newMajorityReligion)
if (shouldUpdateFollowers) {
updateNumberOfFollowers()
}
}
fun updatePressureOnPopulationChange(populationChangeAmount: Int) {
val majorityReligion =
if (getMajorityReligion() != null) getMajorityReligion()!!
else Constants.noReligionName
if (populationChangeAmount > 0) {
addPressure(majorityReligion, 100 * populationChangeAmount)
} else {
updateNumberOfFollowers()
}
}
@ -80,50 +121,94 @@ class CityInfoReligionManager {
religionsAtSomePointAdopted.add(newMajorityReligion)
}
private fun updateNumberOfFollowers() {
val oldMajorityReligion = getMajorityReligion()
followers.clear()
val remainders = HashMap<String, Float>()
val pressurePerFollower = pressures.values.sum() / cityInfo.population.population
// First give each religion an approximate share based on pressure
for ((religion, pressure) in pressures) {
val followersOfThisReligion = (pressure.toFloat() / pressurePerFollower).toInt()
followers.add(religion, followersOfThisReligion)
remainders[religion] = pressure.toFloat() - followersOfThisReligion * pressurePerFollower
}
var unallocatedPopulation = cityInfo.population.population - followers.values.sum()
// Divide up the remaining population
while (unallocatedPopulation > 0) {
val largestRemainder = remainders.maxByOrNull { it.value }
if (largestRemainder == null) {
followers.add(Constants.noReligionName, unallocatedPopulation)
break
}
followers.add(largestRemainder.key, 1)
remainders[largestRemainder.key] = 0f
unallocatedPopulation -= 1
}
followers.remove(Constants.noReligionName)
val newMajorityReligion = getMajorityReligion()
if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) {
triggerReligionAdoption(newMajorityReligion)
}
}
fun getNumberOfFollowers(): Counter<String> {
val totalInfluence = pressures.values.sum()
val population = cityInfo.population.population
if (totalInfluence > 100 * population) {
val toReturn = Counter<String>()
for ((key, value) in pressures)
if (value > 100)
toReturn.add(key, value / 100)
return toReturn
// println(followers) // ToDo: remove this when a UI for viewing followers is added
return followers
}
/** Removes all pantheons except for the one founded by the current owner of the city
* Should be called whenever a city changes hands, e.g. conquering and trading
*/
fun removeUnknownPantheons() {
for (pressure in pressures) {
val correspondingReligion = cityInfo.civInfo.gameInfo.religions[pressure.key]!!
if (correspondingReligion.isPantheon()
&& correspondingReligion.foundingCivName != cityInfo.civInfo.civName
) {
pressures.remove(pressure.key)
}
}
val toReturn = Counter<String>()
for ((key, value) in pressures) {
val percentage = value.toFloat() / totalInfluence
val relativePopulation = (percentage * population).roundToInt()
toReturn.add(key, relativePopulation)
}
return toReturn
updateNumberOfFollowers()
}
fun getMajorityReligion(): String? {
val followersPerReligion = getNumberOfFollowers()
if (followersPerReligion.isEmpty()) return null
val religionWithMaxFollowers = followersPerReligion.maxByOrNull { it.value }!!
return if (religionWithMaxFollowers.value >= cityInfo.population.population) religionWithMaxFollowers.key
return if (religionWithMaxFollowers.value >= cityInfo.population.population / 2) religionWithMaxFollowers.key
else null
}
fun getAffectedBySurroundingCities() {
private fun getAffectedBySurroundingCities() {
// We don't update the amount of followers yet, as only the end result should matter
// If multiple religions would become the majority religion due to pressure,
// this will make it so we only receive a notification for the last one.
// Also, doing it like this increases performance :D
if (cityInfo.isHolyCity()) {
addPressure(religionThisIsTheHolyCityOf!!,5 * pressureFromAdjacentCities, false)
}
val allCitiesWithin10Tiles =
cityInfo.civInfo.gameInfo.civilizations.asSequence().flatMap { it.cities }
cityInfo.civInfo.gameInfo.getCities()
.filter {
it != cityInfo && it.getCenterTile()
.aerialDistanceTo(cityInfo.getCenterTile()) <= 10
it != cityInfo
&& it.getCenterTile().aerialDistanceTo(cityInfo.getCenterTile()) <= 10
}
for (city in allCitiesWithin10Tiles) {
val majorityReligionOfCity = city.religion.getMajorityReligion()
if (majorityReligionOfCity == null) continue
else addPressure(
majorityReligionOfCity,
if (city.isHolyCity()) 30
else 6
)
val majorityReligionOfCity = city.religion.getMajorityReligion() ?: continue
if (!cityInfo.civInfo.gameInfo.religions[majorityReligionOfCity]!!.isMajorReligion()) continue
addPressure(majorityReligionOfCity, pressureFromAdjacentCities, false)
}
updateNumberOfFollowers()
}
}

View File

@ -56,7 +56,7 @@ class PopulationManager {
if (food < 0)
cityInfo.civInfo.addNotification("[${cityInfo.name}] is starving!", cityInfo.location, NotificationIcon.Growth, NotificationIcon.Death)
if (foodStored < 0) { // starvation!
if (population > 1) population--
if (population > 1) addPopulation(-1)
foodStored = 0
}
if (foodStored >= getFoodToNextPopulation()) { // growth!
@ -68,7 +68,7 @@ class PopulationManager {
// Try to avoid runaway food gain in mods, just in case
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
population++
addPopulation(1)
autoAssignPopulation()
cityInfo.civInfo.addNotification("[${cityInfo.name}] has grown!", cityInfo.location, NotificationIcon.Growth)
}
@ -77,14 +77,18 @@ class PopulationManager {
private fun getStatsOfSpecialist(name: String) = cityInfo.cityStats.getStatsOfSpecialist(name)
internal fun addPopulation(count: Int) {
population += count
if (population < 0) population = 0
val changedAmount =
if (population + count < 0) -population
else count
population += changedAmount
val freePopulation = getFreePopulation()
if (freePopulation < 0) {
unassignExtraPopulation()
} else {
autoAssignPopulation()
}
cityInfo.religion.updatePressureOnPopulationChange(changedAmount)
}
internal fun setPopulation(count: Int) {

View File

@ -32,7 +32,7 @@ class CapitalConnectionsFinder(private val civInfo: CivilizationInfo) {
// this is so we know that if we've seen which cities can be connected by port A, and one
// of those is city B, then we don't need to check the cities that B can connect to by port,
// since we'll get the same cities we got from A, since they're connected to the same sea.
while (citiesToCheck.isNotEmpty() && citiesReachedToMediums.size < allCivCities.size) {
while (citiesToCheck.isNotEmpty() && citiesReachedToMediums.size < allCivCities.count()) {
newCitiesToCheck = mutableListOf()
for (cityToConnectFrom in citiesToCheck) {
if (cityToConnectFrom.containsHarbor()) {

View File

@ -87,9 +87,8 @@ class ReligionManager {
religion = Religion(belief.name, civInfo.gameInfo, civInfo.civName)
religion!!.followerBeliefs.add(belief.name)
civInfo.gameInfo.religions[belief.name] = religion!!
// 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
for (city in civInfo.cities)
city.religion.addPressure(belief.name, 200 * city.population.population)
religionState = ReligionState.Pantheon
}
@ -114,10 +113,9 @@ class ReligionManager {
if (Random(civInfo.gameInfo.turns).nextFloat() < prophetSpawnChange) {
val birthCity =
if (religionState == ReligionState.Pantheon) civInfo.getCapital()
else civInfo.cities.firstOrNull { it.id == religion!!.holyCityId }
val prophet = civInfo.addUnit("Great Prophet", birthCity)
if (prophet == null) return
if (religionState <= ReligionState.Pantheon) civInfo.getCapital()
else civInfo.cities.firstOrNull { it.religion.religionThisIsTheHolyCityOf == religion!!.name }
val prophet = civInfo.addUnit("Great Prophet", birthCity) ?: return
prophet.religion = religion!!.name
prophet.abilityUsedCount["Religion Spread"] = 0
storedFaith -= faithForNextGreatProphet()
@ -170,15 +168,14 @@ class ReligionManager {
}
newReligion.followerBeliefs.addAll(followerBeliefs)
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 }!!
// ToDo: check this when implementing followers
holyCity.religion.clearAllPressures()
holyCity.religion.addPressure(name, 100)
val holyCity = civInfo.cities.first { it.id == foundingCityId }
holyCity.religion.religionThisIsTheHolyCityOf = newReligion.name
holyCity.religion.addPressure(name, holyCity.population.population * 500)
foundingCityId = null
}

View File

@ -71,6 +71,9 @@ class MapUnit {
@Transient
var cannotEnterOceanTilesUntilAstronomy = false
@Transient
var canEnterForeignTerrain: Boolean = false
@Transient
var paradropRange = 0
@ -95,7 +98,7 @@ class MapUnit {
fun displayName(): String {
val name = if (instanceName == null) name
else "$instanceName ({${name}})"
return if (religion != null && maxReligionSpreads() > 0) "[$name] ([$religion])"
return if (religion != null) "[$name] ([$religion])"
else name
}
@ -113,6 +116,7 @@ class MapUnit {
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
var religion: String? = null
var religiousStrengthLost = 0
//region pure functions
fun clone(): MapUnit {
@ -130,6 +134,7 @@ class MapUnit {
toReturn.isTransported = isTransported
toReturn.abilityUsedCount.putAll(abilityUsedCount)
toReturn.religion = religion
toReturn.religiousStrengthLost = religiousStrengthLost
return toReturn
}
@ -177,7 +182,7 @@ class MapUnit {
val uniques = ArrayList<Unique>()
val baseUnit = baseUnit()
uniques.addAll(baseUnit.uniqueObjects)
if (type != null) uniques.addAll(type!!.uniqueObjects)
uniques.addAll(type.uniqueObjects)
for (promotion in promotions.promotions) {
uniques.addAll(currentTile.tileMap.gameInfo.ruleSet.unitPromotions[promotion]!!.uniqueObjects)
@ -193,12 +198,14 @@ class MapUnit {
ignoresTerrainCost = hasUnique("Ignores terrain cost")
roughTerrainPenalty = hasUnique("Rough terrain penalty")
doubleMovementInCoast = hasUnique("Double movement in coast")
doubleMovementInForestAndJungle =
hasUnique("Double movement rate through Forest and Jungle")
doubleMovementInForestAndJungle = hasUnique("Double movement rate through Forest and Jungle")
doubleMovementInSnowTundraAndHills = hasUnique("Double movement in Snow, Tundra and Hills")
canEnterIceTiles = hasUnique("Can enter ice tiles")
cannotEnterOceanTiles = hasUnique("Cannot enter ocean tiles")
cannotEnterOceanTilesUntilAstronomy = hasUnique("Cannot enter ocean tiles until Astronomy")
canEnterForeignTerrain =
hasUnique("May enter foreign tiles without open borders, but loses [] religious strength each turn it ends there")
|| hasUnique("May enter foreign tiles without open borders")
}
fun hasUnique(unique: String): Boolean {
@ -239,7 +246,9 @@ class MapUnit {
for (unique in getTile().getAllTerrains().flatMap { it.uniqueObjects })
if (unique.placeholderText == "[] Sight for [] units" && matchesFilter(unique.params[1]))
visibilityRange += unique.params[0].toInt()
if (visibilityRange < 1) visibilityRange = 1
return visibilityRange
}
@ -619,6 +628,23 @@ class MapUnit {
if (action == Constants.unitActionParadrop)
action = null
if (hasUnique("Religious Unit")
&& getTile().getOwner() != null
&& !getTile().getOwner()!!.isCityState()
&& !civInfo.canPassThroughTiles(getTile().getOwner()!!)
) {
val lostReligiousStrength =
getMatchingUniques("May enter foreign tiles without open borders, but loses [] religious strength each turn it ends there")
.map { it.params[0].toInt() }
.minOrNull()
if (lostReligiousStrength != null)
religiousStrengthLost += lostReligiousStrength
if (religiousStrengthLost >= baseUnit.religiousStrength) {
civInfo.addNotification("Your [${name}] lost its faith after spending too long inside enemy territory!", getTile().position, name)
destroy()
}
}
getCitadelDamage()
getTerrainDamage()
@ -653,7 +679,7 @@ class MapUnit {
action = null
val tileOwner = getTile().getOwner()
if (tileOwner != null && !civInfo.canPassThroughTiles(tileOwner) && !tileOwner.isCityState()) // if an enemy city expanded onto this tile while I was in it
if (tileOwner != null && !canEnterForeignTerrain && !civInfo.canPassThroughTiles(tileOwner) && !tileOwner.isCityState()) // if an enemy city expanded onto this tile while I was in it
movement.teleportToClosestMoveableTile()
}
@ -914,6 +940,14 @@ class MapUnit {
return getMatchingUniques("Can spread religion [] times").sumBy { it.params[0].toInt() }
}
fun canSpreadReligion(): Boolean {
return hasUnique("Can spread religion [] times")
}
fun getPressureAddedFromSpread(): Int {
return baseUnit.religiousStrength
}
fun getReligionString(): String {
val maxSpreads = maxReligionSpreads()
if (abilityUsedCount["Religion Spread"] == null) return "" // That is, either the key doesn't exist, or it does exist and the value is null.

View File

@ -498,8 +498,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
return false
}
if (tile.naturalWonder != null) return false
if (!tile.canCivPassThrough(unit.civInfo)) return false
if (!unit.canEnterForeignTerrain && !tile.canCivPassThrough(unit.civInfo)) return false
val firstUnit = tile.getFirstUnit()
if (firstUnit != null && firstUnit.civInfo != unit.civInfo && unit.civInfo.isAtWarWith(firstUnit.civInfo))

View File

@ -12,7 +12,6 @@ class Religion() : INamed {
override lateinit var name: String
var iconName: String = "Pantheon"
lateinit var foundingCivName: String
var holyCityId: String? = null
var founderBeliefs: HashSet<String> = hashSetOf()
var followerBeliefs: HashSet<String> = hashSetOf()
@ -29,7 +28,6 @@ class Religion() : INamed {
fun clone(): Religion {
val toReturn = Religion(name, gameInfo, foundingCivName)
toReturn.iconName = iconName
toReturn.holyCityId = holyCityId
toReturn.founderBeliefs.addAll(founderBeliefs)
toReturn.followerBeliefs.addAll(followerBeliefs)
return toReturn

View File

@ -32,6 +32,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
var movement: Int = 0
var strength: Int = 0
var rangedStrength: Int = 0
var religiousStrength: Int = 0
var range: Int = 2
var interceptRange = 0
lateinit var unitType: String
@ -327,6 +328,8 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
if (unit.hasUnique("Religious Unit")) {
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligion()
if (unit.canSpreadReligion())
unit.abilityUsedCount["Religion Spread"] = 0
}
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller

View File

@ -466,15 +466,12 @@ object UnitActions {
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
val city = tile.getCity() ?: return
actionList += UnitAction(UnitActionType.SpreadReligion,
title = "Spread [${unit.religion!!}]",
action = {
unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1
// ToDo: implement followers
city.religion.clearAllPressures()
city.religion.addPressure(unit.religion!!, 100)
city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread())
unit.currentMovement = 0f
if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) {
addGoldPerGreatPersonUsage(unit.civInfo)
@ -487,7 +484,7 @@ object UnitActions {
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
val finalActions = ArrayList<UnitAction>()
var uniquesToCheck = unit.getMatchingUniques("Can construct []")
if (unit.abilityUsedCount.containsKey("Religion Spread") && unit.abilityUsedCount["Religion Spread"]!! == 0 && unit.maxReligionSpreads() > 0)
if (unit.abilityUsedCount.containsKey("Religion Spread") && unit.abilityUsedCount["Religion Spread"]!! == 0 && unit.canSpreadReligion())
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't spread religion yet")
for (unique in uniquesToCheck) {
val improvementName = unique.params[0]

View File

@ -163,10 +163,15 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
unitDescriptionTable.add(unit.promotions.XP.toString() + "/" + unit.promotions.xpForNextPromotion())
}
if (unit.maxReligionSpreads() > 0) {
if (unit.canSpreadReligion()) {
unitDescriptionTable.add(ImageGetter.getStatIcon("Faith")).size(20f)
unitDescriptionTable.add(unit.getReligionString())
}
if (unit.baseUnit.religiousStrength > 0) {
unitDescriptionTable.add(ImageGetter.getStatIcon("ReligiousStrength")).size(20f)
unitDescriptionTable.add((unit.baseUnit.religiousStrength - unit.religiousStrengthLost).toString())
}
if (unit.promotions.promotions.size != promotionsTable.children.size) // The unit has been promoted! Reload promotions!
selectedUnitHasChanged = true

View File

@ -613,6 +613,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Lock](https://thenounproject.com/search/?q=lock&i=3217613) by Vadim Solomakhin for locked tiles
* [Hourglass](https://thenounproject.com/search/?q=hourglass&i=142268) by I Create Stuff for the 'Turn' icon
* [Dove](https://thenounproject.com/search/?q=dove&i=1344084) by Sandra for Faith
* [Shield](https://thenounproject.com/search/?q=shield&i=813568) by Gregor Cresnar for Religious Strength
## Main menu