From 97da979a043fc2cd445d9c648f0f0fb3b6ed2173 Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Sun, 3 Oct 2021 11:04:15 +0200 Subject: [PATCH] Fixed bugs with fallout (#5379) * Fixed bugs with fallout * Reordered uniques * Reviews * Added missing unique targets --- .../jsons/Civ V - Vanilla/Terrains.json | 9 +- core/src/com/unciv/logic/map/TileInfo.kt | 10 +- .../com/unciv/logic/trade/TradeEvaluation.kt | 2 +- .../com/unciv/models/ruleset/tile/Terrain.kt | 3 +- .../unciv/models/ruleset/unique/UniqueType.kt | 100 ++++++++++-------- 5 files changed, 71 insertions(+), 53 deletions(-) diff --git a/android/assets/jsons/Civ V - Vanilla/Terrains.json b/android/assets/jsons/Civ V - Vanilla/Terrains.json index eab8a363dc..8eb21af6f4 100644 --- a/android/assets/jsons/Civ V - Vanilla/Terrains.json +++ b/android/assets/jsons/Civ V - Vanilla/Terrains.json @@ -152,12 +152,13 @@ { "name": "Fallout", "type": "TerrainFeature", - "food": -3, - "production": -3, - "gold": -3, "movementCost": 2, "unbuildable": true, - "defenceBonus": -0.15, + "uniques": ["Nullifies all other stats this tile provides", "Doesn't generate naturally"], + // For map editor only - the generator won't place it without code or enabling uniques + // If the map generator is ever updated to always take these into account, it should also take the "Doesn't generate naturally" unique into account + "occursOn": ["Grassland","Plains","Desert","Tundra","Snow","Forest","Jungle","Hill","Flood plains","Marsh","Oasis"] + "defenceBonus": -0.15 }, { "name": "Oasis", diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index b65448de04..1fe80bd170 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -218,10 +218,12 @@ open class TileInfo { var stats = getBaseTerrain().clone() for (terrainFeatureBase in getTerrainFeatures()) { - if (terrainFeatureBase.overrideStats) - stats = terrainFeatureBase.clone() - else - stats.add(terrainFeatureBase) + when { + terrainFeatureBase.hasUnique(UniqueType.NullifyYields) -> + return terrainFeatureBase.clone() + terrainFeatureBase.overrideStats -> stats = terrainFeatureBase.clone() + else -> stats.add(terrainFeatureBase) + } } if (naturalWonder != null) { diff --git a/core/src/com/unciv/logic/trade/TradeEvaluation.kt b/core/src/com/unciv/logic/trade/TradeEvaluation.kt index 9c46494ba4..78f5979af8 100644 --- a/core/src/com/unciv/logic/trade/TradeEvaluation.kt +++ b/core/src/com/unciv/logic/trade/TradeEvaluation.kt @@ -261,7 +261,7 @@ class TradeEvaluation { fun evaluatePeaceCostForThem(ourCivilization: CivilizationInfo, otherCivilization: CivilizationInfo): Int { val ourCombatStrength = ourCivilization.getStatForRanking(RankingType.Force) val theirCombatStrength = otherCivilization.getStatForRanking(RankingType.Force) - if (ourCombatStrength*1.5f >= theirCombatStrength && theirCombatStrength * 1.5f >= ourCombatStrength) + if (ourCombatStrength * 1.5f >= theirCombatStrength && theirCombatStrength * 1.5f >= ourCombatStrength) return 0 // we're roughly equal, there's no huge power imbalance if (ourCombatStrength == 0) return -1000 if (theirCombatStrength == 0) return 1000 // Chumps got no combat units diff --git a/core/src/com/unciv/models/ruleset/tile/Terrain.kt b/core/src/com/unciv/models/ruleset/tile/Terrain.kt index 81e16f6fbc..091e8348da 100644 --- a/core/src/com/unciv/models/ruleset/tile/Terrain.kt +++ b/core/src/com/unciv/models/ruleset/tile/Terrain.kt @@ -6,6 +6,7 @@ import com.unciv.models.ruleset.Belief import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetStatsObject import com.unciv.models.ruleset.unique.UniqueTarget +import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.civilopedia.FormattedLine import com.unciv.ui.utils.colorFromRGB @@ -75,7 +76,7 @@ class Terrain : RulesetStatsObject() { textList += FormattedLine("$stats") } - if (occursOn.isNotEmpty()) { + if (occursOn.isNotEmpty() && !hasUnique(UniqueType.NoNaturalGeneration)) { textList += FormattedLine() if (occursOn.size == 1) { with (occursOn[0]) { diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 36413d3c02..caf8f0d6b9 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -57,20 +57,44 @@ enum class UniqueTarget(val inheritsFrom:UniqueTarget?=null) { enum class UniqueType(val text:String, vararg targets: UniqueTarget) { + //////////////////////////////////////// GLOBAL UNIQUES //////////////////////////////////////// + + /////// Stat providing uniques + Stats("[stats]", UniqueTarget.Global), StatsPerCity("[stats] [cityFilter]", UniqueTarget.Global), + @Deprecated("As of 3.16.16", ReplaceWith("[stats] "), DeprecationLevel.WARNING) + StatBonusForNumberOfSpecialists("[stats] if this city has at least [amount] specialists", UniqueTarget.Global), StatPercentBonus("[amount]% [Stat]", UniqueTarget.Global), + BonusStatsFromCityStates("[amount]% [stat] from City-States", UniqueTarget.Global), + + RemoveAnnexUnhappiness("Remove extra unhappiness from annexed cities", UniqueTarget.Building), - ConsumesResources("Consumes [amount] [resource]", - UniqueTarget.Improvement, UniqueTarget.Building, UniqueTarget.Unit), // No conditional support as of yet - ProvidesResources("Provides [amount] [resource]", - UniqueTarget.Improvement, UniqueTarget.Building), + /////// City-State related uniques + // I don't like the fact that currently "city state bonuses" are separate from the "global bonuses", + // todo: merge city state bonuses into global bonuses + CityStateStatsPerTurn("Provides [stats] per turn", UniqueTarget.CityState), // Should not be Happiness! + CityStateStatsPerCity("Provides [stats] [cityFilter] per turn", UniqueTarget.CityState), + CityStateHappiness("Provides [amount] Happiness", UniqueTarget.CityState), + CityStateMilitaryUnits("Provides military units every ≈[amount] turns", UniqueTarget.CityState), // No conditional support as of yet + CityStateUniqueLuxury("Provides a unique luxury", UniqueTarget.CityState), // No conditional support as of yet + + + /////// Other global uniques + FreeUnits("[amount] units cost no maintenance", UniqueTarget.Global), UnitMaintenanceDiscount("[amount]% maintenance costs for [mapUnitFilter] units", UniqueTarget.Global), - BonusStatsFromCityStates("[amount]% [stat] from City-States", UniqueTarget.Global), - RemoveAnnexUnhappiness("Remove extra unhappiness from annexed cities", UniqueTarget.Building), + @Deprecated("As of 3.16.16", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.WARNING) + DecreasedUnitMaintenanceCostsByFilter("-[amount]% [mapUnitFilter] unit maintenance costs", UniqueTarget.Global), + @Deprecated("As of 3.16.16", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.WARNING) + DecreasedUnitMaintenanceCostsGlobally("-[amount]% unit upkeep costs", UniqueTarget.Global), + + ConsumesResources("Consumes [amount] [resource]", + UniqueTarget.Improvement, UniqueTarget.Building, UniqueTarget.Unit), + ProvidesResources("Provides [amount] [resource]", + UniqueTarget.Improvement, UniqueTarget.Building), GrowthPercentBonus("[amount]% growth [cityFilter]", UniqueTarget.Global), @Deprecated("As of 3.16.14", ReplaceWith("[amount]% growth [cityFilter]"), DeprecationLevel.WARNING) @@ -78,15 +102,15 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { @Deprecated("As of 3.16.14", ReplaceWith("[amount]% growth [cityFilter] "), DeprecationLevel.WARNING) GrowthPercentBonusWhenNotAtWar("+[amount]% growth [cityFilter] when not at war", UniqueTarget.Global), - TileProvidesYieldWithoutPopulation("Tile provides yield without assigned population", UniqueTarget.Terrain, UniqueTarget.Improvement), + // TODO: Unify these (I'm in favor of "gain a free" above "provides" because it fits more cases) + ProvidesFreeBuildings("Provides a free [buildingName] [cityFilter]", UniqueTarget.Global), + GainFreeBuildings("Gain a free [buildingName] [cityFilter]", UniqueTarget.Global), - @Deprecated("As of 3.16.16", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.WARNING) - DecreasedUnitMaintenanceCostsByFilter("-[amount]% [mapUnitFilter] unit maintenance costs"), // No conditional support - @Deprecated("As of 3.16.16", ReplaceWith("[amount]% maintenance costs for [mapUnitFilter] units"), DeprecationLevel.WARNING) - DecreasedUnitMaintenanceCostsGlobally("-[amount]% unit upkeep costs"), // No conditional support - @Deprecated("As of 3.16.16", ReplaceWith("[stats] "), DeprecationLevel.WARNING) - StatBonusForNumberOfSpecialists("[stats] if this city has at least [amount] specialists"), // No conditional support + FreeExtraBeliefs("May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion", UniqueTarget.Global), + FreeExtraAnyBeliefs("May choose [amount] additional of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global), + ///////////////////////////////////////// UNIT UNIQUES ///////////////////////////////////////// + Strength("[amount]% Strength", UniqueTarget.Unit, UniqueTarget.Global), @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength"), DeprecationLevel.WARNING) @@ -100,35 +124,6 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength"), DeprecationLevel.WARNING) CombatBonus("+[amount]% Combat Strength", UniqueTarget.Unit), - - // TODO: Unify these (I'm in favor of "gain a free" above "provides" because it fits more cases) - ProvidesFreeBuildings("Provides a free [buildingName] [cityFilter]", UniqueTarget.Global), - GainFreeBuildings("Gain a free [buildingName] [cityFilter]", UniqueTarget.Global), - - FreeExtraBeliefs("May choose [amount] additional [beliefType] beliefs when [foundingOrEnhancing] a religion", UniqueTarget.Global), - FreeExtraAnyBeliefs("May choose [amount] additional of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global), - - // I don't like the fact that currently "city state bonuses" are separate from the "global bonuses", - // todo: merge city state bonuses into global bonuses - CityStateStatsPerTurn("Provides [stats] per turn", UniqueTarget.CityState), // Should not be Happiness! - CityStateStatsPerCity("Provides [stats] [cityFilter] per turn", UniqueTarget.CityState), - CityStateHappiness("Provides [amount] Happiness", UniqueTarget.CityState), - CityStateMilitaryUnits("Provides military units every ≈[amount] turns", UniqueTarget.CityState), // No conditional support as of yet - CityStateUniqueLuxury("Provides a unique luxury", UniqueTarget.CityState), // No conditional support as of yet - - NaturalWonderNeighborCount("Must be adjacent to [amount] [simpleTerrain] tiles", UniqueTarget.Terrain), - NaturalWonderNeighborsRange("Must be adjacent to [amount] to [amount] [simpleTerrain] tiles", UniqueTarget.Terrain), - NaturalWonderSmallerLandmass("Must not be on [amount] largest landmasses", UniqueTarget.Terrain), - NaturalWonderLargerLandmass("Must be on [amount] largest landmasses", UniqueTarget.Terrain), - NaturalWonderLatitude("Occurs on latitudes from [amount] to [amount] percent of distance equator to pole", UniqueTarget.Terrain), - NaturalWonderGroups("Occurs in groups of [amount] to [amount] tiles", UniqueTarget.Terrain), - NaturalWonderConvertNeighbors("Neighboring tiles will convert to [baseTerrain]", UniqueTarget.Terrain), - - // The "Except [terrainFilter]" could theoretically be implemented with a conditional - NaturalWonderConvertNeighborsExcept("Neighboring tiles except [baseTerrain] will convert to [baseTerrain]", UniqueTarget.Terrain), - - TerrainGrantsPromotion("Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game", UniqueTarget.Terrain), - // The following block gets cached in MapUnit for faster getMovementCostBetweenAdjacentTiles DoubleMovementOnTerrain("Double movement in [terrainFilter]", UniqueTarget.Unit), @Deprecated("As of 3.17.1", ReplaceWith("Double movement in [terrainFilter]"), DeprecationLevel.WARNING) @@ -146,8 +141,27 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { CannotEnterOcean("Cannot enter ocean tiles", UniqueTarget.Unit), CannotEnterOceanUntilAstronomy("Cannot enter ocean tiles until Astronomy", UniqueTarget.Unit), + //////////////////////////////////////// TERRAIN UNIQUES //////////////////////////////////////// + + NaturalWonderNeighborCount("Must be adjacent to [amount] [simpleTerrain] tiles", UniqueTarget.Terrain), + NaturalWonderNeighborsRange("Must be adjacent to [amount] to [amount] [simpleTerrain] tiles", UniqueTarget.Terrain), + NaturalWonderSmallerLandmass("Must not be on [amount] largest landmasses", UniqueTarget.Terrain), + NaturalWonderLargerLandmass("Must be on [amount] largest landmasses", UniqueTarget.Terrain), + NaturalWonderLatitude("Occurs on latitudes from [amount] to [amount] percent of distance equator to pole", UniqueTarget.Terrain), + NaturalWonderGroups("Occurs in groups of [amount] to [amount] tiles", UniqueTarget.Terrain), + NaturalWonderConvertNeighbors("Neighboring tiles will convert to [baseTerrain]", UniqueTarget.Terrain), + + // The "Except [terrainFilter]" could theoretically be implemented with a conditional + NaturalWonderConvertNeighborsExcept("Neighboring tiles except [baseTerrain] will convert to [baseTerrain]", UniqueTarget.Terrain), - // Conditionals + TerrainGrantsPromotion("Grants [promotion] ([comment]) to adjacent [mapUnitFilter] units for the rest of the game", UniqueTarget.Terrain), + + TileProvidesYieldWithoutPopulation("Tile provides yield without assigned population", UniqueTarget.Terrain, UniqueTarget.Improvement), + NullifyYields("Nullifies all other stats this tile provides", UniqueTarget.Terrain), + + NoNaturalGeneration("Doesn't generate naturally", UniqueTarget.Terrain), + + ///////////////////////////////////////// CONDITIONALS ///////////////////////////////////////// ConditionalWar("when at war", UniqueTarget.Conditional), ConditionalNotWar("when not at war", UniqueTarget.Conditional),