Added Religious wonders (#5041)

* Added Grand Temple and Great Mosque of Djenne buildings

* Added uniques for Grand Temple

* Added uniques for Mosque of Djenne, refactored ability uses system to count down isntead of up
This commit is contained in:
Xander Lenstra 2021-08-31 21:23:02 +02:00 committed by GitHub
parent cd7bd8fcfd
commit 634f4a3533
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 313 additions and 219 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1 +1 @@
[Tech,Flags,Skin,Construction]
[Flags,Construction,Skin,Tech]

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 635 KiB

After

Width:  |  Height:  |  Size: 642 KiB

View File

@ -214,20 +214,6 @@ ImprovementIcons/Quarry
orig: 100, 100
offset: 0, 0
index: -1
ImprovementIcons/Railroad
rotate: false
xy: 220, 755
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
TileSets/Default/Railroad
rotate: false
xy: 220, 755
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
ImprovementIcons/Road
rotate: false
xy: 220, 107
@ -1705,6 +1691,20 @@ TileSets/Default/OasisOverlay
orig: 100, 100
offset: 0, 0
index: -1
TileSets/Default/Railroad
rotate: false
xy: 220, 755
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
ImprovementIcons/Railroad
rotate: false
xy: 220, 755
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
TileSets/Default/Road
rotate: false
xy: 4, 58

View File

@ -237,7 +237,7 @@
"maintenance": 4,
"hurryCostModifier": 50,
"uniques": ["Remove extra unhappiness from annexed cities",
"Can only be built in annexed cities"],
"Can only be built [in annexed cities]"],
"requiredTech": "Mathematics"
},
{
@ -454,6 +454,26 @@
"requiredTech": "Theology",
"quote": "'For it soars to a height to match the sky, and as if surging up from among the other buildings it stands on high and looks down upon the remainder of the city, adorning it, because it is a part of it, but glorying in its own beauty' - Procopius, De Aedificis"
},
{
"name": "Great Mosque of Djenne",
"culture": 1,
"faith": 3,
"greatPersonPoints": {"Great Engineer": 1},
"isWonder": true,
"uniques": ["Provides a free [Mosque] [in this city]", "Hidden when religion is disabled",
"[Missionary] units built [in this city] can [Spread Religion] [1] extra times", "[Great Prophet] units built [in this city] can [Spread Religion] [1] extra times"],
"requiredTech": "Theology",
"quote": "'With the magnificence of eternity before us, let time, with all its fluctuations, dwindle into its own littleness.' - Thomas Chalmers"
},
{
"name": "Grand Temple",
"culture": 1,
"faith": 8,
"uniques": ["Requires a [Temple] in all cities", "Cost increases by [30] per owned city",
"[+100]% Natural religion spread [in this city]", "Hidden when religion is disabled", "Can only be built [in holy cities]"],
"requiredTech": "Theology",
"isNationalWonder": true
},
{
"name": "Chichen Itza",
"culture": 1,

View File

@ -596,13 +596,14 @@ class CityInfo {
"in non-enemy foreign cities" ->
viewingCiv != civInfo
&& !civInfo.isAtWarWith(viewingCiv)
"in foreign cities" ->
viewingCiv != civInfo
"in foreign cities" -> viewingCiv != civInfo
"in annexed cities" -> foundingCiv != civInfo.civName && !isPuppet
"in holy cities" -> religion.religionThisIsTheHolyCityOf != null
"in City-State cities" -> civInfo.isCityState()
// This is only used in communication to the user indicating that only in cities with this
// religion a unique is active. However, since religion uniques only come from the city itself,
// this will always be true when checked.
"in cities following this religion" -> true
"in City-State cities" -> civInfo.isCityState()
else -> false
}
}

View File

@ -33,10 +33,9 @@ class CityInfoConquestFunctions(val city: CityInfo){
private fun destroyBuildingsOnCapture() {
city.apply {
// Remove all national wonders (must come after the palace relocation because that's a national wonder too!)
for (building in cityConstructions.getBuiltBuildings()) {
when {
building.hasUnique("Never destroyed when the city is captured") -> continue
building.hasUnique("Never destroyed when the city is captured") || building.isWonder -> continue
building.hasUnique("Destroyed when the city is captured") ->
cityConstructions.removeBuilding(building.name)
else -> {

View File

@ -7,7 +7,6 @@ import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException
import com.unciv.logic.automation.NextTurnAutomation
import com.unciv.logic.automation.WorkerAutomation
import com.unciv.logic.battle.CityCombatant
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.RuinsManager.RuinsManager
import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
@ -40,8 +39,6 @@ import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.system.measureNanoTime
import kotlin.system.measureTimeMillis
class CivilizationInfo {
@ -812,6 +809,7 @@ class CivilizationInfo {
placedUnit.religion =
if (city != null) city.cityConstructions.cityInfo.religion.getMajorityReligionName()
else religionManager.religion?.name
placedUnit.setupAbilityUses()
}
return placedUnit

View File

@ -9,6 +9,7 @@ import com.unciv.ui.pickerscreens.BeliefContainer
import kotlin.random.Random
class ReligionManager {
@Transient
lateinit var civInfo: CivilizationInfo
@ -32,9 +33,14 @@ class ReligionManager {
var religionState = ReligionState.None
private set
@Transient
private var foundingCityId: String? = null
// Only used for keeping track of the city a prophet was used when founding a religion
@Transient
private var shouldChoosePantheonBelief: Boolean = false
fun clone(): ReligionManager {
val clone = ReligionManager()
clone.foundingCityId = foundingCityId
@ -134,7 +140,10 @@ class ReligionManager {
fun mayFoundReligionAtAll(prophet: MapUnit): Boolean {
if (religionState >= ReligionState.Religion) return false // Already created a major religion
if (prophet.abilityUsedCount.any { it.value != 0 }) return false // Already used its power for other things
// Already used its power for other things
if (prophet.abilityUsesLeft.any { it.value != prophet.maxAbilityUses[it.key] }) return false
if (!civInfo.isMajorCiv()) return false // Only major civs may use religion
val foundedReligionsCount = civInfo.gameInfo.civilizations.count {
@ -169,12 +178,13 @@ class ReligionManager {
fun useProphetForFoundingReligion(prophet: MapUnit) {
if (!mayFoundReligionNow(prophet)) return // How did you do this?
if (religionState == ReligionState.None) shouldChoosePantheonBelief = true
religionState = ReligionState.FoundingReligion
civInfo.religionManager.foundingCityId = prophet.getTile().getCity()!!.id
}
fun getBeliefsToChooseAtFounding(): BeliefContainer {
if (religionState == ReligionState.None)
if (shouldChoosePantheonBelief)
return BeliefContainer(pantheonBeliefCount = 1, founderBeliefCount = 1, followerBeliefCount = 1)
return BeliefContainer(founderBeliefCount = 1, followerBeliefCount = 1)
}
@ -218,12 +228,14 @@ class ReligionManager {
holyCity.religion.addPressure(name, holyCity.population.population * 500)
foundingCityId = null
shouldChoosePantheonBelief = false
}
fun mayEnhanceReligionAtAll(prophet: MapUnit): Boolean {
if (religion == null) return false // First found a pantheon
if (religionState != ReligionState.Religion) return false // First found an actual religion
if (prophet.abilityUsedCount.any { it.value > 0 }) return false // Already used its ability for other things
// Already used its power for other things
if (prophet.abilityUsesLeft.any { it.value != prophet.maxAbilityUses[it.key] }) return false
if (!civInfo.isMajorCiv()) return false // Only major civs
if (civInfo.gameInfo.ruleSet.beliefs.values.none {

View File

@ -5,6 +5,7 @@ import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.automation.UnitAutomation
import com.unciv.logic.automation.WorkerAutomation
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.LocationAction
import com.unciv.logic.civilization.NotificationIcon
@ -123,7 +124,14 @@ class MapUnit {
var due: Boolean = true
var isTransported: Boolean = false
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
// Deprecated since 3.16.11
@Deprecated("Deprecated since 3.16.11", replaceWith = ReplaceWith("abilityUsesLeft"))
var abilityUsedCount: HashMap<String, Int> = hashMapOf()
//
var abilityUsesLeft: HashMap<String, Int> = hashMapOf()
var maxAbilityUses: HashMap<String, Int> = hashMapOf()
var religion: String? = null
var religiousStrengthLost = 0
@ -141,7 +149,11 @@ class MapUnit {
toReturn.attacksThisTurn = attacksThisTurn
toReturn.promotions = promotions.clone()
toReturn.isTransported = isTransported
toReturn.abilityUsedCount.putAll(abilityUsedCount)
// Deprecated since 3.16.11
toReturn.abilityUsedCount.putAll(abilityUsedCount)
//
toReturn.abilityUsesLeft.putAll(abilityUsesLeft)
toReturn.maxAbilityUses.putAll(maxAbilityUses)
toReturn.religion = religion
toReturn.religiousStrengthLost = religiousStrengthLost
return toReturn
@ -440,6 +452,20 @@ class MapUnit {
//
updateUniques()
// abilityUsedCount deprecated since 3.16.11, this is replacement code
if (abilityUsedCount.isNotEmpty()) {
for (ability in abilityUsedCount) {
val maxUsesOfThisAbility = getMatchingUniques("Can [] [] times")
.filter { it.params[0] == ability.key }
.sumBy { it.params[1].toInt() }
abilityUsesLeft[ability.key] = maxUsesOfThisAbility - ability.value
maxAbilityUses[ability.key] = maxUsesOfThisAbility
}
abilityUsedCount.clear()
}
//
}
fun useMovementPoints(amount: Float) {
@ -950,13 +976,31 @@ class MapUnit {
fun canDoReligiousAction(action: String): Boolean {
return getMatchingUniques("Can [] [] times").any { it.params[0] == action }
}
fun getMaxReligiousActionUses(action: String): Int {
/** For the actual value, check the member variable `maxAbilityUses`
*/
fun getBaseMaxActionUses(action: String): Int {
return getMatchingUniques("Can [] [] times")
.filter { it.params[0] == action }
.sumBy { it.params[1].toInt() }
}
fun setupAbilityUses(buildCity: CityInfo? = null) {
for (action in religiousActionsUnitCanDo()) {
val baseAmount = getBaseMaxActionUses(action)
val additional =
if (buildCity == null) 0
else buildCity.getMatchingUniques("[] units built [] can [] [] extra times")
.filter { matchesFilter(it.params[0]) && buildCity.matchesFilter(it.params[1]) && it.params[2] == action }
.sumBy { println("Addition ability found: ${it.params[1]}"); it.params[3].toInt() }
maxAbilityUses[action] = baseAmount + additional
abilityUsesLeft[action] = maxAbilityUses[action]!!
}
}
fun getPressureAddedFromSpread(): Int {
var pressureAdded = baseUnit.religiousStrength.toFloat()
for (unique in civInfo.getMatchingUniques("[]% Spread Religion Strength for [] units"))
@ -967,9 +1011,9 @@ class MapUnit {
}
fun getActionString(action: String): String {
val maxActionUses = getMaxReligiousActionUses(action)
if (abilityUsedCount[action] == null) return "0/0" // Something went wrong
return "${maxActionUses - abilityUsedCount[action]!!}/${maxActionUses}"
val maxActionUses = maxAbilityUses[action]
if (abilityUsesLeft[action] == null) return "0/0" // Something went wrong
return "${abilityUsesLeft[action]!!}/${maxActionUses}"
}
fun actionsOnDeselect() {

View File

@ -440,11 +440,6 @@ class TileMap {
}
}
// If this unit has special abilities that need to be kept track of, start doing so here
for (action in unit.religiousActionsUnitCanDo()) {
unit.abilityUsedCount[action] = 0
}
// And update civ stats, since the new unit changes both unit upkeep and resource consumption
civInfo.updateStatsForNextTurn()
civInfo.updateDetailedCivResources()

View File

@ -462,8 +462,11 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
"Must have an owned [] within [] tiles" -> if (cityCenter.getTilesInDistance(unique.params[1].toInt()).none {
it.matchesFilter(unique.params[0], civInfo) && it.getOwner() == construction.cityInfo.civInfo
}) return unique.text
"Can only be built in annexed cities" -> if (construction.cityInfo.isPuppet
|| construction.cityInfo.civInfo.civName == construction.cityInfo.foundingCiv) return unique.text
// Deprecated since 3.16.11
"Can only be built in annexed cities" -> if (construction.cityInfo.isPuppet
|| construction.cityInfo.civInfo.civName == construction.cityInfo.foundingCiv) return unique.text
//
"Can only be built []" -> if (!construction.cityInfo.matchesFilter(unique.params[0])) return unique.text
"Obsolete with []" -> if (civInfo.tech.isResearched(unique.params[0])) return unique.text
Constants.hiddenWithoutReligionUnique -> if (!civInfo.gameInfo.hasReligionEnabled()) return unique.text
}

View File

@ -325,8 +325,10 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
if (wasBought && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought"))
unit.currentMovement = 0f
// If this unit has special abilities that need to be kept track of, start doing so here
if (unit.hasUnique("Religious Unit")) {
unit.religion = cityConstructions.cityInfo.religion.getMajorityReligionName()
unit.setupAbilityUses(cityConstructions.cityInfo)
}
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller

View File

@ -226,6 +226,12 @@ object TranslationFileWriter {
"in all cities connected to capital",
"in all cities with a garrison",
"in all cities in which the majority religion is a major religion",
"in all cities in which the majority religion is an enhanced religion",
"in non-enemy foreign cities",
"in foreign cities",
"in annexed cities",
"in holy cities",
"in City-State cities",
"in cities following this religion",
)

View File

@ -522,26 +522,25 @@ object UnitActions {
if (unit.religion == null || unit.civInfo.gameInfo.religions[unit.religion]!!.isPantheon()) return
val city = tile.getCity() ?: return
for (action in actionsToAdd) {
if (!unit.abilityUsedCount.containsKey(action)) continue
val maxActionUses = unit.getMaxReligiousActionUses(action)
if (maxActionUses <= unit.abilityUsedCount[action]!!) continue
if (!unit.abilityUsesLeft.containsKey(action)) continue
if (unit.abilityUsesLeft[action]!! <= 0) continue
when (action) {
Constants.spreadReligionAbilityCount -> addSpreadReligionActions(unit, actionList, city, maxActionUses)
Constants.removeHeresyAbilityCount -> addRemoveHeresyActions(unit, actionList, city, maxActionUses)
Constants.spreadReligionAbilityCount -> addSpreadReligionActions(unit, actionList, city)
Constants.removeHeresyAbilityCount -> addRemoveHeresyActions(unit, actionList, city)
}
}
}
private fun useActionWithLimitedUses(unit: MapUnit, action: String, maximumUses: Int) {
unit.abilityUsedCount[action] = unit.abilityUsedCount[action]!! + 1
if (unit.abilityUsedCount[action] == maximumUses) {
private fun useActionWithLimitedUses(unit: MapUnit, action: String) {
unit.abilityUsesLeft[action] = unit.abilityUsesLeft[action]!! - 1
if (unit.abilityUsesLeft[action]!! <= 0) {
if (unit.isGreatPerson())
addStatsPerGreatPersonUsage(unit)
unit.destroy()
}
}
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo, maxSpreadUses: Int) {
private fun addSpreadReligionActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo) {
val blockedByInquisitor =
city.getCenterTile()
.getTilesInDistance(1)
@ -559,12 +558,12 @@ object UnitActions {
}
city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread())
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.spreadReligionAbilityCount, maxSpreadUses)
useActionWithLimitedUses(unit, Constants.spreadReligionAbilityCount)
}.takeIf { unit.currentMovement > 0 && !blockedByInquisitor }
)
}
private fun addRemoveHeresyActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo, maxHerseyUses: Int) {
private fun addRemoveHeresyActions(unit: MapUnit, actionList: ArrayList<UnitAction>, city: CityInfo) {
if (city.civInfo != unit.civInfo) return
// Only allow the action if the city actually has any foreign religion
// This will almost be always due to pressure from cities close-by
@ -574,7 +573,7 @@ object UnitActions {
action = {
city.religion.removeAllPressuresExceptFor(unit.religion!!)
unit.currentMovement = 0f
useActionWithLimitedUses(unit, Constants.removeHeresyAbilityCount, maxHerseyUses)
useActionWithLimitedUses(unit, Constants.removeHeresyAbilityCount)
}.takeIf { unit.currentMovement > 0f }
)
}
@ -582,7 +581,7 @@ object UnitActions {
fun getImprovementConstructionActions(unit: MapUnit, tile: TileInfo): ArrayList<UnitAction> {
val finalActions = ArrayList<UnitAction>()
var uniquesToCheck = unit.getMatchingUniques("Can construct []")
if (unit.religiousActionsUnitCanDo().all { unit.abilityUsedCount[it] == 0 })
if (unit.religiousActionsUnitCanDo().all { unit.abilityUsesLeft[it] == unit.maxAbilityUses[it] })
uniquesToCheck += unit.getMatchingUniques("Can construct [] if it hasn't used other actions yet")
for (unique in uniquesToCheck) {

View File

@ -264,6 +264,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Shield and Swords](https://thenounproject.com/term/shield-and-swords/1477527/) By Alina Oleynik for Armory
* [Machu Picchu](https://thenounproject.com/browse/?i=1678226/) By [Chanut is Industries](https://thenounproject.com/chanut-is)
* [Garden](https://thenounproject.com/search/?q=garden&i=1478380) By Bharat
* [Mosque](https://thenounproject.com/search/?q=mosque&i=2458353) by yanti for Great Mosque of Djenne
### Renaissance Era
@ -332,7 +333,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Illuminati](https://thenounproject.com/term/illuminati/1617812) by emilegraphics for the Utopia Project
* [Christian Church](https://thenounproject.com/term/christian-church/1174183/) by Andrejs Kirma for Monastery
* [cathedral](https://thenounproject.com/search/?q=Cathedral&i=4136407) by Pixel Bazaar for Cathedral
* [Mosque](https://thenounproject.com/search/?q=mosque&i=4139519) by Ahmad Roaayala for Mosque
* [Mosque](https://thenounproject.com/search/?q=mosque&i=1744106) by yanti for Mosque
* [Pagoda](https://thenounproject.com/search/?q=pagoda&i=446665) by Xinh Studio for Pagoda