diff --git a/core/src/com/unciv/models/ruleset/Belief.kt b/core/src/com/unciv/models/ruleset/Belief.kt index 82cf6c1083..1b71077a79 100644 --- a/core/src/com/unciv/models/ruleset/Belief.kt +++ b/core/src/com/unciv/models/ruleset/Belief.kt @@ -8,9 +8,13 @@ import com.unciv.models.translations.tr import com.unciv.ui.civilopedia.FormattedLine import kotlin.collections.ArrayList -class Belief : RulesetObject() { +class Belief() : RulesetObject() { var type: BeliefType = BeliefType.None + constructor(type: BeliefType) : this() { + this.type = type + } + override fun getUniqueTarget() = if (type == BeliefType.Founder || type == BeliefType.Enhancer) UniqueTarget.FounderBelief else UniqueTarget.FollowerBelief diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 0ade6987ca..f1afa84a1d 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -25,14 +25,14 @@ object UniqueTriggerActivation { tile: TileInfo? = null, notification: String? = null ): Boolean { - if (!unique.conditionalsApply(civInfo, cityInfo)) return false - val timingConditional = unique.conditionals.firstOrNull{it.type == ConditionalTimedUnique} - if (timingConditional!=null) { + if (timingConditional != null) { civInfo.temporaryUniques.add(TemporaryUnique(unique, timingConditional.params[0].toInt())) return true } + if (!unique.conditionalsApply(civInfo, cityInfo)) return false + val chosenCity = cityInfo ?: civInfo.cities.firstOrNull { it.isCapital() } val tileBasedRandom = if (tile != null) Random(tile.position.toString().hashCode()) diff --git a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt index 3672ec0052..6c8050ac59 100644 --- a/tests/src/com/unciv/uniques/GlobalUniquesTests.kt +++ b/tests/src/com/unciv/uniques/GlobalUniquesTests.kt @@ -29,7 +29,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true) - val buildingName = game.createBuildingWithUnique("[+1 Food]").name + val buildingName = game.createBuilding("[+1 Food]").name cityInfo.cityConstructions.addBuilding(buildingName) cityInfo.cityStats.update() @@ -41,7 +41,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true) - val buildingName = game.createBuildingWithUnique("[+1 Production] [in this city]").name + val buildingName = game.createBuilding("[+1 Production] [in this city]").name cityInfo.cityConstructions.addBuilding(buildingName) cityInfo.cityStats.update() @@ -53,7 +53,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 building = game.createBuildingWithUnique("[+3 Gold] from every specialist [in this city]") + val building = game.createBuilding("[+3 Gold] from every specialist [in this city]") val specialistName = game.addEmptySpecialist() building.specialistSlots.add(specialistName, 2) cityInfo.population.specialistAllocations[specialistName] = 2 @@ -68,7 +68,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true, initialPopulation = 4) - val building = game.createBuildingWithUnique("[+3 Gold] per [2] population [in this city]") + val building = game.createBuilding("[+3 Gold] per [2] population [in this city]") cityInfo.cityConstructions.addBuilding(building.name) cityInfo.cityStats.update() @@ -80,7 +80,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 building = game.createBuildingWithUnique("[+3 Gold] in cities with [3] or more population") + val building = game.createBuilding("[+3 Gold] in cities with [3] or more population") cityInfo.cityConstructions.addBuilding(building.name) @@ -96,7 +96,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true) - val building = game.createBuildingWithUnique("[+3 Gold] in cities on [${Constants.desert}] tiles") + val building = game.createBuilding("[+3 Gold] in cities on [${Constants.desert}] tiles") cityInfo.cityConstructions.addBuilding(building.name) cityInfo.cityStats.update() @@ -112,7 +112,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true) - val building = game.createBuildingWithUnique("[+4 Gold] from [${Constants.grassland}] tiles [in all cities]") + val building = game.createBuilding("[+4 Gold] from [${Constants.grassland}] tiles [in all cities]") cityInfo.cityConstructions.addBuilding(building.name) val tile2 = game.setTileFeatures(Vector2(0f,1f), Constants.grassland) @@ -125,7 +125,7 @@ class GlobalUniquesTests { val civInfo = game.addCiv() val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true) - val building = game.createBuildingWithUnique("[+4 Gold] from [${Constants.grassland}] tiles without [${Constants.forest}] [in this city]") + val building = game.createBuilding("[+4 Gold] from [${Constants.grassland}] tiles without [${Constants.forest}] [in this city]") cityInfo.cityConstructions.addBuilding(building.name) val tile2 = game.setTileFeatures(Vector2(0f,1f), Constants.grassland) @@ -144,7 +144,7 @@ class GlobalUniquesTests { val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val cityInfo = game.addCity(civInfo, tile, true, initialPopulation = 2) val specialist = game.addEmptySpecialist() - val building = game.createBuildingWithUnique("[+3 Faith] from every [${specialist}]") + val building = game.createBuilding("[+3 Faith] from every [${specialist}]") cityInfo.cityConstructions.addBuilding(building.name) cityInfo.population.specialistAllocations[specialist] = 2 @@ -153,7 +153,7 @@ class GlobalUniquesTests { Assert.assertTrue(cityInfo.cityStats.finalStatList["Specialists"]!!.faith == 6f) cityInfo.cityConstructions.removeBuilding(building.name) - val building2 = game.createBuildingWithUnique("[+3 Faith] from every [${Constants.grassland}]") + val building2 = game.createBuilding("[+3 Faith] from every [${Constants.grassland}]") cityInfo.cityConstructions.addBuilding(building2.name) val tile2 = game.setTileFeatures(Vector2(0f,1f), Constants.grassland) @@ -161,9 +161,9 @@ class GlobalUniquesTests { cityInfo.cityConstructions.removeBuilding(building2.name) - val emptyBuilding = game.createBuildingWithUniques() + val emptyBuilding = game.createBuilding() - val building3 = game.createBuildingWithUnique("[+3 Faith] from every [${emptyBuilding.name}]") + val building3 = game.createBuilding("[+3 Faith] from every [${emptyBuilding.name}]") cityInfo.cityConstructions.addBuilding(emptyBuilding.name) cityInfo.cityConstructions.addBuilding(building3.name) cityInfo.cityStats.update() @@ -173,13 +173,14 @@ class GlobalUniquesTests { @Test fun statsFromTradeRoute() { game.makeHexagonalMap(3) - val civInfo = game.addCiv(uniques = listOf("[+30 Science] from each Trade Route")) + val civInfo = game.addCiv("[+30 Science] from each Trade Route") civInfo.tech.addTechnology("The Wheel") // Required to form trade routes - val tile = game.setTileFeatures(Vector2(0f,0f), Constants.desert) + val tile1 = game.setTileFeatures(Vector2(0f,0f), Constants.desert) val tile2 = game.setTileFeatures(Vector2(0f,2f), Constants.desert) - tile.roadStatus = RoadStatus.Road + tile1.roadStatus = RoadStatus.Road tile2.roadStatus = RoadStatus.Road - val cityInfo = game.addCity(civInfo, tile) + @Suppress("UNUSED_VARIABLE") + val city1 = game.addCity(civInfo, tile1) val city2 = game.addCity(civInfo, tile2) val inBetweenTile = game.setTileFeatures(Vector2(0f, 1f), Constants.desert) inBetweenTile.roadStatus = RoadStatus.Road @@ -193,7 +194,7 @@ class GlobalUniquesTests { fun statsFromGlobalCitiesFollowingReligion() { val civ1 = game.addCiv() val religion = game.addReligion(civ1) - val belief = game.addBelief(BeliefType.Founder, "[+30 Science] for each global city following this religion") + val belief = game.createBelief(BeliefType.Founder, "[+30 Science] for each global city following this religion") religion.founderBeliefs.add(belief.name) val civ2 = game.addCiv() val tile = game.getTile(Vector2(0f,0f)) @@ -211,7 +212,7 @@ class GlobalUniquesTests { fun happinessFromGlobalCitiesFollowingReligion() { val civ1 = game.addCiv() val religion = game.addReligion(civ1) - val belief = game.addBelief(BeliefType.Founder, "[+42 Happiness] for each global city following this religion") + val belief = game.createBelief(BeliefType.Founder, "[+42 Happiness] for each global city following this religion") religion.founderBeliefs.add(belief.name) val civ2 = game.addCiv() val tile = game.getTile(Vector2(0f,0f)) @@ -229,7 +230,7 @@ class GlobalUniquesTests { fun statsFromGlobalFollowers() { val civ1 = game.addCiv() val religion = game.addReligion(civ1) - val belief = game.addBelief(BeliefType.Founder, "[+30 Science] from every [3] global followers [in all cities]") + val belief = game.createBelief(BeliefType.Founder, "[+30 Science] from every [3] global followers [in all cities]") religion.founderBeliefs.add(belief.name) val civ2 = game.addCiv() val tile = game.getTile(Vector2(0f,0f)) @@ -250,7 +251,7 @@ class GlobalUniquesTests { val civ = game.addCiv() val tile = game.getTile(Vector2(0f, 0f)) val city = game.addCity(civ, tile, true) - val building = game.createBuildingWithUniques(arrayListOf("[+10 Science]", "[+200]% [Science]")) + val building = game.createBuilding("[+10 Science]", "[+200]% [Science]") city.cityConstructions.addBuilding(building.name) city.cityStats.update() @@ -259,10 +260,10 @@ class GlobalUniquesTests { @Test fun statPercentBonusCities() { - val civ = game.addCiv(uniques = listOf("[+200]% [Science] [in all cities]")) + val civ = game.addCiv("[+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]")) + val building = game.createBuilding("[+10 Science]") city.cityConstructions.addBuilding(building.name) city.cityStats.update() @@ -272,17 +273,15 @@ class GlobalUniquesTests { @Test fun statPercentFromObject() { game.makeHexagonalMap(1) - val emptyBuilding = game.createBuildingWithUniques() + val emptyBuilding = game.createBuilding() 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() + val faithBuilding = game.createBuilding() faithBuilding.faith = 3f city.cityConstructions.addBuilding(faithBuilding.name) @@ -299,17 +298,15 @@ class GlobalUniquesTests { @Test fun allStatsPercentFromObject() { game.makeHexagonalMap(1) - val emptyBuilding = game.createBuildingWithUniques() + val emptyBuilding = game.createBuilding() 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() + val faithBuilding = game.createBuilding() faithBuilding.faith = 3f city.cityConstructions.addBuilding(faithBuilding.name) @@ -333,7 +330,7 @@ class GlobalUniquesTests { 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") + val building = game.createBuilding("[+250 Gold] whenever a Great Person is expended") cityInfo.cityConstructions.addBuilding(building.name) civInfo.addGold(-civInfo.gold) // reset gold just to be sure diff --git a/tests/src/com/unciv/uniques/TestGame.kt b/tests/src/com/unciv/uniques/TestGame.kt index f3cbd6b86c..089f292095 100644 --- a/tests/src/com/unciv/uniques/TestGame.kt +++ b/tests/src/com/unciv/uniques/TestGame.kt @@ -87,20 +87,18 @@ class TestGame { return tile } - fun addCiv(uniques: List = emptyList(), isPlayer: Boolean = false, cityState: CityStateType? = null): CivilizationInfo { - val nationName = "Nation-${objectsCreated++}" - ruleset.nations[nationName] = Nation().apply { - name = nationName + fun addCiv(vararg uniques: String, isPlayer: Boolean = false, cityState: CityStateType? = null): CivilizationInfo { + fun nationFactory() = Nation().apply { cities = arrayListOf("The Capital") - if (cityState != null) { - cityStateType = cityState - } - this.uniques = ArrayList(uniques) + cityStateType = cityState + } + val nation = createRulesetObject(ruleset.nations, *uniques) { + nationFactory() } val civInfo = CivilizationInfo() - civInfo.nation = ruleset.nations[nationName]!! + civInfo.nation = nation civInfo.gameInfo = gameInfo - civInfo.civName = nationName + civInfo.civName = nation.name if (isPlayer) civInfo.playerType = PlayerType.Human civInfo.setTransients() if (cityState != null) { @@ -122,7 +120,7 @@ class TestGame { if (replacePalace && civInfo.cities.size == 1) { // Add a capital indicator without any other stats - val palaceWithoutStats = createBuildingWithUnique(UniqueType.IndicatesCapital.text) + val palaceWithoutStats = createBuilding(UniqueType.IndicatesCapital.text) cityInfo.cityConstructions.removeBuilding("Palace") cityInfo.cityConstructions.addBuilding(palaceWithoutStats.name) } @@ -147,18 +145,6 @@ class TestGame { return name } - fun createBuildingWithUnique(unique: String): Building { - return createBuildingWithUniques(arrayListOf(unique)) - } - - fun createBuildingWithUniques(uniques: ArrayList = arrayListOf()): Building { - val building = Building() - building.uniques = uniques - building.name = "Building-${objectsCreated++}" - ruleset.buildings[building.name] = building - return building - } - fun addReligion(foundingCiv: CivilizationInfo): Religion { gameInfo.gameParameters.religionEnabled = true val religion = Religion("Religion-${objectsCreated++}", gameInfo, foundingCiv.civName) @@ -167,12 +153,23 @@ class TestGame { return religion } - fun addBelief(type: BeliefType = BeliefType.Any, vararg uniques: String): Belief { - val belief = Belief() - belief.name = "Belief-${objectsCreated++}" - belief.type = type - belief.uniques = arrayListOf(*uniques) - ruleset.beliefs[belief.name] = belief - return belief + private fun createRulesetObject( + rulesetCollection: LinkedHashMap, + vararg uniques: String, + factory: () -> T + ): T { + val obj = factory() + val name = "${obj::class.simpleName}-${objectsCreated++}" + obj.name = name + uniques.toCollection(obj.uniques) + rulesetCollection[name] = obj + return obj } + + fun createBelief(type: BeliefType = BeliefType.Any, vararg uniques: String) = + createRulesetObject(ruleset.beliefs, *uniques) { Belief(type) } + fun createBuilding(vararg uniques: String) = + createRulesetObject(ruleset.buildings, *uniques) { Building() } + fun createPolicy(vararg uniques: String) = + createRulesetObject(ruleset.policies, *uniques) { Policy() } } diff --git a/tests/src/com/unciv/uniques/TriggeredUniquesTests.kt b/tests/src/com/unciv/uniques/TriggeredUniquesTests.kt new file mode 100644 index 0000000000..6655029ebc --- /dev/null +++ b/tests/src/com/unciv/uniques/TriggeredUniquesTests.kt @@ -0,0 +1,51 @@ +package com.unciv.uniques + +import com.badlogic.gdx.math.Vector2 +import com.unciv.logic.battle.BattleDamage +import com.unciv.logic.battle.MapUnitCombatant +import com.unciv.models.ruleset.unique.StateForConditionals +import com.unciv.models.ruleset.unique.UniqueType +import com.unciv.testing.GdxTestRunner +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(GdxTestRunner::class) +class TriggeredUniquesTests { + /** + * Autocracy Complete was [UniqueType.TimedAttackStrength] + * Now: [UniqueType.Strength], ConditionalAttacking, ConditionalOurUnit, [UniqueType.ConditionalTimedUnique] + */ + + private val game = TestGame().apply { makeHexagonalMap(2) } + private val civInfo = game.addCiv() + private val policy = + game.createPolicy("[+42]% Strength ") + private val enemy = game.addCiv() + private val attacker = + MapUnitCombatant(game.addUnit("Warrior", civInfo, game.setTileFeatures(Vector2.Zero))) + private val defender = + MapUnitCombatant(game.addUnit("Warrior", enemy, game.setTileFeatures(Vector2(1f, 0f)))) + + @Test + fun testConditionalTimedUniqueIsTriggerable() { + val unique = policy.getMatchingUniques(UniqueType.Strength, StateForConditionals.IgnoreConditionals).firstOrNull() + Assert.assertTrue("Unique with timed conditional must be triggerable", unique!!.isTriggerable) + } + + @Test + fun testConditionalTimedUniqueStrength() { + civInfo.policies.adopt(policy, true) + val modifiers = BattleDamage.getAttackModifiers(attacker, defender) + Assert.assertTrue("Timed Strength should work right after triggering", modifiers.sumValues() == 42) + } + + @Test + fun testConditionalTimedUniqueExpires() { + civInfo.policies.adopt(policy, true) + civInfo.endTurn() + val modifiers = BattleDamage.getAttackModifiers(attacker, defender) + Assert.assertTrue("Timed Strength should no longer work after endTurn", modifiers.sumValues() == 0) + } +} diff --git a/tests/src/com/unciv/uniques/UnitUniquesTests.kt b/tests/src/com/unciv/uniques/UnitUniquesTests.kt index 24c4a4afb1..fababdbb0c 100644 --- a/tests/src/com/unciv/uniques/UnitUniquesTests.kt +++ b/tests/src/com/unciv/uniques/UnitUniquesTests.kt @@ -1,13 +1,9 @@ package com.unciv.uniques import com.badlogic.gdx.math.Vector2 -import com.unciv.Constants import com.unciv.logic.civilization.CityStateType import com.unciv.testing.GdxTestRunner import com.unciv.ui.worldscreen.unit.UnitActions -import org.hamcrest.CoreMatchers -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Assert import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test @@ -30,8 +26,7 @@ class UnitUniquesTests { val cityStateCapitalTile = game.getTile(Vector2(0f, 0f)) val cityStateCapital = game.addCity(cityState, cityStateCapitalTile) - val mainCiv = game.addCiv( - uniques = listOf("Gain [90] Influence with a [Great Person] gift to a City-State"), + val mainCiv = game.addCiv("Gain [90] Influence with a [Great Person] gift to a City-State", isPlayer = true ) game.gameInfo.currentPlayerCiv = mainCiv @@ -46,4 +41,4 @@ class UnitUniquesTests { assertNotNull("Great Person should have a gift action", giftAction) } -} \ No newline at end of file +}