mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-08 23:08:35 +07:00
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:
BIN
android/Images/StatIcons/ReligiousStrength.png
Normal file
BIN
android/Images/StatIcons/ReligiousStrength.png
Normal file
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 |
@ -1500,8 +1500,10 @@
|
|||||||
"name": "Great Prophet",
|
"name": "Great Prophet",
|
||||||
"unitType": "Civilian",
|
"unitType": "Civilian",
|
||||||
"uniques": ["Can construct [Holy site] if it hasn't spread religion yet", "Can spread religion [4] times",
|
"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"],
|
"May found a religion", "May enter foreign tiles without open borders", "[-1] Visibility Range",
|
||||||
"movement": 2
|
"Great Person - [Faith]", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
||||||
|
"movement": 2,
|
||||||
|
"religiousStrength": 1000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Great General",
|
"name": "Great General",
|
||||||
@ -1525,9 +1527,11 @@
|
|||||||
{
|
{
|
||||||
"name": "Missionary",
|
"name": "Missionary",
|
||||||
"unitType": "Civilian",
|
"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]",
|
"uniques": ["Can spread religion [2] times", "May enter foreign tiles without open borders, but loses [250] religious strength each turn it ends there",
|
||||||
"Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
"Can be purchased with [Faith] [in all cities in which the majority religion is a major religion]",
|
||||||
"movement": 4
|
"[-1] Visibility Range", "Unbuildable", "Religious Unit", "Hidden when religion is disabled"],
|
||||||
|
"movement": 4,
|
||||||
|
"religiousStrength": 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Spaceship Parts */
|
/* Spaceship Parts */
|
||||||
|
@ -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 [cityName] =
|
||||||
You gained [Stats] as your religion was spread to an unknown city =
|
You gained [Stats] as your religion was spread to an unknown city =
|
||||||
Your city [cityName] was converted to [religionName]! =
|
Your city [cityName] was converted to [religionName]! =
|
||||||
|
Your [unitName] lost its faith after spending too long inside enemy territory! =
|
||||||
|
|
||||||
|
|
||||||
# World Screen UI
|
# World Screen UI
|
||||||
|
@ -63,6 +63,9 @@ object Constants {
|
|||||||
const val unitActionParadrop = "Paradrop"
|
const val unitActionParadrop = "Paradrop"
|
||||||
|
|
||||||
const val futureTech = "Future Tech"
|
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 cancelImprovementOrder = "Cancel improvement order"
|
||||||
const val tutorialPopupNamePrefix = "Tutorial: "
|
const val tutorialPopupNamePrefix = "Tutorial: "
|
||||||
|
@ -91,7 +91,7 @@ class GameInfo {
|
|||||||
fun getCurrentPlayerCivilization() = currentPlayerCiv
|
fun getCurrentPlayerCivilization() = currentPlayerCiv
|
||||||
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
|
fun getBarbarianCivilization() = getCivilization(Constants.barbarians)
|
||||||
fun getDifficulty() = difficultyObject
|
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 getAliveCityStates() = civilizations.filter { it.isAlive() && it.isCityState() }
|
||||||
fun getAliveMajorCivs() = civilizations.filter { it.isAlive() && it.isMajorCiv() }
|
fun getAliveMajorCivs() = civilizations.filter { it.isAlive() && it.isMajorCiv() }
|
||||||
//endregion
|
//endregion
|
||||||
|
@ -485,7 +485,8 @@ class CityInfo {
|
|||||||
}
|
}
|
||||||
} else population.nextTurn(foodForNextTurn())
|
} 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
|
if (this in civInfo.cities) { // city was not destroyed
|
||||||
health = min(health + 20, getMaxHealth())
|
health = min(health + 20, getMaxHealth())
|
||||||
@ -652,7 +653,7 @@ class CityInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isHolyCity(): Boolean {
|
fun isHolyCity(): Boolean {
|
||||||
return civInfo.gameInfo.religions.values.any { it.holyCityId == id }
|
return religion.religionThisIsTheHolyCityOf != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canBeDestroyed(): Boolean {
|
fun canBeDestroyed(): Boolean {
|
||||||
|
@ -215,6 +215,8 @@ class CityInfoConquestFunctions(val city: CityInfo){
|
|||||||
cityConstructions.addBuilding(civEquivalentBuilding.name)
|
cityConstructions.addBuilding(civEquivalentBuilding.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
religion.removeUnknownPantheons()
|
||||||
|
|
||||||
tryUpdateRoadStatus()
|
tryUpdateRoadStatus()
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package com.unciv.logic.city
|
package com.unciv.logic.city
|
||||||
|
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.Constants
|
||||||
import com.unciv.logic.civilization.NotificationIcon
|
import com.unciv.logic.civilization.NotificationIcon
|
||||||
import com.unciv.models.Counter
|
import com.unciv.models.Counter
|
||||||
|
import com.unciv.models.metadata.GameSpeed
|
||||||
import com.unciv.models.ruleset.Unique
|
import com.unciv.models.ruleset.Unique
|
||||||
import com.unciv.models.stats.Stats
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
class CityInfoReligionManager {
|
class CityInfoReligionManager {
|
||||||
@Transient
|
@Transient
|
||||||
@ -16,16 +15,41 @@ class CityInfoReligionManager {
|
|||||||
val religionsAtSomePointAdopted: HashSet<String> = hashSetOf()
|
val religionsAtSomePointAdopted: HashSet<String> = hashSetOf()
|
||||||
|
|
||||||
private val pressures: Counter<String> = Counter()
|
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 {
|
fun clone(): CityInfoReligionManager {
|
||||||
val toReturn = CityInfoReligionManager()
|
val toReturn = CityInfoReligionManager()
|
||||||
toReturn.religionsAtSomePointAdopted.addAll(religionsAtSomePointAdopted)
|
toReturn.religionsAtSomePointAdopted.addAll(religionsAtSomePointAdopted)
|
||||||
toReturn.pressures.putAll(pressures)
|
toReturn.pressures.putAll(pressures)
|
||||||
|
toReturn.followers.putAll(followers)
|
||||||
|
toReturn.religionThisIsTheHolyCityOf = religionThisIsTheHolyCityOf
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTransients(cityInfo: CityInfo) {
|
fun setTransients(cityInfo: CityInfo) {
|
||||||
this.cityInfo = cityInfo
|
this.cityInfo = cityInfo
|
||||||
|
updateNumberOfFollowers()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun endTurn() {
|
||||||
|
getAffectedBySurroundingCities()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUniques(): Sequence<Unique> {
|
fun getUniques(): Sequence<Unique> {
|
||||||
@ -40,14 +64,31 @@ class CityInfoReligionManager {
|
|||||||
|
|
||||||
fun clearAllPressures() {
|
fun clearAllPressures() {
|
||||||
pressures.clear()
|
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) {
|
fun addPressure(religionName: String, amount: Int, shouldUpdateFollowers: Boolean = true) {
|
||||||
val oldMajorityReligion = getMajorityReligion()
|
|
||||||
pressures.add(religionName, amount)
|
pressures.add(religionName, amount)
|
||||||
val newMajorityReligion = getMajorityReligion()
|
|
||||||
if (oldMajorityReligion != newMajorityReligion && newMajorityReligion != null) {
|
if (shouldUpdateFollowers) {
|
||||||
triggerReligionAdoption(newMajorityReligion)
|
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)
|
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> {
|
fun getNumberOfFollowers(): Counter<String> {
|
||||||
val totalInfluence = pressures.values.sum()
|
|
||||||
val population = cityInfo.population.population
|
// println(followers) // ToDo: remove this when a UI for viewing followers is added
|
||||||
if (totalInfluence > 100 * population) {
|
|
||||||
val toReturn = Counter<String>()
|
return followers
|
||||||
for ((key, value) in pressures)
|
}
|
||||||
if (value > 100)
|
|
||||||
toReturn.add(key, value / 100)
|
/** Removes all pantheons except for the one founded by the current owner of the city
|
||||||
return toReturn
|
* 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
updateNumberOfFollowers()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMajorityReligion(): String? {
|
fun getMajorityReligion(): String? {
|
||||||
val followersPerReligion = getNumberOfFollowers()
|
val followersPerReligion = getNumberOfFollowers()
|
||||||
if (followersPerReligion.isEmpty()) return null
|
if (followersPerReligion.isEmpty()) return null
|
||||||
val religionWithMaxFollowers = followersPerReligion.maxByOrNull { it.value }!!
|
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
|
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 =
|
val allCitiesWithin10Tiles =
|
||||||
cityInfo.civInfo.gameInfo.civilizations.asSequence().flatMap { it.cities }
|
cityInfo.civInfo.gameInfo.getCities()
|
||||||
.filter {
|
.filter {
|
||||||
it != cityInfo && it.getCenterTile()
|
it != cityInfo
|
||||||
.aerialDistanceTo(cityInfo.getCenterTile()) <= 10
|
&& it.getCenterTile().aerialDistanceTo(cityInfo.getCenterTile()) <= 10
|
||||||
}
|
}
|
||||||
for (city in allCitiesWithin10Tiles) {
|
for (city in allCitiesWithin10Tiles) {
|
||||||
val majorityReligionOfCity = city.religion.getMajorityReligion()
|
val majorityReligionOfCity = city.religion.getMajorityReligion() ?: continue
|
||||||
if (majorityReligionOfCity == null) continue
|
if (!cityInfo.civInfo.gameInfo.religions[majorityReligionOfCity]!!.isMajorReligion()) continue
|
||||||
else addPressure(
|
addPressure(majorityReligionOfCity, pressureFromAdjacentCities, false)
|
||||||
majorityReligionOfCity,
|
|
||||||
if (city.isHolyCity()) 30
|
|
||||||
else 6
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateNumberOfFollowers()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -56,7 +56,7 @@ class PopulationManager {
|
|||||||
if (food < 0)
|
if (food < 0)
|
||||||
cityInfo.civInfo.addNotification("[${cityInfo.name}] is starving!", cityInfo.location, NotificationIcon.Growth, NotificationIcon.Death)
|
cityInfo.civInfo.addNotification("[${cityInfo.name}] is starving!", cityInfo.location, NotificationIcon.Growth, NotificationIcon.Death)
|
||||||
if (foodStored < 0) { // starvation!
|
if (foodStored < 0) { // starvation!
|
||||||
if (population > 1) population--
|
if (population > 1) addPopulation(-1)
|
||||||
foodStored = 0
|
foodStored = 0
|
||||||
}
|
}
|
||||||
if (foodStored >= getFoodToNextPopulation()) { // growth!
|
if (foodStored >= getFoodToNextPopulation()) { // growth!
|
||||||
@ -68,7 +68,7 @@ class PopulationManager {
|
|||||||
// Try to avoid runaway food gain in mods, just in case
|
// Try to avoid runaway food gain in mods, just in case
|
||||||
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
|
if (percentOfFoodCarriedOver > 95) percentOfFoodCarriedOver = 95
|
||||||
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
|
foodStored += (getFoodToNextPopulation() * percentOfFoodCarriedOver / 100f).toInt()
|
||||||
population++
|
addPopulation(1)
|
||||||
autoAssignPopulation()
|
autoAssignPopulation()
|
||||||
cityInfo.civInfo.addNotification("[${cityInfo.name}] has grown!", cityInfo.location, NotificationIcon.Growth)
|
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)
|
private fun getStatsOfSpecialist(name: String) = cityInfo.cityStats.getStatsOfSpecialist(name)
|
||||||
|
|
||||||
internal fun addPopulation(count: Int) {
|
internal fun addPopulation(count: Int) {
|
||||||
population += count
|
val changedAmount =
|
||||||
if (population < 0) population = 0
|
if (population + count < 0) -population
|
||||||
|
else count
|
||||||
|
population += changedAmount
|
||||||
val freePopulation = getFreePopulation()
|
val freePopulation = getFreePopulation()
|
||||||
if (freePopulation < 0) {
|
if (freePopulation < 0) {
|
||||||
unassignExtraPopulation()
|
unassignExtraPopulation()
|
||||||
} else {
|
} else {
|
||||||
autoAssignPopulation()
|
autoAssignPopulation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cityInfo.religion.updatePressureOnPopulationChange(changedAmount)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun setPopulation(count: Int) {
|
internal fun setPopulation(count: Int) {
|
||||||
|
@ -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
|
// 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,
|
// 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.
|
// 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()
|
newCitiesToCheck = mutableListOf()
|
||||||
for (cityToConnectFrom in citiesToCheck) {
|
for (cityToConnectFrom in citiesToCheck) {
|
||||||
if (cityToConnectFrom.containsHarbor()) {
|
if (cityToConnectFrom.containsHarbor()) {
|
||||||
|
@ -87,9 +87,8 @@ class ReligionManager {
|
|||||||
religion = Religion(belief.name, civInfo.gameInfo, civInfo.civName)
|
religion = Religion(belief.name, civInfo.gameInfo, civInfo.civName)
|
||||||
religion!!.followerBeliefs.add(belief.name)
|
religion!!.followerBeliefs.add(belief.name)
|
||||||
civInfo.gameInfo.religions[belief.name] = religion!!
|
civInfo.gameInfo.religions[belief.name] = religion!!
|
||||||
// ToDo: This should later be changed when religions can have multiple beliefs
|
for (city in civInfo.cities)
|
||||||
civInfo.getCapital().religion.clearAllPressures()
|
city.religion.addPressure(belief.name, 200 * city.population.population)
|
||||||
civInfo.getCapital().religion.addPressure(belief.name, 100) // Capital is religious, other cities are not
|
|
||||||
religionState = ReligionState.Pantheon
|
religionState = ReligionState.Pantheon
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,10 +113,9 @@ class ReligionManager {
|
|||||||
|
|
||||||
if (Random(civInfo.gameInfo.turns).nextFloat() < prophetSpawnChange) {
|
if (Random(civInfo.gameInfo.turns).nextFloat() < prophetSpawnChange) {
|
||||||
val birthCity =
|
val birthCity =
|
||||||
if (religionState == ReligionState.Pantheon) civInfo.getCapital()
|
if (religionState <= ReligionState.Pantheon) civInfo.getCapital()
|
||||||
else civInfo.cities.firstOrNull { it.id == religion!!.holyCityId }
|
else civInfo.cities.firstOrNull { it.religion.religionThisIsTheHolyCityOf == religion!!.name }
|
||||||
val prophet = civInfo.addUnit("Great Prophet", birthCity)
|
val prophet = civInfo.addUnit("Great Prophet", birthCity) ?: return
|
||||||
if (prophet == null) return
|
|
||||||
prophet.religion = religion!!.name
|
prophet.religion = religion!!.name
|
||||||
prophet.abilityUsedCount["Religion Spread"] = 0
|
prophet.abilityUsedCount["Religion Spread"] = 0
|
||||||
storedFaith -= faithForNextGreatProphet()
|
storedFaith -= faithForNextGreatProphet()
|
||||||
@ -170,15 +168,14 @@ class ReligionManager {
|
|||||||
}
|
}
|
||||||
newReligion.followerBeliefs.addAll(followerBeliefs)
|
newReligion.followerBeliefs.addAll(followerBeliefs)
|
||||||
newReligion.founderBeliefs.addAll(founderBelief)
|
newReligion.founderBeliefs.addAll(founderBelief)
|
||||||
newReligion.holyCityId = foundingCityId
|
|
||||||
religion = newReligion
|
religion = newReligion
|
||||||
civInfo.gameInfo.religions[name] = newReligion
|
civInfo.gameInfo.religions[name] = newReligion
|
||||||
|
|
||||||
religionState = ReligionState.Religion
|
religionState = ReligionState.Religion
|
||||||
val holyCity = civInfo.cities.firstOrNull { it.id == newReligion.holyCityId }!!
|
|
||||||
// ToDo: check this when implementing followers
|
val holyCity = civInfo.cities.first { it.id == foundingCityId }
|
||||||
holyCity.religion.clearAllPressures()
|
holyCity.religion.religionThisIsTheHolyCityOf = newReligion.name
|
||||||
holyCity.religion.addPressure(name, 100)
|
holyCity.religion.addPressure(name, holyCity.population.population * 500)
|
||||||
|
|
||||||
foundingCityId = null
|
foundingCityId = null
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,9 @@ class MapUnit {
|
|||||||
@Transient
|
@Transient
|
||||||
var cannotEnterOceanTilesUntilAstronomy = false
|
var cannotEnterOceanTilesUntilAstronomy = false
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
var canEnterForeignTerrain: Boolean = false
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
var paradropRange = 0
|
var paradropRange = 0
|
||||||
|
|
||||||
@ -95,7 +98,7 @@ class MapUnit {
|
|||||||
fun displayName(): String {
|
fun displayName(): String {
|
||||||
val name = if (instanceName == null) name
|
val name = if (instanceName == null) name
|
||||||
else "$instanceName ({${name}})"
|
else "$instanceName ({${name}})"
|
||||||
return if (religion != null && maxReligionSpreads() > 0) "[$name] ([$religion])"
|
return if (religion != null) "[$name] ([$religion])"
|
||||||
else name
|
else name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +116,7 @@ class MapUnit {
|
|||||||
|
|
||||||
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
|
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
|
||||||
var religion: String? = null
|
var religion: String? = null
|
||||||
|
var religiousStrengthLost = 0
|
||||||
|
|
||||||
//region pure functions
|
//region pure functions
|
||||||
fun clone(): MapUnit {
|
fun clone(): MapUnit {
|
||||||
@ -130,6 +134,7 @@ class MapUnit {
|
|||||||
toReturn.isTransported = isTransported
|
toReturn.isTransported = isTransported
|
||||||
toReturn.abilityUsedCount.putAll(abilityUsedCount)
|
toReturn.abilityUsedCount.putAll(abilityUsedCount)
|
||||||
toReturn.religion = religion
|
toReturn.religion = religion
|
||||||
|
toReturn.religiousStrengthLost = religiousStrengthLost
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +182,7 @@ class MapUnit {
|
|||||||
val uniques = ArrayList<Unique>()
|
val uniques = ArrayList<Unique>()
|
||||||
val baseUnit = baseUnit()
|
val baseUnit = baseUnit()
|
||||||
uniques.addAll(baseUnit.uniqueObjects)
|
uniques.addAll(baseUnit.uniqueObjects)
|
||||||
if (type != null) uniques.addAll(type!!.uniqueObjects)
|
uniques.addAll(type.uniqueObjects)
|
||||||
|
|
||||||
for (promotion in promotions.promotions) {
|
for (promotion in promotions.promotions) {
|
||||||
uniques.addAll(currentTile.tileMap.gameInfo.ruleSet.unitPromotions[promotion]!!.uniqueObjects)
|
uniques.addAll(currentTile.tileMap.gameInfo.ruleSet.unitPromotions[promotion]!!.uniqueObjects)
|
||||||
@ -193,12 +198,14 @@ class MapUnit {
|
|||||||
ignoresTerrainCost = hasUnique("Ignores terrain cost")
|
ignoresTerrainCost = hasUnique("Ignores terrain cost")
|
||||||
roughTerrainPenalty = hasUnique("Rough terrain penalty")
|
roughTerrainPenalty = hasUnique("Rough terrain penalty")
|
||||||
doubleMovementInCoast = hasUnique("Double movement in coast")
|
doubleMovementInCoast = hasUnique("Double movement in coast")
|
||||||
doubleMovementInForestAndJungle =
|
doubleMovementInForestAndJungle = hasUnique("Double movement rate through Forest and Jungle")
|
||||||
hasUnique("Double movement rate through Forest and Jungle")
|
|
||||||
doubleMovementInSnowTundraAndHills = hasUnique("Double movement in Snow, Tundra and Hills")
|
doubleMovementInSnowTundraAndHills = hasUnique("Double movement in Snow, Tundra and Hills")
|
||||||
canEnterIceTiles = hasUnique("Can enter ice tiles")
|
canEnterIceTiles = hasUnique("Can enter ice tiles")
|
||||||
cannotEnterOceanTiles = hasUnique("Cannot enter ocean tiles")
|
cannotEnterOceanTiles = hasUnique("Cannot enter ocean tiles")
|
||||||
cannotEnterOceanTilesUntilAstronomy = hasUnique("Cannot enter ocean tiles until Astronomy")
|
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 {
|
fun hasUnique(unique: String): Boolean {
|
||||||
@ -239,7 +246,9 @@ class MapUnit {
|
|||||||
for (unique in getTile().getAllTerrains().flatMap { it.uniqueObjects })
|
for (unique in getTile().getAllTerrains().flatMap { it.uniqueObjects })
|
||||||
if (unique.placeholderText == "[] Sight for [] units" && matchesFilter(unique.params[1]))
|
if (unique.placeholderText == "[] Sight for [] units" && matchesFilter(unique.params[1]))
|
||||||
visibilityRange += unique.params[0].toInt()
|
visibilityRange += unique.params[0].toInt()
|
||||||
|
|
||||||
|
if (visibilityRange < 1) visibilityRange = 1
|
||||||
|
|
||||||
return visibilityRange
|
return visibilityRange
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,6 +628,23 @@ class MapUnit {
|
|||||||
|
|
||||||
if (action == Constants.unitActionParadrop)
|
if (action == Constants.unitActionParadrop)
|
||||||
action = null
|
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()
|
getCitadelDamage()
|
||||||
getTerrainDamage()
|
getTerrainDamage()
|
||||||
@ -653,7 +679,7 @@ class MapUnit {
|
|||||||
action = null
|
action = null
|
||||||
|
|
||||||
val tileOwner = getTile().getOwner()
|
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()
|
movement.teleportToClosestMoveableTile()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,6 +940,14 @@ class MapUnit {
|
|||||||
return getMatchingUniques("Can spread religion [] times").sumBy { it.params[0].toInt() }
|
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 {
|
fun getReligionString(): String {
|
||||||
val maxSpreads = maxReligionSpreads()
|
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.
|
if (abilityUsedCount["Religion Spread"] == null) return "" // That is, either the key doesn't exist, or it does exist and the value is null.
|
||||||
|
@ -498,8 +498,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (tile.naturalWonder != null) 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()
|
val firstUnit = tile.getFirstUnit()
|
||||||
if (firstUnit != null && firstUnit.civInfo != unit.civInfo && unit.civInfo.isAtWarWith(firstUnit.civInfo))
|
if (firstUnit != null && firstUnit.civInfo != unit.civInfo && unit.civInfo.isAtWarWith(firstUnit.civInfo))
|
||||||
|
@ -12,7 +12,6 @@ class Religion() : INamed {
|
|||||||
override lateinit var name: String
|
override lateinit var name: String
|
||||||
var iconName: String = "Pantheon"
|
var iconName: String = "Pantheon"
|
||||||
lateinit var foundingCivName: String
|
lateinit var foundingCivName: String
|
||||||
var holyCityId: String? = null
|
|
||||||
|
|
||||||
var founderBeliefs: HashSet<String> = hashSetOf()
|
var founderBeliefs: HashSet<String> = hashSetOf()
|
||||||
var followerBeliefs: HashSet<String> = hashSetOf()
|
var followerBeliefs: HashSet<String> = hashSetOf()
|
||||||
@ -29,7 +28,6 @@ class Religion() : INamed {
|
|||||||
fun clone(): Religion {
|
fun clone(): Religion {
|
||||||
val toReturn = Religion(name, gameInfo, foundingCivName)
|
val toReturn = Religion(name, gameInfo, foundingCivName)
|
||||||
toReturn.iconName = iconName
|
toReturn.iconName = iconName
|
||||||
toReturn.holyCityId = holyCityId
|
|
||||||
toReturn.founderBeliefs.addAll(founderBeliefs)
|
toReturn.founderBeliefs.addAll(founderBeliefs)
|
||||||
toReturn.followerBeliefs.addAll(followerBeliefs)
|
toReturn.followerBeliefs.addAll(followerBeliefs)
|
||||||
return toReturn
|
return toReturn
|
||||||
|
@ -32,6 +32,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
|||||||
var movement: Int = 0
|
var movement: Int = 0
|
||||||
var strength: Int = 0
|
var strength: Int = 0
|
||||||
var rangedStrength: Int = 0
|
var rangedStrength: Int = 0
|
||||||
|
var religiousStrength: Int = 0
|
||||||
var range: Int = 2
|
var range: Int = 2
|
||||||
var interceptRange = 0
|
var interceptRange = 0
|
||||||
lateinit var unitType: String
|
lateinit var unitType: String
|
||||||
@ -327,6 +328,8 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
|||||||
|
|
||||||
if (unit.hasUnique("Religious Unit")) {
|
if (unit.hasUnique("Religious Unit")) {
|
||||||
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligion()
|
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
|
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
|
||||||
|
@ -466,15 +466,12 @@ object UnitActions {
|
|||||||
val maxReligionSpreads = unit.maxReligionSpreads()
|
val maxReligionSpreads = unit.maxReligionSpreads()
|
||||||
if (!unit.abilityUsedCount.containsKey("Religion Spread")) return // This should be impossible anyways, but just in case
|
if (!unit.abilityUsedCount.containsKey("Religion Spread")) return // This should be impossible anyways, but just in case
|
||||||
if (maxReligionSpreads <= unit.abilityUsedCount["Religion Spread"]!!) return
|
if (maxReligionSpreads <= unit.abilityUsedCount["Religion Spread"]!!) return
|
||||||
val city = tile.getCity()
|
val city = tile.getCity() ?: return
|
||||||
if (city == null) return
|
|
||||||
actionList += UnitAction(UnitActionType.SpreadReligion,
|
actionList += UnitAction(UnitActionType.SpreadReligion,
|
||||||
title = "Spread [${unit.religion!!}]",
|
title = "Spread [${unit.religion!!}]",
|
||||||
action = {
|
action = {
|
||||||
unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1
|
unit.abilityUsedCount["Religion Spread"] = unit.abilityUsedCount["Religion Spread"]!! + 1
|
||||||
// ToDo: implement followers
|
city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread())
|
||||||
city.religion.clearAllPressures()
|
|
||||||
city.religion.addPressure(unit.religion!!, 100)
|
|
||||||
unit.currentMovement = 0f
|
unit.currentMovement = 0f
|
||||||
if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) {
|
if (unit.abilityUsedCount["Religion Spread"] == maxReligionSpreads) {
|
||||||
addGoldPerGreatPersonUsage(unit.civInfo)
|
addGoldPerGreatPersonUsage(unit.civInfo)
|
||||||
@ -487,7 +484,7 @@ object UnitActions {
|
|||||||
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
|
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
|
||||||
val finalActions = ArrayList<UnitAction>()
|
val finalActions = ArrayList<UnitAction>()
|
||||||
var uniquesToCheck = unit.getMatchingUniques("Can construct []")
|
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")
|
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't spread religion yet")
|
||||||
for (unique in uniquesToCheck) {
|
for (unique in uniquesToCheck) {
|
||||||
val improvementName = unique.params[0]
|
val improvementName = unique.params[0]
|
||||||
|
@ -163,10 +163,15 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
unitDescriptionTable.add(unit.promotions.XP.toString() + "/" + unit.promotions.xpForNextPromotion())
|
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(ImageGetter.getStatIcon("Faith")).size(20f)
|
||||||
unitDescriptionTable.add(unit.getReligionString())
|
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!
|
if (unit.promotions.promotions.size != promotionsTable.children.size) // The unit has been promoted! Reload promotions!
|
||||||
selectedUnitHasChanged = true
|
selectedUnitHasChanged = true
|
||||||
|
@ -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
|
* [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
|
* [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
|
* [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
|
## Main menu
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user