Made CN tower functional, and free buildings are removed on capture (#5206)

* Refactored free buildings from civ.policies to civ.constructions

* Made CN tower function like in the base game

* Fixed random buildings being marked culture buildings
This commit is contained in:
Xander Lenstra
2021-09-14 09:12:08 +02:00
committed by GitHub
parent 31f81288a8
commit 0f805fbac4
12 changed files with 292 additions and 144 deletions

View File

@ -43,7 +43,8 @@ class CityConstructions {
val inProgressConstructions = HashMap<String, Int>()
var currentConstructionFromQueue: String
get() {
if (constructionQueue.isEmpty()) return "" else return constructionQueue.first()
return if (constructionQueue.isEmpty()) ""
else constructionQueue.first()
}
set(value) {
if (constructionQueue.isEmpty()) constructionQueue.add(value) else constructionQueue[0] = value
@ -53,6 +54,9 @@ class CityConstructions {
var productionOverflow = 0
val queueMaxSize = 10
// Maps cities to the buildings they received
val freeBuildingsProvidedFromThisCity: HashMap<String, HashSet<String>> = hashMapOf()
//region pure functions
fun clone(): CityConstructions {
val toReturn = CityConstructions()
@ -61,17 +65,22 @@ class CityConstructions {
toReturn.currentConstructionIsUserSet = currentConstructionIsUserSet
toReturn.constructionQueue.addAll(constructionQueue)
toReturn.productionOverflow = productionOverflow
toReturn.freeBuildingsProvidedFromThisCity.putAll(freeBuildingsProvidedFromThisCity)
return toReturn
}
internal fun getBuildableBuildings(): Sequence<Building> = cityInfo.getRuleset().buildings.values
.asSequence().filter { it.isBuildable(this) }
.asSequence().filter { it.isBuildable(this) }
fun getConstructableUnits() = cityInfo.getRuleset().units.values
.asSequence().filter { it.isBuildable(this) }
.asSequence().filter { it.isBuildable(this) }
fun getBasicCultureBuildings() = cityInfo.getRuleset().buildings.values
.asSequence().filter { it.culture > 0f && !it.isAnyWonder() && it.replaces == null }
.asSequence().filter { it.culture > 0f && !it.isAnyWonder() && it.replaces == null }
fun getBasicStatBuildings(stat: Stat) = cityInfo.getRuleset().buildings.values
.asSequence()
.filter { !it.isAnyWonder() && it.replaces == null && it.getStats(null)[stat] > 0f }
/**
* @return [Stats] provided by all built buildings in city plus the bonus from Library
@ -121,13 +130,14 @@ class CityConstructions {
*/
fun getMaintenanceCosts(): Int {
var maintenanceCost = 0
// We cache this to increase performance
val freeBuildings = cityInfo.civInfo.policies.getListOfFreeBuildings(cityInfo.id)
val freeBuildings = cityInfo.civInfo.civConstructions.getFreeBuildings(cityInfo.id)
for (building in getBuiltBuildings()) {
if (building.name !in freeBuildings) {
maintenanceCost += building.maintenance
}
}
return maintenanceCost
}
@ -151,7 +161,27 @@ class CityConstructions {
}
return result
}
fun addFreeBuildings() {
// "Provides a free [buildingName] [cityFilter]"
for (unique in cityInfo.getMatchingUniques("Provides a free [] []")) {
val freeBuildingName = cityInfo.civInfo.getEquivalentBuilding(unique.params[0]).name
val citiesThatApply = when (unique.params[1]) {
"in this city" -> listOf(cityInfo)
"in other cities" -> cityInfo.civInfo.cities.filter { it !== cityInfo }
else -> cityInfo.civInfo.cities.filter { it.matchesFilter(unique.params[1]) }
}
for (city in citiesThatApply) {
if (city.cityConstructions.containsBuildingOrEquivalent(freeBuildingName)) continue
city.cityConstructions.addBuilding(freeBuildingName)
if (city.id !in freeBuildingsProvidedFromThisCity)
freeBuildingsProvidedFromThisCity[city.id] = hashSetOf()
freeBuildingsProvidedFromThisCity[city.id]!!.add(freeBuildingName)
}
}
}
/** @constructionName needs to be a non-perpetual construction, else an empty string is returned */
internal fun getTurnsToConstructionString(constructionName: String, useStoredProduction:Boolean = true): String {
@ -173,20 +203,6 @@ class CityConstructions {
return lines.joinToString("\n", "\n")
}
// This function appears unused, can it be removed?
fun getProductionForTileInfo(): String {
/* this is because there were rare errors that I assume were caused because
currentConstruction changed on another thread */
val currentConstructionSnapshot = currentConstructionFromQueue
var result = currentConstructionSnapshot.tr()
if (currentConstructionSnapshot != ""
&& !PerpetualConstruction.perpetualConstructionsMap.containsKey(currentConstructionSnapshot)) {
val turnsLeft = turnsToConstruction(currentConstructionSnapshot)
result += " - $turnsLeft${Fonts.turn}"
}
return result
}
fun getProductionMarkup(ruleset: Ruleset): FormattedLine {
val currentConstructionSnapshot = currentConstructionFromQueue
if (currentConstructionSnapshot.isEmpty()) return FormattedLine()
@ -519,8 +535,7 @@ class CityConstructions {
&& it.params[2] == stat.name
}
) {
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[constructionName] =
(cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[constructionName] ?: 0) + 1
cityInfo.civInfo.civConstructions.boughtItemsWithIncreasingPrice.add(constructionName, 1)
}
}
@ -530,26 +545,26 @@ class CityConstructions {
return true
}
fun hasBuildableCultureBuilding(): Boolean {
return getBasicCultureBuildings()
.map { cityInfo.civInfo.getEquivalentBuilding(it.name) }
.filter { it.isBuildable(this) || isBeingConstructedOrEnqueued(it.name) }
.any()
fun hasBuildableStatBuildings(stat: Stat): Boolean {
return getBasicStatBuildings(stat)
.map { cityInfo.civInfo.getEquivalentBuilding(it.name) }
.filter { it.isBuildable(this) || isBeingConstructedOrEnqueued(it.name) }
.any()
}
fun addCultureBuilding(): String? {
val buildableCultureBuildings = getBasicCultureBuildings()
.map { cityInfo.civInfo.getEquivalentBuilding(it.name) }
.filter { it.isBuildable(this) || isBeingConstructedOrEnqueued(it.name) }
fun addCheapestBuildableStatBuilding(stat: Stat): String? {
val cheapestBuildableStatBuilding = getBasicStatBuildings(stat)
.map { cityInfo.civInfo.getEquivalentBuilding(it.name) }
.filter { it.isBuildable(this) || isBeingConstructedOrEnqueued(it.name) }
.minByOrNull { it.cost }?.name
if (!buildableCultureBuildings.any())
if (cheapestBuildableStatBuilding == null)
return null
val cultureBuildingToBuild = buildableCultureBuildings.minByOrNull { it.cost }!!.name
constructionComplete(getConstruction(cultureBuildingToBuild) as INonPerpetualConstruction)
constructionComplete(getConstruction(cheapestBuildableStatBuilding) as INonPerpetualConstruction)
return cultureBuildingToBuild
return cheapestBuildableStatBuilding
}
private fun removeCurrentConstruction() = removeFromQueue(0, true)

View File

@ -144,7 +144,7 @@ class CityInfo {
cityConstructions.addBuilding(uniqueBuilding.name)
}
civInfo.policies.tryToAddPolicyBuildings()
civInfo.civConstructions.tryAddFreeBuildings()
for (unique in getMatchingUniques("Gain a free [] []")) {
val freeBuildingName = unique.params[0]
@ -467,6 +467,7 @@ class CityInfo {
// Construct units at the beginning of the turn,
// so they won't be generated out in the open and vulnerable to enemy attacks before you can control them
cityConstructions.constructIfEnough()
cityConstructions.addFreeBuildings()
cityStats.update()
tryUpdateRoadStatus()
attackedThisTurn = false
@ -632,8 +633,8 @@ class CityInfo {
fun matchesFilter(filter: String, viewingCiv: CivilizationInfo = civInfo): Boolean {
return when (filter) {
"in this city" -> true
"in all cities" -> true // Filtered by the way uniques our found
"in other cities" -> true // Filtered by the way uniques our found
"in all cities" -> true // Filtered by the way uniques are found
"in other cities" -> true // Filtered by the way uniques are found
"in all coastal cities" -> isCoastal()
"in capital" -> isCapital()
"in all non-occupied cities" -> !cityStats.hasExtraAnnexUnhappiness() || isPuppet

View File

@ -32,7 +32,8 @@ class CityInfoConquestFunctions(val city: CityInfo){
}
private fun destroyBuildingsOnCapture() {
city.apply {
city.apply {
// Possibly remove other buildings
for (building in cityConstructions.getBuiltBuildings()) {
when {
building.hasUnique("Never destroyed when the city is captured") || building.isWonder -> continue
@ -47,6 +48,32 @@ class CityInfoConquestFunctions(val city: CityInfo){
}
}
}
private fun removeBuildingsOnMoveToCiv(oldCiv: CivilizationInfo) {
city.apply {
// Remove all buildings provided for free to this city
for (building in civInfo.civConstructions.getFreeBuildings(id)) {
cityConstructions.removeBuilding(building)
}
// Remove all buildings provided for free from here to other cities (e.g. CN Tower)
println("Removing buildings: ${cityConstructions.freeBuildingsProvidedFromThisCity}")
for ((cityId, buildings) in cityConstructions.freeBuildingsProvidedFromThisCity) {
val city = oldCiv.cities.firstOrNull { it.id == cityId } ?: continue
println("Removing buildings $buildings from city ${city.name}")
for (building in buildings) {
city.cityConstructions.removeBuilding(building)
}
}
cityConstructions.freeBuildingsProvidedFromThisCity.clear()
// Remove national wonders
for (building in cityConstructions.getBuiltBuildings()) {
if (building.isNationalWonder && !building.hasUnique("Never destroyed when the city is captured"))
cityConstructions.removeBuilding(building.name)
}
}
}
/** Function for stuff that should happen on any capture, be it puppet, annex or liberate.
* Stuff that should happen any time a city is moved between civs, so also when trading,
@ -223,11 +250,11 @@ class CityInfoConquestFunctions(val city: CityInfo){
oldCiv.cities.first().cityConstructions.addBuilding(capitalCityIndicator) // relocate palace
}
}
for (building in cityConstructions.getBuiltBuildings()) {
if (building.isNationalWonder && !building.hasUnique("Never destroyed when the city is captured"))
cityConstructions.removeBuilding(building.name)
}
// Remove their free buildings from this city and remove free buildings provided by the city from their cities
removeBuildingsOnMoveToCiv(oldCiv)
// Add our free buildings to this city and add free buildings provided by the city to other cities
civInfo.civConstructions.tryAddFreeBuildings()
// Place palace for newCiv if this is the only city they have
if (newCivInfo.cities.count() == 1) {

View File

@ -0,0 +1,165 @@
package com.unciv.logic.civilization
import com.unciv.logic.city.INonPerpetualConstruction
import com.unciv.models.Counter
import com.unciv.models.stats.Stat
import java.util.*
import kotlin.collections.HashMap
class CivConstructions() {
@Transient
lateinit var civInfo: CivilizationInfo
// Maps objects to the amount of times bought
val boughtItemsWithIncreasingPrice: Counter<String> = Counter()
// Maps to cities to all free buildings they contain
private val freeBuildings: HashMap<String,HashSet<String>> = hashMapOf()
// Maps stats to the cities that have received a building of that stat
// Android Studio says an EnumMap would be better, but that thing isn't serializable.
// I don't know how to suppress that hint :(
private val freeStatBuildingsProvided: HashMap<Stat, HashSet<String>> = hashMapOf()
// Maps buildings to the cities that have received that building
private val freeSpecificBuildingsProvided: HashMap<String, HashSet<String>> = hashMapOf()
init {
for (stat in Stat.values()) {
freeStatBuildingsProvided[stat] = hashSetOf()
}
}
fun clone(): CivConstructions {
val toReturn = CivConstructions()
toReturn.civInfo = civInfo
toReturn.freeBuildings.putAll(freeBuildings)
toReturn.freeStatBuildingsProvided.putAll(freeStatBuildingsProvided)
toReturn.freeSpecificBuildingsProvided.putAll(freeSpecificBuildingsProvided)
toReturn.boughtItemsWithIncreasingPrice.add(boughtItemsWithIncreasingPrice.clone())
return toReturn
}
fun setTransients(civInfo: CivilizationInfo) {
this.civInfo = civInfo
// civInfo.boughtConstructionsWithGloballyIncreasingPrice deprecated since 3.16.15, this is replacement code
if (civInfo.boughtConstructionsWithGloballyIncreasingPrice.isNotEmpty()) {
for (item in civInfo.boughtConstructionsWithGloballyIncreasingPrice) {
boughtItemsWithIncreasingPrice.add(item.key, item.value)
}
civInfo.boughtConstructionsWithGloballyIncreasingPrice.clear()
}
//
// Deprecated variables in civ.policies since 3.16.15, this is replacement code
if (civInfo.policies.specificBuildingsAdded.isNotEmpty()) {
for ((building, cities) in civInfo.policies.specificBuildingsAdded) {
for (cityId in cities) {
if (building !in freeSpecificBuildingsProvided)
freeSpecificBuildingsProvided[building] = hashSetOf()
freeSpecificBuildingsProvided[building]!!.add(cityId)
if (cityId !in freeBuildings)
freeBuildings[cityId] = hashSetOf()
freeBuildings[cityId]!!.add(building)
}
}
civInfo.policies.specificBuildingsAdded.clear()
}
if (civInfo.policies.cultureBuildingsAdded.isNotEmpty()) {
for ((cityId, building) in civInfo.policies.cultureBuildingsAdded) {
freeStatBuildingsProvided[Stat.Culture]!!.add(cityId)
if (cityId !in freeBuildings)
freeBuildings[cityId] = hashSetOf()
freeBuildings[cityId]!!.add(building)
}
civInfo.policies.cultureBuildingsAdded.clear()
}
//
}
fun startTurn() {
tryAddFreeBuildings()
}
fun tryAddFreeBuildings() {
addFreeStatsBuildings()
addFreeSpecificBuildings()
}
fun getFreeBuildings(cityId: String): HashSet<String> {
val toReturn = freeBuildings[cityId] ?: hashSetOf()
for (city in civInfo.cities) {
toReturn.addAll(city.cityConstructions.freeBuildingsProvidedFromThisCity[city.id] ?: hashSetOf())
}
return toReturn
}
private fun addFreeBuilding(cityId: String, building: String) {
if (!freeBuildings.containsKey(cityId))
freeBuildings[cityId] = hashSetOf()
freeBuildings[cityId]!!.add(building)
}
private fun addFreeStatsBuildings() {
val statUniquesData = civInfo.getMatchingUniques("Provides the cheapest [] building in your first [] cities for free")
.groupBy { it.params[0] }
.mapKeys { Stat.valueOf(it.key) }
.mapValues { unique -> unique.value.sumOf { it.params[1].toInt() } }
.toMutableMap()
// Deprecated since 3.16.15
statUniquesData[Stat.Culture] = (statUniquesData[Stat.Culture] ?: 0) +
civInfo.getMatchingUniques("Immediately creates the cheapest available cultural building in each of your first [] cities for free")
.sumOf { it.params[1].toInt() }
//
for ((stat, amount) in statUniquesData) {
addFreeStatBuildings(stat, amount)
}
}
private fun addFreeStatBuildings(stat: Stat, amount: Int) {
for (city in civInfo.cities.take(amount)) {
if (freeStatBuildingsProvided[stat]!!.contains(city.id) || !city.cityConstructions.hasBuildableStatBuildings(stat)) continue
val builtBuilding = city.cityConstructions.addCheapestBuildableStatBuilding(stat)
if (builtBuilding != null) {
freeStatBuildingsProvided[stat]!!.add(city.id)
addFreeBuilding(city.id, builtBuilding)
}
}
}
private fun addFreeSpecificBuildings() {
val buildingsUniquesData = (civInfo.getMatchingUniques("Provides a [] in your first [] cities for free")
// Deprecated since 3.16.15
+ civInfo.getMatchingUniques("Immediately creates a [] in each of your first [] cities for free")
//
).groupBy { it.params[0] }
.mapValues { unique -> unique.value.sumOf { it.params[1].toInt() } }
for ((building, amount) in buildingsUniquesData) {
addFreeBuildings(building, amount)
}
}
private fun addFreeBuildings(building: String, amount: Int) {
for (city in civInfo.cities.take(amount)) {
if (freeSpecificBuildingsProvided[building]?.contains(city.id) == true || city.cityConstructions.containsBuildingOrEquivalent(building)) continue
(city.cityConstructions.getConstruction(building) as INonPerpetualConstruction).postBuildEvent(city.cityConstructions)
if (!freeSpecificBuildingsProvided.containsKey(building))
freeSpecificBuildingsProvided[building] = hashSetOf()
freeSpecificBuildingsProvided[building]!!.add(city.id)
addFreeBuilding(city.id, building)
}
}
}

View File

@ -101,6 +101,7 @@ class CivilizationInfo {
var civName = ""
var tech = TechManager()
var policies = PolicyManager()
var civConstructions = CivConstructions()
var questManager = QuestManager()
var religionManager = ReligionManager()
var goldenAges = GoldenAgeManager()
@ -124,8 +125,11 @@ class CivilizationInfo {
*/
val temporaryUniques = ArrayList<Pair<Unique, Int>>()
/** Maps the name of the construction to the amount of times bought */
val boughtConstructionsWithGloballyIncreasingPrice = HashMap<String, Int>()
// Deprecated since 3.16.15
/** Maps the name of the construction to the amount of times bought */
@Deprecated("Deprecated since 3.16.15", replaceWith = ReplaceWith("civWideConstructions.boughtItemsWithIncreasingPrice"))
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.
@ -153,6 +157,7 @@ class CivilizationInfo {
toReturn.civName = civName
toReturn.tech = tech.clone()
toReturn.policies = policies.clone()
toReturn.civConstructions = civConstructions.clone()
toReturn.religionManager = religionManager.clone()
toReturn.questManager = questManager.clone()
toReturn.goldenAges = goldenAges.clone()
@ -178,7 +183,9 @@ class CivilizationInfo {
toReturn.cityStateUniqueUnit = cityStateUniqueUnit
toReturn.flagsCountdown.putAll(flagsCountdown)
toReturn.temporaryUniques.addAll(temporaryUniques)
toReturn.boughtConstructionsWithGloballyIncreasingPrice.putAll(boughtConstructionsWithGloballyIncreasingPrice)
// Deprecated since 3.16.15
toReturn.boughtConstructionsWithGloballyIncreasingPrice.putAll(boughtConstructionsWithGloballyIncreasingPrice)
//
toReturn.hasEverOwnedOriginalCapital = hasEverOwnedOriginalCapital
return toReturn
}
@ -557,6 +564,8 @@ class CivilizationInfo {
fun setTransients() {
goldenAges.civInfo = this
civConstructions.setTransients(civInfo = this)
policies.civInfo = this
if (policies.adoptedPolicies.size > 0 && policies.numberOfAdoptedPolicies == 0)
policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !Policy.isBranchCompleteByName(it) }
@ -602,7 +611,7 @@ class CivilizationInfo {
fun updateDetailedCivResources() = transients().updateDetailedCivResources()
fun startTurn() {
policies.startTurn()
civConstructions.startTurn()
updateStatsForNextTurn() // for things that change when turn passes e.g. golden age, city state influence
// Generate great people at the start of the turn,

View File

@ -30,8 +30,12 @@ class PolicyManager {
var shouldOpenPolicyPicker = false
get() = field && canAdoptPolicy()
private var cultureBuildingsAdded = HashMap<String, String>() // Maps cities to buildings
private var specificBuildingsAdded = HashMap<String, MutableSet<String>>() // Maps buildings to cities
// Deprecated since 3.16.15
@Deprecated("Deprecated since 3.16.15", ReplaceWith("civInfo.civWideConstructions.freeStatBuildingsProvided[Stat.Culture]"))
var cultureBuildingsAdded = HashMap<String, String>() // Maps cities to buildings
@Deprecated("Deprecated since 3.16.15", ReplaceWith("civInfo.civWideConstructions.freeSpecificBuildingsProvided"))
var specificBuildingsAdded = HashMap<String, MutableSet<String>>() // Maps buildings to cities
//
fun clone(): PolicyManager {
@ -41,8 +45,10 @@ class PolicyManager {
toReturn.freePolicies = freePolicies
toReturn.shouldOpenPolicyPicker = shouldOpenPolicyPicker
toReturn.storedCulture = storedCulture
toReturn.cultureBuildingsAdded.putAll(cultureBuildingsAdded)
toReturn.specificBuildingsAdded.putAll(specificBuildingsAdded)
// Deprecated since 3.16.15
toReturn.cultureBuildingsAdded.putAll(cultureBuildingsAdded)
toReturn.specificBuildingsAdded.putAll(specificBuildingsAdded)
//
return toReturn
}
@ -70,10 +76,6 @@ class PolicyManager {
policyUniques.addUnique(unique)
}
fun startTurn() {
tryToAddPolicyBuildings()
}
fun addCulture(culture: Int) {
val couldAdoptPolicyBefore = canAdoptPolicy()
storedCulture += culture
@ -171,8 +173,6 @@ class PolicyManager {
for (unique in policy.uniqueObjects)
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
tryToAddPolicyBuildings()
// This ALSO has the side-effect of updating the CivInfo statForNextTurn so we don't need to call it explicitly
for (cityInfo in civInfo.cities)
cityInfo.cityStats.update()
@ -180,65 +180,6 @@ class PolicyManager {
if (!canAdoptPolicy()) shouldOpenPolicyPicker = false
}
fun tryToAddPolicyBuildings() {
tryAddCultureBuildings()
tryAddFreeBuildings()
}
private fun tryAddCultureBuildings() {
val cultureBuildingUniques = civInfo.getMatchingUniques("Immediately creates the cheapest available cultural building in each of your first [] cities for free")
val citiesToReceiveCultureBuilding = cultureBuildingUniques.sumOf { it.params[0].toInt() }
if (!cultureBuildingUniques.any()) return
if (cultureBuildingsAdded.size >= citiesToReceiveCultureBuilding) return
val candidateCities = civInfo.cities
.sortedBy { it.turnAcquired }
.subList(0, min(citiesToReceiveCultureBuilding, civInfo.cities.size))
.filter {
it.id !in cultureBuildingsAdded
&& it.cityConstructions.hasBuildableCultureBuilding()
}
for (city in candidateCities) {
val builtBuilding = city.cityConstructions.addCultureBuilding()
if (builtBuilding != null) cultureBuildingsAdded[city.id] = builtBuilding
}
}
private fun tryAddFreeBuildings() {
val matchingUniques = civInfo.getMatchingUniques("Immediately creates a [] in each of your first [] cities for free")
// If we have "create a free aqueduct in first 3 cities" and "create free aqueduct in first 4 cities", we do: "create free aqueduct in first 3+4=7 cities"
val sortedUniques = matchingUniques.groupBy {it.params[0]}
for (unique in sortedUniques) {
tryAddSpecificBuilding(unique.key, unique.value.sumOf {it.params[1].toInt()})
}
}
private fun tryAddSpecificBuilding(building: String, cityCount: Int) {
if (specificBuildingsAdded[building] == null) specificBuildingsAdded[building] = mutableSetOf()
val citiesAlreadyGivenBuilding = specificBuildingsAdded[building]
if (citiesAlreadyGivenBuilding!!.size >= cityCount) return
val candidateCities = civInfo.cities
.sortedBy { it.turnAcquired }
.subList(0, min(cityCount, civInfo.cities.size))
.filter {
it.id !in citiesAlreadyGivenBuilding && !it.cityConstructions.containsBuildingOrEquivalent(building)
}
for (city in candidateCities) {
(city.cityConstructions.getConstruction(building) as INonPerpetualConstruction).postBuildEvent(city.cityConstructions)
citiesAlreadyGivenBuilding.add(city.id)
}
}
fun getListOfFreeBuildings(cityId: String): MutableSet<String> {
val freeBuildings = cultureBuildingsAdded.filter { it.key == cityId }.values.toMutableSet()
for (building in specificBuildingsAdded.filter { it.value.contains(cityId) }) {
freeBuildings.add(building.key)
}
return freeBuildings
}
private fun triggerGlobalAlerts(policy: Policy, extraNotificationText: String = "") {
var extraNotificationTextCopy = extraNotificationText
if (extraNotificationText != "") {

View File

@ -28,7 +28,7 @@ class ReligionManager {
// contain the master list, and the ReligionManagers retrieve it from there every time the game loads.
// Deprecated since 3.16.13
@Deprecated("Replace by adding to `civInfo.boughtConstructionsWithGloballyIncreasingPrice`")
@Deprecated("Replace by adding to `civInfo.civWideConstructions.boughtItemsWithIncreasingPrice`")
var greatProphetsEarned = 0
private set
//
@ -67,7 +67,7 @@ class ReligionManager {
// greatProphetsEarned deprecated since 3.16.13, replacement code
if (greatProphetsEarned != 0) {
civInfo.boughtConstructionsWithGloballyIncreasingPrice[getGreatProphetEquivalent()!!] = greatProphetsEarned
civInfo.civConstructions.boughtItemsWithIncreasingPrice[getGreatProphetEquivalent()!!] = greatProphetsEarned
greatProphetsEarned = 0
}
//
@ -115,7 +115,7 @@ class ReligionManager {
// https://www.reddit.com/r/civ/comments/2m82wu/can_anyone_detail_the_finer_points_of_great/
// Game files (globaldefines.xml)
fun faithForNextGreatProphet(): Int {
val greatProphetsEarned = civInfo.boughtConstructionsWithGloballyIncreasingPrice[getGreatProphetEquivalent()!!] ?: 0
val greatProphetsEarned = civInfo.civConstructions.boughtItemsWithIncreasingPrice[getGreatProphetEquivalent()!!] ?: 0
var faithCost =
(200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1) / 2f) *
@ -152,8 +152,7 @@ class ReligionManager {
val prophet = civInfo.addUnit(prophetUnitName, birthCity) ?: return
prophet.religion = religion!!.name
storedFaith -= faithForNextGreatProphet()
civInfo.boughtConstructionsWithGloballyIncreasingPrice[prophetUnitName] =
(civInfo.boughtConstructionsWithGloballyIncreasingPrice[prophetUnitName] ?: 0) + 1
civInfo.civConstructions.boughtItemsWithIncreasingPrice.add(prophetUnitName, 1)
}
}

View File

@ -43,7 +43,7 @@ class RuinsManager {
if (civInfo.gameInfo.difficulty in possibleReward.excludedDifficulties) continue
if (Constants.hiddenWithoutReligionUnique in possibleReward.uniques && !civInfo.gameInfo.hasReligionEnabled()) continue
if ("Hidden after generating a Great Prophet" in possibleReward.uniques
&& civInfo.boughtConstructionsWithGloballyIncreasingPrice[civInfo.religionManager.getGreatProphetEquivalent()] ?: 0 > 0
&& civInfo.civConstructions.boughtItemsWithIncreasingPrice[civInfo.religionManager.getGreatProphetEquivalent()] ?: 0 > 0
) continue
if (possibleReward.uniqueObjects.any { unique ->
unique.placeholderText == "Only available after [] turns"

View File

@ -151,7 +151,8 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
}
fun getStats(city: CityInfo?): Stats {
val stats = this.clone()
// Calls the clone function of the NamedStats this class is derived from, not a clone function of this class
val stats = this.clone()
if (city == null) return stats
val civInfo = city.civInfo
@ -651,20 +652,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText {
}
// "Provides a free [buildingName] [cityFilter]"
val freeBuildingUniques = uniqueObjects.asSequence().filter { it.placeholderText=="Provides a free [] []" }
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]) }
val freeBuildingName = civInfo.getEquivalentBuilding(unique.params[0]).name
for (city in affectedCities) {
if (cityConstructions.containsBuildingOrEquivalent(freeBuildingName)) continue
cityConstructions.addBuilding(freeBuildingName)
}
}
cityConstructions.addFreeBuildings()
for (unique in uniqueObjects)
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo, cityConstructions.cityInfo)

View File

@ -457,6 +457,10 @@ object UniqueTriggerActivation {
civInfo.addNotification(notification, NotificationIcon.Diplomacy)
return true
}
"Provides the cheapest [] building in your first [] cities for free",
"Provides a [] in your first [] cities for free" ->
civInfo.civConstructions.tryAddFreeBuildings()
}
return false
}

View File

@ -14,7 +14,6 @@ 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
import kotlin.collections.HashSet
@ -254,7 +253,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
getCostForConstructionsIncreasingInPrice(
it.params[1].toInt(),
it.params[5].toInt(),
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
cityInfo.civInfo.civConstructions.boughtItemsWithIncreasingPrice[name] ?: 0
)
}
)
@ -267,7 +266,7 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText {
getCostForConstructionsIncreasingInPrice(
it.params[1].toInt(),
it.params[4].toInt(),
cityInfo.civInfo.boughtConstructionsWithGloballyIncreasingPrice[name] ?: 0
cityInfo.civInfo.civConstructions.boughtItemsWithIncreasingPrice[name] ?: 0
)
}
)