mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-15 04:14:44 +07:00
Fix consuming resources not being affected by conditionals (#10270)
* Fix consuming resources not being affected by condtionals * Add requirements from buildings back in * one too many parenthesis * Whoops, forgot a bracket * Fix Iconstruction * Accidental font regression * Address suggested changes
This commit is contained in:
parent
249241247b
commit
3eff519264
@ -13,6 +13,7 @@ import com.unciv.models.ruleset.Victory
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
import com.unciv.models.ruleset.unique.LocalUniqueCache
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
@ -247,7 +248,7 @@ object Automation {
|
||||
construction: INonPerpetualConstruction
|
||||
): Boolean {
|
||||
return allowCreateImprovementBuildings(civInfo, city, construction)
|
||||
&& allowSpendingResource(civInfo, construction)
|
||||
&& allowSpendingResource(civInfo, construction, city)
|
||||
}
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@ -268,7 +269,7 @@ object Automation {
|
||||
|
||||
/** Determines whether the AI should be willing to spend strategic resources to build
|
||||
* [construction] for [civInfo], assumes that we are actually able to do so. */
|
||||
fun allowSpendingResource(civInfo: Civilization, construction: INonPerpetualConstruction): Boolean {
|
||||
fun allowSpendingResource(civInfo: Civilization, construction: INonPerpetualConstruction, cityInfo: City? = null): Boolean {
|
||||
// City states do whatever they want
|
||||
if (civInfo.isCityState())
|
||||
return true
|
||||
@ -277,7 +278,9 @@ object Automation {
|
||||
if (construction.name in civInfo.gameInfo.spaceResources)
|
||||
return true
|
||||
|
||||
val requiredResources = construction.getResourceRequirementsPerTurn()
|
||||
val requiredResources = if (construction is BaseUnit)
|
||||
construction.getResourceRequirementsPerTurn(StateForConditionals(civInfo))
|
||||
else construction.getResourceRequirementsPerTurn(StateForConditionals(civInfo, cityInfo))
|
||||
// Does it even require any resources?
|
||||
if (requiredResources.isEmpty())
|
||||
return true
|
||||
@ -295,9 +298,11 @@ object Automation {
|
||||
for (city in civInfo.cities) {
|
||||
val otherConstruction = city.cityConstructions.getCurrentConstruction()
|
||||
if (otherConstruction is Building)
|
||||
futureForBuildings += otherConstruction.getResourceRequirementsPerTurn()[resource]
|
||||
futureForBuildings += otherConstruction.getResourceRequirementsPerTurn(
|
||||
StateForConditionals(civInfo, city))[resource]
|
||||
else
|
||||
futureForUnits += otherConstruction.getResourceRequirementsPerTurn()[resource]
|
||||
futureForUnits += otherConstruction.getResourceRequirementsPerTurn(
|
||||
StateForConditionals(civInfo))[resource]
|
||||
}
|
||||
|
||||
// Make sure we have some for space
|
||||
|
@ -480,7 +480,7 @@ object NextTurnAutomation {
|
||||
continue
|
||||
|
||||
val unitToDisband = civInfo.units.getCivUnits()
|
||||
.filter { it.baseUnit.requiresResource(resource) }
|
||||
.filter { it.requiresResource(resource) }
|
||||
.minByOrNull { it.getForceEvaluation() }
|
||||
unitToDisband?.disband()
|
||||
|
||||
@ -489,7 +489,7 @@ object NextTurnAutomation {
|
||||
continue
|
||||
val buildingToSell = civInfo.gameInfo.ruleset.buildings.values.filter {
|
||||
city.cityConstructions.isBuilt(it.name)
|
||||
&& it.requiresResource(resource)
|
||||
&& it.requiresResource(resource, StateForConditionals(civInfo, city))
|
||||
&& it.isSellable()
|
||||
&& !civInfo.civConstructions.hasFreeBuilding(city, it) }
|
||||
.randomOrNull()
|
||||
|
@ -14,6 +14,7 @@ import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsPillage
|
||||
import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade
|
||||
@ -130,7 +131,7 @@ object UnitAutomation {
|
||||
val upgradedUnit = unit.upgrade.getUnitToUpgradeTo()
|
||||
if (!upgradedUnit.isBuildable(unit.civ)) return false // for resource reasons, usually
|
||||
|
||||
if (upgradedUnit.getResourceRequirementsPerTurn().keys.any { !unit.baseUnit.requiresResource(it) }) {
|
||||
if (upgradedUnit.getResourceRequirementsPerTurn(StateForConditionals(unit.civ, unit = unit)).keys.any { !unit.requiresResource(it) }) {
|
||||
// The upgrade requires new resource types, so check if we are willing to invest them
|
||||
if (!Automation.allowSpendingResource(unit.civ, upgradedUnit)) return false
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ object BattleDamage {
|
||||
private fun addResourceLackingMalus(combatant: MapUnitCombatant, modifiers: Counter<String>) {
|
||||
val civInfo = combatant.getCivInfo()
|
||||
val civResources = civInfo.getCivResourcesByName()
|
||||
for (resource in combatant.unit.baseUnit.getResourceRequirementsPerTurn().keys)
|
||||
for (resource in combatant.unit.getResourceRequirementsPerTurn().keys)
|
||||
if (civResources[resource]!! < 0 && !civInfo.isBarbarian())
|
||||
modifiers["Missing resource"] = BattleConstants.MISSING_RESOURCES_MALUS
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ object Nuke {
|
||||
|
||||
var damageModifierFromMissingResource = 1f
|
||||
val civResources = attacker.getCivInfo().getCivResourcesByName()
|
||||
for (resource in attacker.unit.baseUnit.getResourceRequirementsPerTurn().keys) {
|
||||
for (resource in attacker.unit.getResourceRequirementsPerTurn().keys) {
|
||||
if (civResources[resource]!! < 0 && !attacker.getCivInfo().isBarbarian())
|
||||
damageModifierFromMissingResource *= 0.5f // I could not find a source for this number, but this felt about right
|
||||
// - Original Civ5 does *not* reduce damage from missing resource, from source inspection
|
||||
|
@ -78,7 +78,7 @@ object CityResources {
|
||||
for (building in city.cityConstructions.getBuiltBuildings()) {
|
||||
// Free buildings cost no resources
|
||||
if (building.name in freeBuildings) continue
|
||||
cityResources.subtractResourceRequirements(building.getResourceRequirementsPerTurn(), city.getRuleset(), "Buildings")
|
||||
cityResources.subtractResourceRequirements(building.getResourceRequirementsPerTurn(StateForConditionals(city.civ, city)), city.getRuleset(), "Buildings")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ class UnitManager(val civInfo:Civilization) {
|
||||
if (unique.conditionals.any { it.isOfType(UniqueType.TriggerUponGainingUnit) &&
|
||||
unit.matchesFilter(unique.params[0]) })
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo, triggerNotificationText = triggerNotificationText)
|
||||
if (unit.baseUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
if (unit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
|
||||
for (unique in civInfo.getMatchingUniques(UniqueType.LandUnitsCrossTerrainAfterUnitGained)) {
|
||||
@ -126,7 +126,7 @@ class UnitManager(val civInfo:Civilization) {
|
||||
// Not relevant when updating Tile transients, since some info of the civ itself isn't yet available,
|
||||
// and in any case it'll be updated once civ info transients are
|
||||
civInfo.updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
if (mapUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
}
|
||||
}
|
||||
@ -139,7 +139,7 @@ class UnitManager(val civInfo:Civilization) {
|
||||
nextPotentiallyDueAt = 0
|
||||
|
||||
civInfo.updateStatsForNextTurn() // unit upkeep
|
||||
if (mapUnit.baseUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
if (mapUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,8 @@ class CivInfoTransientCache(val civInfo: Civilization) {
|
||||
val ruleset = civInfo.gameInfo.ruleset
|
||||
|
||||
for (resource in ruleset.tileResources.values.asSequence().filter { it.resourceType == ResourceType.Strategic }.map { it.name }) {
|
||||
val applicableBuildings = ruleset.buildings.values.filter { it.requiresResource(resource) && civInfo.getEquivalentBuilding(it) == it }
|
||||
val applicableUnits = ruleset.units.values.filter { it.requiresResource(resource) && civInfo.getEquivalentUnit(it) == it }
|
||||
val applicableBuildings = ruleset.buildings.values.filter { it.requiresResource(resource, StateForConditionals.IgnoreConditionals) && civInfo.getEquivalentBuilding(it) == it }
|
||||
val applicableUnits = ruleset.units.values.filter { it.requiresResource(resource, StateForConditionals.IgnoreConditionals) && civInfo.getEquivalentUnit(it) == it }
|
||||
|
||||
val lastEraForBuilding = applicableBuildings.maxOfOrNull { ruleset.eras[ruleset.technologies[it.requiredTech]?.era()]?.eraNumber ?: 0 }
|
||||
val lastEraForUnit = applicableUnits.maxOfOrNull { ruleset.eras[ruleset.technologies[it.requiredTech]?.era()]?.eraNumber ?: 0 }
|
||||
@ -316,7 +316,7 @@ class CivInfoTransientCache(val civInfo: Civilization) {
|
||||
|
||||
for (unit in civInfo.units.getCivUnits())
|
||||
newDetailedCivResources.subtractResourceRequirements(
|
||||
unit.baseUnit.getResourceRequirementsPerTurn(), civInfo.gameInfo.ruleset, "Units")
|
||||
unit.getResourceRequirementsPerTurn(), civInfo.gameInfo.ruleset, "Units")
|
||||
|
||||
newDetailedCivResources.removeAll { it.resource.hasUnique(UniqueType.CityResource) }
|
||||
|
||||
|
@ -587,7 +587,7 @@ class TileMap(initialCapacity: Int = 10) : IsPartOfGameInfoSerialization {
|
||||
// And update civ stats, since the new unit changes both unit upkeep and resource consumption
|
||||
civInfo.updateStatsForNextTurn()
|
||||
|
||||
if (unit.baseUnit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
if (unit.getResourceRequirementsPerTurn().isNotEmpty())
|
||||
civInfo.cache.updateCivResources()
|
||||
|
||||
return unit
|
||||
|
@ -12,6 +12,7 @@ import com.unciv.logic.civilization.NotificationCategory
|
||||
import com.unciv.logic.civilization.NotificationIcon
|
||||
import com.unciv.logic.map.mapunit.movement.UnitMovement
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
@ -259,6 +260,23 @@ class MapUnit : IsPartOfGameInfoSerialization {
|
||||
newUnit.updateVisibleTiles()
|
||||
}
|
||||
|
||||
/** Gets *per turn* resource requirements - does not include immediate costs for stockpiled resources.
|
||||
* StateForConditionals is assumed to regarding this mapUnit*/
|
||||
fun getResourceRequirementsPerTurn(): Counter<String> {
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (baseUnit.requiredResource != null) resourceRequirements[baseUnit.requiredResource!!] = 1
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, StateForConditionals(civ, unit = this)))
|
||||
resourceRequirements[unique.params[1]] += unique.params[0].toInt()
|
||||
return resourceRequirements
|
||||
}
|
||||
|
||||
fun requiresResource(resource: String): Boolean {
|
||||
if (getResourceRequirementsPerTurn().contains(resource)) return true
|
||||
for (unique in getMatchingUniques(UniqueType.CostsResources, StateForConditionals(civ, unit = this))) {
|
||||
if (unique.params[1] == resource) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getMaxMovement(): Int {
|
||||
var movement =
|
||||
|
@ -62,7 +62,7 @@ class UnitUpgradeManager(val unit:MapUnit) {
|
||||
): Boolean {
|
||||
if (unit.name == unitToUpgradeTo.name) return false
|
||||
|
||||
val rejectionReasons = unitToUpgradeTo.getRejectionReasons(unit.civ, additionalResources = unit.baseUnit.getResourceRequirementsPerTurn())
|
||||
val rejectionReasons = unitToUpgradeTo.getRejectionReasons(unit.civ, additionalResources = unit.getResourceRequirementsPerTurn())
|
||||
|
||||
var relevantRejectionReasons = rejectionReasons.filterNot { it.type == RejectionReasonType.Unbuildable }
|
||||
if (ignoreRequirements)
|
||||
|
@ -11,6 +11,7 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.ModOptionsConstants
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.ui.components.extensions.toPercent
|
||||
import com.unciv.ui.screens.victoryscreen.RankingType
|
||||
@ -127,9 +128,11 @@ class TradeEvaluation {
|
||||
val amountToBuyInOffer = min(amountWillingToBuy, offer.amount)
|
||||
|
||||
val canUseForBuildings = civInfo.cities
|
||||
.any { city -> city.cityConstructions.getBuildableBuildings().any { it.getResourceRequirementsPerTurn().containsKey(offer.name) } }
|
||||
.any { city -> city.cityConstructions.getBuildableBuildings().any {
|
||||
it.getResourceRequirementsPerTurn(StateForConditionals(civInfo, city)).containsKey(offer.name) } }
|
||||
val canUseForUnits = civInfo.cities
|
||||
.any { city -> city.cityConstructions.getConstructableUnits().any { it.getResourceRequirementsPerTurn().containsKey(offer.name) } }
|
||||
.any { city -> city.cityConstructions.getConstructableUnits().any {
|
||||
it.getResourceRequirementsPerTurn(StateForConditionals(civInfo)).containsKey(offer.name) } }
|
||||
if (!canUseForBuildings && !canUseForUnits) return 0
|
||||
|
||||
return 50 * amountToBuyInOffer
|
||||
@ -229,7 +232,7 @@ class TradeEvaluation {
|
||||
if (!civInfo.isAtWar()) return 50 * offer.amount
|
||||
|
||||
val canUseForUnits = civInfo.gameInfo.ruleset.units.values
|
||||
.any { it.getResourceRequirementsPerTurn().containsKey(offer.name)
|
||||
.any { it.getResourceRequirementsPerTurn(StateForConditionals(civInfo)).containsKey(offer.name)
|
||||
&& it.isBuildable(civInfo) }
|
||||
if (!canUseForUnits) return 50 * offer.amount
|
||||
|
||||
|
@ -86,7 +86,6 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
if (!tileBonusHashmap.containsKey(stats)) tileBonusHashmap[stats] = ArrayList()
|
||||
tileBonusHashmap[stats]!!.add(unique.params[1])
|
||||
}
|
||||
unique.isOfType(UniqueType.ConsumesResources) -> Unit // skip these,
|
||||
else -> yield(unique.text)
|
||||
}
|
||||
for ((key, value) in tileBonusHashmap)
|
||||
@ -116,7 +115,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
if (isWonder) translatedLines += "Wonder".tr()
|
||||
if (isNationalWonder) translatedLines += "National Wonder".tr()
|
||||
if (!isFree) {
|
||||
for ((resourceName, amount) in getResourceRequirementsPerTurn()) {
|
||||
for ((resourceName, amount) in getResourceRequirementsPerTurn(StateForConditionals(city.civ, city))) {
|
||||
val available = city.getResourceAmount(resourceName)
|
||||
val resource = city.getRuleset().tileResources[resourceName] ?: continue
|
||||
val consumesString = resourceName.getConsumesAmountString(amount, resource.isStockpiled())
|
||||
@ -247,15 +246,12 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
textList += FormattedLine("Requires [$requiredBuilding] to be built in the city",
|
||||
link="Building/$requiredBuilding")
|
||||
|
||||
val resourceRequirements = getResourceRequirementsPerTurn()
|
||||
if (resourceRequirements.isNotEmpty()) {
|
||||
if (requiredResource != null) {
|
||||
textList += FormattedLine()
|
||||
for ((resourceName, amount) in resourceRequirements) {
|
||||
val resource = ruleset.tileResources[resourceName] ?: continue
|
||||
textList += FormattedLine(
|
||||
resourceName.getConsumesAmountString(amount, resource.isStockpiled()),
|
||||
link="Resources/$resourceName", color="#F42" )
|
||||
}
|
||||
val resource = ruleset.tileResources[requiredResource]
|
||||
textList += FormattedLine(
|
||||
requiredResource!!.getConsumesAmountString(1, resource!!.isStockpiled()),
|
||||
link="Resources/$requiredResource", color="#F42" )
|
||||
}
|
||||
|
||||
val stats = cloneStats()
|
||||
@ -269,7 +265,10 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
} else if (uniques.isNotEmpty()) {
|
||||
for (unique in uniqueObjects) {
|
||||
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
|
||||
if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements
|
||||
if (unique.type == UniqueType.ConsumesResources) {
|
||||
textList += FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42")
|
||||
continue
|
||||
}
|
||||
textList += FormattedLine(unique)
|
||||
}
|
||||
}
|
||||
@ -620,7 +619,9 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
yield(RejectionReasonType.RequiresBuildingInThisCity.toInstance("Requires a [${civ.getEquivalentBuilding(requiredBuilding!!)}] in this city"))
|
||||
}
|
||||
|
||||
for ((resourceName, requiredAmount) in getResourceRequirementsPerTurn()) {
|
||||
for ((resourceName, requiredAmount) in getResourceRequirementsPerTurn(
|
||||
StateForConditionals(cityConstructions.city.civ, cityConstructions.city))
|
||||
) {
|
||||
val availableAmount = cityConstructions.city.getResourceAmount(resourceName)
|
||||
if (availableAmount < requiredAmount) {
|
||||
yield(RejectionReasonType.ConsumesResources.toInstance(resourceName.getNeedMoreAmountString(requiredAmount - availableAmount)))
|
||||
@ -704,20 +705,17 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction {
|
||||
|
||||
fun isSellable() = !isAnyWonder() && !hasUnique(UniqueType.Unsellable)
|
||||
|
||||
override fun getResourceRequirementsPerTurn(): Counter<String> = resourceRequirementsInternal
|
||||
|
||||
private val resourceRequirementsInternal: Counter<String> by lazy {
|
||||
override fun getResourceRequirementsPerTurn(stateForConditionals: StateForConditionals?): Counter<String> {
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
|
||||
for (unique in uniqueObjects)
|
||||
if (unique.isOfType(UniqueType.ConsumesResources))
|
||||
resourceRequirements[unique.params[1]] = unique.params[0].toInt()
|
||||
resourceRequirements
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, stateForConditionals))
|
||||
resourceRequirements[unique.params[1]] += unique.params[0].toInt()
|
||||
return resourceRequirements
|
||||
}
|
||||
|
||||
override fun requiresResource(resource: String): Boolean {
|
||||
if (resourceRequirementsInternal.contains(resource)) return true
|
||||
for (unique in getMatchingUniques(UniqueType.CostsResources)) {
|
||||
override fun requiresResource(resource: String, stateForConditionals: StateForConditionals?): Boolean {
|
||||
if (getResourceRequirementsPerTurn(stateForConditionals).contains(resource)) return true
|
||||
for (unique in getMatchingUniques(UniqueType.CostsResources, stateForConditionals)) {
|
||||
if (unique.params[1] == resource) return true
|
||||
}
|
||||
return false
|
||||
|
@ -18,9 +18,10 @@ import kotlin.math.roundToInt
|
||||
interface IConstruction : INamed {
|
||||
fun isBuildable(cityConstructions: CityConstructions): Boolean
|
||||
fun shouldBeDisplayed(cityConstructions: CityConstructions): Boolean
|
||||
/** Gets *per turn* resource requirements - does not include immediate costs for stockpiled resources */
|
||||
fun getResourceRequirementsPerTurn(): Counter<String>
|
||||
fun requiresResource(resource: String): Boolean
|
||||
/** Gets *per turn* resource requirements - does not include immediate costs for stockpiled resources.
|
||||
* Uses [stateForConditionals] to determine which civ or city this is built for*/
|
||||
fun getResourceRequirementsPerTurn(stateForConditionals: StateForConditionals? = null): Counter<String>
|
||||
fun requiresResource(resource: String, stateForConditionals: StateForConditionals? = null): Boolean
|
||||
/** We can't call this getMatchingUniques because then it would conflict with IHasUniques */
|
||||
fun getMatchingUniquesNotConflicting(uniqueType: UniqueType) = sequenceOf<Unique>()
|
||||
}
|
||||
@ -206,7 +207,6 @@ enum class RejectionReasonType(val shouldShow: Boolean, val errorMessage: String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class PerpetualConstruction(override var name: String, val description: String) :
|
||||
IConstruction {
|
||||
|
||||
@ -232,9 +232,9 @@ open class PerpetualConstruction(override var name: String, val description: Str
|
||||
override fun isBuildable(cityConstructions: CityConstructions): Boolean =
|
||||
throw Exception("Impossible!")
|
||||
|
||||
override fun getResourceRequirementsPerTurn() = Counter.ZERO
|
||||
override fun getResourceRequirementsPerTurn(stateForConditionals: StateForConditionals?) = Counter.ZERO
|
||||
|
||||
override fun requiresResource(resource: String) = false
|
||||
override fun requiresResource(resource: String, stateForConditionals: StateForConditionals?) = false
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import com.unciv.logic.map.tile.Tile
|
||||
import com.unciv.models.ruleset.Belief
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetStatsObject
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueFlag
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -101,7 +102,8 @@ class TileResource : RulesetStatsObject() {
|
||||
}
|
||||
}
|
||||
|
||||
val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.getResourceRequirementsPerTurn().containsKey(name) }
|
||||
val buildingsThatConsumeThis = ruleset.buildings.values.filter { it.getResourceRequirementsPerTurn(
|
||||
StateForConditionals.IgnoreConditionals).containsKey(name) }
|
||||
if (buildingsThatConsumeThis.isNotEmpty()) {
|
||||
textList += FormattedLine()
|
||||
textList += FormattedLine("{Buildings that consume this resource}:")
|
||||
@ -110,7 +112,8 @@ class TileResource : RulesetStatsObject() {
|
||||
}
|
||||
}
|
||||
|
||||
val unitsThatConsumeThis = ruleset.units.values.filter { it.getResourceRequirementsPerTurn().containsKey(name) }
|
||||
val unitsThatConsumeThis = ruleset.units.values.filter { it.getResourceRequirementsPerTurn(
|
||||
StateForConditionals.IgnoreConditionals).containsKey(name) }
|
||||
if (unitsThatConsumeThis.isNotEmpty()) {
|
||||
textList += FormattedLine()
|
||||
textList += FormattedLine("{Units that consume this resource}: ")
|
||||
|
@ -40,7 +40,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
|
||||
val type by lazy { ruleset.unitTypes[unitType]!! }
|
||||
override var requiredTech: String? = null
|
||||
private var requiredResource: String? = null
|
||||
var requiredResource: String? = null
|
||||
|
||||
override fun getUniqueTarget() = UniqueTarget.Unit
|
||||
|
||||
@ -182,7 +182,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
|
||||
if (!civ.isBarbarian()) { // Barbarians don't need resources
|
||||
val civResources = Counter(civ.getCivResourcesByName()) + additionalResources
|
||||
for ((resource, requiredAmount) in getResourceRequirementsPerTurn()) {
|
||||
for ((resource, requiredAmount) in getResourceRequirementsPerTurn(StateForConditionals(civ))) {
|
||||
val availableAmount = civResources[resource]
|
||||
if (availableAmount < requiredAmount) {
|
||||
val message = resource.getNeedMoreAmountString(requiredAmount - availableAmount)
|
||||
@ -310,17 +310,21 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction {
|
||||
fun movesLikeAirUnits() = type.getMovementType() == UnitMovementType.Air
|
||||
|
||||
/** Returns resource requirements from both uniques and requiredResource field */
|
||||
override fun getResourceRequirementsPerTurn(): Counter<String> = resourceRequirementsInternal
|
||||
|
||||
private val resourceRequirementsInternal: Counter<String> by lazy {
|
||||
override fun getResourceRequirementsPerTurn(stateForConditionals: StateForConditionals?): Counter<String> {
|
||||
val resourceRequirements = Counter<String>()
|
||||
if (requiredResource != null) resourceRequirements[requiredResource!!] = 1
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources))
|
||||
resourceRequirements[unique.params[1]] = unique.params[0].toInt()
|
||||
resourceRequirements
|
||||
for (unique in getMatchingUniques(UniqueType.ConsumesResources, stateForConditionals))
|
||||
resourceRequirements[unique.params[1]] += unique.params[0].toInt()
|
||||
return resourceRequirements
|
||||
}
|
||||
|
||||
override fun requiresResource(resource: String) = getResourceRequirementsPerTurn().containsKey(resource)
|
||||
override fun requiresResource(resource: String, stateForConditionals: StateForConditionals?): Boolean {
|
||||
if (getResourceRequirementsPerTurn(stateForConditionals).contains(resource)) return true
|
||||
for (unique in getMatchingUniques(UniqueType.CostsResources, stateForConditionals)) {
|
||||
if (unique.params[1] == resource) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun isRanged() = rangedStrength > 0
|
||||
fun isMelee() = !isRanged() && strength > 0
|
||||
|
@ -433,7 +433,7 @@ class RulesetValidator(val ruleset: Ruleset) {
|
||||
for (specialistName in building.specialistSlots.keys)
|
||||
if (!ruleset.specialists.containsKey(specialistName))
|
||||
lines += "${building.name} provides specialist $specialistName which does not exist!"
|
||||
for (resource in building.getResourceRequirementsPerTurn().keys)
|
||||
for (resource in building.getResourceRequirementsPerTurn(StateForConditionals.IgnoreConditionals).keys)
|
||||
if (!ruleset.tileResources.containsKey(resource))
|
||||
lines += "${building.name} requires resource $resource which does not exist!"
|
||||
if (building.replaces != null && !ruleset.buildings.containsKey(building.replaces!!))
|
||||
@ -649,7 +649,7 @@ class RulesetValidator(val ruleset: Ruleset) {
|
||||
)
|
||||
}
|
||||
|
||||
for (resource in unit.getResourceRequirementsPerTurn().keys)
|
||||
for (resource in unit.getResourceRequirementsPerTurn(StateForConditionals.IgnoreConditionals).keys)
|
||||
if (!ruleset.tileResources.containsKey(resource))
|
||||
lines += "${unit.name} requires resource $resource which does not exist!"
|
||||
if (unit.replaces != null && !ruleset.units.containsKey(unit.replaces!!))
|
||||
|
@ -7,6 +7,7 @@ import com.unciv.logic.city.City
|
||||
import com.unciv.models.metadata.GameSettings
|
||||
import com.unciv.models.ruleset.IRulesetObject
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueFlag
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -43,7 +44,7 @@ object BaseUnitDescriptions {
|
||||
fun getDescription(baseUnit: BaseUnit, city: City): String {
|
||||
val lines = mutableListOf<String>()
|
||||
val availableResources = city.civ.getCivResourcesByName()
|
||||
for ((resourceName, amount) in baseUnit.getResourceRequirementsPerTurn()) {
|
||||
for ((resourceName, amount) in baseUnit.getResourceRequirementsPerTurn(StateForConditionals(city.civ))) {
|
||||
val available = availableResources[resourceName] ?: 0
|
||||
val resource = baseUnit.ruleset.tileResources[resourceName] ?: continue
|
||||
val consumesString = resourceName.getConsumesAmountString(amount, resource.isStockpiled())
|
||||
@ -60,7 +61,6 @@ object BaseUnitDescriptions {
|
||||
if (baseUnit.replacementTextForUniques != "") lines += baseUnit.replacementTextForUniques
|
||||
else for (unique in baseUnit.uniqueObjects.filterNot {
|
||||
it.type == UniqueType.Unbuildable
|
||||
|| it.type == UniqueType.ConsumesResources // already shown from getResourceRequirements
|
||||
|| it.type?.flags?.contains(UniqueFlag.HiddenToUsers) == true
|
||||
})
|
||||
lines += unique.text.tr()
|
||||
@ -110,21 +110,20 @@ object BaseUnitDescriptions {
|
||||
textList += FormattedLine()
|
||||
for (unique in baseUnit.uniqueObjects.sortedBy { it.text }) {
|
||||
if (unique.hasFlag(UniqueFlag.HiddenToUsers)) continue
|
||||
if (unique.type == UniqueType.ConsumesResources) continue // already shown from getResourceRequirements
|
||||
if (unique.type == UniqueType.ConsumesResources) {
|
||||
textList += FormattedLine(unique.text, link = "Resources/${unique.params[1]}", color = "#F42")
|
||||
continue
|
||||
}
|
||||
textList += FormattedLine(unique)
|
||||
}
|
||||
}
|
||||
|
||||
val resourceRequirements = baseUnit.getResourceRequirementsPerTurn()
|
||||
if (resourceRequirements.isNotEmpty()) {
|
||||
if (baseUnit.requiredResource != null) {
|
||||
textList += FormattedLine()
|
||||
for ((resourceName, amount) in resourceRequirements) {
|
||||
val resource = ruleset.tileResources[resourceName] ?: continue
|
||||
textList += FormattedLine(
|
||||
resourceName.getConsumesAmountString(amount, resource.isStockpiled()),
|
||||
link = "Resource/$resource", color = "#F42"
|
||||
)
|
||||
}
|
||||
val resource = ruleset.tileResources[baseUnit.requiredResource]
|
||||
textList += FormattedLine(
|
||||
baseUnit.requiredResource!!.getConsumesAmountString(1, resource!!.isStockpiled()),
|
||||
link="Resources/${baseUnit.requiredResource}", color="#F42")
|
||||
}
|
||||
|
||||
if (baseUnit.uniqueTo != null) {
|
||||
@ -293,8 +292,8 @@ object BaseUnitDescriptions {
|
||||
if (betterUnit.movement != originalUnit.movement)
|
||||
yield("${Fonts.movement} {[${betterUnit.movement}] vs [${originalUnit.movement}]}" to null)
|
||||
|
||||
for (resource in originalUnit.getResourceRequirementsPerTurn().keys)
|
||||
if (!betterUnit.getResourceRequirementsPerTurn().containsKey(resource)) {
|
||||
for (resource in originalUnit.getResourceRequirementsPerTurn(StateForConditionals.IgnoreConditionals).keys)
|
||||
if (!betterUnit.getResourceRequirementsPerTurn(StateForConditionals.IgnoreConditionals).containsKey(resource)) {
|
||||
yield("[$resource] not required" to "Resource/$resource")
|
||||
}
|
||||
// We return the unique text directly, so Nation.getUniqueUnitsText will not use the
|
||||
|
@ -19,6 +19,7 @@ import com.unciv.models.ruleset.INonPerpetualConstruction
|
||||
import com.unciv.models.ruleset.PerpetualConstruction
|
||||
import com.unciv.models.ruleset.RejectionReason
|
||||
import com.unciv.models.ruleset.RejectionReasonType
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
@ -210,7 +211,9 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
|
||||
val useStoredProduction = entry is Building || !cityConstructions.isBeingConstructedOrEnqueued(entry.name)
|
||||
val buttonText = cityConstructions.getTurnsToConstructionString(entry, useStoredProduction).trim()
|
||||
val resourcesRequired = entry.getResourceRequirementsPerTurn()
|
||||
val resourcesRequired = if (entry is BaseUnit)
|
||||
entry.getResourceRequirementsPerTurn(StateForConditionals(city.civ))
|
||||
else entry.getResourceRequirementsPerTurn(StateForConditionals(city.civ, city))
|
||||
val mostImportantRejection =
|
||||
entry.getRejectionReasons(cityConstructions)
|
||||
.filter { it.isImportantRejection() }
|
||||
@ -325,7 +328,9 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
if (constructionName in PerpetualConstruction.perpetualConstructionsMap) "\n∞"
|
||||
else cityConstructions.getTurnsToConstructionString(construction, isFirstConstructionOfItsKind)
|
||||
|
||||
val constructionResource = construction.getResourceRequirementsPerTurn()
|
||||
val constructionResource = if (construction is BaseUnit)
|
||||
construction.getResourceRequirementsPerTurn(StateForConditionals(city.civ, city))
|
||||
else construction.getResourceRequirementsPerTurn(StateForConditionals(city.civ))
|
||||
for ((resourceName, amount) in constructionResource) {
|
||||
val resource = cityConstructions.city.getRuleset().tileResources[resourceName] ?: continue
|
||||
text += "\n" + resourceName.getConsumesAmountString(amount, resource.isStockpiled()).tr()
|
||||
|
@ -298,9 +298,9 @@ object UnitActionsFromUniques {
|
||||
// Check _new_ resource requirements
|
||||
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
|
||||
val resourceRequirementsDelta = Counter<String>()
|
||||
for ((resource, amount) in unit.baseUnit().getResourceRequirementsPerTurn())
|
||||
for ((resource, amount) in unit.getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, -amount)
|
||||
for ((resource, amount) in unitToTransformTo.getResourceRequirementsPerTurn())
|
||||
for ((resource, amount) in unitToTransformTo.getResourceRequirementsPerTurn(StateForConditionals(unit.civ, unit = unit)))
|
||||
resourceRequirementsDelta.add(resource, amount)
|
||||
val newResourceRequirementsString = resourceRequirementsDelta.entries
|
||||
.filter { it.value > 0 }
|
||||
|
@ -4,6 +4,7 @@ import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.UnitAction
|
||||
import com.unciv.models.UpgradeUnitAction
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.translations.tr
|
||||
|
||||
@ -43,9 +44,9 @@ object UnitActionsUpgrade {
|
||||
// Check _new_ resource requirements (display only - yes even for free or special upgrades)
|
||||
// Using Counter to aggregate is a bit exaggerated, but - respect the mad modder.
|
||||
val resourceRequirementsDelta = Counter<String>()
|
||||
for ((resource, amount) in unit.baseUnit().getResourceRequirementsPerTurn())
|
||||
for ((resource, amount) in unit.getResourceRequirementsPerTurn())
|
||||
resourceRequirementsDelta.add(resource, -amount)
|
||||
for ((resource, amount) in upgradedUnit.getResourceRequirementsPerTurn())
|
||||
for ((resource, amount) in upgradedUnit.getResourceRequirementsPerTurn(StateForConditionals(unit.civ, unit = unit)))
|
||||
resourceRequirementsDelta.add(resource, amount)
|
||||
for ((resource, _) in resourceRequirementsDelta.filter { it.value < 0 }) // filter copies, so no CCM
|
||||
resourceRequirementsDelta[resource] = 0
|
||||
|
Loading…
Reference in New Issue
Block a user