Finishing the later five policy trees now allows you to buy great people with faith (#5038)

This commit is contained in:
Xander Lenstra
2021-09-01 08:46:27 +02:00
committed by GitHub
parent 634f4a3533
commit cffe8e441e
8 changed files with 130 additions and 70 deletions

View File

@ -275,7 +275,9 @@
},
{
"name": "Commerce Complete",
"uniques": ["[+1 Gold] from every [Trading post]", "Double gold from Great Merchant trade missions"]
"uniques": ["[+1 Gold] from every [Trading post]", "Double gold from Great Merchant trade missions",
"May buy [Great Merchant] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
}
]
},
@ -320,7 +322,9 @@
},
{
"name": "Rationalism Complete",
"uniques": ["[2] Free Technologies"]
"uniques": ["[2] Free Technologies",
"May buy [Great Scientist] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
}
]
},
@ -363,7 +367,9 @@
},
{
"name": "Freedom Complete",
"uniques": ["+[100]% yield from every [Great Improvement]", "Golden Age length increased by [50]%"]
"uniques": ["+[100]% yield from every [Great Improvement]", "Golden Age length increased by [50]%",
"May buy [Great Artist] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
}
]
},
@ -409,7 +415,10 @@
},
{
"name": "Autocracy Complete",
"uniques": ["+[25]% attack strength to all [Military] units for [50] turns"]
"uniques": ["+[25]% attack strength to all [Military] units for [50] turns",
"May buy [Great General] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])",
"May buy [Great Admiral] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
}
]
},
@ -452,7 +461,9 @@
},
{
"name": "Order Complete",
"uniques": ["[+2 Food, +2 Production, +2 Science, +2 Gold, +2 Culture] [in all cities]"]
"uniques": ["[+2 Food, +2 Production, +2 Science, +2 Gold, +2 Culture] [in all cities]",
"May buy [Great Engineer] units for [1000] [Faith] [in all cities in which the majority religion is a major religion] starting from the [Industrial era] at an increasing price ([500])"
]
}
]
}

View File

@ -328,16 +328,12 @@ object NextTurnAutomation {
}
private fun foundReligion(civInfo: CivilizationInfo) {
println("Founding check?")
if (civInfo.religionManager.religionState != ReligionState.FoundingReligion) return
println("Founding check!!")
val religionIcon = civInfo.gameInfo.ruleSet.religions
.filterNot { civInfo.gameInfo.religions.values.map { religion -> religion.iconName }.contains(it) }
.randomOrNull()
?: return // Wait what? How did we pass the checking when using a great prophet but not this?
println("Icon has been chosen")
val chosenBeliefs = chooseBeliefs(civInfo, civInfo.religionManager.getBeliefsToChooseAtFounding()).toList()
println("Beliefs have been chosen")
civInfo.religionManager.chooseBeliefs(religionIcon, religionIcon, chosenBeliefs)
}

View File

@ -251,8 +251,8 @@ class CityConstructions {
isBuilt(building) || getBuiltBuildings().any { it.replaces == building }
fun getWorkDone(constructionName: String): Int {
if (inProgressConstructions.containsKey(constructionName)) return inProgressConstructions[constructionName]!!
else return 0
return if (inProgressConstructions.containsKey(constructionName)) inProgressConstructions[constructionName]!!
else 0
}
fun getRemainingWork(constructionName: String, useStoredProduction: Boolean = true): Int {
@ -425,7 +425,7 @@ class CityConstructions {
}
}
private fun constructionComplete(construction: IConstruction) {
private fun constructionComplete(construction: INonPerpetualConstruction) {
construction.postBuildEvent(this)
if (construction.name in inProgressConstructions)
inProgressConstructions.remove(construction.name)
@ -501,7 +501,7 @@ class CityConstructions {
automatic: Boolean,
stat: Stat = Stat.Gold
): Boolean {
if (!getConstruction(constructionName).postBuildEvent(this, true))
if (!(getConstruction(constructionName) as INonPerpetualConstruction).postBuildEvent(this, stat))
return false // nothing built - no pay
if (!cityInfo.civInfo.gameInfo.gameParameters.godMode) {
@ -535,7 +535,7 @@ class CityConstructions {
return null
val cultureBuildingToBuild = buildableCultureBuildings.minByOrNull { it.cost }!!.name
constructionComplete(getConstruction(cultureBuildingToBuild))
constructionComplete(getConstruction(cultureBuildingToBuild) as INonPerpetualConstruction)
return cultureBuildingToBuild
}

View File

@ -13,7 +13,6 @@ import kotlin.math.roundToInt
interface IConstruction : INamed {
fun isBuildable(cityConstructions: CityConstructions): Boolean
fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean
fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean = false): Boolean // Yes I'm hilarious.
fun getResourceRequirements(): HashMap<String,Int>
}
@ -23,6 +22,7 @@ interface INonPerpetualConstruction : IConstruction, INamed, IHasUniques {
fun getProductionCost(civInfo: CivilizationInfo): Int
fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int?
fun getRejectionReason(cityConstructions: CityConstructions): String
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 }
@ -118,9 +118,6 @@ open class PerpetualConstruction(override var name: String, val description: Str
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
throw Exception("Impossible!")
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean) =
throw Exception("Impossible!")
override fun getResourceRequirements(): HashMap<String, Int> = hashMapOf()
}

View File

@ -122,7 +122,10 @@ class CivilizationInfo {
* Pairs of Uniques and the amount of turns they are still active
* If the counter reaches 0 at the end of a turn, it is removed immediately
*/
var temporaryUniques = ArrayList<Pair<Unique, Int>>()
val temporaryUniques = ArrayList<Pair<Unique, Int>>()
/** Maps the name of the construction to the amount of times bouhgt */
val boughtConstructionsWithGloballyIncreasingPrice = HashMap<String, Int>()
// if we only use lists, and change the list each time the cities are changed,
// we won't get concurrent modification exceptions.
@ -174,6 +177,7 @@ class CivilizationInfo {
toReturn.cityStateResource = cityStateResource
toReturn.flagsCountdown.putAll(flagsCountdown)
toReturn.temporaryUniques.addAll(temporaryUniques)
toReturn.boughtConstructionsWithGloballyIncreasingPrice.putAll(boughtConstructionsWithGloballyIncreasingPrice)
toReturn.hasEverOwnedOriginalCapital = hasEverOwnedOriginalCapital
return toReturn
}

View File

@ -1,5 +1,6 @@
package com.unciv.logic.civilization
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.logic.map.MapSize
import com.unciv.models.ruleset.Policy
import com.unciv.models.ruleset.Policy.PolicyBranchType
@ -214,7 +215,7 @@ class PolicyManager {
}
for (city in candidateCities) {
city.cityConstructions.getConstruction(building).postBuildEvent(city.cityConstructions, false)
(city.cityConstructions.getConstruction(building) as INonPerpetualConstruction).postBuildEvent(city.cityConstructions)
citiesAlreadyGivenBuilding.add(city.id)
}
}

View File

@ -205,38 +205,6 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
return stats
}
override fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean): Boolean {
if (stat == Stat.Gold && isAnyWonder()) return false
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
if (!ignoreCityRequirements && cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.any { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3]) }
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
val lowestCostFromUnique =
(
// Can be purchased for [amount] [Stat] [cityFilter]
getMatchingUniques("Can be purchased for [] [] []")
.filter { it.params[1] == stat.name && cityInfo.matchesFilter(it.params[2]) }
.map { it.params[0].toInt() }
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
+ cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.filter { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3])}
.map { it.params[1].toInt() }
).minOrNull()
if (lowestCostFromUnique != null) return lowestCostFromUnique
// Can be purchased with [Stat] [cityFilter]
if (getMatchingUniques("Can be purchased with [] []")
.any { it.params[0] == stat.name && cityInfo.matchesFilter(it.params[1])}
) return cityInfo.civInfo.gameInfo.ruleSet.eras[cityInfo.civInfo.getEra()]!!.baseUnitBuyCost
return null
}
override fun getCivilopediaTextHeader() = FormattedLine(name, header=2, icon=makeLink())
override fun makeLink() = if (isAnyWonder()) "Wonder/$name" else "Building/$name"
override fun hasCivilopediaTextLines() = true
@ -385,6 +353,32 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
return productionCost.toInt()
}
override fun canBePurchasedWithStat(cityInfo: CityInfo, stat: Stat, ignoreCityRequirements: Boolean): Boolean {
if (stat == Stat.Gold && isAnyWonder()) return false
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
if (!ignoreCityRequirements && cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.any { it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(it.params[3]) }
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
return (
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
// May buy [buildingFilter] buildings for [amount] [Stat] [cityFilter]
+ cityInfo.getMatchingUniques("May buy [] buildings for [] [] []")
.filter {
it.params[2] == stat.name && matchesFilter(it.params[0]) && cityInfo.matchesFilter(
it.params[3]
)
}
.map { it.params[1].toInt() }
).minOrNull()
}
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
if (cost == null) return null
@ -603,7 +597,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
getRejectionReason(cityConstructions) == ""
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean {
override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean {
val civInfo = cityConstructions.cityInfo.civInfo
if ("Spaceship part" in uniques) {
@ -627,7 +621,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
var freeBuildingUniques = uniqueObjects.asSequence().filter { it.placeholderText=="Provides a free [] []" }
if (providesFreeBuilding!=null) freeBuildingUniques += sequenceOf(Unique("Provides a free [$providesFreeBuilding] [in this city]"))
for(unique in freeBuildingUniques) {
for (unique in freeBuildingUniques) {
val affectedCities =
if (unique.params[1] == "in this city") sequenceOf(cityConstructions.cityInfo)
else civInfo.cities.asSequence().filter { it.matchesFilter(unique.params[1]) }

View File

@ -15,6 +15,7 @@ import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.FormattedLine
import com.unciv.ui.civilopedia.ICivilopediaText
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.toPercent
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
@ -212,6 +213,49 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
return productionCost.toInt()
}
override fun canBePurchasedWithStat(
cityInfo: CityInfo,
stat: Stat,
ignoreCityRequirements: Boolean
): Boolean {
// May buy [unitFilter] units for [amount] [Stat] starting from the [eraName] at an increasing price ([amount])
if (cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
.any {
matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == stat.name
}
) return true
return super.canBePurchasedWithStat(cityInfo, stat, ignoreCityRequirements)
}
private fun getCostForConstructionsIncreasingInPrice(baseCost: Int, increaseCost: Int, previouslyBought: Int): Int {
return (baseCost + increaseCost / 2f * ( previouslyBought * previouslyBought + previouslyBought )).toInt()
}
override fun getBaseBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
if (stat == Stat.Gold) return getBaseGoldCost(cityInfo.civInfo).toInt()
return (
sequenceOf(super.getBaseBuyCost(cityInfo, stat)).filterNotNull()
// 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 ([])")
.filter {
matchesFilter(it.params[0])
&& cityInfo.matchesFilter(it.params[3])
&& cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == stat.name
}.map {
getCostForConstructionsIncreasingInPrice(
it.params[1].toInt(),
it.params[5].toInt(),
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
)
}
).minOrNull()
}
override fun getStatBuyCost(cityInfo: CityInfo, stat: Stat): Int? {
var cost = getBaseBuyCost(cityInfo, stat)?.toDouble()
if (cost == null) return null
@ -226,11 +270,11 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing [] units []%")) {
if (stat.name == unique.params[0] && matchesFilter(unique.params[1]))
cost *= 1f + unique.params[2].toFloat() / 100f
cost *= unique.params[2].toPercent()
}
for (unique in cityInfo.getMatchingUniques("[] cost of purchasing items in cities []%"))
if (stat.name == unique.params[0])
cost *= 1f + (unique.params[1].toFloat() / 100f)
cost *= unique.params[1].toPercent()
return (cost / 10f).toInt() * 10
}
@ -316,13 +360,13 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
fun isBuildableIgnoringTechs(civInfo: CivilizationInfo) =
getRejectionReason(civInfo, true) == ""
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean {
override fun postBuildEvent(cityConstructions: CityConstructions, boughtWith: Stat?): Boolean {
val civInfo = cityConstructions.cityInfo.civInfo
val unit = civInfo.placeUnitNearTile(cityConstructions.cityInfo.location, name)
?: return false // couldn't place the unit, so there's actually no unit =(
//movement penalty
if (wasBought && !civInfo.gameInfo.gameParameters.godMode && !unit.hasUnique("Can move immediately once bought"))
if (boughtWith != null && !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
@ -331,6 +375,18 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
unit.setupAbilityUses(cityConstructions.cityInfo)
}
if (boughtWith != null && cityConstructions.cityInfo.civInfo.getMatchingUniques("May buy [] units for [] [] [] starting from the [] at an increasing price ([])")
.filter {
matchesFilter(it.params[0])
&& cityConstructions.cityInfo.matchesFilter(it.params[3])
&& cityConstructions.cityInfo.civInfo.getEraNumber() >= ruleset.getEraNumber(it.params[4])
&& it.params[2] == boughtWith.name
}.any()
) {
cityConstructions.cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] =
(cityConstructions.cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0) + 1
}
if (this.isCivilian()) return true // tiny optimization makes save files a few bytes smaller
addConstructionBonuses(unit, cityConstructions)
@ -340,6 +396,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
fun addConstructionBonuses(unit: MapUnit, cityConstructions: CityConstructions) {
val civInfo = cityConstructions.cityInfo.civInfo
@Suppress("LocalVariableName")
var XP = 0
for (unique in
@ -361,10 +418,10 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
val filter = unique.params[0]
val promotion = unique.params.last()
if (unit.matchesFilter(filter) ||
(
filter == "relevant" &&
civInfo.gameInfo.ruleSet.unitPromotions.values
if (unit.matchesFilter(filter)
|| (
filter == "relevant"
&& civInfo.gameInfo.ruleSet.unitPromotions.values
.any {
it.name == promotion
&& unit.type.name in it.unitTypes