From 160b51d5785891c3dad99d8188c4d8e2b82979b1 Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Thu, 14 Jul 2022 09:27:06 +0200 Subject: [PATCH] Added more unit tests (#7448) --- .../jsons/Civ V - Gods & Kings/Nations.json | 8 +- .../assets/jsons/Civ V - Vanilla/Nations.json | 4 +- core/src/com/unciv/logic/city/CityStats.kt | 5 +- .../unciv/models/ruleset/unique/UniqueType.kt | 3 +- .../com/unciv/uniques/GlobalUniquesTests.kt | 110 +++++++++++++++++- tests/src/com/unciv/uniques/TestGame.kt | 21 +++- 6 files changed, 134 insertions(+), 17 deletions(-) diff --git a/android/assets/jsons/Civ V - Gods & Kings/Nations.json b/android/assets/jsons/Civ V - Gods & Kings/Nations.json index 271fec53c5..a9816e6d32 100644 --- a/android/assets/jsons/Civ V - Gods & Kings/Nations.json +++ b/android/assets/jsons/Civ V - Gods & Kings/Nations.json @@ -542,7 +542,7 @@ "favoredReligion": "Christianity", "uniqueName": "Seven Cities of Gold", "uniques": ["100 Gold for discovering a Natural Wonder (bonus enhanced to 500 Gold if first to discover it)", - "Double Happiness from Natural Wonders", "Tile yields from Natural Wonders doubled"], + "Double Happiness from Natural Wonders", "[+100]% Yield from every [Natural Wonder]"], "cities": ["Madrid","Barcelona","Seville","Cordoba","Toledo","Santiago","Salamanca","Murcia","Valencia","Zaragoza","Pamplona", "Vitoria","Santander","Oviedo","Jaen","Logroño","Valladolid","Palma","Teruel","Almeria","Leon","Zamora","Mida", "Lugo","Alicante","Càdiz","Eiche","Alcorcon","Burgos","Vigo","Badajoz","La Coruña","Guadalquivir","Bilbao", @@ -852,9 +852,9 @@ "uniqueName": "Patriarchate of Constantinople", "uniques": ["May choose [1] additional belief(s) of any type when [founding] a religion"], - "cities": ["Constantinople", "Adrianople", "Nicaea", "Antioch", "Varna", "Ohrid", "Nicomedia", "Trebizond", "Cherson", "Sardica", - "Ani", "Dyrrachium", "Edessa", "Chalcedon", "Naissus", "Bari", "Iconium", "Prilep", "Samosata", "Kars", "Nicopolis", "Theodosiopolis", - "Tyana", "Gaza", "Kerkyra", "Phoenice", "Selymbria", "Sillyon", "Chrysopolis", "Vodena", "Caesarea", "Traianoupoli", "Constantia", "Athens", + "cities": ["Constantinople", "Adrianople", "Nicaea", "Antioch", "Varna", "Ohrid", "Nicomedia", "Trebizond", "Cherson", "Sardica", + "Ani", "Dyrrachium", "Edessa", "Chalcedon", "Naissus", "Bari", "Iconium", "Prilep", "Samosata", "Kars", "Nicopolis", "Theodosiopolis", + "Tyana", "Gaza", "Kerkyra", "Phoenice", "Selymbria", "Sillyon", "Chrysopolis", "Vodena", "Caesarea", "Traianoupoli", "Constantia", "Athens", "Patra", "Korinthos"] }, { diff --git a/android/assets/jsons/Civ V - Vanilla/Nations.json b/android/assets/jsons/Civ V - Vanilla/Nations.json index b660c65f13..337b40f43e 100644 --- a/android/assets/jsons/Civ V - Vanilla/Nations.json +++ b/android/assets/jsons/Civ V - Vanilla/Nations.json @@ -520,7 +520,7 @@ "innerColor": [255,102,102], "uniqueName": "Seven Cities of Gold", "uniques": ["100 Gold for discovering a Natural Wonder (bonus enhanced to 500 Gold if first to discover it)", - "Double Happiness from Natural Wonders", "Tile yields from Natural Wonders doubled"], + "Double Happiness from Natural Wonders", "[+100]% Yield from every [Natural Wonder]"], "cities": ["Madrid","Barcelona","Seville","Cordoba","Toledo","Santiago","Salamanca","Murcia","Valencia","Zaragoza","Pamplona", "Vitoria","Santander","Oviedo","Jaen","Logroño","Valladolid","Palma","Teruel","Almeria","Leon","Zamora","Mida", "Lugo","Alicante","Càdiz","Eiche","Alcorcon","Burgos","Vigo","Badajoz","La Coruña","Guadalquivir","Bilbao", @@ -1045,7 +1045,7 @@ "innerColor": [0,102,102], "cities": ["Valletta"] }, - + //Barbarian { diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index f3874aa84b..071681d7ef 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -599,9 +599,12 @@ class CityStats(val cityInfo: CityInfo) { val growthNullifyingUnique = cityInfo.getMatchingUniques(UniqueType.NullifiesGrowth).firstOrNull() if (growthNullifyingUnique != null) { + // Note that negative food will also be nullified. Pretty sure that's conform civ V, but haven't checked. val amountToRemove = -newFinalStatList.values.sumOf { it[Stat.Food].toDouble() } - newFinalStatList[getSourceNameForUnique(growthNullifyingUnique)] = + newFinalStatList.add( + getSourceNameForUnique(growthNullifyingUnique), Stats().apply { this[Stat.Food] = amountToRemove.toFloat() } + ) } if (cityInfo.isInResistance()) diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 3471f3f77a..069595b62c 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -102,11 +102,12 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags: NullifiesStat("Nullifies [stat] [cityFilter]", UniqueTarget.Global), NullifiesGrowth("Nullifies Growth [cityFilter]", UniqueTarget.Global), - PercentProductionWonders("[relativeAmount]% Production when constructing [buildingFilter] wonders [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), PercentProductionBuildings("[relativeAmount]% Production when constructing [buildingFilter] buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), PercentProductionUnits("[relativeAmount]% Production when constructing [baseUnitFilter] units [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), + PercentProductionWonders("[relativeAmount]% Production when constructing [buildingFilter] wonders [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief), PercentProductionBuildingsInCapital("[relativeAmount]% Production towards any buildings that already exist in the Capital", UniqueTarget.Global, UniqueTarget.FollowerBelief), // todo: maybe should be converted to "[+100]% Yield from every [Natural Wonder]"? + @Deprecated("As of 4.1.19", ReplaceWith("[+100]% Yield from every [Natural Wonder]")) DoubleStatsFromNaturalWonders("Tile yields from Natural Wonders doubled", UniqueTarget.Global), //endregion Stat providing uniques diff --git a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt index 8d66c7af9a..ad6a9c5061 100644 --- a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt +++ b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt @@ -24,7 +24,7 @@ class GlobalUniquesTests { game = TestGame() } - // region stat uniques + // region base stat bonus providing uniques @Test fun stats() { @@ -56,7 +56,7 @@ class GlobalUniquesTests { val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true, initialPopulation = 2) val building = game.createBuilding("[+3 Gold] from every specialist [in this city]") - val specialistName = game.addEmptySpecialist() + val specialistName = game.createSpecialist() building.specialistSlots.add(specialistName, 2) cityInfo.population.specialistAllocations[specialistName] = 2 @@ -145,7 +145,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true, initialPopulation = 2) - val specialist = game.addEmptySpecialist() + val specialist = game.createSpecialist() val building = game.createBuilding("[+3 Faith] from every [${specialist}]") cityInfo.cityConstructions.addBuilding(building.name) @@ -350,7 +350,6 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val cityState = game.addCiv(cityState = CityStateType.Maritime) - val tile = game.getTile(Vector2(0f,0f)) val city = game.addCity(civInfo, tile, true) val cityStateTile = game.getTile(Vector2(0f, 1f)) @@ -393,6 +392,109 @@ class GlobalUniquesTests { // endregion + // region stat nullifying uniques + + @Test + fun nullifiesStat() { + game.makeHexagonalMap(1) + val civInfo = game.addCiv() + val tile = game.getTile(Vector2(0f,0f)) + val city = game.addCity(civInfo, tile, true, 1) + + val building = game.createBuilding("Nullifies [Faith] [in this city]", "[+10 Gold, +10 Faith] [in this city]") + city.cityConstructions.addBuilding(building.name) + city.cityStats.update() + Assert.assertTrue(city.cityStats.finalStatList.map { it.value.gold }.sum() >= 10f) + Assert.assertTrue(city.cityStats.finalStatList.map { it.value.faith }.sum() == 0f) + } + + @Test + fun nullifiesGrowth() { + game.makeHexagonalMap(1) + val civInfo = game.addCiv() + val tile = game.getTile(Vector2(0f,0f)) + val city = game.addCity(civInfo, tile, true, 1) + + val building = game.createBuilding("Nullifies Growth [in this city]", "[+10 Food, +10 Gold] [in this city]") + city.cityConstructions.addBuilding(building.name) + city.cityStats.update() + Assert.assertTrue(city.cityStats.finalStatList.map { it.value.gold }.sum() >= 10f) + Assert.assertTrue(city.cityStats.finalStatList.map { it.value.food }.sum() == 0f) + + city.population.addPopulation(1) + city.cityStats.update() + Assert.assertTrue(city.cityStats.finalStatList.map { it.value.food }.sum() == 0f) + } + + // endregion + + //region production percentage bonus providing uniques based on production + + @Test + fun percentProductionBuildings() { + val civInfo = game.addCiv() + val tile = game.getTile(Vector2(0f,0f)) + val city = game.addCity(civInfo, tile, true, 0) + + val buildingToConstruct = game.createBuilding() + val building = game.createBuilding("[+300]% Production when constructing [${buildingToConstruct.name}] buildings [in all cities]", "[+1 Production]") + city.cityConstructions.addBuilding(building.name) + city.cityConstructions.addToQueue(buildingToConstruct.name) + city.cityStats.update() + Assert.assertTrue(city.cityStats.statPercentBonusTree.totalStats.production == 300f) + } + + @Test + fun percentProductionUnits() { + val civInfo = game.addCiv() + val tile = game.getTile(Vector2(0f,0f)) + val city = game.addCity(civInfo, tile, true, 0) + + val unitToConstruct = game.createBaseUnit() + val building = game.createBuilding("[+300]% Production when constructing [${unitToConstruct.name}] units [in all cities]", "[+1 Production]") + city.cityConstructions.addBuilding(building.name) + city.cityConstructions.addToQueue(unitToConstruct.name) + city.cityStats.update() + Assert.assertTrue(city.cityStats.statPercentBonusTree.totalStats.production == 300f) + } + + @Test + fun percentProductionWonders() { + val civInfo = game.addCiv() + val tile = game.getTile(Vector2(0f,0f)) + val city = game.addCity(civInfo, tile, true, 0) + + val buildingToConstruct = game.createBuilding() + val building = game.createBuilding("[+300]% Production when constructing [${buildingToConstruct.name}] wonders [in all cities]", "[+1 Production]") + city.cityConstructions.addBuilding(building.name) + city.cityConstructions.addToQueue(buildingToConstruct.name) + city.cityStats.update() + Assert.assertTrue(city.cityStats.statPercentBonusTree.totalStats.production == 0f) + + buildingToConstruct.isWonder = true + city.cityStats.update() + Assert.assertTrue(city.cityStats.statPercentBonusTree.totalStats.production == 300f) + } + + @Test + fun percentProductionBuildingsInCapital() { + game.makeHexagonalMap(3) + val civInfo = game.addCiv("[+300]% Production towards any buildings that already exist in the Capital") + val tile = game.getTile(Vector2(0f,2f)) + val city = game.addCity(civInfo, tile, true, 0) + val city2 = game.addCity(civInfo, game.getTile(Vector2(0f, -2f)), initialPopulation = 0) + + val buildingToConstruct = game.createBuilding() + city2.cityConstructions.addToQueue(buildingToConstruct.name) + city2.cityStats.update() + Assert.assertTrue(city2.cityStats.statPercentBonusTree.totalStats.production == 0f) + + city.cityConstructions.addBuilding(buildingToConstruct.name) + city2.cityStats.update() + Assert.assertTrue(city2.cityStats.statPercentBonusTree.totalStats.production == 300f) + } + + //endregion @Test fun statsSpendingGreatPeople() { diff --git a/tests/src/com/unciv/uniques/TestGame.kt b/tests/src/com/unciv/uniques/TestGame.kt index adcef31c1b..0a0df07381 100644 --- a/tests/src/com/unciv/uniques/TestGame.kt +++ b/tests/src/com/unciv/uniques/TestGame.kt @@ -18,6 +18,8 @@ import com.unciv.models.metadata.GameSettings import com.unciv.models.ruleset.* import com.unciv.models.ruleset.tile.TileImprovement import com.unciv.models.ruleset.unique.UniqueType +import com.unciv.models.ruleset.unit.BaseUnit +import com.unciv.models.ruleset.unit.UnitType class TestGame { @@ -145,7 +147,7 @@ class TestGame { return mapUnit } - fun addEmptySpecialist(): String { + fun createSpecialist(): String { val name = "specialist-${objectsCreated++}" ruleset.specialists[name] = Specialist() return name @@ -172,12 +174,21 @@ class TestGame { return obj } + fun createBaseUnit(unitType: String = createUnitType().name, vararg uniques: String) = + createRulesetObject(ruleset.units, *uniques) { + val baseUnit = BaseUnit() + baseUnit.ruleset = gameInfo.ruleSet + baseUnit.unitType = unitType + baseUnit + } fun createBelief(type: BeliefType = BeliefType.Any, vararg uniques: String) = - createRulesetObject(ruleset.beliefs, *uniques) { Belief(type) } + createRulesetObject(ruleset.beliefs, *uniques) { Belief(type) } fun createBuilding(vararg uniques: String) = - createRulesetObject(ruleset.buildings, *uniques) { Building() } + createRulesetObject(ruleset.buildings, *uniques) { Building() } fun createPolicy(vararg uniques: String) = - createRulesetObject(ruleset.policies, *uniques) { Policy() } + createRulesetObject(ruleset.policies, *uniques) { Policy() } fun createTileImprovement(vararg uniques: String) = - createRulesetObject(ruleset.tileImprovements, *uniques) { TileImprovement() } + createRulesetObject(ruleset.tileImprovements, *uniques) { TileImprovement() } + fun createUnitType(vararg uniques: String) = + createRulesetObject(ruleset.unitTypes, *uniques) { UnitType() } }