Added "Consumes [amount] [resourceName]" unique for buildings

This commit is contained in:
Yair Morgenstern 2021-02-06 21:12:44 +02:00
parent 9054480bf7
commit 3d683c767a
8 changed files with 84 additions and 63 deletions

View File

@ -38,6 +38,7 @@ Wonder is being built elsewhere =
Requires a [buildingName] in all cities =
Requires a [buildingName] in this city =
Consumes 1 [resource] =
Consumes [amount] [resource] =
Required tech: [requiredTech] =
Requires [PolicyOrNationalWonder] =
Cannot be purchased =

View File

@ -34,14 +34,19 @@ import kotlin.math.roundToInt
class CityInfo {
@Transient
lateinit var civInfo: CivilizationInfo
@Transient
lateinit private var centerTileInfo: TileInfo // cached for better performance
@Transient
val range = 2
@Transient
lateinit var tileMap: TileMap
@Transient
lateinit var tilesInRange: HashSet<TileInfo>
@Transient
var hasJustBeenConquered = false // this is so that military units can enter the city, even before we decide what to do with it
@ -197,9 +202,15 @@ class CityInfo {
cityResources.add(resource, unique.params[0].toInt() * civInfo.getResourceModifier(resource), "Tiles")
}
}
for (building in cityConstructions.getBuiltBuildings().filter { it.requiredResource != null }) {
val resource = getRuleset().tileResources[building.requiredResource]!!
cityResources.add(resource, -1, "Buildings")
for (building in cityConstructions.getBuiltBuildings()) {
for ((resourceName, amount) in building.getResourceRequirements()) {
val resource = getRuleset().tileResources[resourceName]!!
cityResources.add(resource, -amount, "Buildings")
}
for (unique in building.uniqueObjects.filter { it.placeholderText == "Consumes [] []" }) {
val resource = getRuleset().tileResources[unique.params[1]]
if (resource != null) cityResources.add(resource, -unique.params[0].toInt(), "Buildings")
}
}
for (unique in cityConstructions.builtBuildingUniqueMap.getUniques("Provides [] []")) { // E.G "Provides [1] [Iron]"
val resource = getRuleset().tileResources[unique.params[1]]

View File

@ -1,9 +1,7 @@
package com.unciv.logic.city
import com.unciv.Constants
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.stats.INamed
import com.unciv.models.translations.tr
import com.unciv.ui.utils.Fonts
import kotlin.math.roundToInt
@ -13,16 +11,14 @@ interface IConstruction : INamed {
fun isBuildable(cityConstructions: CityConstructions): Boolean
fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean
fun postBuildEvent(construction: CityConstructions, wasBought: Boolean = false): Boolean // Yes I'm hilarious.
fun getResource(): String?
fun getResourceRequirements(): HashMap<String,Int>
fun canBePurchased(): Boolean
}
open class PerpetualConstruction(override var name: String, val description: String) : IConstruction {
override fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean {
return isBuildable(cityConstructions)
}
override fun shouldBeDisplayed(cityConstructions: CityConstructions) = isBuildable(cityConstructions)
open fun getProductionTooltip(cityInfo: CityInfo) : String
= "\r\n${(cityInfo.cityStats.currentCityStats.production / CONVERSION_RATE).roundToInt()}/${Fonts.turn}"
open fun getConversionRate(cityInfo: CityInfo) : Int
@ -54,26 +50,18 @@ open class PerpetualConstruction(override var name: String, val description: Str
= mapOf(science.name to science, gold.name to gold, idle.name to idle)
}
override fun canBePurchased(): Boolean {
return false
}
override fun canBePurchased() = false
override fun getProductionCost(civInfo: CivilizationInfo): Int {
throw Exception("Impossible!")
}
override fun getProductionCost(civInfo: CivilizationInfo) = throw Exception("Impossible!")
override fun getGoldCost(civInfo: CivilizationInfo): Int {
throw Exception("Impossible!")
}
override fun getGoldCost(civInfo: CivilizationInfo) = throw Exception("Impossible!")
override fun isBuildable(cityConstructions: CityConstructions): Boolean {
throw Exception("Impossible!")
}
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
throw Exception("Impossible!")
override fun postBuildEvent(construction: CityConstructions, wasBought: Boolean): Boolean {
throw Exception("Impossible!")
}
override fun postBuildEvent(construction: CityConstructions, wasBought: Boolean) =
throw Exception("Impossible!")
override fun getResource(): String? =null
override fun getResourceRequirements(): HashMap<String, Int> = hashMapOf()
}

View File

@ -1,6 +1,5 @@
package com.unciv.models.ruleset
import com.unciv.Constants
import com.unciv.logic.city.CityConstructions
import com.unciv.logic.city.IConstruction
import com.unciv.logic.civilization.CivilizationInfo
@ -12,6 +11,7 @@ import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.pow
@ -47,7 +47,7 @@ class Building : NamedStats(), IConstruction {
var requiredBuildingInAllCities: String? = null
/** A strategic resource that will be consumed by this building */
var requiredResource: String? = null
private var requiredResource: String? = null
/** City can only be built if one of these resources is nearby - it must be improved! */
private var requiredNearbyImprovedResources: List<String>? = null
@ -105,8 +105,10 @@ class Building : NamedStats(), IConstruction {
stringBuilder.appendln("Requires [$requiredBuilding] to be built in the city".tr())
if (!forBuildingPickerScreen && requiredBuildingInAllCities != null)
stringBuilder.appendln("Requires [$requiredBuildingInAllCities] to be built in all cities".tr())
if (requiredResource != null)
stringBuilder.appendln("Consumes 1 [$requiredResource]".tr())
for ((resource, amount) in getResourceRequirements()) {
if (amount == 1) stringBuilder.appendln("Consumes 1 [$resource]".tr()) // For now, to keep the existing translations
else stringBuilder.appendln("Consumes [$amount] [$resource]".tr())
}
if (providesFreeBuilding != null)
stringBuilder.appendln("Provides a free [$providesFreeBuilding] in the city".tr())
if (uniques.isNotEmpty()) {
@ -359,8 +361,11 @@ class Building : NamedStats(), IConstruction {
if (cannotBeBuiltWith != null && construction.isBuilt(cannotBeBuiltWith!!))
return "Cannot be built with $cannotBeBuiltWith"
if (requiredResource != null && !civInfo.hasResource(requiredResource!!) && !civInfo.gameInfo.gameParameters.godMode)
return "Consumes 1 [$requiredResource]"
for ((resource, amount) in getResourceRequirements())
if (civInfo.getCivResourcesByName()[resource]!! < amount) {
if (amount == 1) return "Consumes 1 [$resource]" // Again, to preserve existing translations
else return "Consumes [$amount] [$resource]"
}
if (requiredNearbyImprovedResources != null) {
val containsResourceWithImprovement = construction.cityInfo.getWorkableTiles()
@ -381,9 +386,8 @@ class Building : NamedStats(), IConstruction {
return ""
}
override fun isBuildable(cityConstructions: CityConstructions): Boolean {
return getRejectionReason(cityConstructions) == ""
}
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
getRejectionReason(cityConstructions) == ""
override fun postBuildEvent(cityConstructions: CityConstructions, wasBought: Boolean): Boolean {
val civInfo = cityConstructions.cityInfo.civInfo
@ -433,8 +437,6 @@ class Building : NamedStats(), IConstruction {
return true
}
override fun getResource(): String? = requiredResource
fun isStatRelated(stat: Stat): Boolean {
if (get(stat) > 0) return true
if (getStatPercentageBonuses(null).get(stat) > 0) return true
@ -455,4 +457,13 @@ class Building : NamedStats(), IConstruction {
}
fun isSellable() = !isWonder && !isNationalWonder && !uniques.contains("Unsellable")
override fun getResourceRequirements(): HashMap<String, Int> {
val resourceRequirements = HashMap<String, Int>()
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
for (unique in uniqueObjects)
if (unique.placeholderText == "Consumes [] []")
resourceRequirements[unique.params[1]] = unique.params[0].toInt()
return resourceRequirements
}
}

View File

@ -267,8 +267,9 @@ class Ruleset {
for (building in buildings.values) {
if (building.requiredTech != null && !technologies.containsKey(building.requiredTech!!))
lines += "${building.name} requires tech ${building.requiredTech} which does not exist!"
if (building.requiredResource != null && !tileResources.containsKey(building.requiredResource!!))
lines += "${building.name} requires resource ${building.requiredResource} which does not exist!"
for(resource in building.getResourceRequirements().keys)
if (!tileResources.containsKey(resource))
lines += "${building.name} requires resource $resource which does not exist!"
if (building.replaces != null && !buildings.containsKey(building.replaces!!))
lines += "${building.name} replaces ${building.replaces} which does not exist!"
if (building.requiredBuilding != null && !buildings.containsKey(building.requiredBuilding!!))
@ -315,7 +316,7 @@ class Ruleset {
* save all of the loaded rulesets somewhere for later use
* */
object RulesetCache :HashMap<String,Ruleset>() {
fun loadRulesets(consoleMode:Boolean=false, printOutput: Boolean=false) {
fun loadRulesets(consoleMode: Boolean = false, printOutput: Boolean = false) {
clear()
for (ruleset in BaseRuleset.values()) {
val fileName = "jsons/${ruleset.fullName}"
@ -373,7 +374,7 @@ object RulesetCache :HashMap<String,Ruleset>() {
class Specialist: NamedStats() {
var color = ArrayList<Int>()
val colorObject by lazy { colorFromRGB(color) }
var greatPersonPoints= Stats()
var greatPersonPoints = Stats()
companion object {
internal fun specialistNameByStat(stat: Stat) = when (stat) {

View File

@ -32,35 +32,34 @@ class TileResource : NamedStats() {
stringBuilder.appendln("Improved by [$improvement]".tr())
stringBuilder.appendln("{Bonus stats for improvement}: ".tr() + "$improvementStats".tr())
val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.requiredResource==name }
if(buildingsThatConsumeThis.isNotEmpty())
val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.getResourceRequirements().containsKey(name) }
if (buildingsThatConsumeThis.isNotEmpty())
stringBuilder.appendln("{Buildings that consume this resource}: ".tr()
+ buildingsThatConsumeThis.joinToString { it.name.tr() })
val unitsThatConsumeThis = ruleset.units.values.filter { it.requiredResource==name }
if(unitsThatConsumeThis.isNotEmpty())
val unitsThatConsumeThis = ruleset.units.values.filter { it.requiredResource == name }
if (unitsThatConsumeThis.isNotEmpty())
stringBuilder.appendln("{Units that consume this resource}: ".tr()
+ unitsThatConsumeThis.joinToString { it.name.tr() })
if(unique!=null) stringBuilder.appendln(unique!!.tr())
if (unique != null) stringBuilder.appendln(unique!!.tr())
return stringBuilder.toString()
}
}
data class ResourceSupply(val resource:TileResource,var amount:Int, val origin:String)
class ResourceSupplyList:ArrayList<ResourceSupply>(){
fun add(resource: TileResource, amount: Int, origin: String){
val existingResourceSupply=firstOrNull{it.resource==resource && it.origin==origin}
if(existingResourceSupply!=null) {
class ResourceSupplyList:ArrayList<ResourceSupply>() {
fun add(resource: TileResource, amount: Int, origin: String) {
val existingResourceSupply = firstOrNull { it.resource == resource && it.origin == origin }
if (existingResourceSupply != null) {
existingResourceSupply.amount += amount
if(existingResourceSupply.amount==0) remove(existingResourceSupply)
}
else add(ResourceSupply(resource,amount,origin))
if (existingResourceSupply.amount == 0) remove(existingResourceSupply)
} else add(ResourceSupply(resource, amount, origin))
}
fun add(resourceSupplyList: ResourceSupplyList){
for(resourceSupply in resourceSupplyList)
add(resourceSupply.resource,resourceSupply.amount,resourceSupply.origin)
fun add(resourceSupplyList: ResourceSupplyList) {
for (resourceSupply in resourceSupplyList)
add(resourceSupply.resource, resourceSupply.amount, resourceSupply.origin)
}
}

View File

@ -151,9 +151,9 @@ class BaseUnit : INamed, IConstruction {
&& uniques.contains("Nuclear weapon")) return "Disabled by setting"
for (unique in uniqueObjects.filter { it.placeholderText == "Unlocked with []" })
if(civInfo.tech.researchedTechnologies.none { it.era() == unique.params[0] || it.name == unique.params[0] }
if (civInfo.tech.researchedTechnologies.none { it.era() == unique.params[0] || it.name == unique.params[0] }
&& !civInfo.policies.isAdopted(unique.params[0]))
return unique.text
return unique.text
for (unique in uniqueObjects.filter { it.placeholderText == "Requires []" }) {
val filter = unique.params[0]
@ -208,7 +208,6 @@ class BaseUnit : INamed, IConstruction {
return true
}
override fun getResource(): String? = requiredResource
fun getDirectUpgradeUnit(civInfo: CivilizationInfo): BaseUnit {
return civInfo.getEquivalentUnit(upgradesTo!!)
@ -234,4 +233,13 @@ class BaseUnit : INamed, IConstruction {
}
fun isGreatPerson() = uniqueObjects.any { it.placeholderText == "Great Person - []" }
override fun getResourceRequirements(): HashMap<String, Int> {
val resourceRequirements = HashMap<String, Int>()
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
for (unique in uniqueObjects)
if (unique.placeholderText == "Consumes [] []")
resourceRequirements[unique.params[1]] = unique.params[0].toInt()
return resourceRequirements
}
}

View File

@ -33,7 +33,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
private val buttons = Table()
private val pad = 10f
var improvementBuildingToConstruct:Building?=null
var improvementBuildingToConstruct: Building? = null
init {
@ -136,8 +136,10 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
for (building in city.getRuleset().buildings.values.filter { it.shouldBeDisplayed(cityConstructions) }) {
val turnsToBuilding = cityConstructions.turnsToConstruction(building.name)
var buttonText = building.name.tr() + turnOrTurns(turnsToBuilding)
if (building.requiredResource != null)
buttonText += "\n" + "Consumes 1 [${building.requiredResource}]".tr()
for ((resource, amount) in building.getResourceRequirements()) {
if (amount == 1) buttonText += "\n" + "Consumes 1 [$resource]".tr()
else buttonText += "\n" + "Consumes [$amount] [$resource]".tr()
}
constructionButtonDTOList.add(ConstructionButtonDTO(building,
buttonText,
@ -223,7 +225,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
if (name in PerpetualConstruction.perpetualConstructionsMap) "\n"
else turnOrTurns(turnsToComplete)
val constructionResource = cityConstructions.getConstruction(name).getResource()
val constructionResource = cityConstructions.getConstruction(name).getResourceRequirements()
if (constructionResource != null)
text += "\n" + "Consumes 1 [$constructionResource]".tr()
@ -347,7 +349,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
}
fun addConstructionToQueue(construction: IConstruction, cityConstructions: CityConstructions) {
if (construction is Building && construction.uniqueObjects.any { it.placeholderText=="Creates a [] improvement on a specific tile" }){
if (construction is Building && construction.uniqueObjects.any { it.placeholderText == "Creates a [] improvement on a specific tile" }) {
cityScreen.selectedTile
improvementBuildingToConstruct = construction
return