From 82e72ddcfaa58b73fd7b4dd41ed89f54ed7c0d3e Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Mon, 4 Oct 2021 21:30:09 +0200 Subject: [PATCH] Added `in [tileFilter] tiles` conditional to combat uniques (#5393) * Some code cleaning * Added `in [tileFilter] tiles` conditional * Limited Visibility -> [-1] Sight * Fix tests and rename conditional * Actually made the conditional functional * Renamed conditional once again --- .../assets/jsons/Civ V - Vanilla/Beliefs.json | 4 +- .../jsons/Civ V - Vanilla/Buildings.json | 4 +- .../jsons/Civ V - Vanilla/Policies.json | 2 +- .../jsons/Civ V - Vanilla/UnitPromotions.json | 26 ++++---- .../assets/jsons/Civ V - Vanilla/Units.json | 34 +++++----- .../jsons/translations/template.properties | 7 +++ .../com/unciv/logic/battle/BattleDamage.kt | 63 ++++++++++++------- core/src/com/unciv/logic/map/MapUnit.kt | 5 +- .../ruleset/unique/StateForConditionals.kt | 8 +-- .../com/unciv/models/ruleset/unique/Unique.kt | 20 +++--- .../unciv/models/ruleset/unique/UniqueType.kt | 23 +++++-- .../com/unciv/models/ruleset/unit/BaseUnit.kt | 14 +++-- .../unciv/models/translations/Translations.kt | 3 +- 13 files changed, 127 insertions(+), 86 deletions(-) diff --git a/android/assets/jsons/Civ V - Vanilla/Beliefs.json b/android/assets/jsons/Civ V - Vanilla/Beliefs.json index 9581eb6ab0..3def03c3e8 100644 --- a/android/assets/jsons/Civ V - Vanilla/Beliefs.json +++ b/android/assets/jsons/Civ V - Vanilla/Beliefs.json @@ -248,7 +248,7 @@ { "name": "Defender of the Faith", "type": "Enhancer", - "uniques": ["[+20]% Strength for [All] units in [Friendly Land]"], + "uniques": ["[+20]% Strength "], // ToDo: Should only be friendly territory of cities that follow this religion }, { @@ -264,7 +264,7 @@ { "name": "Just War", "type": "Enhancer", - "uniques": ["[+20]% Strength for [Non-City] units in [Enemy Land]"], + "uniques": ["[+20]% Strength "], // ToDo: Should only be enemy territory of cities that follow this religion }, { diff --git a/android/assets/jsons/Civ V - Vanilla/Buildings.json b/android/assets/jsons/Civ V - Vanilla/Buildings.json index 0ac9252a2b..eec831344f 100644 --- a/android/assets/jsons/Civ V - Vanilla/Buildings.json +++ b/android/assets/jsons/Civ V - Vanilla/Buildings.json @@ -194,7 +194,7 @@ "name": "Statue of Zeus", "culture": 1, "isWonder": true, - "uniques": ["+15% Combat Strength for all units when attacking Cities"], + "uniques": ["[+15]% Strength "], "requiredTech": "Bronze Working", "quote": "'He spoke, the son of Kronos, and nodded his head with the dark brows, and the immortally anointed hair of the great god swept from his divine head, and all Olympos was shaken' - The Iliad" // "Requires [Honor]" in BNW @@ -767,7 +767,7 @@ "culture": 3, "isWonder": true, "greatPersonPoints": {"Great Engineer": 2}, - "uniques": ["+[15]% Strength for [Non-City] units fighting in [Friendly Land]", + "uniques": ["[+15]% Strength ", "Provides a free [Castle] [in this city]"], "requiredTech": "Gunpowder", "quote": "'Bushido is realized in the presence of death. This means choosing death whenever there is a choice between life and death. There is no other reasoning.' - Yamamoto Tsunetomo" diff --git a/android/assets/jsons/Civ V - Vanilla/Policies.json b/android/assets/jsons/Civ V - Vanilla/Policies.json index 51d7125ea3..aadb5940fb 100644 --- a/android/assets/jsons/Civ V - Vanilla/Policies.json +++ b/android/assets/jsons/Civ V - Vanilla/Policies.json @@ -432,7 +432,7 @@ }, { "name": "Nationalism", - "uniques": ["+[15]% Strength for [Non-City] units fighting in [Friendly Land]"], + "uniques": ["[+15]% Strength "], "row": 1, "column": 5 }, diff --git a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json index c9d5f6b141..698bce9123 100644 --- a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json +++ b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json @@ -9,37 +9,37 @@ // Ranged+Siege { "name": "Accuracy I", - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, { "name": "Accuracy II", "prerequisites": ["Accuracy I"], - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, { "name": "Accuracy III", "prerequisites": ["Accuracy II"], - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, { "name": "Barrage I", - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, { "name": "Barrage II", "prerequisites": ["Barrage I"], - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, { "name": "Barrage III", "prerequisites": ["Barrage II"], - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Siege","Archery","Ranged Gunpowder"] }, @@ -65,37 +65,37 @@ // Melee, Mounted+Armor { "name": "Shock I", - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { "name": "Shock II", "prerequisites": ["Shock I"], - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { "name": "Shock III", "prerequisites": ["Shock II"], - "uniques": ["+[15]% Strength in [Open terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { "name": "Drill I", - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { "name": "Drill II", "prerequisites": ["Drill I"], - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { "name": "Drill III", "prerequisites": ["Drill II"], - "uniques": ["+[15]% Strength in [Rough terrain]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted","Armored"] }, { @@ -537,7 +537,7 @@ }, { "name": "Pictish Courage", // only for Pictish Warrior and subsequent upgrades - "uniques": ["No movement cost to pillage", "+[20]% Strength in [Foreign Land]"] + "uniques": ["No movement cost to pillage", "[+20]% Strength "] }, { "name": "Home Sweet Home", // only for Mehal Sefari and subsequent upgrades diff --git a/android/assets/jsons/Civ V - Vanilla/Units.json b/android/assets/jsons/Civ V - Vanilla/Units.json index 10f8ebad74..9c64803187 100644 --- a/android/assets/jsons/Civ V - Vanilla/Units.json +++ b/android/assets/jsons/Civ V - Vanilla/Units.json @@ -66,7 +66,7 @@ "strength": 8, "cost": 40, "obsoleteTech": "Metal Casting", - "uniques": ["+[33]% Strength in [Forest]", "+[33]% Strength in [Jungle]", "Heals [25] damage if it kills a unit"], + "uniques": ["[+33]% Strength ", "[+33]% Strength ", "Heals [25] damage if it kills a unit"], "promotions": ["Woodsman"], "upgradesTo": "Swordsman", "attackSound": "nonmetalhit" @@ -315,7 +315,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["[+300]% Strength ", "No defensive terrain bonus", "[-33]% Strength ", + "uniques": ["[+300]% Strength ", "No defensive terrain bonus", "[-33]% Strength ", "[-1] Sight", "Can only attack [City] units"], "promotions": ["Cover I"], "attackSound": "throw" @@ -425,8 +425,8 @@ "requiredTech": "Mathematics", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["[+200]% Strength ", "No defensive terrain bonus", - "Must set up to ranged attack", "Limited Visibility"], + "uniques": ["[+200]% Strength ", "No defensive terrain bonus", + "Must set up to ranged attack", "[-1] Sight"], "hurryCostModifier": 20, "attackSound": "throw" }, @@ -442,8 +442,8 @@ "requiredTech": "Mathematics", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["[+200]% Strength ", "No defensive terrain bonus", - "Must set up to ranged attack", "Limited Visibility"], + "uniques": ["[+200]% Strength ", "No defensive terrain bonus", + "Must set up to ranged attack", "[-1] Sight"], "hurryCostModifier": 20, "attackSound": "throw" }, @@ -500,7 +500,7 @@ "upgradesTo": "Longswordsman", "obsoleteTech": "Gunpowder", "hurryCostModifier": 20, - "uniques": ["+[33]% Strength in [Forest]", "+[33]% Strength in [Jungle]"], + "uniques": ["[+33]% Strength ", "[+33]% Strength "], "attackSound": "metalhit" }, /* @@ -709,7 +709,7 @@ "requiredTech": "Physics", "obsoleteTech": "Chemistry", "upgradesTo": "Cannon", - "uniques": ["[+200]% Strength ","No defensive terrain bonus","Must set up to ranged attack","Limited Visibility"], + "uniques": ["[+200]% Strength ","No defensive terrain bonus","Must set up to ranged attack","[-1] Sight"], "attackSound": "throw" }, { @@ -985,7 +985,7 @@ "requiredTech": "Chemistry", "upgradesTo": "Artillery", "obsoleteTech": "Dynamite", - "uniques": ["[+200]% Strength ","No defensive terrain bonus","Must set up to ranged attack","Limited Visibility"], + "uniques": ["[+200]% Strength ","No defensive terrain bonus","Must set up to ranged attack","[-1] Sight"], "attackSound": "cannon" }, @@ -1026,9 +1026,9 @@ "requiredTech": "Rifling", "obsoleteTech": "Replaceable Parts", "upgradesTo": "Great War Infantry", - "uniques": ["+[25]% Strength in [Snow]", - "+[25]% Strength in [Tundra]", - "+[25]% Strength in [Hill]", + "uniques": ["[+25]% Strength ", + "[+25]% Strength ", + "[+25]% Strength ", "Double movement in [Snow]", "Double movement in [Tundra]", "Double movement in [Hill]"], @@ -1130,8 +1130,8 @@ "cost": 320, "requiredTech": "Dynamite", "upgradesTo": "Rocket Artillery", - "uniques": ["[+200]% Strength ","No defensive terrain bonus", - "Must set up to ranged attack","Limited Visibility","Ranged attacks may be performed over obstacles"], + "uniques": ["[+200]% Strength ","No defensive terrain bonus", + "Must set up to ranged attack","[-1] Sight","Ranged attacks may be performed over obstacles"], "attackSound": "artillery" }, @@ -1171,7 +1171,7 @@ "requiredTech": "Replaceable Parts", "upgradesTo": "Infantry", "obsoleteTech": "Plastics", - "uniques": ["+[20]% Strength in [Foreign Land]"], + "uniques": ["[+20]% Strength "], "attackSound": "shot" }, { @@ -1440,8 +1440,8 @@ "cost": 425, "requiredTech": "Rocketry", "requiredResource": "Aluminum", - "uniques": ["[+200]% Strength ","No defensive terrain bonus", - "Limited Visibility","Ranged attacks may be performed over obstacles"], + "uniques": ["[+200]% Strength ","No defensive terrain bonus", + "[-1] Sight","Ranged attacks may be performed over obstacles"], "attackSound": "artillery" }, { diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index e5001d24d3..0296e11b40 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1304,12 +1304,19 @@ Invisible to others = # In this case "" is a conditional. when not at war = when at war = +while the empire is happy = +during a Golden Age = + if this city has at least [amount] specialists = + +for [mapUnitFilter] units = vs cities = vs [mapUnitFilter] units = +for combat in [tileFilter] tiles = when attacking = when defending = + # In English we just paste all these conditionals at the end of each unique, but in your language that # may not turn into valid sentences. Therefore we have the following two translations to determine # where they should go. diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index 2bcc8c47df..2463260e3c 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -33,9 +33,14 @@ object BattleDamage { val civInfo = combatant.getCivInfo() if (combatant is MapUnitCombatant) { + val attackedTile = + if (combatAction == CombatAction.Attack) enemy.getTile() + else combatant.getTile() for (unique in combatant.unit.getMatchingUniques( UniqueType.Strength, - StateForConditionals(civInfo, defender = enemy, attacker = combatant, combatAction = combatAction)) + StateForConditionals( + civInfo, theirCombatant = enemy, ourCombatant = combatant, combatAction = combatAction, attackedTile = attackedTile) + ) ) { modifiers.add(getModifierStringFromUnique(unique), unique.params[0].toInt()) } @@ -127,11 +132,12 @@ object BattleDamage { if (civInfo.goldenAges.isGoldenAge() && civInfo.hasUnique(UniqueType.StrengthGoldenAge)) modifiers["Golden Age"] = 10 // - + if (enemy.getCivInfo() .isCityState() && civInfo.hasUnique("+30% Strength when fighting City-State units and cities") ) modifiers["vs [City-States]"] = 30 + } if (enemy.getCivInfo().isBarbarian()) { @@ -195,11 +201,12 @@ object BattleDamage { } } - if (defender is CityCombatant && - attacker.getCivInfo() - .hasUnique("+15% Combat Strength for all units when attacking Cities") - ) - modifiers["Statue of Zeus"] = 15 + // Deprecated since 3.17.5 + if (defender is CityCombatant && + attacker.getCivInfo().hasUnique(UniqueType.StrengthVsCities) + ) + modifiers["Statue of Zeus"] = 15 + // } else if (attacker is CityCombatant) { if (attacker.city.getCenterTile().militaryUnit != null) { val garrisonBonus = attacker.city.getMatchingUniques("+[]% attacking strength for cities with garrisoned units") @@ -250,10 +257,12 @@ object BattleDamage { } // - for (unique in defender.unit.getMatchingUniques("+[]% defence in [] tiles")) { - if (tile.matchesFilter(unique.params[1])) - modifiers.add("[${unique.params[1]}] defence", unique.params[0].toInt()) - } + // Deprecated since 3.17.5 + for (unique in defender.unit.getMatchingUniques(UniqueType.StrengthDefenseTiles)) { + if (tile.matchesFilter(unique.params[1])) + modifiers.add("[${unique.params[1]}] defence", unique.params[0].toInt()) + } + // if (defender.unit.isFortified()) modifiers["Fortification"] = 20 * defender.unit.getFortificationTurns() @@ -270,11 +279,13 @@ object BattleDamage { private fun getTileSpecificModifiers(unit: MapUnitCombatant, tile: TileInfo): Counter { val modifiers = Counter() - for (unique in unit.unit.getMatchingUniques("+[]% Strength in []")) { - val filter = unique.params[1] - if (tile.matchesFilter(filter, unit.getCivInfo())) - modifiers.add(filter, unique.params[0].toInt()) - } + // Deprecated since 3.17.5 + for (unique in unit.unit.getMatchingUniques(UniqueType.StrengthIn)) { + val filter = unique.params[1] + if (tile.matchesFilter(filter, unit.getCivInfo())) + modifiers.add(filter, unique.params[0].toInt()) + } + // for (unique in unit.getCivInfo().getMatchingUniques("+[]% Strength if within [] tiles of a []")) { if (tile.getTilesInDistance(unique.params[1].toInt()) @@ -282,11 +293,14 @@ object BattleDamage { ) modifiers[unique.params[2]] = unique.params[0].toInt() } - for (unique in unit.getCivInfo().getMatchingUniques("[]% Strength for [] units in []")) { - if (unit.matchesCategory(unique.params[1]) && tile.matchesFilter(unique.params[2], unit.getCivInfo())) { - modifiers.add(unique.params[2], unique.params[0].toInt()) + + // Deprecated since 3.17.5 + for (unique in unit.getCivInfo().getMatchingUniques(UniqueType.StrengthUnitsTiles)) { + if (unit.matchesCategory(unique.params[1]) && tile.matchesFilter(unique.params[2], unit.getCivInfo())) { + modifiers.add(unique.params[2], unique.params[0].toInt()) + } } - } + // return modifiers } @@ -299,11 +313,12 @@ object BattleDamage { private fun getHealthDependantDamageRatio(combatant: ICombatant): Float { return if (combatant !is MapUnitCombatant // is city - || combatant.getCivInfo() - .hasUnique("Units fight as though they were at full strength even when damaged") - && !combatant.unit.baseUnit.movesLikeAirUnits() - ) + || (combatant.getCivInfo().hasUnique("Units fight as though they were at full strength even when damaged") + && !combatant.unit.baseUnit.movesLikeAirUnits() + ) + ) { 1f + } else 1 - (100 - combatant.getHealth()) / 300f// Each 3 points of health reduces damage dealt by 1% like original game } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 556b0640b1..8458cc9dfc 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -352,11 +352,10 @@ class MapUnit { visibilityRange += getMatchingUniques(UniqueType.VisibilityRange).sumOf { it.params[0].toInt() } + + if (hasUnique(UniqueType.LimitedVisibility)) visibilityRange -= 1 // - // Should this be consolidated as "[-1] Sight"? - if (hasUnique("Limited Visibility")) visibilityRange -= 1 - // Maybe add the uniques of the tile a unit is standing on to the tempUniques of the unit? for (unique in getTile().getAllTerrains().flatMap { it.uniqueObjects }) if (unique.placeholderText == "[] Sight for [] units" && matchesFilter(unique.params[1])) diff --git a/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt b/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt index fd455f165b..4c1c12dc8a 100644 --- a/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt +++ b/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt @@ -11,9 +11,9 @@ data class StateForConditionals( val civInfo: CivilizationInfo? = null, val cityInfo: CityInfo? = null, val unit: MapUnit? = null, - - val attacker: ICombatant? = null, - val defender: ICombatant? = null, -// val attackedTile: TileInfo? = null, + + val ourCombatant: ICombatant? = null, + val theirCombatant: ICombatant? = null, + val attackedTile: TileInfo? = null, val combatAction: CombatAction? = null, ) \ No newline at end of file diff --git a/core/src/com/unciv/models/ruleset/unique/Unique.kt b/core/src/com/unciv/models/ruleset/unique/Unique.kt index 99c5ea7eea..cc1517f7f4 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -56,17 +56,19 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s state.cityInfo != null && state.cityInfo.population.getNumberOfSpecialists() >= condition.params[0].toInt() UniqueType.ConditionalVsCity -> - state.defender != null && state.defender.matchesCategory("City") + state.theirCombatant != null && state.theirCombatant.matchesCategory("City") UniqueType.ConditionalVsUnits -> - state.defender != null && state.defender.matchesCategory(condition.params[0]) + state.theirCombatant != null && state.theirCombatant.matchesCategory(condition.params[0]) UniqueType.ConditionalOurUnit -> - (state.attacker != null && state.attacker.matchesCategory(condition.params[0])) + (state.ourCombatant != null && state.ourCombatant.matchesCategory(condition.params[0])) || (state.unit != null && state.unit.matchesFilter(condition.params[0])) UniqueType.ConditionalAttacking -> state.combatAction == CombatAction.Attack UniqueType.ConditionalDefending -> state.combatAction == CombatAction.Defend + UniqueType.ConditionalInTiles -> + state.attackedTile != null && state.attackedTile.matchesFilter(condition.params[0]) UniqueType.ConditionalVsLargerCiv -> { val yourCities = state.civInfo?.cities?.size ?: 1 - val theirCities = state.defender?.getCivInfo()?.cities?.size ?: 0 + val theirCities = state.theirCombatant?.getCivInfo()?.cities?.size ?: 0 yourCities < theirCities } @@ -76,11 +78,11 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s it.matchesFilter(condition.params[2], state.civInfo) } in (condition.params[0].toInt())..(condition.params[1].toInt()) UniqueType.ConditionalNeighborTilesAnd -> - state.cityInfo != null && - state.cityInfo.getCenterTile().neighbors.count { - it.matchesFilter(condition.params[2], state.civInfo) && - it.matchesFilter(condition.params[3], state.civInfo) - } in (condition.params[0].toInt())..(condition.params[1].toInt()) + state.cityInfo != null + && state.cityInfo.getCenterTile().neighbors.count { + it.matchesFilter(condition.params[2], state.civInfo) && + it.matchesFilter(condition.params[3], state.civInfo) + } in (condition.params[0].toInt())..(condition.params[1].toInt()) else -> false } } diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index c613a274fd..b16c743bf5 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -59,6 +59,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { //////////////////////////////////////// GLOBAL UNIQUES //////////////////////////////////////// + /////// Stat providing uniques Stats("[stats]", UniqueTarget.Global), @@ -114,10 +115,10 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { 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), StrengthNearCapital("[amount]% Strength decreasing with distance from the capital", UniqueTarget.Unit), @@ -141,6 +142,15 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { DamageForUnits("[mapUnitFilter] units deal +[amount]% damage", UniqueTarget.Global), @Deprecated("As of 3.17.5", ReplaceWith("[+10]% Strength "), DeprecationLevel.WARNING) StrengthGoldenAge("+10% Strength for all units during Golden Age", UniqueTarget.Global), + @Deprecated("As of 3.17.5", ReplaceWith("[amount]% Strength "), DeprecationLevel.WARNING) + StrengthDefenseTiles("+[amount]% defence in [tileFilter] tiles", UniqueTarget.Unit), + @Deprecated("As of 3.17.5", ReplaceWith("[amount]% Strength "), DeprecationLevel.WARNING) + StrengthIn("+[amount]% Strength in [tileFilter]", UniqueTarget.Unit), + @Deprecated("As of 3.17.5", ReplaceWith("[amount]% Strength ")) + StrengthUnitsTiles("[amount]% Strength for [mapUnitFilter] units in [tileFilter]", UniqueTarget.Global), + @Deprecated("As of 3.17.5", ReplaceWith("[+15]% Strength ")) + StrengthVsCities("+15% Combat Strength for all units when attacking Cities", UniqueTarget.Global), + Movement("[amount] Movement", UniqueTarget.Unit, UniqueTarget.Global), Sight("[amount] Sight", UniqueTarget.Unit, UniqueTarget.Global), @@ -155,6 +165,8 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { SightUnits("[amount] Sight for all [mapUnitFilter] units", UniqueTarget.Global), @Deprecated("As of 3.17.5", ReplaceWith("[amount] Sight"), DeprecationLevel.WARNING) VisibilityRange("[amount] Visibility Range", UniqueTarget.Unit), + @Deprecated("As of 3.17.5", ReplaceWith("[-1] Sight"), DeprecationLevel.WARNING) + LimitedVisibility("Limited Visibility", UniqueTarget.Unit), @Deprecated("As of 3.17.5", ReplaceWith("[amount]% Spread Religion Strength "), DeprecationLevel.WARNING) SpreadReligionStrengthUnits("[amount]% Spread Religion Strength for [mapUnitFilter] units", UniqueTarget.Global), @@ -176,10 +188,10 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { CanEnterIceTiles("Can enter ice tiles", UniqueTarget.Unit), 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), @@ -200,6 +212,7 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { ///////////////////////////////////////// CONDITIONALS ///////////////////////////////////////// + // civ conditionals ConditionalWar("when at war", UniqueTarget.Conditional), ConditionalNotWar("when not at war", UniqueTarget.Conditional), @@ -216,8 +229,8 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { ConditionalVsLargerCiv("when fighting units from a Civilization with more Cities than you", UniqueTarget.Conditional), ConditionalAttacking("when attacking", UniqueTarget.Conditional), ConditionalDefending("when defending", UniqueTarget.Conditional), + ConditionalInTiles("when fighting in [tileFilter] tiles", UniqueTarget.Conditional), // ConditionalIntercepting("when intercepting", UniqueTarget.Conditional), -// ConditionalInTiles("fighting in [tileFilter] tiles", UniqueTarget.Conditional), // tile conditionals ConditionalNeighborTiles("with [amount] to [amount] neighboring [tileFilter] tiles", UniqueTarget.Conditional), diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 0bc44a9780..663ce7523c 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -601,9 +601,11 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsUnits) } ) { // Bonus vs some units - a quarter of the bonus power *= (unique.params[0].toInt() / 4f).toPercent() } else if ( - unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsCity) } || // City Attack - half the bonus - unique.conditionals.any { it.isOfType(UniqueType.ConditionalAttacking) } || // Attack - half the bonus - unique.conditionals.any { it.isOfType(UniqueType.ConditionalDefending) } // Defense - half the bonus + unique.conditionals.any { + it.isOfType(UniqueType.ConditionalVsCity) // City Attack - half the bonus + || it.isOfType(UniqueType.ConditionalAttacking) // Attack - half the bonus + || it.isOfType(UniqueType.ConditionalDefending) // Defense - half the bonus + || it.isOfType(UniqueType.ConditionalInTiles) } // Bonus in terrain or feature - half the bonus ) { power *= (unique.params[0].toInt() / 2f).toPercent() } @@ -629,8 +631,10 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { -> power -= power / 5 unique.placeholderText == "[] additional attacks per turn" // Extra attacks - 20% bonus per extra attack -> power += (power * unique.params[0].toInt()) / 5 - unique.placeholderText == "+[]% Strength in []" // Bonus in terrain or feature - half the bonus - -> power += (power * unique.params[0].toInt()) / 200 + // Deprecated since 3.17.5 + unique.isOfType(UniqueType.StrengthIn) // Bonus in terrain or feature - half the bonus + -> power += (power * unique.params[0].toInt()) / 200 + // } } diff --git a/core/src/com/unciv/models/translations/Translations.kt b/core/src/com/unciv/models/translations/Translations.kt index 8125102694..6d4c450d6f 100644 --- a/core/src/com/unciv/models/translations/Translations.kt +++ b/core/src/com/unciv/models/translations/Translations.kt @@ -212,7 +212,8 @@ class Translations : LinkedHashMap(){ companion object { // Whenever this string is changed, it should also be changed in the translation files! // It is mostly used as the template for translating the order of conditionals - const val englishConditionalOrderingString = " " + const val englishConditionalOrderingString = + " " const val conditionalUniqueOrderString = "ConditionalsPlacement" const val shouldCapitalizeString = "StartWithCapitalLetter" }