Add missing pantheons, fix minor bugs (#4419)

* Added all remaining pantheons

* AI now choose pantheons, AI no longer tries to get mutually exclusive policies

* I don't know why this was changed

* Implemented requested changes
This commit is contained in:
Xander Lenstra 2021-07-10 21:50:50 +02:00 committed by GitHub
parent 77b4bcd26a
commit b650b95356
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 140 additions and 25 deletions

View File

@ -5,20 +5,33 @@
"type": "Pantheon",
"uniques": ["[+1 Culture] from every [Shrine]"]
},
// Missing: Dance of the aurora
{
"name": "Dance of the Aurora",
"type": "Pantheon",
"uniques": ["[+1 Faith] from [Tundra] tiles without [Forest] [in this city]"]
},
{
"name": "Desert Folklore",
"type": "Pantheon",
"uniques": ["[+1 Faith] from every [Desert]"]
},
// Missing: Faith Healers
{
"name": "Faith Healers",
"type": "Pantheon",
"uniques": ["[All] Units adjacent to this city heal [+30] HP per turn when healing"]
// This should be worded better
},
{
"name": "Fertility Rates",
"type": "Pantheon",
"uniques": ["+[10]% Growth [in this city]"]
// Preferably I would not have a cityFilter here, but doing so requires no additional implementation
},
// Missing: God of Craftsman
{
"name": "God of Craftsman",
"type": "Pantheon",
"uniques": ["[+1 Production] in cities with [3] or more population"]
},
{
"name": "God of the Open Sky",
"type": "Pantheon",
@ -29,22 +42,52 @@
"type": "Pantheon",
"uniques": ["[+1 Production] from every [Fishing Boats]"]
},
// Missing: God of War
{
"name": "God of War",
"type": "Pantheon",
"uniques": ["Earn [50]% of [Military] unit's [Strength] as [Faith] when killed within 4 tiles of a city following this religion"]
}
{
"name": "Goddess of Festivals",
"type": "Pantheon",
"uniques": ["[+1 Culture, +1 Faith] from every [Wine]", "[+1 Culture, +1 Faith] from every [Incense]"]
},
// Missing: Goddess of Love
// Missing: Godess of Protection
{
"name": "Goddess of Love",
"type": "Pantheon",
"uniques": ["[+1 Happiness] in cities with [6] or more population"]
},
{
"name": "Goddess of Protection",
"type": "Pantheon",
"uniques": ["[+30]% attacking Strength for cities"]
},
{
"name": "Goddess of the Hunt",
"type": "Pantheon",
"uniques": ["[+1 Food] from every [Camp]"]
},
// Missing: Messenger of the Gods
// Missing: Monument to the Gods
// Missing: One with Nature
{
"name": "Messenger of the Gods",
"type": "Pantheon",
"uniques": ["[+2 Science] from each Trade Route"]
},
{
"name": "Monument to the Gods",
"type": "Pantheon",
"uniques": ["+[15]% Production when constructing [Wonders]"]
// Should only be ancient/classical era wonders, but implementing that is another can of worms
// For that we really should need an era.matchesFilter() AND support for multiple values in
// construction.matchesFilter(), so we could write something like:
//"uniques": ["[+15]% Production when constructing [{Ancient Era} {Wonders}]",
// "[+15]% Production when constructing [{Classical Era} {Wonders}]"]
// For now this feels like overkill, but I'll leave this here for the future
},
{
"name": "One with Nature",
"type": "Pantheon",
"uniques": ["[+4 Faith] from every [Natural Wonder]"]
},
{
"name": "Oral Tradition",
"type": "Pantheon",
@ -55,17 +98,25 @@
"type": "Pantheon",
"uniques": ["[+1 Culture, +1 Faith] from every [Gold]", "[+1 Culture, +1 Faith] from every [Silver]"]
},
// Missing: Religious Settlements
{
"name": "Religious Settlements",
"type": "Pantheon",
"uniques": ["[-15]% cost of natural border growth"]
},
{
"name": "Sacred Path",
"type": "Pantheon",
"uniques": ["[+1 Culture] from every [Jungle]"]
},
// Missing: Sacred Waters
{
"name": "Sacred Waters",
"type": "Pantheon",
"uniques": ["[+1 Happiness] in cities on [River] tiles"]
},
{
"name": "Stone Circles",
"type": "Pantheon",
"uniques": ["[+2 Faith] from every [Quarry]"]
},
}
]

View File

@ -37,6 +37,7 @@ object NextTurnAutomation {
exchangeLuxuries(civInfo)
issueRequests(civInfo)
adoptPolicy(civInfo)
choosePantheon(civInfo)
} else {
getFreeTechForCityStates(civInfo)
updateDiplomaticRelationshipForCityStates(civInfo)
@ -204,9 +205,9 @@ object NextTurnAutomation {
val preferredVictoryType = civInfo.victoryType()
val policyBranchPriority =
when (preferredVictoryType) {
VictoryType.Cultural -> listOf("Piety", "Freedom", "Tradition", "Rationalism", "Commerce")
VictoryType.Scientific -> listOf("Rationalism", "Commerce", "Liberty", "Freedom", "Piety")
VictoryType.Domination -> listOf("Autocracy", "Honor", "Liberty", "Rationalism", "Freedom")
VictoryType.Cultural -> listOf("Piety", "Freedom", "Tradition", "Commerce", "Patronage")
VictoryType.Scientific -> listOf("Rationalism", "Commerce", "Liberty", "Order", "Patronage")
VictoryType.Domination -> listOf("Autocracy", "Honor", "Liberty", "Rationalism", "Commerce")
VictoryType.Neutral -> listOf()
}
val policiesByPreference = adoptablePolicies
@ -221,6 +222,24 @@ object NextTurnAutomation {
civInfo.policies.adopt(policyToAdopt)
}
}
private fun choosePantheon(civInfo: CivilizationInfo) {
if (!civInfo.religionManager.canFoundPantheon()) return
// So looking through the source code of the base game available online,
// the functions for choosing beliefs total in at around 400 lines.
// https://github.com/Gedemon/Civ5-DLL/blob/aa29e80751f541ae04858b6d2a2c7dcca454201e/CvGameCoreDLL_Expansion1/CvReligionClasses.cpp
// line 4426 through 4870.
// This is way to much work for now, so I'll just choose a random pantheon instead.
// Should probably be changed later, but it works for now.
// If this is omitted, the AI will never choose a religion,
// instead automatically choosing the same one as the player,
// which is not good.
val availablePantheons = civInfo.gameInfo.ruleSet.beliefs.values
.filter { civInfo.religionManager.isPickablePantheonBelief(it) }
if (availablePantheons.isEmpty()) return // panic!
val chosenPantheon = availablePantheons.random() // Why calculate stuff?
civInfo.religionManager.choosePantheonBelief(chosenPantheon)
}
private fun potentialLuxuryTrades(civInfo: CivilizationInfo, otherCivInfo: CivilizationInfo): ArrayList<Trade> {
val tradeLogic = TradeLogic(civInfo, otherCivInfo)

View File

@ -104,7 +104,7 @@ object Battle {
private fun tryEarnFromKilling(civUnit: ICombatant, defeatedUnit: MapUnitCombatant) {
val unitStr = max(defeatedUnit.unit.baseUnit.strength, defeatedUnit.unit.baseUnit.rangedStrength)
val unitCost = defeatedUnit.unit.baseUnit.cost
val bonusUniquePlaceholderText = "Earn []% of killed [] unit's [] as []"
var bonusUniquePlaceholderText = "Earn []% of killed [] unit's [] as []"
val bonusUniques = ArrayList<Unique>()
@ -113,6 +113,15 @@ object Battle {
if (civUnit is MapUnitCombatant) {
bonusUniques.addAll(civUnit.unit.getMatchingUniques(bonusUniquePlaceholderText))
}
bonusUniquePlaceholderText = "Earn []% of [] unit's [] as [] when killed within 4 tiles of a city following this religion"
val cityWithReligion =
civUnit.getTile().getTilesInDistance(4).firstOrNull {
it.isCityCenter() && it.getCity()!!.getMatchingUniques(bonusUniquePlaceholderText).any()
}?.getCity()
if (cityWithReligion != null) {
bonusUniques.addAll(cityWithReligion.getLocalMatchingUniques(bonusUniquePlaceholderText))
}
for (unique in bonusUniques) {
if (!defeatedUnit.matchesCategory(unique.params[1])) continue

View File

@ -159,11 +159,14 @@ object BattleDamage {
modifiers["Statue of Zeus"] = 15
} else if (attacker is CityCombatant) {
if (attacker.city.getCenterTile().militaryUnit != null) {
val garrisonBonus = attacker.getCivInfo().getMatchingUniques("+[]% attacking strength for cities with garrisoned units")
val garrisonBonus = attacker.city.getMatchingUniques("+[]% attacking strength for cities with garrisoned units")
.sumBy { it.params[0].toInt() }
if (garrisonBonus != 0)
modifiers["Garrisoned unit"] = garrisonBonus
}
for (unique in attacker.city.getMatchingUniques("[]% attacking Strength for cities")) {
modifiers.add("Attacking Bonus", unique.params[0].toInt())
}
}
return modifiers

View File

@ -39,8 +39,13 @@ class CityExpansionManager {
if (cityInfo.matchesFilter(unique.params[1]))
cultureToNextTile *= (100 - unique.params[0].toFloat()) / 100
}
if (cityInfo.civInfo.hasUnique("Increased rate of border expansion")) cultureToNextTile *= 0.75
for (unique in cityInfo.getMatchingUniques("[]% cost of natural border growth"))
cultureToNextTile *= 1 + unique.params[0].toFloat() / 100f
// Unique deprecated since 3.15.10 (seems unused, and should be replaced by the unique above)
if (cityInfo.civInfo.hasUnique("Increased rate of border expansion")) cultureToNextTile *= 0.75
//
return cultureToNextTile.roundToInt()
}

View File

@ -223,6 +223,8 @@ class CityStats {
newHappinessList["Wonders"] = getStatsFromUniques(civInfo.getCivWideBuildingUniques()).happiness
newHappinessList["Religion"] = getStatsFromUniques(cityInfo.religion.getUniques()).happiness
newHappinessList["Tile yields"] = getStatsFromTiles().happiness
// we don't want to modify the existing happiness list because that leads
@ -268,6 +270,14 @@ class CityStats {
val amountOfEffects = (cityInfo.population.population / unique.params[1].toInt()).toFloat()
stats.add(unique.stats.times(amountOfEffects))
}
// "[stats] in cities with [amount] or more population
if (unique.placeholderText == "[] in cities with [] or more population" && cityInfo.population.population >= unique.params[1].toInt())
stats.add(unique.stats)
// "[stats] in cities on [tileFilter] tiles"
if (unique.placeholderText == "[] in cities on [] tiles" && cityInfo.getCenterTile().matchesTerrainFilter(unique.params[1]))
{stats.add(unique.stats); println(unique.text)}
}
return stats

View File

@ -43,6 +43,7 @@ class ReligionManager {
fun canFoundPantheon(): Boolean {
if (pantheonBelief != null) return false
if (!civInfo.gameInfo.hasReligionEnabled()) return false
if (!civInfo.isMajorCiv()) return false
if (civInfo.gameInfo.ruleSet.beliefs.values.none { isPickablePantheonBelief(it) })
return false
return storedFaith >= faithForPantheon()

View File

@ -560,20 +560,28 @@ class MapUnit {
}
val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique("May heal outside of friendly territory"))
if (!mayHeal) return healing
// Deprecated since 3.15.6
if (hasUnique("This unit and all others in adjacent tiles heal 5 additional HP. This unit heals 5 additional HP outside of friendly territory.")
&& !isFriendlyTerritory
&& mayHeal
)// Additional healing from medic is only applied when the unit is able to heal
healing += 5
//
if (mayHeal) {
for (unique in getMatchingUniques("[] HP when healing in [] tiles")) {
if (tileInfo.matchesFilter(unique.params[1], civInfo)) {
healing += unique.params[0].toInt()
}
for (unique in getMatchingUniques("[] HP when healing in [] tiles")) {
if (tileInfo.matchesFilter(unique.params[1], civInfo)) {
healing += unique.params[0].toInt()
}
}
val healingCity = tileInfo.getTilesInDistance(1).firstOrNull {
it.isCityCenter() && it.getCity()!!.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing").any()
}?.getCity()
if (healingCity != null) {
for (unique in healingCity.getMatchingUniques("[] Units adjacent to this city heal [] HP per turn when healing")) {
if (!matchesFilter(unique.params[0])) continue
healing += unique.params[1].toInt()
}
}

View File

@ -237,6 +237,14 @@ open class TileInfo {
if (matchesTerrainFilter(tileType, observingCiv))
stats.add(unique.stats)
}
for (unique in city.getMatchingUniques("[] from [] tiles without [] []"))
if (
matchesTerrainFilter(unique.params[1]) &&
!matchesTerrainFilter(unique.params[2]) &&
city.matchesFilter(unique.params[3])
)
stats.add(unique.stats)
}
if (naturalWonder != null) {
@ -415,6 +423,7 @@ open class TileInfo {
"Friendly Land", "Friendly" -> observingCiv != null && isFriendlyTerritory(observingCiv)
resource -> observingCiv != null && hasViewableResource(observingCiv)
"Water resource" -> isWater && observingCiv != null && hasViewableResource(observingCiv)
"Natural Wonder" -> naturalWonder != null
else -> {
if (terrainFeatures.contains(filter)) return true
if (hasUnique(filter)) return true