From b347366d50e00f12354487c2f2f5c78527d7cec3 Mon Sep 17 00:00:00 2001 From: Xander Lenstra <71121390+xlenstra@users.noreply.github.com> Date: Wed, 1 Sep 2021 18:20:04 +0200 Subject: [PATCH] Refactored some code and uniques (#5051) * Refactored some code and uniques * Fixed compilation errors, tests and crashes * Moved influence bounds check from add to set --- .../jsons/Civ V - Vanilla/Buildings.json | 6 +- .../assets/jsons/Civ V - Vanilla/Nations.json | 4 +- .../jsons/Civ V - Vanilla/Policies.json | 8 +- core/src/com/unciv/logic/GameInfo.kt | 12 ++- .../logic/automation/NextTurnAutomation.kt | 2 +- core/src/com/unciv/logic/battle/Battle.kt | 43 ++++++++--- .../unciv/logic/battle/MapUnitCombatant.kt | 2 + core/src/com/unciv/logic/city/CityInfo.kt | 14 ++-- .../logic/city/CityInfoConquestFunctions.kt | 2 +- core/src/com/unciv/logic/city/CityReligion.kt | 5 +- core/src/com/unciv/logic/city/CityStats.kt | 77 ++++++++++++------- .../unciv/logic/civilization/CivInfoStats.kt | 31 ++++---- .../logic/civilization/CivilizationInfo.kt | 22 +++--- .../unciv/logic/civilization/QuestManager.kt | 2 +- .../logic/civilization/ReligionManager.kt | 3 +- .../diplomacy/DiplomacyManager.kt | 16 +++- core/src/com/unciv/logic/map/MapUnit.kt | 27 +++---- core/src/com/unciv/logic/map/TileMap.kt | 2 +- core/src/com/unciv/models/ruleset/Building.kt | 10 +-- .../com/unciv/models/ruleset/unit/BaseUnit.kt | 16 ++-- .../unciv/ui/worldscreen/unit/UnitActions.kt | 30 ++++---- 21 files changed, 190 insertions(+), 144 deletions(-) diff --git a/android/assets/jsons/Civ V - Vanilla/Buildings.json b/android/assets/jsons/Civ V - Vanilla/Buildings.json index 4331933491..353985865f 100644 --- a/android/assets/jsons/Civ V - Vanilla/Buildings.json +++ b/android/assets/jsons/Civ V - Vanilla/Buildings.json @@ -717,7 +717,7 @@ "culture": 1, "isWonder": true, "greatPersonPoints": {"Great Artist": 1}, - "uniques": ["Unhappiness from population decreased by [10]%"], + "uniques": ["[-10]% unhappiness from population [in all cities]"], "requiredTech": "Banking", "quote": "'Most of us can, as we choose, make of this world either a palace or a prison' - John Lubbock" }, @@ -969,7 +969,7 @@ "culture": 1, "isWonder": true, "greatPersonPoints": {"Great Engineer": 2}, - "uniques": ["[+1 Production] from every specialist"], + "uniques": ["[+1 Production] from every specialist [in all cities]"], "requiredTech": "Replaceable Parts", "quote": "'Give me your tired, your poor, your huddled masses yearning to breathe free, the wretched refuse of your teeming shore. Send these, the homeless, tempest-tossed to me, I lift my lamp beside the golden door!' - Emma Lazarus" }, @@ -1085,7 +1085,7 @@ "cost": 300, "maintenance": 1, "requiredTech": "Telecommunications", - "uniques": ["Population loss from nuclear attacks -[75]%"] + "uniques": ["Population loss from nuclear attacks [-75]% [in this city]"] }, { "name": "SS Cockpit", diff --git a/android/assets/jsons/Civ V - Vanilla/Nations.json b/android/assets/jsons/Civ V - Vanilla/Nations.json index 199a84e20b..0965d2f670 100644 --- a/android/assets/jsons/Civ V - Vanilla/Nations.json +++ b/android/assets/jsons/Civ V - Vanilla/Nations.json @@ -314,7 +314,7 @@ "outerColor": [16,126,5], "innerColor": [255,153,51], "uniqueName": "Population Growth", - "uniques": ["Unhappiness from number of Cities doubled", "Unhappiness from population decreased by [50]%"], + "uniques": ["Unhappiness from number of Cities doubled", "[-50]% unhappiness from population [in all cities]"], "cities": ["Delhi","Mumbai","Vijayanagara","Pataliputra","Varanasi","Agra","Calcutta","Lahore","Bangalore","Hyderabad","Madurai","Ahmedabad", "Kolhapur","Prayaga","Ayodhya","Indraprastha","Mathura","Ujjain","Gulbarga","Jaunpur","Rajagriha","Sravasti","Tiruchirapalli","Thanjavur", "Bodhgaya","Kushinagar","Amaravati","Gaur","Gwalior","Jaipur","Karachi"] @@ -392,7 +392,7 @@ "outerColor": [26,32,96], "innerColor": [255,0,0], "uniqueName": "Scholars of the Jade Hall", - "uniques": ["[+2 Science] from every specialist", "[+2 Science] from every [Great Improvement]","Receive a tech boost when scientific buildings/wonders are built in capital"], + "uniques": ["[+2 Science] from every specialist [in all cities]", "[+2 Science] from every [Great Improvement]","Receive a tech boost when scientific buildings/wonders are built in capital"], "cities": ["Seoul","Busan","Jeonju","Daegu","Pyongyang","Kaesong","Suwon","Gwangju","Gangneung","Hamhung","Wonju","Ulsan", "Changwon","Andong","Gongju","Haeju","Cheongju","Mokpo","Dongducheon","Geoje","Suncheon","Jinju","Sangju", "Rason","Gyeongju","Chungju","Sacheon","Gimje","Anju"] diff --git a/android/assets/jsons/Civ V - Vanilla/Policies.json b/android/assets/jsons/Civ V - Vanilla/Policies.json index a110223d36..4c3071a894 100644 --- a/android/assets/jsons/Civ V - Vanilla/Policies.json +++ b/android/assets/jsons/Civ V - Vanilla/Policies.json @@ -75,7 +75,7 @@ }, { "name": "Meritocracy", - "uniques": ["[+1 Happiness] [in all cities connected to capital]", "Unhappiness from population decreased by [5]% [in all non-occupied cities]"], + "uniques": ["[+1 Happiness] [in all cities connected to capital]", "[-5]% unhappiness from population [in all non-occupied cities]"], "requires": ["Citizenship"], "row": 2, "column": 5 @@ -288,7 +288,7 @@ "policies": [ { "name": "Secularism", - "uniques": ["[+2 Science] from every specialist"], + "uniques": ["[+2 Science] from every specialist [in all cities]"], "row": 1, "column": 2 }, @@ -347,7 +347,7 @@ }, { "name": "Civil Society", - "uniques": ["-[50]% food consumption by specialists"], + "uniques": ["-[50]% food consumption by specialists [in all cities]"], "row": 1, "column": 5 }, @@ -360,7 +360,7 @@ }, { "name": "Democracy", - "uniques": ["Specialists only produce [50]% of normal unhappiness"], + "uniques": ["[-50]% unhappiness from specialists [in all cities]"], "requires": ["Civil Society"], "row": 2, "column": 5 diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 78a817e63a..90313195ea 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -292,22 +292,20 @@ class GameInfo { for (baseUnit in ruleSet.units.values) baseUnit.ruleset = ruleSet + // This needs to go before tileMap.setTransients, as units need to access + // the nation of their civilization when setting transients + for (civInfo in civilizations) civInfo.gameInfo = this + for (civInfo in civilizations) civInfo.setNationTransient() + tileMap.setTransients(ruleSet) if (currentPlayer == "") currentPlayer = civilizations.first { it.isPlayerCivilization() }.civName currentPlayerCiv = getCivilization(currentPlayer) - // this is separated into 2 loops because when we activate updateVisibleTiles in civ.setTransients, - // we try to find new civs, and we check if civ is barbarian, which we can't know unless the gameInfo is already set. - for (civInfo in civilizations) civInfo.gameInfo = this - difficultyObject = ruleSet.difficulties[difficulty]!! for (religion in religions.values) religion.setTransients(this) - // This doesn't HAVE to go here, but why not. - - for (civInfo in civilizations) civInfo.setNationTransient() for (civInfo in civilizations) civInfo.setTransients() for (civInfo in civilizations) civInfo.updateSightAndResources() diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index 700f6677ba..9b1e26976e 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -484,7 +484,7 @@ object NextTurnAutomation { val unitsInBorder = otherCiv.getCivUnits().count { !it.isCivilian() && it.getTile().getOwner() == civInfo } if (unitsInBorder > 0 && diplomacy.relationshipLevel() < RelationshipLevel.Friend) { - diplomacy.influence -= 10f + diplomacy.addInfluence(-10f) if (!diplomacy.hasFlag(DiplomacyFlags.BorderConflict)) { otherCiv.popupAlerts.add(PopupAlert(AlertType.BorderConflict, civInfo.civName)) diplomacy.setFlag(DiplomacyFlags.BorderConflict, 10) diff --git a/core/src/com/unciv/logic/battle/Battle.kt b/core/src/com/unciv/logic/battle/Battle.kt index 74be534e26..47477d3d41 100644 --- a/core/src/com/unciv/logic/battle/Battle.kt +++ b/core/src/com/unciv/logic/battle/Battle.kt @@ -6,6 +6,7 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.* import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers import com.unciv.logic.civilization.diplomacy.DiplomaticStatus +import com.unciv.logic.map.MapUnit import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo import com.unciv.models.AttackableTile @@ -13,6 +14,7 @@ import com.unciv.models.UnitActionType import com.unciv.models.ruleset.Unique import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats +import com.unciv.ui.utils.toPercent import java.util.* import kotlin.math.max import kotlin.math.min @@ -121,10 +123,11 @@ object Battle { val bonusUniques = ArrayList() - bonusUniques.addAll(civUnit.getCivInfo().getMatchingUniques(bonusUniquePlaceholderText)) if (civUnit is MapUnitCombatant) { - bonusUniques.addAll(civUnit.unit.getMatchingUniques(bonusUniquePlaceholderText)) + bonusUniques.addAll(civUnit.getMatchingUniques(bonusUniquePlaceholderText)) + } else { + bonusUniques.addAll(civUnit.getCivInfo().getMatchingUniques(bonusUniquePlaceholderText)) } bonusUniquePlaceholderText = "Earn []% of [] unit's [] as [] when killed within 4 tiles of a city following this religion" @@ -386,9 +389,7 @@ object Battle { if (thisCombatant.getCivInfo().isMajorCiv()) { var greatGeneralPointsModifier = 1f - val unitUniques = thisCombatant.unit.getMatchingUniques("[] is earned []% faster") - val civUniques = thisCombatant.getCivInfo().getMatchingUniques("[] is earned []% faster") - for (unique in unitUniques + civUniques) { + for (unique in thisCombatant.getMatchingUniques("[] is earned []% faster")) { val unitName = unique.params[0] val unit = thisCombatant.getCivInfo().gameInfo.ruleSet.units[unitName] if (unit != null && unit.uniques.contains("Great Person - [War]")) @@ -400,7 +401,7 @@ object Battle { } } - private fun conquerCity(city: CityInfo, attacker: ICombatant) { + private fun conquerCity(city: CityInfo, attacker: MapUnitCombatant) { val attackerCiv = attacker.getCivInfo() attackerCiv.addNotification("We have conquered the city of [${city.name}]!", city.location, NotificationIcon.War) @@ -412,10 +413,10 @@ object Battle { for (airUnit in airUnits.toList()) airUnit.destroy() } - for (unique in attackerCiv.getMatchingUniques("Upon capturing a city, receive [] times its [] production as [] immediately")) { + for (unique in attacker.getMatchingUniques("Upon capturing a city, receive [] times its [] production as [] immediately")) { attackerCiv.addStat( Stat.valueOf(unique.params[2]), - unique.params[0].toInt() * city.cityStats.currentCityStats.get(Stat.valueOf(unique.params[1])).toInt() + unique.params[0].toInt() * city.cityStats.currentCityStats[Stat.valueOf(unique.params[1])].toInt() ) } @@ -559,6 +560,10 @@ object Battle { for (civ in attackingCiv.getKnownCivs()) { civ.getDiplomacyManager(attackingCiv).setModifier(DiplomaticModifiers.UsedNuclearWeapons, -50f) } + + if (!attacker.isDefeated()) { + attacker.unit.attacksThisTurn += 1 + } } // todo: reduce extreme code duplication, parameterize probabilities where an unique already used @@ -578,8 +583,15 @@ object Battle { if (city != null && tile.position == city.location) { var populationLoss = city.population.population * (0.3 + Random().nextFloat() * 0.4) var populationLossReduced = false - for (unique in city.civInfo.getMatchingUniques("Population loss from nuclear attacks -[]%")) { - populationLoss *= 1 - unique.params[0].toFloat() / 100f + // Deprecated since 3.16.11 + for (unique in city.getLocalMatchingUniques("Population loss from nuclear attacks -[]%")) { + populationLoss *= 1 - unique.params[0].toFloat() / 100f + populationLossReduced = true + } + // + for (unique in city.getMatchingUniques("Population loss from nuclear attacks []% []")) { + if (!city.matchesFilter(unique.params[1])) continue + populationLoss *= unique.params[0].toPercent() populationLossReduced = true } if (city.population.population < 5 && !populationLossReduced) { @@ -647,8 +659,15 @@ object Battle { } else { var populationLoss = city.population.population * (0.6 + Random().nextFloat() * 0.2) var populationLossReduced = false - for (unique in city.civInfo.getMatchingUniques("Population loss from nuclear attacks -[]%")) { - populationLoss *= 1 - unique.params[0].toFloat() / 100f + // Deprecated since 3.15.11 + for (unique in city.getLocalMatchingUniques("Population loss from nuclear attacks -[]%")) { + populationLoss *= 1 - unique.params[0].toFloat() / 100f + populationLossReduced = true + } + // + for (unique in city.getMatchingUniques("Population loss from nuclear attacks []% []")) { + if (!city.matchesFilter(unique.params[1])) + populationLoss *= unique.params[0].toPercent() populationLossReduced = true } city.population.addPopulation(-populationLoss.toInt()) diff --git a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt index 1a9455887c..d0a3b8bc28 100644 --- a/core/src/com/unciv/logic/battle/MapUnitCombatant.kt +++ b/core/src/com/unciv/logic/battle/MapUnitCombatant.kt @@ -4,6 +4,7 @@ import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo import com.unciv.models.UncivSound +import com.unciv.models.ruleset.Unique import com.unciv.models.ruleset.unit.UnitType class MapUnitCombatant(val unit: MapUnit) : ICombatant { @@ -43,5 +44,6 @@ class MapUnitCombatant(val unit: MapUnit) : ICombatant { return unit.name+" of "+unit.civInfo.civName } + fun getMatchingUniques(uniqueTemplate: String): Sequence = unit.getMatchingUniques(uniqueTemplate) } \ No newline at end of file diff --git a/core/src/com/unciv/logic/city/CityInfo.kt b/core/src/com/unciv/logic/city/CityInfo.kt index 49bfaeffdb..74a0177670 100644 --- a/core/src/com/unciv/logic/city/CityInfo.kt +++ b/core/src/com/unciv/logic/city/CityInfo.kt @@ -141,7 +141,7 @@ class CityInfo { civInfo.policies.tryToAddPolicyBuildings() - for (unique in civInfo.getMatchingUniques("Gain a free [] []")) { + for (unique in getMatchingUniques("Gain a free [] []")) { val freeBuildingName = unique.params[0] if (matchesFilter(unique.params[1])) { if (!cityConstructions.isBuilt(freeBuildingName)) @@ -370,15 +370,15 @@ class CityInfo { } // Sweden UP - for (otherciv in civInfo.getKnownCivs()) { - if (!civInfo.getDiplomacyManager(otherciv) + for (otherCiv in civInfo.getKnownCivs()) { + if (!civInfo.getDiplomacyManager(otherCiv) .hasFlag(DiplomacyFlags.DeclarationOfFriendship) ) continue - for (ourunique in civInfo.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) - allGppPercentageBonus += ourunique.params[0].toInt() - for (theirunique in otherciv.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) - allGppPercentageBonus += theirunique.params[0].toInt() + for (ourUnique in civInfo.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) + allGppPercentageBonus += ourUnique.params[0].toInt() + for (theirUnique in otherCiv.getMatchingUniques("When declaring friendship, both parties gain a []% boost to great person generation")) + allGppPercentageBonus += theirUnique.params[0].toInt() } for (unitName in gppCounter.keys) diff --git a/core/src/com/unciv/logic/city/CityInfoConquestFunctions.kt b/core/src/com/unciv/logic/city/CityInfoConquestFunctions.kt index c0b8801249..6328c5d73b 100644 --- a/core/src/com/unciv/logic/city/CityInfoConquestFunctions.kt +++ b/core/src/com/unciv/logic/city/CityInfoConquestFunctions.kt @@ -181,7 +181,7 @@ class CityInfoConquestFunctions(val city: CityInfo){ .addModifier(DiplomaticModifiers.CapturedOurCities, respectForLiberatingOurCity) } else { //Liberating a city state gives a large amount of influence, and peace - foundingCiv.getDiplomacyManager(conqueringCiv).influence = 90f + foundingCiv.getDiplomacyManager(conqueringCiv).setInfluence(90f) if (foundingCiv.isAtWarWith(conqueringCiv)) { val tradeLogic = TradeLogic(foundingCiv, conqueringCiv) tradeLogic.currentTrade.ourOffers.add(TradeOffer(Constants.peaceTreaty, TradeType.Treaty)) diff --git a/core/src/com/unciv/logic/city/CityReligion.kt b/core/src/com/unciv/logic/city/CityReligion.kt index ce54a723fc..dc98b20aff 100644 --- a/core/src/com/unciv/logic/city/CityReligion.kt +++ b/core/src/com/unciv/logic/city/CityReligion.kt @@ -294,10 +294,7 @@ class CityInfoReligionManager { for (unique in cityInfo.getMatchingUniques("[]% Natural religion spread [] with []")) if (pressuredCity.matchesFilter(unique.params[1]) - && ( - cityInfo.civInfo.tech.isResearched(unique.params[2]) - || cityInfo.civInfo.policies.isAdopted(unique.params[2]) - ) + && cityInfo.civInfo.hasTechOrPolicy(unique.params[2]) ) pressure *= 1f + unique.params[0].toFloat() / 100f return pressure.toInt() diff --git a/core/src/com/unciv/logic/city/CityStats.kt b/core/src/com/unciv/logic/city/CityStats.kt index d01f74584a..6046581885 100644 --- a/core/src/com/unciv/logic/city/CityStats.kt +++ b/core/src/com/unciv/logic/city/CityStats.kt @@ -55,7 +55,7 @@ class CityStats(val cityInfo: CityInfo) { if (!cityInfo.isCapital() && cityInfo.isConnectedToCapital()) { val civInfo = cityInfo.civInfo stats.gold = civInfo.getCapital().population.population * 0.15f + cityInfo.population.population * 1.1f - 1 // Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5) - for (unique in civInfo.getMatchingUniques("[] from each Trade Route")) + for (unique in cityInfo.getMatchingUniques("[] from each Trade Route")) stats.add(unique.stats) if (civInfo.hasUnique("Gold from all trade routes +25%")) stats.gold *= 1.25f // Machu Picchu speciality } @@ -105,20 +105,7 @@ class CityStats(val cityInfo: CityInfo) { } private fun getStatsFromNationUnique(): Stats { - val stats = Stats() - - stats.add(getStatsFromUniques(cityInfo.civInfo.nation.uniqueObjects.asSequence())) - - if (cityInfo.civInfo.hasUnique("+2 Culture per turn from cities before discovering Steam Power") - && !cityInfo.civInfo.tech.isResearched("Steam Power")) - stats.culture += 2 - - for (unique in cityInfo.civInfo.getMatchingUniques("[] per turn from cities before []")) { - if (!cityInfo.civInfo.tech.isResearched(unique.params[1]) - && !cityInfo.civInfo.policies.adoptedPolicies.contains(unique.params[1])) - stats.add(unique.stats) - } - return stats + return getStatsFromUniques(cityInfo.civInfo.nation.uniqueObjects.asSequence()) } private fun getStatsFromCityStates(): Stats { @@ -140,8 +127,11 @@ class CityStats(val cityInfo: CityInfo) { return stats } - for (bonus in if (otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() == RelationshipLevel.Friend) - eraInfo.friendBonus[otherCiv.cityStateType.name]!! else eraInfo.allyBonus[otherCiv.cityStateType.name]!!) { + for (bonus in + if (otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() == RelationshipLevel.Friend) + eraInfo.friendBonus[otherCiv.cityStateType.name]!! + else eraInfo.allyBonus[otherCiv.cityStateType.name]!! + ) { if (bonus.getPlaceholderText() == "Provides [] [] []" && cityInfo.matchesFilter(bonus.getPlaceholderParameters()[2])) { stats.add(Stat.valueOf(bonus.getPlaceholderParameters()[1]), bonus.getPlaceholderParameters()[0].toFloat()) } @@ -200,8 +190,13 @@ class CityStats(val cityInfo: CityInfo) { val specialist = cityInfo.getRuleset().specialists[specialistName] ?: return Stats() val stats = specialist.clone() - for (unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist")) - stats.add(unique.stats) + // Deprecated since 3.16.11 + for (unique in cityInfo.civInfo.getMatchingUniques("[] from every specialist")) + stats.add(unique.stats) + // + for (unique in cityInfo.getMatchingUniques("[] from every specialist []")) + if (cityInfo.matchesFilter(unique.params[1])) + stats.add(unique.stats) for (unique in cityInfo.civInfo.getMatchingUniques("[] from every []")) if (unique.params[1] == specialistName) stats.add(unique.stats) @@ -240,6 +235,14 @@ class CityStats(val cityInfo: CityInfo) { // "[stats] if this city has at least [amount] specialists" if (unique.placeholderText == "[] if this city has at least [] specialists" && cityInfo.population.getNumberOfSpecialists() >= unique.params[1].toInt()) stats.add(unique.stats) + + // Deprecated since a very long time ago, moved here from another code section + if (unique.placeholderText == "+2 Culture per turn from cities before discovering Steam Power" && !cityInfo.civInfo.tech.isResearched("Steam Power")) + stats.culture += 2 + // + + if (unique.placeholderText == "[] per turn from cities before []" && !cityInfo.civInfo.hasTechOrPolicy(unique.params[1])) + stats.add(unique.stats) } return stats @@ -371,8 +374,14 @@ class CityStats(val cityInfo: CityInfo) { var unhappinessFromCitizens = cityInfo.population.population.toFloat() var unhappinessFromSpecialists = cityInfo.population.getNumberOfSpecialists().toFloat() - for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness")) { - unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f) + // Deprecated since 3.16.11 + for (unique in civInfo.getMatchingUniques("Specialists only produce []% of normal unhappiness")) + unhappinessFromSpecialists *= (1f - unique.params[0].toFloat() / 100f) + // + + for (unique in cityInfo.getMatchingUniques("[]% unhappiness from specialists []")) { + if (cityInfo.matchesFilter(unique.params[1])) + unhappinessFromSpecialists *= unique.params[0].toPercent() } unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists().toFloat() - unhappinessFromSpecialists @@ -382,12 +391,18 @@ class CityStats(val cityInfo: CityInfo) { else if (hasExtraAnnexUnhappiness()) unhappinessFromCitizens *= 2f - for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []%")) - unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100) - - for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []% []")) - if (cityInfo.matchesFilter(unique.params[1])) + // Deprecated since 3.16.11 + for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []%")) unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100) + + for (unique in civInfo.getMatchingUniques("Unhappiness from population decreased by []% []")) + if (cityInfo.matchesFilter(unique.params[1])) + unhappinessFromCitizens *= (1 - unique.params[0].toFloat() / 100) + // + + for (unique in cityInfo.getMatchingUniques("[]% unhappiness from population []")) + if (cityInfo.matchesFilter(unique.params[1])) + unhappinessFromCitizens *= unique.params[0].toPercent() newHappinessList["Population"] = -unhappinessFromCitizens * unhappinessModifier @@ -563,8 +578,14 @@ class CityStats(val cityInfo: CityInfo) { foodEaten = cityInfo.population.population.toFloat() * 2 var foodEatenBySpecialists = 2f * cityInfo.population.getNumberOfSpecialists() - for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists")) - foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f + // Deprecated since 3.16.11 + for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists")) + foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f + // + + for (unique in cityInfo.getMatchingUniques("[]% food consumption by specialists []")) + if (cityInfo.matchesFilter(unique.params[1])) + foodEatenBySpecialists *= unique.params[0].toPercent() foodEaten -= 2f * cityInfo.population.getNumberOfSpecialists() - foodEatenBySpecialists } diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index aaf8e342af..a8ee9d1da2 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -1,6 +1,7 @@ package com.unciv.logic.civilization import com.unciv.logic.civilization.diplomacy.RelationshipLevel +import com.unciv.logic.map.RoadStatus import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS import com.unciv.models.ruleset.BeliefType import com.unciv.models.ruleset.Policy @@ -60,12 +61,13 @@ class CivInfoStats(val civInfo: CivilizationInfo) { // just to go over them once is a waste of memory - there are low-end phones who don't have much ram val ignoredTileTypes = civInfo.getMatchingUniques("No Maintenance costs for improvements in [] tiles") - .map { it.params[0] }.toHashSet() // needs to be .toHashSet()ed, + .map { it.params[0] }.toHashSet() // needs to be .toHashSet()ed, // Because we go over every tile in every city and check if it's in this list, which can get real heavy. for (city in civInfo.cities) { for (tile in city.getTiles()) { if (tile.isCityCenter()) continue + if (tile.roadStatus == RoadStatus.None) continue // Cheap checks before pricy checks if (ignoredTileTypes.any { tile.matchesFilter(it, civInfo) }) continue transportationUpkeep += tile.roadStatus.upkeep @@ -185,20 +187,21 @@ class CivInfoStats(val civInfo: CivilizationInfo) { val ownedLuxuries = civInfo.getCivResources().map { it.resource }.filter { it.resourceType == ResourceType.Luxury } - statMap["Luxury resources"] = civInfo.getCivResources().map { it.resource } - .count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury + statMap["Luxury resources"] = civInfo.getCivResources() + .map { it.resource } + .count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury - val happinessBonusForCityStateProvidedLuxuries = + val happinessBonusForCityStateProvidedLuxuries = civInfo.getMatchingUniques("Happiness from Luxury Resources gifted by City-States increased by []%") - .map { it.params[0].toFloat() / 100f }.sum() + .sumBy { it.params[0].toInt() } / 100f - val luxuriesProvidedByCityStates = - civInfo.getKnownCivs().asSequence() - .filter { it.isCityState() && it.getAllyCiv() == civInfo.civName } - .flatMap { it.getCivResources().map { res -> res.resource } } - .distinct().count { it.resourceType === ResourceType.Luxury } + val luxuriesProvidedByCityStates = civInfo.getKnownCivs().asSequence() + .filter { it.isCityState() && it.getAllyCiv() == civInfo.civName } + .flatMap { it.getCivResources().map { res -> res.resource } } + .distinct() + .count { it.resourceType === ResourceType.Luxury && ownedLuxuries.contains(it) } - statMap["City-State Luxuries"] = happinessBonusForCityStateProvidedLuxuries * luxuriesProvidedByCityStates * happinessPerUniqueLuxury + statMap["City-State Luxuries"] = happinessPerUniqueLuxury * luxuriesProvidedByCityStates * happinessBonusForCityStateProvidedLuxuries val luxuriesAllOfWhichAreTradedAway = civInfo.detailedCivResources .filter { it.amount < 0 && it.resource.resourceType == ResourceType.Luxury @@ -256,7 +259,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { for (otherCiv in civInfo.getKnownCivs()) { if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo).relationshipLevel() >= RelationshipLevel.Friend) { val eraInfo = civInfo.getEraObject() - val relevantbonuses = + val relevantBonuses = when { eraInfo == null -> null otherCiv.getDiplomacyManager(civInfo).relationshipLevel() == RelationshipLevel.Friend -> @@ -265,8 +268,8 @@ class CivInfoStats(val civInfo: CivilizationInfo) { eraInfo.allyBonus[otherCiv.cityStateType.name] } - if (relevantbonuses != null) { - for (bonus in relevantbonuses) { + if (relevantBonuses != null) { + for (bonus in relevantBonuses) { if (bonus.getPlaceholderText() == "Provides [] Happiness") { if (statMap.containsKey("City-States")) statMap["City-States"] = statMap["City-States"]!! + bonus.getPlaceholderParameters()[0].toFloat() diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 73e30d5c2e..8a62b8b672 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -510,6 +510,9 @@ class CivilizationInfo { return if (!gameInfo.hasReligionEnabled()) greatPeople.filter { !it.uniques.contains("Great Person - [Faith]")}.toHashSet() else greatPeople.toHashSet() } + + fun hasTechOrPolicy(techOrPolicyName: String) = + tech.isResearched(techOrPolicyName) || policies.isAdopted(techOrPolicyName) //endregion @@ -881,8 +884,7 @@ class CivilizationInfo { if (!cityState.isCityState()) throw Exception("You can only gain influence with City-States!") addGold(-giftAmount) cityState.addGold(giftAmount) - cityState.getDiplomacyManager(this).influence += influenceGainedByGift(giftAmount) - cityState.updateAllyCivForCityState() + cityState.getDiplomacyManager(this).addInfluence(influenceGainedByGift(giftAmount).toFloat()) updateStatsForNextTurn() } @@ -940,20 +942,20 @@ class CivilizationInfo { } fun addProtectorCiv(otherCiv: CivilizationInfo) { - if(!this.isCityState() or !otherCiv.isMajorCiv() or otherCiv.isDefeated()) return - if(!knows(otherCiv) or isAtWarWith(otherCiv)) return //Exception + if (!isCityState() || !otherCiv.isMajorCiv() || otherCiv.isDefeated()) return + if (!knows(otherCiv) || isAtWarWith(otherCiv)) return //Exception val diplomacy = getDiplomacyManager(otherCiv.civName) diplomacy.diplomaticStatus = DiplomaticStatus.Protector } fun removeProtectorCiv(otherCiv: CivilizationInfo) { - if(!this.isCityState() or !otherCiv.isMajorCiv() or otherCiv.isDefeated()) return - if(!knows(otherCiv) or isAtWarWith(otherCiv)) return //Exception + if (!isCityState() || !otherCiv.isMajorCiv() || otherCiv.isDefeated()) return + if (!knows(otherCiv) || isAtWarWith(otherCiv)) return //Exception val diplomacy = getDiplomacyManager(otherCiv.civName) diplomacy.diplomaticStatus = DiplomaticStatus.Peace - diplomacy.influence -= 20 + diplomacy.addInfluence(-20f) } fun updateAllyCivForCityState() { @@ -1136,9 +1138,8 @@ class CivilizationInfo { if (!cityState.isCityState()) throw Exception("You can only demand gold from City-States!") val goldAmount = goldGainedByTribute() addGold(goldAmount) - cityState.getDiplomacyManager(this).influence -= 15 + cityState.getDiplomacyManager(this).addInfluence(-15f) cityState.addFlag(CivFlags.RecentlyBullied.name, 20) - cityState.updateAllyCivForCityState() updateStatsForNextTurn() } @@ -1153,9 +1154,8 @@ class CivilizationInfo { if (buildableWorkerLikeUnits.isEmpty()) return // Bad luck? placeUnitNearTile(cityState.getCapital().location, buildableWorkerLikeUnits.keys.random()) - cityState.getDiplomacyManager(this).influence -= 50 + cityState.getDiplomacyManager(this).addInfluence(-50f) cityState.addFlag(CivFlags.RecentlyBullied.name, 20) - cityState.updateAllyCivForCityState() } fun canGiveStat(statType: Stat): Boolean { diff --git a/core/src/com/unciv/logic/civilization/QuestManager.kt b/core/src/com/unciv/logic/civilization/QuestManager.kt index fc92d13008..8aa50dfbcd 100644 --- a/core/src/com/unciv/logic/civilization/QuestManager.kt +++ b/core/src/com/unciv/logic/civilization/QuestManager.kt @@ -343,7 +343,7 @@ class QuestManager { val rewardInfluence = civInfo.gameInfo.ruleSet.quests[assignedQuest.questName]!!.influece val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) - civInfo.getDiplomacyManager(assignedQuest.assignee).influence += rewardInfluence + civInfo.getDiplomacyManager(assignedQuest.assignee).addInfluence(rewardInfluence) if (rewardInfluence > 0) assignee.addNotification( "[${civInfo.civName}] rewarded you with [${rewardInfluence.toInt()}] influence for completing the [${assignedQuest.questName}] quest.", diff --git a/core/src/com/unciv/logic/civilization/ReligionManager.kt b/core/src/com/unciv/logic/civilization/ReligionManager.kt index a278f47bc2..a368dda5c0 100644 --- a/core/src/com/unciv/logic/civilization/ReligionManager.kt +++ b/core/src/com/unciv/logic/civilization/ReligionManager.kt @@ -6,6 +6,7 @@ import com.unciv.models.Religion import com.unciv.models.ruleset.Belief import com.unciv.models.ruleset.BeliefType import com.unciv.ui.pickerscreens.BeliefContainer +import com.unciv.ui.utils.toPercent import kotlin.random.Random class ReligionManager { @@ -110,7 +111,7 @@ class ReligionManager { civInfo.gameInfo.gameParameters.gameSpeed.modifier for (unique in civInfo.getMatchingUniques("[]% Faith cost of generating Great Prophet equivalents")) - faithCost *= 1f + unique.params[0].toFloat() / 100f + faithCost *= unique.params[0].toPercent() return faithCost.toInt() } diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index 82c07980b6..d50bf68c73 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -100,9 +100,7 @@ class DiplomacyManager() { /** For city-states. Influence is saved in the CITY STATE -> major civ Diplomacy, NOT in the major civ -> city state diplomacy. * Won't go below [MINIMUM_INFLUENCE]. Note this declaration leads to Major Civs getting MINIMUM_INFLUENCE serialized, but that is ignored. */ var influence = 0f - set(value) { - field = max(value, MINIMUM_INFLUENCE) - } + private set get() = if (civInfo.isAtWarWith(otherCiv())) MINIMUM_INFLUENCE else field /** Total of each turn Science during Research Agreement */ @@ -198,6 +196,15 @@ class DiplomacyManager() { else -> false } } + + fun addInfluence(amount: Float) { + setInfluence(influence + amount) + } + + fun setInfluence(amount: Float) { + influence = max(amount, MINIMUM_INFLUENCE) + civInfo.updateAllyCivForCityState() + } // To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different. fun getCityStateInfluenceRestingPoint(): Float { @@ -393,6 +400,7 @@ class DiplomacyManager() { val increment = getCityStateInfluenceRecovery() influence = min(restingPoint, influence + increment) } + civInfo.updateAllyCivForCityState() if (!civInfo.isDefeated()) { // don't display city state relationship notifications when the city state is currently defeated val civCapitalLocation = if (civInfo.cities.isNotEmpty()) civInfo.getCapital().location else null @@ -658,7 +666,7 @@ class DiplomacyManager() { thirdCiv.getDiplomacyManager(otherCiv).makePeace() // Other city states that are not our ally don't like the fact that we made peace with their enemy if (thirdCiv.getAllyCiv() != civInfo.civName && thirdCiv.isAtWarWith(otherCiv)) - thirdCiv.getDiplomacyManager(civInfo).influence -= 10 + thirdCiv.getDiplomacyManager(civInfo).addInfluence(-10f) } } diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index 860560902a..e16d58adce 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -168,9 +168,10 @@ class MapUnit { fun getTile(): TileInfo = currentTile fun getMaxMovement(): Int { - if (isEmbarked()) return getEmbarkedMovement() - - var movement = baseUnit.movement + var movement = + if (isEmbarked()) 2 + else baseUnit.movement + movement += getMatchingUniques("[] Movement").sumBy { it.params[0].toInt() } for (unique in civInfo.getMatchingUniques("+[] Movement for all [] units")) @@ -182,6 +183,13 @@ class MapUnit { ) movement += 1 + // Deprecated since 3.16.11 + if (isEmbarked()) { + movement += civInfo.getMatchingUniques("Increases embarked movement +1").count() + if (civInfo.hasUnique("+1 Movement for all embarked units")) movement += 1 + } + // + return movement } @@ -194,10 +202,11 @@ class MapUnit { fun getUniques(): ArrayList = tempUniques fun getMatchingUniques(placeholderText: String): Sequence = - tempUniques.asSequence().filter { it.placeholderText == placeholderText } + tempUniques.asSequence().filter { it.placeholderText == placeholderText } + + civInfo.getMatchingUniques(placeholderText) fun hasUnique(unique: String): Boolean { - return getUniques().any { it.placeholderText == unique } + return getUniques().any { it.placeholderText == unique } || civInfo.hasUnique(unique) } fun updateUniques() { @@ -341,7 +350,6 @@ class MapUnit { return range } - fun isEmbarked(): Boolean { if (!baseUnit.isLandUnit()) return false return currentTile.isWater @@ -357,13 +365,6 @@ class MapUnit { return false } - fun getEmbarkedMovement(): Int { - var movement = 2 - movement += civInfo.getMatchingUniques("Increases embarked movement +1").count() - if (civInfo.hasUnique("+1 Movement for all embarked units")) movement += 1 - return movement - } - fun getUnitToUpgradeTo(): BaseUnit { var unit = baseUnit() diff --git a/core/src/com/unciv/logic/map/TileMap.kt b/core/src/com/unciv/logic/map/TileMap.kt index 0511b68188..888158d134 100644 --- a/core/src/com/unciv/logic/map/TileMap.kt +++ b/core/src/com/unciv/logic/map/TileMap.kt @@ -392,7 +392,7 @@ class TileMap { unitName: String, civInfo: CivilizationInfo ): MapUnit? { - val unit = gameInfo.ruleSet.units[unitName]!!.getMapUnit(gameInfo.ruleSet) + val unit = gameInfo.ruleSet.units[unitName]!!.getMapUnit(civInfo) fun getPassableNeighbours(tileInfo: TileInfo): Set = tileInfo.neighbors.filter { unit.movement.canPassThrough(it) }.toSet() diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index 5c3d7b7c88..4de0658603 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -192,10 +192,8 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { val stats = percentStatBonus?.clone() ?: Stats() val civInfo = cityInfo?.civInfo ?: return stats // initial stats - val baseBuildingName = getBaseBuilding(civInfo.gameInfo.ruleSet).name - for (unique in civInfo.getMatchingUniques("+[]% [] from every []")) { - if (unique.params[2] == baseBuildingName) + if (matchesFilter(unique.params[2])) stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat()) } @@ -521,7 +519,7 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { val filter = unique.params[0] if (filter in civInfo.gameInfo.ruleSet.buildings) { if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) }) return unique.text // Wonder is not built - } else if (!civInfo.policies.adoptedPolicies.contains(filter)) return "Policy is not adopted" // this reason should not be displayed + } else if (!civInfo.policies.isAdopted(filter)) return "Policy is not adopted" // this reason should not be displayed } "Requires a [] in this city" -> { @@ -673,10 +671,6 @@ class Building : NamedStats(), INonPerpetualConstruction, ICivilopediaText { return false } - fun getBaseBuilding(ruleset: Ruleset): Building { - return if (replaces == null) this else ruleset.buildings[replaces!!]!! - } - fun getImprovement(ruleset: Ruleset): TileImprovement? { val improvementUnique = uniqueObjects .firstOrNull { it.placeholderText == "Creates a [] improvement on a specific tile" } diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 3037eaa95e..0981521814 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -192,11 +192,14 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText { return textList } - fun getMapUnit(ruleset: Ruleset): MapUnit { + fun getMapUnit(civInfo: CivilizationInfo): MapUnit { val unit = MapUnit() unit.name = name + unit.civInfo = civInfo - unit.setTransients(ruleset) // must be after setting name because it sets the baseUnit according to the name + // must be after setting name & civInfo because it sets the baseUnit according to the name + // and the civInfo is required for using `hasUnique` when determining its movement options + unit.setTransients(civInfo.gameInfo.ruleSet) return unit } @@ -326,15 +329,16 @@ class BaseUnit : INamed, INonPerpetualConstruction, ICivilopediaText { ) return "Disabled by setting" for (unique in uniqueObjects.filter { it.placeholderText == "Unlocked with []" }) - if (civInfo.tech.researchedTechnologies.none { it.era() == unique.params[0] || it.name == unique.params[0] } - && !civInfo.policies.isAdopted(unique.params[0])) - return unique.text + // ToDo: Clean this up when eras.json is required + if ((civInfo.gameInfo.ruleSet.getEraNumber(unique.params[0]) != -1 && civInfo.getEraNumber() >= civInfo.gameInfo.ruleSet.getEraNumber(unique.params[0])) + || civInfo.hasTechOrPolicy(unique.params[0]) + ) return unique.text for (unique in uniqueObjects.filter { it.placeholderText == "Requires []" }) { val filter = unique.params[0] if (!ignoreTechPolicyRequirements && filter in civInfo.gameInfo.ruleSet.buildings) { if (civInfo.cities.none { it.cityConstructions.containsBuildingOrEquivalent(filter) }) return unique.text // Wonder is not built - } else if (!ignoreTechPolicyRequirements && !civInfo.policies.adoptedPolicies.contains(filter)) return "Policy is not adopted" + } else if (!ignoreTechPolicyRequirements && !civInfo.policies.isAdopted(filter)) return "Policy is not adopted" } for ((resource, amount) in getResourceRequirements()) diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 78c3e7212a..4dbbb355f1 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -464,7 +464,7 @@ object UnitActions { "Can undertake a trade mission with City-State, giving a large sum of gold and [] Influence" -> { val canConductTradeMission = tile.owningCity?.civInfo?.isCityState() == true && tile.owningCity?.civInfo?.isAtWarWith(unit.civInfo) == false - val influenceEarned = unique.params[0].toInt() + val influenceEarned = unique.params[0].toFloat() actionList += UnitAction(UnitActionType.ConductTradeMission, action = { // http://civilization.wikia.com/wiki/Great_Merchant_(Civ5) @@ -472,7 +472,7 @@ object UnitActions { if (unit.civInfo.hasUnique("Double gold from Great Merchant trade missions")) goldEarned *= 2 unit.civInfo.addGold(goldEarned) - tile.owningCity!!.civInfo.getDiplomacyManager(unit.civInfo).influence += influenceEarned + tile.owningCity!!.civInfo.getDiplomacyManager(unit.civInfo).addInfluence(influenceEarned) unit.civInfo.addNotification("Your trade mission to [${tile.owningCity!!.civInfo}] has earned you [${goldEarned}] gold and [$influenceEarned] influence!", tile.owningCity!!.civInfo.civName, NotificationIcon.Gold, NotificationIcon.Culture) addStatsPerGreatPersonUsage(unit) @@ -553,7 +553,7 @@ object UnitActions { title = "Spread [${unit.religion!!}]", action = { val followersOfOtherReligions = city.religion.getFollowersOfOtherReligionsThan(unit.religion!!) - for (unique in unit.civInfo.getMatchingUniques("When spreading religion to a city, gain [] times the amount of followers of other religions as []")) { + for (unique in unit.getMatchingUniques("When spreading religion to a city, gain [] times the amount of followers of other religions as []")) { unit.civInfo.addStat(Stat.valueOf(unique.params[1]), followersOfOtherReligions * unique.params[0].toInt()) } city.religion.addPressure(unit.religion!!, unit.getPressureAddedFromSpread()) @@ -751,14 +751,12 @@ object UnitActions { // We need to be in another civs territory. if (recipient == null || recipient.isCurrentPlayer()) return null - // City States only take military units (and GPs for certain civs) + // City States only take military units (and units specifically allowed by uniques) if (recipient.isCityState()) { - if (unit.isGreatPerson()) { - // Do we have a unique ability to gift GPs? - if (unit.civInfo.getMatchingUniques("Gain [] Influence with a [] gift to a City-State").none { - it.params[1] == "Great Person" } ) return null - } - else if (!unit.baseUnit().matchesFilter("Military")) return null + if (!unit.matchesFilter("Military") + && unit.getMatchingUniques("Gain [] Influence with a [] gift to a City-State") + .none { unit.matchesFilter(it.params[1]) } + ) return null } // If gifting to major civ they need to be friendly else if (!tile.isFriendlyTerritory(unit.civInfo)) return null @@ -769,15 +767,15 @@ object UnitActions { val giftAction = { if (recipient.isCityState()) { for (unique in unit.civInfo.getMatchingUniques("Gain [] Influence with a [] gift to a City-State")) { - if((unit.isGreatPerson() && unique.params[1] == "Great Person") - || unit.matchesFilter(unique.params[1])) { - recipient.getDiplomacyManager(unit.civInfo).influence += unique.params[0].toInt() - 5 + if ((unit.isGreatPerson() && unique.params[1] == "Great Person") + || unit.matchesFilter(unique.params[1]) + ) { + recipient.getDiplomacyManager(unit.civInfo).addInfluence(unique.params[0].toFloat() - 5f) + break } } - recipient.getDiplomacyManager(unit.civInfo).influence += 5 - - recipient.updateAllyCivForCityState() + recipient.getDiplomacyManager(unit.civInfo).addInfluence(5f) } else recipient.getDiplomacyManager(unit.civInfo).addModifier(DiplomaticModifiers.GaveUsUnits, 5f)