diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index 161ddb859d..598b37ba94 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -539,6 +539,7 @@ class CityStats(val cityInfo: CityInfo) { entry.gold *= statPercentBonusesSum.gold.toPercent() entry.culture *= statPercentBonusesSum.culture.toPercent() entry.food *= statPercentBonusesSum.food.toPercent() + entry.faith *= statPercentBonusesSum.faith.toPercent() } // AFTER we've gotten all the gold stats figured out, only THEN do we plonk that gold into Science diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index 995cdfe441..f8f8e26882 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -8,11 +8,9 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.PlayerType import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.tile.* -import com.unciv.models.ruleset.unique.LocalUniqueCache -import com.unciv.models.ruleset.unique.StateForConditionals -import com.unciv.models.ruleset.unique.Unique +import com.unciv.models.ruleset.unique.* +import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats import com.unciv.models.translations.tr import com.unciv.ui.civilopedia.FormattedLine @@ -259,13 +257,13 @@ open class TileInfo { fun getTerrainMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(tile=this) ): Sequence { return getAllTerrains().flatMap { it.getMatchingUniques(uniqueType, stateForConditionals) } } - + /** Get all uniques of this type that any part of this tile has: terrains, improvement, resource */ - fun getMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(tile=this)) = + fun getMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals = StateForConditionals(tile=this)) = getTerrainMatchingUniques(uniqueType, stateForConditionals) + (getTileImprovement()?.getMatchingUniques(uniqueType, stateForConditionals) ?: sequenceOf()) + if (resource == null) sequenceOf() else tileResource.getMatchingUniques(uniqueType, stateForConditionals) - + fun getWorkingCity(): CityInfo? { val civInfo = getOwner() ?: return null return civInfo.cities.firstOrNull { it.isWorked(this) } @@ -319,22 +317,26 @@ open class TileInfo { tileUniques += city.getMatchingUniques(UniqueType.StatsFromObject, stateForConditionals) for (unique in localUniqueCache.get("StatsFromTilesAndObjects", tileUniques)) { val tileType = unique.params[1] - if (tileType == improvement) continue // This is added to the calculation in getImprovementStats. we don't want to add it twice - if (matchesTerrainFilter(tileType, observingCiv)) - stats.add(unique.stats) - if (tileType == "Natural Wonder" && naturalWonder != null && city.civInfo.hasUnique(UniqueType.DoubleStatsFromNaturalWonders)) { + if (!matchesTerrainFilter(tileType, observingCiv)) continue + stats.add(unique.stats) + if (naturalWonder != null + && tileType == "Natural Wonder" + && city.civInfo.hasUnique(UniqueType.DoubleStatsFromNaturalWonders) + ) { stats.add(unique.stats) } } - for (unique in localUniqueCache.get("StatsFromTilesWithout", - city.getMatchingUniques(UniqueType.StatsFromTilesWithout, stateForConditionals))) + for (unique in localUniqueCache.get("StatsFromTilesWithout", + city.getMatchingUniques(UniqueType.StatsFromTilesWithout, stateForConditionals)) + ) { if ( matchesTerrainFilter(unique.params[1]) && !matchesTerrainFilter(unique.params[2]) && city.matchesFilter(unique.params[3]) ) stats.add(unique.stats) + } } if (isAdjacentToRiver()) stats.gold++ @@ -347,17 +349,61 @@ open class TileInfo { if (improvement != null) stats.add(getImprovementStats(improvement, observingCiv, city)) - if (isCityCenter()) { - if (stats.food < 2) stats.food = 2f - if (stats.production < 1) stats.production = 1f - } - if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge()) stats.gold++ } + if (isCityCenter()) { + if (stats.food < 2) stats.food = 2f + if (stats.production < 1) stats.production = 1f + } + for ((stat, value) in stats) if (value < 0f) stats[stat] = 0f + for ((stat, value) in getTilePercentageStats(observingCiv, city)) { + stats[stat] *= value.toPercent() + } + + return stats + } + + // Only gets the tile percentage bonus, not the improvement percentage bonus + @Suppress("MemberVisibilityCanBePrivate") + fun getTilePercentageStats(observingCiv: CivilizationInfo?, city: CityInfo?): Stats { + val stats = Stats() + val stateForConditionals = StateForConditionals(civInfo = observingCiv, cityInfo = city, tile = this) + + if (city != null) { + for (unique in city.getMatchingUniques(UniqueType.StatPercentFromObject, stateForConditionals)) { + val tileFilter = unique.params[2] + if (matchesTerrainFilter(tileFilter, observingCiv)) + stats[Stat.valueOf(unique.params[1])] += unique.params[0].toFloat() + } + + for (unique in city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, stateForConditionals)) { + val tileFilter = unique.params[1] + if (!matchesTerrainFilter(tileFilter, observingCiv)) continue + val statPercentage = unique.params[0].toFloat() + for (stat in Stat.values()) + stats[stat] += statPercentage + } + + } else if (observingCiv != null) { + for (unique in observingCiv.getMatchingUniques(UniqueType.StatPercentFromObject, stateForConditionals)) { + val tileFilter = unique.params[2] + if (matchesTerrainFilter(tileFilter, observingCiv)) + stats[Stat.valueOf(unique.params[1])] += unique.params[0].toFloat() + } + + for (unique in observingCiv.getMatchingUniques(UniqueType.AllStatsPercentFromObject, stateForConditionals)) { + val tileFilter = unique.params[1] + if (!matchesTerrainFilter(tileFilter, observingCiv)) continue + val statPercentage = unique.params[0].toFloat() + for (stat in Stat.values()) + stats[stat] += statPercentage + } + } + return stats } @@ -421,6 +467,7 @@ open class TileInfo { return fertility } + // Also multiplies the stats by the percentage bonus for improvements (but not for tiles) fun getImprovementStats(improvement: TileImprovement, observingCiv: CivilizationInfo, city: CityInfo?): Stats { val stats = improvement.cloneStats() if (hasViewableResource(observingCiv) && tileResource.isImprovedBy(improvement.name) @@ -464,17 +511,49 @@ open class TileInfo { stats.add(unique.stats) } } - - for (unique in city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, conditionalState)) { - if (improvement.matchesFilter(unique.params[1])) - stats.timesInPlace(unique.params[0].toPercent()) - } } - if (city == null) { // As otherwise we already got this above + for ((stat, value) in getImprovementPercentageStats(improvement, observingCiv, city)) { + stats[stat] *= value.toPercent() + } + + return stats + } + + @Suppress("MemberVisibilityCanBePrivate") + fun getImprovementPercentageStats(improvement: TileImprovement, observingCiv: CivilizationInfo, city: CityInfo?): Stats { + val stats = Stats() + val conditionalState = StateForConditionals(civInfo = observingCiv, cityInfo = city, tile = this) + + // I would love to make an interface 'canCallMatchingUniques' + // from which both cityInfo and CivilizationInfo derive, so I don't have to duplicate all this code + // But something something too much for this PR. + + if (city != null) { + for (unique in city.getMatchingUniques(UniqueType.AllStatsPercentFromObject, conditionalState)) { + if (!improvement.matchesFilter(unique.params[1])) continue + for (stat in Stat.values()) { + stats[stat] += unique.params[0].toFloat() + } + } + + for (unique in city.getMatchingUniques(UniqueType.StatPercentFromObject, conditionalState)) { + if (!improvement.matchesFilter(unique.params[2])) continue + val stat = Stat.valueOf(unique.params[1]) + stats[stat] += unique.params[0].toFloat() + } + + } else { for (unique in observingCiv.getMatchingUniques(UniqueType.AllStatsPercentFromObject, conditionalState)) { - if (improvement.matchesFilter(unique.params[1])) - stats.timesInPlace(unique.params[0].toPercent()) + if (!improvement.matchesFilter(unique.params[1])) continue + for (stat in Stat.values()) { + stats[stat] += unique.params[0].toFloat() + } + } + for (unique in observingCiv.getMatchingUniques(UniqueType.StatPercentFromObject, conditionalState)) { + if (!improvement.matchesFilter(unique.params[2])) continue + val stat = Stat.valueOf(unique.params[1]) + stats[stat] += unique.params[0].toFloat() } } @@ -488,10 +567,10 @@ open class TileInfo { if (terrainFilter == Constants.freshWater && isAdjacentToRiver()) return true return (neighbors + this).any { neighbor -> neighbor.matchesFilter(terrainFilter) } } - + /** Returns true if the [improvement] can be built on this [TileInfo] */ fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean { - + val stateForConditionals = StateForConditionals(civInfo, tile=this) val knownFeatureRemovals = ruleset.tileImprovements.values .filter { rulesetImprovement -> @@ -523,7 +602,7 @@ open class TileInfo { else -> canImprovementBeBuiltHere(improvement, hasViewableResource(civInfo), knownFeatureRemovals, stateForConditionals) } } - + /** Without regards to what CivInfo it is, a lot of the checks are just for the improvement on the tile. * Doubles as a check for the map editor. */ @@ -551,13 +630,13 @@ open class TileInfo { clonedTile.removeTerrainFeature(topTerrain.name) return clonedTile.canImprovementBeBuiltHere(improvement, resourceIsVisible, knownFeatureRemovals, stateForConditionals) } - + return when { improvement.name == this.improvement -> false isCityCenter() -> false - + // First we handle a few special improvements - + // Can only cancel if there is actually an improvement being built improvement.name == Constants.cancelImprovementOrder -> (this.improvementInProgress != null) // Can only remove roads if that road is actually there @@ -566,7 +645,7 @@ open class TileInfo { improvement.name.startsWith(Constants.remove) -> terrainFeatures.any { it == improvement.name.removePrefix(Constants.remove) } // Can only build roads if on land and they are better than the current road RoadStatus.values().any { it.name == improvement.name } -> !isWater && RoadStatus.valueOf(improvement.name) > roadStatus - + // Then we check if there is any reason to not allow this improvement to be build // Can't build if there is already an irremovable improvement here @@ -574,7 +653,7 @@ open class TileInfo { // Can't build if this terrain is unbuildable, except when we are specifically allowed to getLastTerrain().unbuildable && !improvement.canBeBuildOnThisUnbuildableTerrain(knownFeatureRemovals) -> false - + // Can't build if any terrain specifically prevents building this improvement getTerrainMatchingUniques(UniqueType.RestrictedBuildableImprovements, stateForConditionals).any { unique -> !improvement.matchesFilter(unique.params[0]) @@ -602,20 +681,20 @@ open class TileInfo { ) -> false // At this point we know this is a normal improvement and that there is no reason not to allow it to be built. - - // Lastly we check if the improvement may be built on this terrain or resource + + // Lastly we check if the improvement may be built on this terrain or resource improvement.canBeBuiltOn(getLastTerrain().name) -> true isLand && improvement.canBeBuiltOn("Land") -> true isWater && improvement.canBeBuiltOn("Water") -> true // DO NOT reverse this &&. isAdjacentToFreshwater() is a lazy which calls a function, and reversing it breaks the tests. - improvement.hasUnique(UniqueType.ImprovementBuildableByFreshWater, stateForConditionals) + improvement.hasUnique(UniqueType.ImprovementBuildableByFreshWater, stateForConditionals) && isAdjacentTo(Constants.freshWater) -> true - + // I don't particularly like this check, but it is required to build mines on non-hill resources resourceIsVisible && tileResource.isImprovedBy(improvement.name) -> true // DEPRECATED since 4.0.14, REMOVE SOON: isLand && improvement.terrainsCanBeBuiltOn.isEmpty() && !improvement.hasUnique(UniqueType.CanOnlyImproveResource) -> true - // No reason this improvement should be built here, so can't build it + // No reason this improvement should be built here, so can't build it else -> false } } @@ -722,7 +801,7 @@ open class TileInfo { if (isWater || isImpassible()) return false if (getTilesInDistance(modConstants.minimalCityDistanceOnDifferentContinents) - .any { it.isCityCenter() && it.getContinent() != getContinent() } + .any { it.isCityCenter() && it.getContinent() != getContinent() } || getTilesInDistance(modConstants.minimalCityDistance) .any { it.isCityCenter() && it.getContinent() == getContinent() } ) { @@ -942,7 +1021,7 @@ open class TileInfo { /** * Sets this tile's [resource] and, if [newResource] is a Strategic resource, [resourceAmount] fields. - * + * * [resourceAmount] is determined by [MapParameters.mapResources] and [majorDeposit], and * if the latter is `null` a random choice between major and minor deposit is made, approximating * the frequency [MapRegions][com.unciv.logic.map.mapgenerator.MapRegions] would use. diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index b8e2771301..3a9fbd4e90 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -198,6 +198,13 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { if (matchesFilter(unique.params[2])) stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat()) } + + for (unique in localUniqueCache.get("AllStatsPercentFromObject", civInfo.getMatchingUniques(UniqueType.AllStatsPercentFromObject))) { + if (!matchesFilter(unique.params[1])) continue + for (stat in Stat.values()) { + stats.add(stat, unique.params[0].toFloat()) + } + } return stats } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 95af8e2a9b..0b55e6c121 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -84,7 +84,6 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: StatsFromCitiesOnSpecificTiles("[stats] in cities on [terrainFilter] tiles", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatsFromBuildings("[stats] from all [buildingFilter] buildings", UniqueTarget.Global, UniqueTarget.FollowerBelief), - StatsSpendingGreatPeople("[stats] whenever a Great Person is expended", UniqueTarget.Global), StatsFromTiles("[stats] from [tileFilter] tiles [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatsFromTilesWithout("[stats] from [tileFilter] tiles without [tileFilter] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), // This is a doozy @@ -96,8 +95,9 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: // Stat percentage boosts StatPercentBonus("[relativeAmount]% [stat]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatPercentBonusCities("[relativeAmount]% [stat] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), - StatPercentFromObject("[relativeAmount]% [stat] from every [tileFilter/specialist/buildingName]", UniqueTarget.Global, UniqueTarget.FollowerBelief), - AllStatsPercentFromObject("[relativeAmount]% Yield from every [tileFilter]", UniqueTarget.FollowerBelief, UniqueTarget.Global), + // Todo: Add support for specialist next to buildingName + StatPercentFromObject("[relativeAmount]% [stat] from every [tileFilter/buildingFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), + AllStatsPercentFromObject("[relativeAmount]% Yield from every [tileFilter/buildingFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), StatPercentFromReligionFollowers("[relativeAmount]% [stat] from every follower, up to [relativeAmount]%", UniqueTarget.FollowerBelief), BonusStatsFromCityStates("[relativeAmount]% [stat] from City-States", UniqueTarget.Global), StatPercentFromTradeRoutes("[relativeAmount]% [stat] from Trade Routes", UniqueTarget.Global), @@ -165,6 +165,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: FreeExtraAnyBeliefs("May choose [amount] additional belief(s) of any type when [foundingOrEnhancing] a religion", UniqueTarget.Global), StatsWhenAdoptingReligionSpeed("[stats] when a city adopts this religion for the first time (modified by game speed)", UniqueTarget.Global), StatsWhenAdoptingReligion("[stats] when a city adopts this religion for the first time", UniqueTarget.Global), + StatsSpendingGreatPeople("[stats] whenever a Great Person is expended", UniqueTarget.Global), UnhappinessFromPopulationTypePercentageChange("[relativeAmount]% Unhappiness from [populationFilter] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), @Deprecated("As of 3.19.19", ReplaceWith("[relativeAmount]% Unhappiness from [Population] [cityFilter]")) diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index e905195261..791226583e 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -98,11 +98,6 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Global, FollowerBelief -??? example "[stats] whenever a Great Person is expended" - Example: "[+1 Gold, +2 Production] whenever a Great Person is expended" - - Applicable to: Global - ??? example "[stats] from [tileFilter] tiles [cityFilter]" Example: "[+1 Gold, +2 Production] from [Farm] tiles [in all cities]" @@ -133,12 +128,12 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Global, FollowerBelief -??? example "[relativeAmount]% [stat] from every [tileFilter/specialist/buildingName]" +??? example "[relativeAmount]% [stat] from every [tileFilter/buildingFilter]" Example: "[+20]% [Culture] from every [Farm]" Applicable to: Global, FollowerBelief -??? example "[relativeAmount]% Yield from every [tileFilter]" +??? example "[relativeAmount]% Yield from every [tileFilter/buildingFilter]" Example: "[+20]% Yield from every [Farm]" Applicable to: Global, FollowerBelief @@ -290,6 +285,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Global +??? example "[stats] whenever a Great Person is expended" + Example: "[+1 Gold, +2 Production] whenever a Great Person is expended" + + Applicable to: Global + ??? example "[relativeAmount]% Unhappiness from [populationFilter] [cityFilter]" Example: "[+20]% Unhappiness from [Followers of this Religion] [in all cities]" diff --git a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt index 7e1fdcade3..3672ec0052 100644 --- a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt +++ b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt @@ -106,21 +106,6 @@ class GlobalUniquesTests { Assert.assertTrue(cityInfo.cityStats.finalStatList["Buildings"]!!.gold == 0f) } - @Test - fun statsSpendingGreatPeople() { - val civInfo = game.addCiv() - val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) - val cityInfo = game.addCity(civInfo, tile, true) - val unit = game.addUnit("Great Engineer", civInfo, tile) - val building = game.createBuildingWithUnique("[+250 Gold] whenever a Great Person is expended") - cityInfo.cityConstructions.addBuilding(building.name) - civInfo.addGold(-civInfo.gold) - - civInfo.addGold(-civInfo.gold) // reset gold just to be sure - unit.consume() - Assert.assertTrue(civInfo.gold == 250) - } - @Test fun statsFromTiles() { game.makeHexagonalMap(2) @@ -200,8 +185,6 @@ class GlobalUniquesTests { inBetweenTile.roadStatus = RoadStatus.Road civInfo.transients().updateCitiesConnectedToCapital() city2.cityStats.update() - println(city2.isConnectedToCapital()) - println(city2.cityStats.finalStatList) Assert.assertTrue(city2.cityStats.finalStatList["Trade routes"]!!.science == 30f) } @@ -255,8 +238,6 @@ class GlobalUniquesTests { civ1.updateStatsForNextTurn() - println(civ1.statsForNextTurn.science) - Assert.assertTrue(civ1.statsForNextTurn.science == 90f) } @@ -273,11 +254,92 @@ class GlobalUniquesTests { city.cityConstructions.addBuilding(building.name) city.cityStats.update() - println(city.cityStats.finalStatList) + Assert.assertTrue(city.cityStats.finalStatList["Buildings"]!!.science == 30f) + } + + @Test + fun statPercentBonusCities() { + val civ = game.addCiv(uniques = listOf("[+200]% [Science] [in all cities]")) + val tile = game.getTile(Vector2(0f, 0f)) + val city = game.addCity(civ, tile, true) + val building = game.createBuildingWithUniques(arrayListOf("[+10 Science]")) + city.cityConstructions.addBuilding(building.name) + city.cityStats.update() Assert.assertTrue(city.cityStats.finalStatList["Buildings"]!!.science == 30f) } + @Test + fun statPercentFromObject() { + game.makeHexagonalMap(1) + val emptyBuilding = game.createBuildingWithUniques() + val civInfo = game.addCiv( + uniques = listOf( + "[+3 Faith] from every [Farm]", + "[+200]% [Faith] from every [${emptyBuilding.name}]", + "[+200]% [Faith] from every [Farm]", + ) + ) + val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) + val city = game.addCity(civInfo, tile, true) + val faithBuilding = game.createBuildingWithUniques() + faithBuilding.faith = 3f + city.cityConstructions.addBuilding(faithBuilding.name) + + val tile2 = game.setTileFeatures(Vector2(0f,1f), Constants.grassland) + tile2.improvement = "Farm" + Assert.assertTrue(tile2.getTileStats(city, civInfo).faith == 9f) + + city.cityConstructions.addBuilding(emptyBuilding.name) + city.cityStats.update() + + Assert.assertTrue(city.cityStats.finalStatList["Buildings"]!!.faith == 9f) + } + + @Test + fun allStatsPercentFromObject() { + game.makeHexagonalMap(1) + val emptyBuilding = game.createBuildingWithUniques() + val civInfo = game.addCiv( + uniques = listOf( + "[+3 Faith] from every [Farm]", + "[+200]% Yield from every [${emptyBuilding.name}]", + "[+200]% Yield from every [Farm]", + ) + ) + val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) + val city = game.addCity(civInfo, tile, true) + val faithBuilding = game.createBuildingWithUniques() + faithBuilding.faith = 3f + city.cityConstructions.addBuilding(faithBuilding.name) + + val tile2 = game.setTileFeatures(Vector2(0f,1f), Constants.grassland) + tile2.improvement = "Farm" + Assert.assertTrue(tile2.getTileStats(city, civInfo).faith == 9f) + + city.cityConstructions.addBuilding(emptyBuilding.name) + city.cityStats.update() + + Assert.assertTrue(city.cityStats.finalStatList["Buildings"]!!.faith == 9f) + } + // endregion + + + @Test + fun statsSpendingGreatPeople() { + val civInfo = game.addCiv() + val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) + val cityInfo = game.addCity(civInfo, tile, true) + val unit = game.addUnit("Great Engineer", civInfo, tile) + val building = game.createBuildingWithUnique("[+250 Gold] whenever a Great Person is expended") + cityInfo.cityConstructions.addBuilding(building.name) + + civInfo.addGold(-civInfo.gold) // reset gold just to be sure + + unit.consume() + Assert.assertTrue(civInfo.gold == 250) + } + } diff --git a/tests/src/com/unciv/uniques/TestGame.kt b/tests/src/com/unciv/uniques/TestGame.kt index 3952d6407d..f3cbd6b86c 100644 --- a/tests/src/com/unciv/uniques/TestGame.kt +++ b/tests/src/com/unciv/uniques/TestGame.kt @@ -17,9 +17,6 @@ import com.unciv.models.metadata.BaseRuleset import com.unciv.models.metadata.GameSettings import com.unciv.models.ruleset.* import com.unciv.models.ruleset.unique.UniqueType -import com.unciv.ui.utils.withItem -import kotlin.math.abs -import kotlin.math.max class TestGame { @@ -61,7 +58,9 @@ class TestGame { gameInfo.tileMap = newTileMap } - /** Makes a new hexagonal tileMap and sets it in gameInfo. Removes all existing tiles. All new tiles have terrain [baseTerrain] */ + /** Makes a new hexagonal tileMap with radius [newRadius] and sets it in gameInfo. + * Removes all existing tiles. All new tiles have terrain [baseTerrain] + */ fun makeHexagonalMap(newRadius: Int, baseTerrain: String = Constants.desert) { val newTileMap = TileMap(newRadius, ruleset, tileMap.mapParameters.worldWrap) newTileMap.mapParameters.mapSize = MapSizeNew(newRadius)