diff --git a/android/assets/game.png b/android/assets/game.png index aac2fef514..0aa405f435 100644 Binary files a/android/assets/game.png and b/android/assets/game.png differ diff --git a/android/assets/jsons/Civ V - Vanilla/Policies.json b/android/assets/jsons/Civ V - Vanilla/Policies.json index 098985e23f..200f5d1a12 100644 --- a/android/assets/jsons/Civ V - Vanilla/Policies.json +++ b/android/assets/jsons/Civ V - Vanilla/Policies.json @@ -89,7 +89,7 @@ { "name": "Honor", "era": "Ancient era", - "uniques": ["+[33]% Strength vs [Barbarians]", "Earn [100]% of killed [Barbarian] unit's [Strength] as [Culture]", + "uniques": ["[+33]% Strength ", "Earn [100]% of killed [Barbarian] unit's [Strength] as [Culture]", "Notified of new Barbarian encampments"], "policies": [ { diff --git a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json index fa67274ac5..243259fff5 100644 --- a/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json +++ b/android/assets/jsons/Civ V - Vanilla/UnitPromotions.json @@ -46,7 +46,7 @@ { "name": "Volley", "prerequisites": ["Accuracy I","Barrage I"], - "uniques": ["+[50]% Strength vs [City]"], + "uniques": ["[+50]% Strength "], "unitTypes": ["Archery","Ranged Gunpowder","Siege"] }, { @@ -101,25 +101,25 @@ { "name": "Charge", "prerequisites": ["Shock II","Drill II"], - "uniques": ["+[33]% Strength vs [wounded units]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Mounted","Armored"] }, { "name": "Besiege", // Not called "Siege" in order to not conflict with siege type units for translations "prerequisites": ["Shock II","Drill II"], - "uniques": ["+[50]% Strength vs [City]"], + "uniques": ["[+50]% Strength "], "unitTypes": ["Sword","Gunpowder"] }, { "name": "Formation I", "prerequisites": ["Shock II","Drill II"], // G&K also has Accuracy II & Barrage II as possible prerequisites for this, but I couldn't find a source for the unittypes - "uniques": ["+[33]% Strength vs [Mounted]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted"] }, { "name": "Formation II", "prerequisites": ["Formation I"], - "uniques": ["+[33]% Strength vs [Mounted]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Sword","Gunpowder","Mounted"] }, @@ -194,56 +194,56 @@ // Water melee { "name": "Boarding Party I", - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Melee Water"] }, { "name": "Boarding Party II", "prerequisites": ["Boarding Party I"], - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Melee Water"] }, { "name": "Boarding Party III", "prerequisites": ["Boarding Party II"], - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["+[15]% Strength "], "unitTypes": ["Melee Water"] }, { "name": "Coastal Raider I", - "uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"], + "uniques": ["[+20]% Strength ", "Earn [33]% of the damage done to [City] units as [Gold]"], "unitTypes": ["Melee Water"] }, { "name": "Coastal Raider II", "prerequisites": ["Coastal Raider I"], - "uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"], + "uniques": ["[+20]% Strength ", "Earn [33]% of the damage done to [City] units as [Gold]"], "unitTypes": ["Melee Water"] }, { "name": "Coastal Raider III", "prerequisites": ["Coastal Raider II"], - "uniques": ["+[20]% Strength vs [City]", "Earn [33]% of the damage done to [City] units as [Gold]"], + "uniques": ["[+20]% Strength ", "Earn [33]% of the damage done to [City] units as [Gold]"], "unitTypes": ["Melee Water"] }, // Water Ranged { "name": "Targeting I", - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Ranged Water"] }, { "name": "Targeting II", "prerequisites": ["Targeting I"], - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Ranged Water"] }, { "name": "Targeting III", "prerequisites": ["Targeting II"], - "uniques": ["+[15]% Strength vs [water units]"], + "uniques": ["[+15]% Strength "], "unitTypes": ["Ranged Water"] }, @@ -313,19 +313,19 @@ // Bomber { "name": "Siege I", - "uniques": ["+[33]% Strength vs [City]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Bomber"] }, { "name": "Siege II", "prerequisites": ["Siege I"], - "uniques": ["+[33]% Strength vs [City]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Bomber"] }, { "name": "Siege III", "prerequisites": ["Siege II"], - "uniques": ["+[34]% Strength vs [City]"], + "uniques": ["[+34]% Strength "], "unitTypes": ["Bomber"] }, { @@ -376,13 +376,13 @@ { "name": "Air Targeting I", "prerequisites": ["Interception I","Dogfighting I", "Siege I","Bombardment I"], - "uniques": ["+[33]% Strength vs [water units]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Fighter","Bomber"] }, { "name": "Air Targeting II", "prerequisites": ["Air Targeting I"], - "uniques": ["+[33]% Strength vs [water units]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Fighter","Bomber"] }, @@ -420,13 +420,13 @@ }, { "name": "Anti-Armor I", - "uniques": ["+[25]% Strength vs [Armored]"], + "uniques": ["[+25]% Strength "], "unitTypes": ["Helicopter"] }, { "name": "Anti-Armor II", "prerequisites": ["Anti-Armor I"], - "uniques": ["+[25]% Strength vs [Armored]"], + "uniques": ["[+25]% Strength "], "unitTypes": ["Helicopter"] }, @@ -472,13 +472,13 @@ { "name": "Ambush I", - "uniques": ["+[33]% Strength vs [Armored]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Sword","Gunpowder","Fighter","Bomber"] }, { "name": "Ambush II", "prerequisites": ["Ambush I"], - "uniques": ["+[33]% Strength vs [Armored]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Sword","Gunpowder","Fighter","Bomber"] }, @@ -486,26 +486,26 @@ // Water ranged and air units { "name": "Bombardment I", - "uniques": ["+[33]% Strength vs [land units]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Ranged Water","Fighter","Bomber"] }, { "name": "Bombardment II", "prerequisites": ["Bombardment I"], - "uniques": ["+[33]% Strength vs [land units]"], + "uniques": ["[+33]% Strength "], "unitTypes": ["Ranged Water","Fighter","Bomber"] }, { "name": "Bombardment III", "prerequisites": ["Bombardment II"], - "uniques": ["+[34]% Strength vs [land units]"], + "uniques": ["[+34]% Strength "], "unitTypes": ["Ranged Water","Fighter","Bomber"] }, // Uniques that should be kept on upgrades { "name": "Morale", // Heroic Epic - "uniques": ["+[15]% Combat Strength"] + "uniques": ["[+15]% Strength"] }, { "name": "Great Generals I", // only for Companion Cavalry, Keshik and their subsequent upgrades diff --git a/android/assets/jsons/Civ V - Vanilla/Units.json b/android/assets/jsons/Civ V - Vanilla/Units.json index df3182ae00..5c242321b1 100644 --- a/android/assets/jsons/Civ V - Vanilla/Units.json +++ b/android/assets/jsons/Civ V - Vanilla/Units.json @@ -185,7 +185,7 @@ "rangedStrength": 10, "cost": 56, "requiredTech": "Sailing", - "uniques": ["Cannot enter ocean tiles", "+[50]% Strength vs [Water] units"], + "uniques": ["Cannot enter ocean tiles", "[+50]% Strength "], "upgradesTo": "Galleass", "obsoleteTech": "Astronomy", "attackSound": "arrow" @@ -273,7 +273,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Civil Service", "upgradesTo": "Pikeman", - "uniques": ["+[50]% Strength vs [Mounted]"], + "uniques": ["[+50]% Strength "], "attackSound": "metalhit" }, { @@ -287,7 +287,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Civil Service", "upgradesTo": "Pikeman", - "uniques": ["+[50]% Strength vs [Mounted]"], + "uniques": ["[+50]% Strength "], "attackSound": "metalhit" }, { @@ -301,7 +301,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Civil Service", "upgradesTo": "Pikeman", - "uniques": ["+[50]% Strength vs [Mounted]","[+10] HP when healing"], + "uniques": ["[+50]% Strength ","[+10] HP when healing"], "attackSound": "metalhit" }, { @@ -315,7 +315,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["+[300]% Strength vs [City]", "No defensive terrain bonus", "+[-33]% Strength when defending", + "uniques": ["[+300]% Strength ", "No defensive terrain bonus", "+[-33]% Strength when defending", "-[1] Visibility Range", "Can only attack [City] units"], "promotions": ["Cover I"], "attackSound": "throw" @@ -330,7 +330,7 @@ "requiredTech": "Bronze Working", "obsoleteTech": "Civil Service", "upgradesTo": "Pikeman", - "uniques": ["+[50]% Strength vs [Mounted]"], + "uniques": ["[+50]% Strength "], "attackSound": "metalhit" // Barbarian unique Spearman. Has same icon and name but slightly different 3d texture }, @@ -347,7 +347,7 @@ "requiredResource": "Horses", "upgradesTo": "Knight", "obsoleteTech": "Chivalry", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]" ], + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength " ], "hurryCostModifier": 20, "attackSound": "horse" }, @@ -364,7 +364,7 @@ "obsoleteTech": "Chivalry", "promotions": ["Great Generals I"], "requiredResource": "Horses", - "uniques": ["Can move after attacking", "No defensive terrain bonus", "-[33]% Strength vs [City]"], + "uniques": ["Can move after attacking", "No defensive terrain bonus", "[-33]% Strength "], "hurryCostModifier": 20, "attackSound": "horse" }, @@ -380,7 +380,7 @@ "upgradesTo": "Knight", "obsoleteTech": "Chivalry", "promotions": ["Great Generals II"], - "uniques": ["Can move after attacking", "No defensive terrain bonus", "-[33]% Strength vs [City]", + "uniques": ["Can move after attacking", "No defensive terrain bonus", "[-33]% Strength ", "[-10]% Strength for enemy [Military] units in adjacent [All] tiles"], "hurryCostModifier": 20, "attackSound": "elephant" @@ -396,7 +396,7 @@ "requiredTech": "Horseback Riding", "upgradesTo": "Knight", "obsoleteTech": "Chivalry", - "uniques": ["Can move after attacking", "-[25]% Strength vs [City]"], + "uniques": ["Can move after attacking", "[-25]% Strength "], "hurryCostModifier": 20, "attackSound": "horse" }, @@ -410,7 +410,7 @@ "requiredTech": "Mathematics", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["+[200]% Strength vs [City]", "No defensive terrain bonus", + "uniques": ["[+200]% Strength ", "No defensive terrain bonus", "Must set up to ranged attack", "Limited Visibility"], "hurryCostModifier": 20, "attackSound": "throw" @@ -427,7 +427,7 @@ "requiredTech": "Mathematics", "obsoleteTech": "Physics", "upgradesTo": "Trebuchet", - "uniques": ["+[200]% Strength vs [City]", "No defensive terrain bonus", + "uniques": ["[+200]% Strength ", "No defensive terrain bonus", "Must set up to ranged attack", "Limited Visibility"], "hurryCostModifier": 20, "attackSound": "throw" @@ -513,7 +513,7 @@ "strength": 16, "cost": 90, "requiredTech": "Civil Service", - "uniques": ["+[50]% Strength vs [Mounted]"], + "uniques": ["[+50]% Strength "], "upgradesTo": "Lancer", "obsoleteTech": "Gunpowder", "attackSound": "metalhit" @@ -527,7 +527,7 @@ "strength": 16, "cost": 45, "requiredTech": "Civil Service", - "uniques": ["+[50]% Strength vs [Mounted]", "Can move immediately once bought" ], + "uniques": ["[+50]% Strength ", "Can move immediately once bought" ], "upgradesTo": "Lancer", "obsoleteTech": "Gunpowder", "attackSound": "metalhit" @@ -556,7 +556,7 @@ "obsoleteTech": "Military Science", "upgradesTo": "Cavalry", "requiredResource": "Horses", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]" ], + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength " ], "attackSound": "horse" }, { @@ -604,7 +604,7 @@ "requiredTech": "Chivalry", "obsoleteTech": "Military Science", "upgradesTo": "Cavalry", - "uniques": ["Can move after attacking","No defensive terrain bonus","+[50]% Strength vs [Mounted]","-[33]% Strength vs [City]"], + "uniques": ["Can move after attacking","No defensive terrain bonus","[+50]% Strength ","[-33]% Strength "], "attackSound": "elephant" }, { @@ -694,7 +694,7 @@ "requiredTech": "Physics", "obsoleteTech": "Chemistry", "upgradesTo": "Cannon", - "uniques": ["+[200]% Strength vs [City]","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","Limited Visibility"], "attackSound": "throw" }, { @@ -852,7 +852,7 @@ "requiredTech": "Gunpowder", "upgradesTo": "Rifleman", "obsoleteTech": "Rifling", - "uniques": ["+[50]% Strength vs [Mounted]"], + "uniques": ["[+50]% Strength "], "attackSound": "shot" }, { @@ -920,7 +920,7 @@ "cost": 185, "requiredTech": "Metallurgy", "requiredResource": "Horses", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]"], + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength "], "promotions": ["Formation I"], "upgradesTo": "Anti-Tank Gun", "obsoleteTech": "Combined Arms", @@ -936,7 +936,7 @@ "cost": 185, "requiredTech": "Metallurgy", "requiredResource": "Horses", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]", + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength ", "[+1] Visibility Range", "No movement cost to pillage"], "promotions": ["Formation I"], "upgradesTo": "Anti-Tank Gun", @@ -953,7 +953,7 @@ "cost": 185, "requiredTech": "Metallurgy", "requiredResource": "Horses", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]", + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength ", "Transfer Movement to [Great General]", "[+15]% Strength when stacked with [Great General]"], "promotions": ["Formation I"], "upgradesTo": "Anti-Tank Gun", @@ -970,7 +970,7 @@ "requiredTech": "Chemistry", "upgradesTo": "Artillery", "obsoleteTech": "Dynamite", - "uniques": ["+[200]% Strength vs [City]","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","Limited Visibility"], "attackSound": "cannon" }, @@ -1043,7 +1043,7 @@ "obsoleteTech": "Combustion", "requiredResource": "Horses", "upgradesTo": "Landship", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]" ], + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength " ], "attackSound": "horse" }, { @@ -1059,7 +1059,7 @@ "requiredResource": "Horses", "upgradesTo": "Landship", "uniques": ["Can move after attacking","No defensive terrain bonus", - "-[33]% Strength vs [City]", "+[50]% Strength vs [wounded units]"], + "[-33]% Strength ", "[+50]% Strength "], "attackSound": "horse" }, { @@ -1074,7 +1074,7 @@ "obsoleteTech": "Combustion", "requiredResource": "Horses", "upgradesTo": "Landship", - "uniques": ["Can move after attacking","No defensive terrain bonus","-[33]% Strength vs [City]" , + "uniques": ["Can move after attacking","No defensive terrain bonus","[-33]% Strength " , "[+1] Visibility Range", "[+50]% to Flank Attack bonuses" ], "attackSound": "horse" }, @@ -1088,7 +1088,7 @@ "requiredResource": "Coal", "upgradesTo": "Destroyer", "obsoleteTech": "Combustion", - "uniques": ["+[33]% Strength vs [City]","Double movement in [Coast]"], + "uniques": ["[+33]% Strength ","Double movement in [Coast]"], "attackSound": "shipguns" }, { @@ -1101,7 +1101,7 @@ "cost": 320, "requiredTech": "Dynamite", "upgradesTo": "Rocket Artillery", - "uniques": ["+[200]% Strength vs [City]","No defensive terrain bonus", + "uniques": ["[+200]% Strength ","No defensive terrain bonus", "Must set up to ranged attack","Limited Visibility","Ranged attacks may be performed over obstacles"], "attackSound": "artillery" }, @@ -1158,7 +1158,7 @@ "requiredResource": "Oil", "upgradesTo": "Fighter", "obsoleteTech": "Radar", - "uniques": ["[50]% chance to intercept air attacks", "+[150]% Strength vs [Bomber]", "+[150]% Strength vs [Helicopter]"], + "uniques": ["[50]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength "], "attackSound": "machinegun" }, { @@ -1232,7 +1232,7 @@ "requiredTech": "Ballistics", "upgradesTo": "Mobile SAM", "obsoleteTech": "Rocketry", - "uniques": ["[100]% chance to intercept air attacks", "+[150]% Strength vs [air units]", "+[150]% Strength vs [Helicopter]"], + "uniques": ["[100]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength "], "attackSound": "machinegun" }, { @@ -1257,7 +1257,7 @@ "cost": 375, "requiredTech": "Combustion", "uniques": ["Can see invisible [Submarine] units", "[40]% chance to intercept air attacks", - "May withdraw before melee ([80]%)", "+[100]% Strength vs [submarine units]"], + "May withdraw before melee ([80]%)", "[+100]% Strength "], "attackSound": "shipguns" }, @@ -1286,7 +1286,7 @@ "requiredTech": "Radar", "requiredResource": "Oil", "upgradesTo": "Jet Fighter", - "uniques": ["[100]% chance to intercept air attacks", "+[150]% Strength vs [Bomber]", "+[150]% Strength vs [Helicopter]"], + "uniques": ["[100]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength "], "attackSound": "machinegun" }, { @@ -1302,8 +1302,8 @@ "cost": 375, "requiredTech": "Radar", "upgradesTo": "Jet Fighter", - "uniques": ["[100]% chance to intercept air attacks", "+[150]% Strength vs [Bomber]", "+[150]% Strength vs [Helicopter]", - "+[33]% Strength vs [Fighter]"], + "uniques": ["[100]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength ", + "[+33]% Strength "], "attackSound": "machinegun" }, { @@ -1381,7 +1381,7 @@ "cost": 300, "requiredTech": "Combined Arms", "upgradesTo": "Helicopter Gunship", - "uniques": ["+[100]% Strength vs [Armored]"], + "uniques": ["[+100]% Strength "], "attackSound": "machinegun" }, { @@ -1411,7 +1411,7 @@ "cost": 425, "requiredTech": "Rocketry", "requiredResource": "Aluminum", - "uniques": ["+[200]% Strength vs [City]","No defensive terrain bonus", + "uniques": ["[+200]% Strength ","No defensive terrain bonus", "Limited Visibility","Ranged attacks may be performed over obstacles"], "attackSound": "artillery" }, @@ -1423,7 +1423,7 @@ "strength": 65, "cost": 425, "requiredTech": "Rocketry", - "uniques": ["[100]% chance to intercept air attacks", "+[150]% Strength vs [air units]", "+[150]% Strength vs [Helicopter]"], + "uniques": ["[100]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength "], "attackSound": "missile" }, { @@ -1460,7 +1460,7 @@ "cost": 425, "requiredTech": "Computers", "requiredResource": "Aluminum", - "uniques": ["+[100]% Strength vs [Armored]", "No defensive terrain bonus", "Can move after attacking", + "uniques": ["[+100]% Strength ", "No defensive terrain bonus", "Can move after attacking", "All tiles cost 1 movement", "Ignores Zone of Control", "Unable to capture cities"], "attackSound": "machinegun" }, @@ -1499,7 +1499,7 @@ "requiredTech": "Robotics", "uniques": ["[100]% chance to intercept air attacks", "Can see invisible [Submarine] units", "Ranged attacks may be performed over obstacles", "Can carry [3] [Missile] units", - "+[100]% Strength vs [submarine units]"], + "[+100]% Strength "], "attackSound": "shipguns" }, { @@ -1525,7 +1525,7 @@ "cost": 425, "requiredTech": "Lasers", "requiredResource": "Aluminum", - "uniques": ["[100]% chance to intercept air attacks", "+[150]% Strength vs [Bomber]", "+[150]% Strength vs [Helicopter]"], + "uniques": ["[100]% chance to intercept air attacks", "[+150]% Strength ", "[+150]% Strength "], "attackSound": "jetgun" }, { diff --git a/core/src/com/unciv/logic/battle/BattleDamage.kt b/core/src/com/unciv/logic/battle/BattleDamage.kt index bc1c69d0b3..29754baf57 100644 --- a/core/src/com/unciv/logic/battle/BattleDamage.kt +++ b/core/src/com/unciv/logic/battle/BattleDamage.kt @@ -2,6 +2,8 @@ package com.unciv.logic.battle import com.unciv.logic.map.TileInfo import com.unciv.models.Counter +import com.unciv.models.ruleset.unique.StateForConditionals +import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.utils.toPercent import java.util.* import kotlin.collections.set @@ -21,23 +23,30 @@ object BattleDamage { val civInfo = combatant.getCivInfo() if (combatant is MapUnitCombatant) { - for (unique in - combatant.unit.getMatchingUniques("+[]% Strength vs []") + - civInfo.getMatchingUniques("+[]% Strength vs []") + for (unique in combatant.unit.getMatchingUniques( + UniqueType.Strength, + StateForConditionals(civInfo, defender = enemy)) ) { - if (enemy.matchesCategory(unique.params[1])) - modifiers.add("vs [${unique.params[1]}]", unique.params[0].toInt()) + modifiers.add("${unique.sourceObjectName} (${unique.sourceObjectType})", unique.params[0].toInt()) } - for (unique in combatant.unit.getMatchingUniques("-[]% Strength vs []")+ - civInfo.getMatchingUniques("-[]% Strength vs []") - ) { - if (enemy.matchesCategory(unique.params[1])) - modifiers.add("vs [${unique.params[1]}]", -unique.params[0].toInt()) - } - - for (unique in combatant.unit.getMatchingUniques("+[]% Combat Strength")) - modifiers.add("Combat Strength", unique.params[0].toInt()) - + + // Deprecated since 3.17.3 + for (unique in + combatant.unit.getMatchingUniques("+[]% Strength vs []") + ) { + if (enemy.matchesCategory(unique.params[1])) + modifiers.add("vs [${unique.params[1]}]", unique.params[0].toInt()) + } + for (unique in combatant.unit.getMatchingUniques("-[]% Strength vs []") + ) { + if (enemy.matchesCategory(unique.params[1])) + modifiers.add("vs [${unique.params[1]}]", -unique.params[0].toInt()) + } + + for (unique in combatant.unit.getMatchingUniques("+[]% Combat Strength")) + modifiers.add("Combat Strength", unique.params[0].toInt()) + // + //https://www.carlsguides.com/strategy/civilization5/war/combatbonuses.php val civHappiness = if (civInfo.isCityState() && civInfo.getAllyCiv() != null) // If we are a city state with an ally we are vulnerable to their unhappiness. diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index a038cb770e..a4c2aecd0b 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -14,6 +14,7 @@ import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.tile.TileImprovement +import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.UnitType @@ -228,9 +229,12 @@ class MapUnit { tempUniques.asSequence().filter { it.placeholderText == placeholderText } + civInfo.getMatchingUniques(placeholderText) - fun getMatchingUniques(uniqueType: UniqueType): Sequence = - tempUniques.asSequence().filter { it.type == uniqueType } + - civInfo.getMatchingUniques(uniqueType) + fun getMatchingUniques(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null) = sequence { + yieldAll(tempUniques.asSequence() + .filter { it.type == uniqueType && it.conditionalsApply(stateForConditionals)} + ) + yieldAll(civInfo.getMatchingUniques(uniqueType, stateForConditionals)) + } fun hasUnique(unique: String): Boolean { return tempUniques.any { it.placeholderText == unique } || civInfo.hasUnique(unique) diff --git a/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt b/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt index cf75ee0df8..9edf5baffd 100644 --- a/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt +++ b/core/src/com/unciv/models/ruleset/unique/StateForConditionals.kt @@ -1,9 +1,21 @@ package com.unciv.models.ruleset.unique +import com.unciv.logic.battle.ICombatant import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo +import com.unciv.logic.map.TileInfo data class StateForConditionals( val civInfo: CivilizationInfo? = null, val cityInfo: CityInfo? = null, -) \ No newline at end of file + val defender: ICombatant? = null, +// val attacker: ICombatant? = null, +// val attackedTile: TileInfo? = null, +// val combatAction: CombatAction? = null, +) + +//enum class CombatAction() { +// Attack, +// Defend, +// Intercept, +//} \ 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 a9bf562682..fbed208623 100644 --- a/core/src/com/unciv/models/ruleset/unique/Unique.kt +++ b/core/src/com/unciv/models/ruleset/unique/Unique.kt @@ -50,6 +50,10 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s state.cityInfo != null && state.cityInfo.population.getNumberOfSpecialists() >= condition.params[0].toInt() UniqueType.ConditionalHappy.placeholderText -> state.civInfo != null && state.civInfo.statsForNextTurn.happiness >= 0 + UniqueType.ConditionalVsCity.placeholderText -> + state.defender != null && state.defender.matchesCategory("City") + UniqueType.ConditionalVsUnits.placeholderText -> + state.defender != null && state.defender.matchesCategory(condition.params[0]) 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 405b87aa0b..cc054dc25b 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -80,7 +80,6 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { TileProvidesYieldWithoutPopulation("Tile provides yield without assigned population", UniqueTarget.Improvement), - @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) @@ -88,6 +87,20 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { @Deprecated("As of 3.16.16", ReplaceWith("[stats] "), DeprecationLevel.WARNING) StatBonusForNumberOfSpecialists("[stats] if this city has at least [amount] specialists"), // No conditional support + Strength("[amount]% Strength", UniqueTarget.Unit, UniqueTarget.Global), + + @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength"), DeprecationLevel.WARNING) + StrengthPlus("+[amount]% Strength"), + @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength"), DeprecationLevel.WARNING) + StrengthMin("-[amount]% Strength"), + @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength OR [amount]% Strength "), DeprecationLevel.WARNING) + StrengthPlusVs("+[amount]% Strength vs [combatantFilter]"), + @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength OR [amount]% Strength "), DeprecationLevel.WARNING) + StrengthMinVs("-[amount]% Strength vs [combatantFilter]"), + @Deprecated("As of 3.17.3", ReplaceWith("[amount]% Strength"), DeprecationLevel.WARNING) + CombatBonus("+[amount]% Combat Strength"), + + // 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), @@ -134,12 +147,18 @@ enum class UniqueType(val text:String, vararg targets: UniqueTarget) { CannotEnterOceanUntilAstronomy("Cannot enter ocean tiles until Astronomy", UniqueTarget.Unit), - ///// CONDITIONALS + // Conditionals ConditionalWar("when at war", UniqueTarget.Conditional), ConditionalNotWar("when not at war", UniqueTarget.Conditional), ConditionalSpecialistCount("if this city has at least [amount] specialists", UniqueTarget.Conditional), ConditionalHappy("while the empire is happy", UniqueTarget.Conditional), + ConditionalVsCity("vs cities", UniqueTarget.Conditional), + ConditionalVsUnits("vs [mapUnitFilter] units", UniqueTarget.Conditional), +// ConditionalInTiles("fighting in [tileFilter] tiles", UniqueTarget.Conditional), +// ConditionalAttacking("when attacking", UniqueTarget.Conditional), +// ConditionalDefending("when defending", UniqueTarget.Conditional), +// ConditionalIntercepting("when intercepting", UniqueTarget.Conditional), ; /** For uniques that have "special" parameters that can accept multiple types, we can override them manually diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 957ab01aa6..43f4d8a17d 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -556,7 +556,10 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { ( isRanged() && (uniqueObjects + getType().uniqueObjects) - .any { it.placeholderText == "+[]% Strength vs []" && it.params[1] == "City" } + .any { it.isOfType(UniqueType.Strength) + && it.params[0].toInt() > 0 + && it.conditionals.any { conditional -> conditional.isOfType(UniqueType.ConditionalVsCity) } + } ) fun getForceEvaluation(): Int { @@ -593,10 +596,18 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { for (unique in uniqueObjects) { when { - unique.placeholderText == "+[]% Strength vs []" && unique.params[1] == "City" // City Attack - half the bonus - -> power += (power * unique.params[0].toInt()) / 200 - unique.placeholderText == "+[]% Strength vs []" && unique.params[1] != "City" // Bonus vs something else - a quarter of the bonus - -> power += (power * unique.params[0].toInt()) / 400 + unique.isOfType(UniqueType.Strength) && unique.params[0].toInt() > 0 -> { + if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsCity) }) + power += (power * unique.params[0].toInt()) / 200 + else if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsUnits) }) + power += (power * unique.params[0].toInt()) / 400 + } + // Deprecated since 3.17.3 + unique.placeholderText == "+[]% Strength vs []" && unique.params[1] == "City" // City Attack - half the bonus + -> power += (power * unique.params[0].toInt()) / 200 + unique.placeholderText == "+[]% Strength vs []" && unique.params[1] != "City" // Bonus vs something else - a quarter of the bonus + -> power += (power * unique.params[0].toInt()) / 400 + // unique.placeholderText == "+[]% Strength when attacking" // Attack - half the bonus -> power += (power * unique.params[0].toInt()) / 200 unique.placeholderText == "+[]% Strength when defending" // Defense - half the bonus @@ -614,10 +625,18 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { for (promotionName in promotions) { for (unique in ruleset.unitPromotions[promotionName]!!.uniqueObjects) { when { + unique.isOfType(UniqueType.Strength) && unique.params[0].toInt() > 0 -> { + if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsCity) }) + power += (power * unique.params[0].toInt()) / 200 + else if (unique.conditionals.any { it.isOfType(UniqueType.ConditionalVsUnits) }) + power += (power * unique.params[0].toInt()) / 400 + } + // Deprecated since 3.17.3 unique.placeholderText == "+[]% Strength vs []" && unique.params[1] == "City" // City Attack - half the bonus -> power += (power * unique.params[0].toInt()) / 200 unique.placeholderText == "+[]% Strength vs []" && unique.params[1] != "City" // Bonus vs something else - a quarter of the bonus -> power += (power * unique.params[0].toInt()) / 400 + // unique.placeholderText == "+[]% Strength when attacking" // Attack - half the bonus -> power += (power * unique.params[0].toInt()) / 200 unique.placeholderText == "+[]% Strength when defending" // Defense - half the bonus