mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-09 15:29:32 +07:00
From the indstrial era onwards, things change in religion (#5095)
* Improved redability * From the industrial era onwards, religion goes into 'second phase' * Fixed tests * Fixed formula for buying great prophets starting from the industrial era * Added `getMatchingUniques`, `hasUnique` to `IHasUniques`, cleaned up some code * Fix compilation errors
This commit is contained in:
@ -137,7 +137,11 @@
|
|||||||
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
||||||
"Militaristic": ["Provides military units every [17] turns"]
|
"Militaristic": ["Provides military units every [17] turns"]
|
||||||
},
|
},
|
||||||
"iconRGB": [63, 81, 182]
|
"iconRGB": [63, 81, 182],
|
||||||
|
"uniques": ["May not generate great prophet equivalents naturally",
|
||||||
|
"May buy [Great Prophet] units for [200] [Faith] [in all cities in which the majority religion is a major religion] at an increasing price ([100])",
|
||||||
|
"Starting in this era disables religion"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Modern era",
|
"name": "Modern era",
|
||||||
@ -168,7 +172,11 @@
|
|||||||
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
||||||
"Militaristic": ["Provides military units every [17] turns"]
|
"Militaristic": ["Provides military units every [17] turns"]
|
||||||
},
|
},
|
||||||
"iconRGB": [33, 150, 243]
|
"iconRGB": [33, 150, 243],
|
||||||
|
"uniques": ["May not generate great prophet equivalents naturally",
|
||||||
|
"May buy [Great Prophet] units for [200] [Faith] [in all cities in which the majority religion is a major religion] at an increasing price ([100])",
|
||||||
|
"Starting in this era disables religion"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Atomic era",
|
"name": "Atomic era",
|
||||||
@ -200,7 +208,11 @@
|
|||||||
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
||||||
"Militaristic": ["Provides military units every [17] turns"]
|
"Militaristic": ["Provides military units every [17] turns"]
|
||||||
},
|
},
|
||||||
"iconRGB": [0, 150, 136]
|
"iconRGB": [0, 150, 136],
|
||||||
|
"uniques": ["May not generate great prophet equivalents naturally",
|
||||||
|
"May buy [Great Prophet] units for [200] [Faith] [in all cities in which the majority religion is a major religion] at an increasing price ([100])",
|
||||||
|
"Starting in this era disables religion"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Information era",
|
"name": "Information era",
|
||||||
@ -236,7 +248,11 @@
|
|||||||
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
||||||
"Militaristic": ["Provides military units every [17] turns"]
|
"Militaristic": ["Provides military units every [17] turns"]
|
||||||
},
|
},
|
||||||
"iconRGB": [76, 176, 81]
|
"iconRGB": [76, 176, 81],
|
||||||
|
"uniques": ["May not generate great prophet equivalents naturally",
|
||||||
|
"May buy [Great Prophet] units for [200] [Faith] [in all cities in which the majority religion is a major religion] at an increasing price ([100])",
|
||||||
|
"Starting in this era disables religion"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{ // Technically, this Era doesn't exist in the original game.
|
{ // Technically, this Era doesn't exist in the original game.
|
||||||
// But as it is _really_ usefull to have for testing, I'd like to keep it.
|
// But as it is _really_ usefull to have for testing, I'd like to keep it.
|
||||||
@ -271,6 +287,10 @@
|
|||||||
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
|
||||||
"Militaristic": ["Provides military units every [17] turns"]
|
"Militaristic": ["Provides military units every [17] turns"]
|
||||||
},
|
},
|
||||||
"iconRGB": [76, 176, 81]
|
"iconRGB": [76, 176, 81],
|
||||||
|
"uniques": ["May not generate great prophet equivalents naturally",
|
||||||
|
"May buy [Great Prophet] units for [200] [Faith] [in all cities in which the majority religion is a major religion] at an increasing price ([100])",
|
||||||
|
"Starting in this era disables religion"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
@ -433,7 +433,10 @@ class GameInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun hasReligionEnabled() = gameParameters.religionEnabled || ruleSet.hasReligion() // Temporary function to check whether religion should be used for this game
|
fun hasReligionEnabled() =
|
||||||
|
// Temporary function to check whether religion should be used for this game
|
||||||
|
(gameParameters.religionEnabled || ruleSet.hasReligion())
|
||||||
|
&& (ruleSet.eras.isEmpty() || !ruleSet.eras[gameParameters.startingEra]!!.hasUnique("Starting in this era disables religion"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduced variant only for load preview
|
// reduced variant only for load preview
|
||||||
|
@ -43,15 +43,15 @@ class CityInfo {
|
|||||||
lateinit var tilesInRange: HashSet<TileInfo>
|
lateinit var tilesInRange: HashSet<TileInfo>
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
var hasJustBeenConquered =
|
// This is so that military units can enter the city, even before we decide what to do with it
|
||||||
false // this is so that military units can enter the city, even before we decide what to do with it
|
var hasJustBeenConquered = false
|
||||||
|
|
||||||
var location: Vector2 = Vector2.Zero
|
var location: Vector2 = Vector2.Zero
|
||||||
var id: String = UUID.randomUUID().toString()
|
var id: String = UUID.randomUUID().toString()
|
||||||
var name: String = ""
|
var name: String = ""
|
||||||
var foundingCiv = ""
|
var foundingCiv = ""
|
||||||
var previousOwner =
|
// This is so that cities in resistance that are recaptured aren't in resistance anymore
|
||||||
"" // This is so that cities in resistance that re recaptured aren't in resistance anymore
|
var previousOwner = ""
|
||||||
var turnAcquired = 0
|
var turnAcquired = 0
|
||||||
var health = 200
|
var health = 200
|
||||||
var resistanceCounter = 0
|
var resistanceCounter = 0
|
||||||
@ -245,8 +245,10 @@ class CityInfo {
|
|||||||
fun isCapital(): Boolean = cityConstructions.builtBuildings.contains(capitalCityIndicator())
|
fun isCapital(): Boolean = cityConstructions.builtBuildings.contains(capitalCityIndicator())
|
||||||
fun isCoastal(): Boolean = centerTileInfo.isCoastalTile()
|
fun isCoastal(): Boolean = centerTileInfo.isCoastalTile()
|
||||||
fun capitalCityIndicator(): String {
|
fun capitalCityIndicator(): String {
|
||||||
val indicatorBuildings = getRuleset().buildings.values.asSequence()
|
val indicatorBuildings = getRuleset().buildings.values
|
||||||
|
.asSequence()
|
||||||
.filter { it.uniques.contains("Indicates the capital city") }
|
.filter { it.uniques.contains("Indicates the capital city") }
|
||||||
|
|
||||||
val civSpecificBuilding = indicatorBuildings.firstOrNull { it.uniqueTo == civInfo.civName }
|
val civSpecificBuilding = indicatorBuildings.firstOrNull { it.uniqueTo == civInfo.civName }
|
||||||
if (civSpecificBuilding != null) return civSpecificBuilding.name
|
if (civSpecificBuilding != null) return civSpecificBuilding.name
|
||||||
else return indicatorBuildings.first().name
|
else return indicatorBuildings.first().name
|
||||||
@ -294,8 +296,9 @@ class CityInfo {
|
|||||||
val resource = getRuleset().tileResources[unique.params[1]]
|
val resource = getRuleset().tileResources[unique.params[1]]
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
cityResources.add(
|
cityResources.add(
|
||||||
resource, unique.params[0].toInt()
|
resource,
|
||||||
* civInfo.getResourceModifier(resource), "Tiles"
|
unique.params[0].toInt() * civInfo.getResourceModifier(resource),
|
||||||
|
"Tiles"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,11 +599,15 @@ class CityInfo {
|
|||||||
*/
|
*/
|
||||||
private fun triggerCitiesSettledNearOtherCiv() {
|
private fun triggerCitiesSettledNearOtherCiv() {
|
||||||
val citiesWithin6Tiles =
|
val citiesWithin6Tiles =
|
||||||
civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != civInfo }
|
civInfo.gameInfo.civilizations
|
||||||
|
.filter { it.isMajorCiv() && it != civInfo }
|
||||||
.flatMap { it.cities }
|
.flatMap { it.cities }
|
||||||
.filter { it.getCenterTile().aerialDistanceTo(getCenterTile()) <= 6 }
|
.filter { it.getCenterTile().aerialDistanceTo(getCenterTile()) <= 6 }
|
||||||
val civsWithCloseCities = citiesWithin6Tiles.map { it.civInfo }.distinct()
|
val civsWithCloseCities =
|
||||||
.filter { it.knows(civInfo) && it.exploredTiles.contains(location) }
|
citiesWithin6Tiles
|
||||||
|
.map { it.civInfo }
|
||||||
|
.distinct()
|
||||||
|
.filter { it.knows(civInfo) && it.exploredTiles.contains(location) }
|
||||||
for (otherCiv in civsWithCloseCities)
|
for (otherCiv in civsWithCloseCities)
|
||||||
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs, 30)
|
otherCiv.getDiplomacyManager(civInfo).setFlag(DiplomacyFlags.SettledCitiesNearUs, 30)
|
||||||
}
|
}
|
||||||
@ -627,13 +634,13 @@ class CityInfo {
|
|||||||
"in all cities with a garrison" -> getCenterTile().militaryUnit != null
|
"in all cities with a garrison" -> getCenterTile().militaryUnit != null
|
||||||
"in all cities in which the majority religion is a major religion" ->
|
"in all cities in which the majority religion is a major religion" ->
|
||||||
religion.getMajorityReligionName() != null
|
religion.getMajorityReligionName() != null
|
||||||
&& religion.getMajorityReligion()!!.isMajorReligion()
|
&& religion.getMajorityReligion()!!.isMajorReligion()
|
||||||
"in all cities in which the majority religion is an enhanced religion" ->
|
"in all cities in which the majority religion is an enhanced religion" ->
|
||||||
religion.getMajorityReligionName() != null
|
religion.getMajorityReligionName() != null
|
||||||
&& religion.getMajorityReligion()!!.isEnhancedReligion()
|
&& religion.getMajorityReligion()!!.isEnhancedReligion()
|
||||||
"in non-enemy foreign cities" ->
|
"in non-enemy foreign cities" ->
|
||||||
viewingCiv != civInfo
|
viewingCiv != civInfo
|
||||||
&& !civInfo.isAtWarWith(viewingCiv)
|
&& !civInfo.isAtWarWith(viewingCiv)
|
||||||
"in foreign cities" -> viewingCiv != civInfo
|
"in foreign cities" -> viewingCiv != civInfo
|
||||||
"in annexed cities" -> foundingCiv != civInfo.civName && !isPuppet
|
"in annexed cities" -> foundingCiv != civInfo.civName && !isPuppet
|
||||||
"in holy cities" -> religion.religionThisIsTheHolyCityOf != null
|
"in holy cities" -> religion.religionThisIsTheHolyCityOf != null
|
||||||
@ -715,9 +722,11 @@ class CityInfo {
|
|||||||
if (!tilesList.contains(tile))
|
if (!tilesList.contains(tile))
|
||||||
cityPositionList.add(tile)
|
cityPositionList.add(tile)
|
||||||
|
|
||||||
return cityPositionList.asSequence()
|
return cityPositionList
|
||||||
.map { it.getOwner()?.civName }.filterNotNull()
|
.asSequence()
|
||||||
.distinct().toList()
|
.mapNotNull { it.getOwner()?.civName }
|
||||||
|
.distinct()
|
||||||
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImprovableTiles(): Sequence<TileInfo> = getTiles()
|
fun getImprovableTiles(): Sequence<TileInfo> = getTiles()
|
||||||
|
@ -24,13 +24,6 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
|
|||||||
fun getRejectionReasons(cityConstructions: CityConstructions): RejectionReasons
|
fun getRejectionReasons(cityConstructions: CityConstructions): RejectionReasons
|
||||||
fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat? = null): Boolean // Yes I'm hilarious.
|
fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat? = null): Boolean // Yes I'm hilarious.
|
||||||
|
|
||||||
fun getMatchingUniques(uniqueTemplate: String): Sequence<Unique> {
|
|
||||||
return uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate }
|
|
||||||
}
|
|
||||||
fun hasUnique(uniqueTemplate: String): Boolean {
|
|
||||||
return uniqueObjects.any { it.placeholderText == uniqueTemplate }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canBePurchasedWithStat(cityInfo: CityInfo?, stat: Stat): Boolean {
|
fun canBePurchasedWithStat(cityInfo: CityInfo?, stat: Stat): Boolean {
|
||||||
if (stat in listOf(Stat.Production, Stat.Happiness)) return false
|
if (stat in listOf(Stat.Production, Stat.Happiness)) return false
|
||||||
if ("Cannot be purchased" in uniques) return false
|
if ("Cannot be purchased" in uniques) return false
|
||||||
@ -82,41 +75,46 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
|
|||||||
|
|
||||||
|
|
||||||
class RejectionReasons(): HashSet<RejectionReason>() {
|
class RejectionReasons(): HashSet<RejectionReason>() {
|
||||||
private val techPolicyEraWonderRequirements = hashSetOf(
|
|
||||||
RejectionReason.Obsoleted,
|
|
||||||
RejectionReason.RequiresTech,
|
|
||||||
RejectionReason.RequiresPolicy,
|
|
||||||
RejectionReason.MorePolicyBranches,
|
|
||||||
RejectionReason.RequiresBuildingInSomeCity
|
|
||||||
)
|
|
||||||
fun filterTechPolicyEraWonderRequirements(): HashSet<RejectionReason> {
|
fun filterTechPolicyEraWonderRequirements(): HashSet<RejectionReason> {
|
||||||
return filterNot { it in techPolicyEraWonderRequirements }.toHashSet()
|
return filterNot { it in techPolicyEraWonderRequirements }.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val reasonsToDefinitivelyRemoveFromQueue = hashSetOf(
|
|
||||||
RejectionReason.Obsoleted,
|
|
||||||
RejectionReason.WonderAlreadyBuilt,
|
|
||||||
RejectionReason.NationalWonderAlreadyBuilt,
|
|
||||||
RejectionReason.CannotBeBuiltWith,
|
|
||||||
RejectionReason.ReachedBuildCap
|
|
||||||
)
|
|
||||||
fun hasAReasonToBeRemovedFromQueue(): Boolean {
|
fun hasAReasonToBeRemovedFromQueue(): Boolean {
|
||||||
return any { it in reasonsToDefinitivelyRemoveFromQueue }
|
return any { it in reasonsToDefinitivelyRemoveFromQueue }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val orderOfErrorMessages = listOf(
|
|
||||||
RejectionReason.WonderBeingBuiltElsewhere,
|
|
||||||
RejectionReason.NationalWonderBeingBuiltElsewhere,
|
|
||||||
RejectionReason.RequiresBuildingInAllCities,
|
|
||||||
RejectionReason.RequiresBuildingInThisCity,
|
|
||||||
RejectionReason.RequiresBuildingInSomeCity,
|
|
||||||
RejectionReason.PopulationRequirement,
|
|
||||||
RejectionReason.ConsumesResources,
|
|
||||||
RejectionReason.CanOnlyBePurchased
|
|
||||||
)
|
|
||||||
fun getMostImportantRejectionReason(): String? {
|
fun getMostImportantRejectionReason(): String? {
|
||||||
return orderOfErrorMessages.firstOrNull { it in this }?.errorMessage
|
return orderOfErrorMessages.firstOrNull { it in this }?.errorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for constant variables in the functions above
|
||||||
|
companion object {
|
||||||
|
private val techPolicyEraWonderRequirements = hashSetOf(
|
||||||
|
RejectionReason.Obsoleted,
|
||||||
|
RejectionReason.RequiresTech,
|
||||||
|
RejectionReason.RequiresPolicy,
|
||||||
|
RejectionReason.MorePolicyBranches,
|
||||||
|
RejectionReason.RequiresBuildingInSomeCity
|
||||||
|
)
|
||||||
|
private val reasonsToDefinitivelyRemoveFromQueue = hashSetOf(
|
||||||
|
RejectionReason.Obsoleted,
|
||||||
|
RejectionReason.WonderAlreadyBuilt,
|
||||||
|
RejectionReason.NationalWonderAlreadyBuilt,
|
||||||
|
RejectionReason.CannotBeBuiltWith,
|
||||||
|
RejectionReason.ReachedBuildCap
|
||||||
|
)
|
||||||
|
private val orderOfErrorMessages = listOf(
|
||||||
|
RejectionReason.WonderBeingBuiltElsewhere,
|
||||||
|
RejectionReason.NationalWonderBeingBuiltElsewhere,
|
||||||
|
RejectionReason.RequiresBuildingInAllCities,
|
||||||
|
RejectionReason.RequiresBuildingInThisCity,
|
||||||
|
RejectionReason.RequiresBuildingInSomeCity,
|
||||||
|
RejectionReason.PopulationRequirement,
|
||||||
|
RejectionReason.ConsumesResources,
|
||||||
|
RejectionReason.CanOnlyBePurchased
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -293,11 +293,15 @@ class CivilizationInfo {
|
|||||||
temporaryUniques
|
temporaryUniques
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.first.placeholderText == uniqueTemplate }.map { it.first } +
|
.filter { it.first.placeholderText == uniqueTemplate }.map { it.first } +
|
||||||
if (religionManager.religion != null)
|
getEra().getMatchingUniques(uniqueTemplate)
|
||||||
religionManager.religion!!.getFounderUniques()
|
.asSequence() +
|
||||||
.asSequence()
|
(
|
||||||
.filter { it.placeholderText == uniqueTemplate }
|
if (religionManager.religion != null)
|
||||||
else sequenceOf()
|
religionManager.religion!!.getFounderUniques()
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.placeholderText == uniqueTemplate }
|
||||||
|
else sequenceOf()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//region Units
|
//region Units
|
||||||
|
@ -27,8 +27,11 @@ class ReligionManager {
|
|||||||
// But the other one should still be _somewhere_. So our only option is to have the GameInfo
|
// But the other one should still be _somewhere_. So our only option is to have the GameInfo
|
||||||
// contain the master list, and the ReligionManagers retrieve it from there every time the game loads.
|
// contain the master list, and the ReligionManagers retrieve it from there every time the game loads.
|
||||||
|
|
||||||
var greatProphetsEarned = 0
|
// Deprecated since 3.16.13
|
||||||
private set
|
@Deprecated("Replace by adding to `civInfo.boughtConstructionsWithGloballyIncreasingPrice`")
|
||||||
|
var greatProphetsEarned = 0
|
||||||
|
private set
|
||||||
|
//
|
||||||
|
|
||||||
var religionState = ReligionState.None
|
var religionState = ReligionState.None
|
||||||
private set
|
private set
|
||||||
@ -47,7 +50,6 @@ class ReligionManager {
|
|||||||
clone.shouldChoosePantheonBelief = shouldChoosePantheonBelief
|
clone.shouldChoosePantheonBelief = shouldChoosePantheonBelief
|
||||||
clone.storedFaith = storedFaith
|
clone.storedFaith = storedFaith
|
||||||
clone.religionState = religionState
|
clone.religionState = religionState
|
||||||
clone.greatProphetsEarned = greatProphetsEarned
|
|
||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +64,13 @@ class ReligionManager {
|
|||||||
religion = civInfo.gameInfo.religions.values.firstOrNull {
|
religion = civInfo.gameInfo.religions.values.firstOrNull {
|
||||||
it.foundingCivName == civInfo.civName
|
it.foundingCivName == civInfo.civName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// greatProphetsEarned deprecated since 3.16.13, replacement code
|
||||||
|
if (greatProphetsEarned != 0) {
|
||||||
|
civInfo.boughtConstructionsWithGloballyIncreasingPrice[getGreatProphetEquivalent()!!] = greatProphetsEarned
|
||||||
|
greatProphetsEarned = 0
|
||||||
|
}
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startTurn() {
|
fun startTurn() {
|
||||||
@ -106,6 +115,8 @@ class ReligionManager {
|
|||||||
// https://www.reddit.com/r/civ/comments/2m82wu/can_anyone_detail_the_finer_points_of_great/
|
// https://www.reddit.com/r/civ/comments/2m82wu/can_anyone_detail_the_finer_points_of_great/
|
||||||
// Game files (globaldefines.xml)
|
// Game files (globaldefines.xml)
|
||||||
fun faithForNextGreatProphet(): Int {
|
fun faithForNextGreatProphet(): Int {
|
||||||
|
val greatProphetsEarned = civInfo.boughtConstructionsWithGloballyIncreasingPrice[getGreatProphetEquivalent()!!] ?: 0
|
||||||
|
|
||||||
var faithCost =
|
var faithCost =
|
||||||
(200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1) / 2f) *
|
(200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1) / 2f) *
|
||||||
civInfo.gameInfo.gameParameters.gameSpeed.modifier
|
civInfo.gameInfo.gameParameters.gameSpeed.modifier
|
||||||
@ -120,22 +131,28 @@ class ReligionManager {
|
|||||||
if (religion == null || religionState == ReligionState.None) return false // First get a pantheon, then we'll talk about a real religion
|
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 (storedFaith < faithForNextGreatProphet()) return false
|
||||||
if (!civInfo.isMajorCiv()) return false
|
if (!civInfo.isMajorCiv()) return false
|
||||||
// In the base game, great prophets shouldn't generate anymore starting from the industrial era
|
if (civInfo.hasUnique("May not generate great prophet equivalents naturally")) return false
|
||||||
// This is difficult to implement in the current codebase, probably requires an additional variable in eras.json
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getGreatProphetEquivalent(): String? {
|
||||||
|
return civInfo.gameInfo.ruleSet.units.values.firstOrNull { it.hasUnique("May found a religion") }?.name
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateProphet() {
|
private fun generateProphet() {
|
||||||
|
val prophetUnitName = getGreatProphetEquivalent() ?: return // No prophet units in this mod
|
||||||
|
|
||||||
val prophetSpawnChange = (5f + storedFaith - faithForNextGreatProphet()) / 100f
|
val prophetSpawnChange = (5f + storedFaith - faithForNextGreatProphet()) / 100f
|
||||||
|
|
||||||
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.religion.religionThisIsTheHolyCityOf == religion!!.name }
|
else civInfo.cities.firstOrNull { it.religion.religionThisIsTheHolyCityOf == religion!!.name }
|
||||||
val prophet = civInfo.addUnit("Great Prophet", birthCity) ?: return
|
val prophet = civInfo.addUnit(prophetUnitName, birthCity) ?: return
|
||||||
prophet.religion = religion!!.name
|
prophet.religion = religion!!.name
|
||||||
storedFaith -= faithForNextGreatProphet()
|
storedFaith -= faithForNextGreatProphet()
|
||||||
greatProphetsEarned += 1
|
civInfo.boughtConstructionsWithGloballyIncreasingPrice[prophetUnitName] =
|
||||||
|
(civInfo.boughtConstructionsWithGloballyIncreasingPrice[prophetUnitName] ?: 0) + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,9 @@ class RuinsManager {
|
|||||||
for (possibleReward in possibleRewards) {
|
for (possibleReward in possibleRewards) {
|
||||||
if (civInfo.gameInfo.difficulty in possibleReward.excludedDifficulties) continue
|
if (civInfo.gameInfo.difficulty in possibleReward.excludedDifficulties) continue
|
||||||
if (Constants.hiddenWithoutReligionUnique in possibleReward.uniques && !civInfo.gameInfo.hasReligionEnabled()) continue
|
if (Constants.hiddenWithoutReligionUnique in possibleReward.uniques && !civInfo.gameInfo.hasReligionEnabled()) continue
|
||||||
if ("Hidden after generating a Great Prophet" in possibleReward.uniques && civInfo.religionManager.greatProphetsEarned > 0) continue
|
if ("Hidden after generating a Great Prophet" in possibleReward.uniques
|
||||||
|
&& civInfo.boughtConstructionsWithGloballyIncreasingPrice[civInfo.religionManager.getGreatProphetEquivalent()] ?: 0 > 0
|
||||||
|
) continue
|
||||||
if (possibleReward.uniqueObjects.any { unique ->
|
if (possibleReward.uniqueObjects.any { unique ->
|
||||||
unique.placeholderText == "Only available after [] turns"
|
unique.placeholderText == "Only available after [] turns"
|
||||||
&& unique.params[0].toInt() < civInfo.gameInfo.turns
|
&& unique.params[0].toInt() < civInfo.gameInfo.turns
|
||||||
|
@ -5,7 +5,7 @@ import com.unciv.logic.civilization.CityStateType
|
|||||||
import com.unciv.models.stats.INamed
|
import com.unciv.models.stats.INamed
|
||||||
import com.unciv.ui.utils.colorFromRGB
|
import com.unciv.ui.utils.colorFromRGB
|
||||||
|
|
||||||
class Era : INamed {
|
class Era : INamed, IHasUniques {
|
||||||
override var name: String = ""
|
override var name: String = ""
|
||||||
var eraNumber: Int = -1
|
var eraNumber: Int = -1
|
||||||
var researchAgreementCost = 300
|
var researchAgreementCost = 300
|
||||||
@ -25,6 +25,8 @@ class Era : INamed {
|
|||||||
var friendBonus = HashMap<String, List<String>>()
|
var friendBonus = HashMap<String, List<String>>()
|
||||||
var allyBonus = HashMap<String, List<String>>()
|
var allyBonus = HashMap<String, List<String>>()
|
||||||
var iconRGB: List<Int>? = null
|
var iconRGB: List<Int>? = null
|
||||||
|
override var uniques: ArrayList<String> = arrayListOf()
|
||||||
|
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||||
|
|
||||||
fun getStartingUnits(): List<String> {
|
fun getStartingUnits(): List<String> {
|
||||||
val startingUnits = mutableListOf<String>()
|
val startingUnits = mutableListOf<String>()
|
||||||
|
@ -6,4 +6,8 @@ package com.unciv.models.ruleset
|
|||||||
interface IHasUniques {
|
interface IHasUniques {
|
||||||
var uniques: ArrayList<String> // Can not be a hashset as that would remove doubles
|
var uniques: ArrayList<String> // Can not be a hashset as that would remove doubles
|
||||||
val uniqueObjects: List<Unique>
|
val uniqueObjects: List<Unique>
|
||||||
|
|
||||||
|
fun getMatchingUniques(uniqueTemplate: String) = uniqueObjects.asSequence().filter { it.placeholderText == uniqueTemplate }
|
||||||
|
|
||||||
|
fun hasUnique(uniqueTemplate: String) = uniqueObjects.any { it.placeholderText == uniqueTemplate }
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ class RuinReward : INamed, ICivilopediaText, IHasUniques {
|
|||||||
override var uniques = ArrayList<String>()
|
override var uniques = ArrayList<String>()
|
||||||
@delegate:Transient // Defense in depth against mad modders
|
@delegate:Transient // Defense in depth against mad modders
|
||||||
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||||
|
|
||||||
val excludedDifficulties: List<String> = listOf()
|
val excludedDifficulties: List<String> = listOf()
|
||||||
val weight: Int = 1
|
val weight: Int = 1
|
||||||
val color: String = "" // For Civilopedia
|
val color: String = "" // For Civilopedia
|
||||||
|
@ -3,6 +3,7 @@ package com.unciv.models.ruleset.tile
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.models.ruleset.Belief
|
import com.unciv.models.ruleset.Belief
|
||||||
|
import com.unciv.models.ruleset.IHasUniques
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.Unique
|
import com.unciv.models.ruleset.Unique
|
||||||
import com.unciv.models.stats.NamedStats
|
import com.unciv.models.stats.NamedStats
|
||||||
@ -10,7 +11,7 @@ import com.unciv.ui.civilopedia.FormattedLine
|
|||||||
import com.unciv.ui.civilopedia.ICivilopediaText
|
import com.unciv.ui.civilopedia.ICivilopediaText
|
||||||
import com.unciv.ui.utils.colorFromRGB
|
import com.unciv.ui.utils.colorFromRGB
|
||||||
|
|
||||||
class Terrain : NamedStats(), ICivilopediaText {
|
class Terrain : NamedStats(), ICivilopediaText, IHasUniques {
|
||||||
|
|
||||||
lateinit var type: TerrainType
|
lateinit var type: TerrainType
|
||||||
|
|
||||||
@ -26,8 +27,8 @@ class Terrain : NamedStats(), ICivilopediaText {
|
|||||||
val turnsInto: String? = null
|
val turnsInto: String? = null
|
||||||
|
|
||||||
/** Uniques (Properties such as Temp/humidity, Fresh water, elevation, rough, defense, Natural Wonder specials) */
|
/** Uniques (Properties such as Temp/humidity, Fresh water, elevation, rough, defense, Natural Wonder specials) */
|
||||||
val uniques = ArrayList<String>()
|
override var uniques = ArrayList<String>()
|
||||||
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||||
|
|
||||||
/** Natural Wonder weight: probability to be picked */
|
/** Natural Wonder weight: probability to be picked */
|
||||||
var weight = 10
|
var weight = 10
|
||||||
|
@ -70,7 +70,6 @@ class TileImprovement : NamedStats(), ICivilopediaText, IHasUniques {
|
|||||||
return lines.joinToString("\n")
|
return lines.joinToString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasUnique(unique: String) = uniques.contains(unique)
|
|
||||||
fun isGreatImprovement() = hasUnique("Great Improvement")
|
fun isGreatImprovement() = hasUnique("Great Improvement")
|
||||||
fun isRoad() = RoadStatus.values().any { it != RoadStatus.None && it.name == this.name }
|
fun isRoad() = RoadStatus.values().any { it != RoadStatus.None && it.name == this.name }
|
||||||
fun isAncientRuinsEquivalent() = hasUnique("Provides a random bonus when entered")
|
fun isAncientRuinsEquivalent() = hasUnique("Provides a random bonus when entered")
|
||||||
|
@ -225,6 +225,15 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
|||||||
}
|
}
|
||||||
) return true
|
) return true
|
||||||
|
|
||||||
|
// May buy [unitFilter] units for [amount] [Stat] [cityFilter] at an increasing price ([amount])
|
||||||
|
if (cityInfo != null && cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] at an increasing price ([])")
|
||||||
|
.any {
|
||||||
|
matchesFilter(it.params[0])
|
||||||
|
&& cityInfo.matchesFilter(it.params[3])
|
||||||
|
&& it.params[2] == stat.name
|
||||||
|
}
|
||||||
|
) return true
|
||||||
|
|
||||||
return super.canBePurchasedWithStat(cityInfo, stat)
|
return super.canBePurchasedWithStat(cityInfo, stat)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,12 +246,12 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
|||||||
return (
|
return (
|
||||||
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
|
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
|
||||||
// May buy [unitFilter] units for [amount] [Stat] starting from the [eraName] at an increasing price ([amount])
|
// May buy [unitFilter] units for [amount] [Stat] starting from the [eraName] at an increasing price ([amount])
|
||||||
+ cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
|
+ (cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
|
||||||
.filter {
|
.filter {
|
||||||
matchesFilter(it.params[0])
|
matchesFilter(it.params[0])
|
||||||
&& cityInfo.matchesFilter(it.params[3])
|
&& cityInfo.matchesFilter(it.params[3])
|
||||||
&& cityInfo.civInfo.getEraNumber() >= ruleset.eras[it.params[4]]!!.eraNumber
|
&& cityInfo.civInfo.getEraNumber() >= ruleset.eras[it.params[4]]!!.eraNumber
|
||||||
&& it.params[2] == stat.name
|
&& it.params[2] == stat.name
|
||||||
}.map {
|
}.map {
|
||||||
getCostForConstructionsIncreasingInPrice(
|
getCostForConstructionsIncreasingInPrice(
|
||||||
it.params[1].toInt(),
|
it.params[1].toInt(),
|
||||||
@ -250,6 +259,20 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
|
|||||||
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
|
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
+ (cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] at an increasing price ([])")
|
||||||
|
.filter {
|
||||||
|
matchesFilter(it.params[0])
|
||||||
|
&& cityInfo.matchesFilter(it.params[3])
|
||||||
|
&& it.params[2] == stat.name
|
||||||
|
}.map {
|
||||||
|
getCostForConstructionsIncreasingInPrice(
|
||||||
|
it.params[1].toInt(),
|
||||||
|
it.params[4].toInt(),
|
||||||
|
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
).minOrNull()
|
).minOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.unciv.models.ruleset.unit
|
package com.unciv.models.ruleset.unit
|
||||||
|
|
||||||
|
import com.unciv.models.ruleset.IHasUniques
|
||||||
import com.unciv.models.ruleset.Unique
|
import com.unciv.models.ruleset.Unique
|
||||||
import com.unciv.models.stats.INamed
|
import com.unciv.models.stats.INamed
|
||||||
|
|
||||||
@ -16,13 +17,13 @@ enum class UnitMovementType { // The types of tiles the unit can by default ente
|
|||||||
Air // Only city tiles and carrying units
|
Air // Only city tiles and carrying units
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnitType() : INamed {
|
class UnitType() : INamed, IHasUniques {
|
||||||
override lateinit var name: String
|
override lateinit var name: String
|
||||||
private var movementType: String? = null
|
private var movementType: String? = null
|
||||||
private val unitMovementType: UnitMovementType? by lazy { if (movementType == null) null else UnitMovementType.valueOf(movementType!!) }
|
private val unitMovementType: UnitMovementType? by lazy { if (movementType == null) null else UnitMovementType.valueOf(movementType!!) }
|
||||||
|
|
||||||
val uniques: ArrayList<String> = ArrayList()
|
override var uniques: ArrayList<String> = ArrayList()
|
||||||
val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
|
||||||
|
|
||||||
constructor(name: String, domain: String? = null) : this() {
|
constructor(name: String, domain: String? = null) : this() {
|
||||||
this.name = name
|
this.name = name
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
package com.unciv.logic.map
|
package com.unciv.logic.map
|
||||||
|
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.logic.GameInfo
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
import com.unciv.logic.civilization.diplomacy.DiplomacyManager
|
import com.unciv.logic.civilization.diplomacy.DiplomacyManager
|
||||||
@ -37,6 +38,8 @@ class UnitMovementAlgorithmsTests {
|
|||||||
name = "My nation"
|
name = "My nation"
|
||||||
cities = arrayListOf("The Capital")
|
cities = arrayListOf("The Capital")
|
||||||
}
|
}
|
||||||
|
civInfo.gameInfo = GameInfo()
|
||||||
|
civInfo.gameInfo.ruleSet = ruleSet
|
||||||
unit.civInfo = civInfo
|
unit.civInfo = civInfo
|
||||||
|
|
||||||
|
|
||||||
@ -117,10 +120,13 @@ class UnitMovementAlgorithmsTests {
|
|||||||
unit.baseUnit = BaseUnit().apply { unitType = type.key; ruleset = ruleSet }
|
unit.baseUnit = BaseUnit().apply { unitType = type.key; ruleset = ruleSet }
|
||||||
unit.updateUniques()
|
unit.updateUniques()
|
||||||
|
|
||||||
Assert.assertTrue("$type cannot be in Ice", (
|
Assert.assertTrue(
|
||||||
type.value.uniques.contains("Can enter ice tiles"))
|
"$type cannot be in Ice",
|
||||||
|| type.value.uniques.contains("Can pass through impassable tiles"
|
unit.movement.canPassThrough(tile) == (
|
||||||
) == unit.movement.canPassThrough(tile))
|
type.value.uniques.contains("Can enter ice tiles")
|
||||||
|
|| type.value.uniques.contains("Can pass through impassable tiles")
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user