Created Patronage policy branch (#4186)
* Created Patronage policy branch -- draft * Patronage branch is now functional * Added images for the policies * Temporarily bandaged backwards compatability, added incompatabilities * Implemented recommended changes * Fixed acquirement of 'patronage complete' not being saved * Reverted change I was unhappy with * Implemented requested changes * Fixed build errors * Implemented recommended changes * City States can now give any great person, including unique ones, conform Ravignirs tests
BIN
android/Images/PolicyIcons/Aesthetics.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
android/Images/PolicyIcons/Cultural Diplomacy.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
android/Images/PolicyIcons/Educated Elite.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
android/Images/PolicyIcons/Philantropy.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
android/Images/PolicyIcons/Scholasticism.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 988 KiB After Width: | Height: | Size: 998 KiB |
@ -135,7 +135,7 @@
|
||||
},{
|
||||
"name": "Piety",
|
||||
"era": "Classical era",
|
||||
"uniques": ["+[15]% Production when constructing [Culture] buildings"],
|
||||
"uniques": ["+[15]% Production when constructing [Culture] buildings", "Incompatible with [Rationalism]"],
|
||||
"policies": [
|
||||
{
|
||||
"name": "Organized Religion",
|
||||
@ -177,8 +177,15 @@
|
||||
"uniques": ["Culture cost of adopting new Policies reduced by [10]%"]
|
||||
}
|
||||
]
|
||||
},/*{
|
||||
"name": "Patronage",
|
||||
},
|
||||
{
|
||||
"name": "Patronage ",
|
||||
// Yes, there is a space behind this word, and yes, this is necessary
|
||||
// This is, because at the time of writing there existed another policy called 'Patronage' that was recently deprecated
|
||||
// It would, however, still be possible for save-files to contain this policy
|
||||
// Therefore, we had to differentiate between these two, and this was the least intrusive way to do so
|
||||
// NOTE: If you remove the space here, also remove the extra space between 'patronage' and 'complete' in the 'patronage complete' policy.
|
||||
// Otherwise, weird stuff will happen.
|
||||
"era": "Classical era",
|
||||
"uniques": ["City-State Influence degrades [25]% slower"],
|
||||
"policies": [
|
||||
@ -196,14 +203,15 @@
|
||||
},
|
||||
{
|
||||
"name": "Scholasticism",
|
||||
"uniques":["Allied City-States provide Science equal to [25]% of what they produce for themselves"],
|
||||
"uniques":["Allied City-States provide [Science] equal to [25]% of what they produce for themselves"],
|
||||
"requires": ["Philantropy"],
|
||||
"row": 2,
|
||||
"column": 2
|
||||
},
|
||||
{
|
||||
"name": "Cultural Diplomacy",
|
||||
"uniques": ["Quantity of Resources gifted by City-States increased by [100]%"],
|
||||
"uniques": ["Quantity of Resources gifted by City-States increased by [100]%",
|
||||
"Happiness from Luxury Resources gifted by City-States increased by [50]%"],
|
||||
"requires": ["Scholasticism"],
|
||||
"row": 3,
|
||||
"column": 2
|
||||
@ -211,14 +219,19 @@
|
||||
{
|
||||
"name": "Educated Elite",
|
||||
"requires": ["Scholasticism","Aesthetics"],
|
||||
"uniques": ["Allied City-States will occasionally gift Great People"],
|
||||
"row": 3,
|
||||
"column": 4
|
||||
},
|
||||
{
|
||||
"name": "Patronage Complete"
|
||||
}
|
||||
"name": "Patronage Complete",
|
||||
// This extra space is intentional, see above.
|
||||
"uniques": ["Influence of all other civilizations with all city-states degrades [33]% faster",
|
||||
"Triggers the following global alert: [Our influence with City-States has started dropping faster!]"]
|
||||
// This triggers a global alert in the G&K game also, based on my memory of playing it
|
||||
}
|
||||
]
|
||||
},*/
|
||||
},
|
||||
{
|
||||
"name": "Commerce",
|
||||
"uniques": ["+[25]% [Gold] [in capital]"],
|
||||
@ -269,7 +282,7 @@
|
||||
{
|
||||
"name": "Rationalism",
|
||||
"era": "Renaissance era",
|
||||
"uniques": ["+[15]% [Science] while the empire is happy"],
|
||||
"uniques": ["+[15]% [Science] while the empire is happy", "Incompatible with [Piety]"],
|
||||
"policies": [
|
||||
{
|
||||
"name": "Secularism",
|
||||
|
@ -483,6 +483,9 @@ Clearing a [forest] has created [amount] Production for [cityName] =
|
||||
The resistance in [cityName] has ended! =
|
||||
Our [name] took [tileDamage] tile damage and was destroyed =
|
||||
Our [name] took [tileDamage] tile damage =
|
||||
[civName] has adopted the [policyName] policy =
|
||||
An unknown civilization has adopted the [policyName] policy =
|
||||
Our influence with City-States has started dropping faster! =
|
||||
|
||||
# World Screen UI
|
||||
|
||||
|
@ -103,13 +103,26 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
statMap.add("City-States", cultureBonus)
|
||||
}
|
||||
|
||||
|
||||
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() >= RelationshipLevel.Ally) {
|
||||
val sciencePercentage = civInfo
|
||||
.getMatchingUniques("Allied City-States provide Science equal to []% of what they produce for themselves")
|
||||
.sumBy { it.params[0].toInt() }
|
||||
statMap.add("City-States", Stats().apply { science = otherCiv.statsForNextTurn.science * (sciencePercentage / 100f) })
|
||||
}
|
||||
if (otherCiv.isCityState())
|
||||
for (unique in civInfo.getMatchingUniques("Allied City-States provide [] equal to []% of what they produce for themselves")) {
|
||||
if (otherCiv.diplomacy[civInfo.civName]!!.matchesCityStateRelationshipFilter(unique.params[0]) && otherCiv.cities.isNotEmpty()) {
|
||||
statMap.add(
|
||||
"City-States",
|
||||
Stats().add(
|
||||
Stat.valueOf(unique.params[1]),
|
||||
otherCiv.statsForNextTurn.get(Stat.valueOf(unique.params[1])) * unique.params[2].toFloat() / 100f
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
// Deprecated since 3.15.1
|
||||
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() >= RelationshipLevel.Ally) {
|
||||
val sciencePercentage = civInfo
|
||||
.getMatchingUniques("Allied City-States provide Science equal to []% of what they produce for themselves")
|
||||
.sumBy { it.params[0].toInt() }
|
||||
statMap.add("City-States", Stats().apply { science = otherCiv.statsForNextTurn.science * (sciencePercentage / 100f) })
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
statMap["Transportation upkeep"] = Stats().apply { gold = -getTransportationUpkeep().toFloat() }
|
||||
@ -147,9 +160,19 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
||||
for (unique in civInfo.getMatchingUniques("+1 happiness from each type of luxury resource"))
|
||||
happinessPerUniqueLuxury += 1
|
||||
//
|
||||
|
||||
statMap["Luxury resources"] = civInfo.getCivResources().map { it.resource }
|
||||
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury
|
||||
|
||||
val happinessBonusForCityStateProvidedLuxuries =
|
||||
civInfo.getMatchingUniques("Happiness from Luxury Resources gifted by City-States increased by []%")
|
||||
.map { it.params[0].toFloat() / 100f }.sum()
|
||||
|
||||
val luxuriesProvidedByCityStates =
|
||||
civInfo.getKnownCivs().filter { it.isCityState() && it.getAllyCiv() == civInfo.civName }
|
||||
.map { it.getCivResources().map { res -> res.resource } }.flatten().count { it.resourceType === ResourceType.Luxury }
|
||||
|
||||
statMap["City-State Luxuries"] = happinessBonusForCityStateProvidedLuxuries * luxuriesProvidedByCityStates * happinessPerUniqueLuxury
|
||||
|
||||
|
||||
for (city in civInfo.cities) {
|
||||
// There appears to be a concurrency problem? In concurrent thread in ConstructionsTable.getConstructionButtonDTOs
|
||||
|
@ -14,6 +14,7 @@ import com.unciv.logic.map.MapUnit
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.logic.trade.TradeEvaluation
|
||||
import com.unciv.logic.trade.TradeRequest
|
||||
import com.unciv.models.metadata.GameSpeed
|
||||
import com.unciv.models.ruleset.*
|
||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
@ -27,6 +28,7 @@ import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.min
|
||||
|
||||
class CivilizationInfo {
|
||||
|
||||
@ -93,7 +95,7 @@ class CivilizationInfo {
|
||||
|
||||
/** See DiplomacyManager.flagsCountdown to why not eEnum */
|
||||
private var flagsCountdown = HashMap<String, Int>()
|
||||
/** Arraylist instead of HashMap as there might be doubles
|
||||
/** Arraylist instead of HashMap as there might be doubles
|
||||
* Pairs of Uniques and the amount of turns they are still active
|
||||
* If the counter reaches 0 at the end of a turn, it is removed immediately
|
||||
*/
|
||||
@ -227,7 +229,7 @@ class CivilizationInfo {
|
||||
if (resource.resourceType == ResourceType.Strategic) {
|
||||
resourceModifier *= 1f + getMatchingUniques("Quantity of strategic resources produced by the empire +[]%")
|
||||
.map { it.params[0].toFloat() / 100f }.sum()
|
||||
|
||||
|
||||
// Deprecated since 3.15
|
||||
if (hasUnique("Quantity of strategic resources produced by the empire increased by 100%")) {
|
||||
resourceModifier *= 2f
|
||||
@ -386,7 +388,7 @@ class CivilizationInfo {
|
||||
* Returns a civilization caption suitable for greetings including player type info:
|
||||
* Like "Milan" if the nation is a city state, "Caesar of Rome" otherwise, with an added
|
||||
* " (AI)", " (Human - Hotseat)", or " (Human - Multiplayer)" if the game is multiplayer.
|
||||
*/
|
||||
*/
|
||||
fun getLeaderDisplayName(): String {
|
||||
val severalHumans = gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
|
||||
val online = gameInfo.gameParameters.isOnlineMultiplayer
|
||||
@ -510,6 +512,7 @@ class CivilizationInfo {
|
||||
|
||||
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
|
||||
transients().updateCitiesConnectedToCapital()
|
||||
turnStartFlags()
|
||||
for (city in cities) city.startTurn()
|
||||
|
||||
for (unit in getCivUnits()) unit.startTurn()
|
||||
@ -561,7 +564,7 @@ class CivilizationInfo {
|
||||
for (city in cities.toList()) { // a city can be removed while iterating (if it's being razed) so we need to iterate over a copy
|
||||
city.endTurn()
|
||||
}
|
||||
|
||||
|
||||
// Update turn counter for temporary uniques
|
||||
for (unique in temporaryUniques.toList()) {
|
||||
temporaryUniques.remove(unique)
|
||||
@ -575,8 +578,34 @@ class CivilizationInfo {
|
||||
updateHasActiveGreatWall()
|
||||
}
|
||||
|
||||
private fun turnStartFlags() {
|
||||
// This function may be too abstracted for what it currently does (only managing a single flag)
|
||||
// But eh, it works.
|
||||
for (flag in flagsCountdown.keys.toList()) {
|
||||
|
||||
if (flag == CivFlags.cityStateGreatPersonGift.name) {
|
||||
val cityStateAllies = getKnownCivs().filter { it.isCityState() && it.getAllyCiv() == civName }.count()
|
||||
|
||||
if (cityStateAllies >= 1) flagsCountdown[flag] = flagsCountdown[flag]!! - 1
|
||||
|
||||
if (flagsCountdown[flag]!! < min(cityStateAllies, 10)) {
|
||||
gainGreatPersonFromCityState()
|
||||
flagsCountdown[flag] = turnsForGreatPersonFromCityState()
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (flagsCountdown[flag]!! > 0)
|
||||
flagsCountdown[flag] = flagsCountdown[flag]!! - 1
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun addFlag(flag: String, count: Int) { flagsCountdown[flag] = count }
|
||||
|
||||
/** Modify gold by a given amount making sure it does neither overflow nor underflow.
|
||||
* @param delta the amount to add (can be negative)
|
||||
* @param delta the amount to add (can be negative)
|
||||
*/
|
||||
fun addGold(delta: Int) {
|
||||
// not using Long.coerceIn - this stays in 32 bits
|
||||
@ -586,7 +615,7 @@ class CivilizationInfo {
|
||||
else -> gold + delta
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addStat(stat: Stat, amount: Int) {
|
||||
when (stat) {
|
||||
Stat.Culture -> policies.addCulture(amount)
|
||||
@ -673,8 +702,8 @@ class CivilizationInfo {
|
||||
|
||||
fun influenceGainedByGift(cityState: CivilizationInfo, giftAmount: Int): Int {
|
||||
var influenceGained = giftAmount / 10f
|
||||
for (unique in cityState.getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
||||
influenceGained *= (100f + unique.params[0].toInt()) / 100
|
||||
for (unique in getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
||||
influenceGained *= 1f + unique.params[0].toFloat() / 100f
|
||||
return influenceGained.toInt()
|
||||
}
|
||||
|
||||
@ -713,6 +742,22 @@ class CivilizationInfo {
|
||||
addNotification("[${otherCiv.civName}] gave us a [${militaryUnit.name}] as gift near [${city.name}]!", locations, otherCiv.civName, militaryUnit.name)
|
||||
}
|
||||
|
||||
/** Gain a random great person from a random city state */
|
||||
private fun gainGreatPersonFromCityState() {
|
||||
val givingCityState = getKnownCivs().filter { it.isCityState() && it.getAllyCiv() == civName}.random()
|
||||
val giftedUnit = gameInfo.ruleSet.units.values.filter { it.isGreatPerson() }.random()
|
||||
val cities = NextTurnAutomation.getClosestCities(this, givingCityState)
|
||||
val placedUnit = placeUnitNearTile(cities.city1.location, giftedUnit.name)
|
||||
if (placedUnit == null) return
|
||||
val locations = LocationAction(listOf(placedUnit.getTile().position, cities.city2.location))
|
||||
addNotification( "[${givingCityState.civName}] gave us a [${giftedUnit.name}] as a gift!", locations, givingCityState.civName, giftedUnit.name)
|
||||
}
|
||||
|
||||
fun turnsForGreatPersonFromCityState(): Int = (40 + -2 + Random().nextInt(5)) * gameInfo.gameParameters.gameSpeed.modifier.toInt()
|
||||
// There seems to be some randomness in the amount of turns between receiving each great person,
|
||||
// but I have no idea what the actual lower and upper bound are, so this is just an approximation
|
||||
|
||||
|
||||
fun getAllyCiv() = allyCivName
|
||||
|
||||
fun getProtectorCivs() : List<CivilizationInfo> {
|
||||
@ -786,3 +831,7 @@ class CivilizationInfoPreview {
|
||||
var playerId = ""
|
||||
fun isPlayerCivilization() = playerType == PlayerType.Human
|
||||
}
|
||||
|
||||
enum class CivFlags {
|
||||
cityStateGreatPersonGift
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import com.unciv.models.ruleset.Policy
|
||||
import com.unciv.models.ruleset.Unique
|
||||
import com.unciv.models.ruleset.UniqueMap
|
||||
import com.unciv.models.ruleset.UniqueTriggerActivation
|
||||
import com.unciv.models.translations.equalsPlaceholderText
|
||||
import com.unciv.models.translations.getPlaceholderParameters
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
@ -168,6 +170,14 @@ class PolicyManager {
|
||||
}
|
||||
}
|
||||
|
||||
for (unique in policy.uniques) {
|
||||
if (unique == "Triggers a global alert") {
|
||||
triggerGlobalAlerts(policy)
|
||||
} else if (unique.equalsPlaceholderText("Triggers the following global alert: []")) {
|
||||
triggerGlobalAlerts(policy, unique.getPlaceholderParameters()[0])
|
||||
}
|
||||
}
|
||||
|
||||
for (unique in policy.uniqueObjects)
|
||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||
|
||||
@ -238,4 +248,21 @@ class PolicyManager {
|
||||
}
|
||||
return freeBuildings
|
||||
}
|
||||
|
||||
private fun triggerGlobalAlerts(policy: Policy, extraNotificationText: String = "") {
|
||||
var extraNotificationTextCopy = extraNotificationText
|
||||
if (extraNotificationText != "") {
|
||||
extraNotificationTextCopy = "\n${extraNotificationText}"
|
||||
}
|
||||
for (civ in civInfo.gameInfo.civilizations) {
|
||||
if (civ == civInfo) continue
|
||||
val defaultNotificationText =
|
||||
if (civ.getKnownCivs().contains(civInfo)) {
|
||||
"[${civInfo.civName}] has adopted the [${policy.name}] policy"
|
||||
} else {
|
||||
"An unknown civilization has adopted the [${policy.name}] policy"
|
||||
}
|
||||
civ.addNotification("${defaultNotificationText}${extraNotificationTextCopy}", NotificationIcon.Culture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,13 +176,25 @@ class DiplomacyManager() {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun matchesCityStateRelationshipFilter(filter: String): Boolean {
|
||||
val relationshipLevel = relationshipLevel()
|
||||
return when (filter) {
|
||||
"Allied" -> relationshipLevel == RelationshipLevel.Ally
|
||||
"Friendly" -> relationshipLevel == RelationshipLevel.Friend
|
||||
"Enemy" -> relationshipLevel == RelationshipLevel.Enemy
|
||||
"Unforgiving" -> relationshipLevel == RelationshipLevel.Unforgivable
|
||||
"Neutral" -> relationshipLevel == RelationshipLevel.Neutral
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
// To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different.
|
||||
fun getCityStateInfluenceRestingPoint(): Float {
|
||||
var restingPoint = 0f
|
||||
for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []"))
|
||||
restingPoint += unique.params[0].toInt()
|
||||
if(diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5
|
||||
if (diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5
|
||||
return restingPoint
|
||||
}
|
||||
|
||||
@ -203,7 +215,13 @@ class DiplomacyManager() {
|
||||
}
|
||||
|
||||
for (unique in otherCiv().getMatchingUniques("City-State Influence degrades []% slower"))
|
||||
modifier *= (100f - unique.params[0].toInt()) / 100
|
||||
modifier *= 1f - unique.params[0].toFloat() / 100f
|
||||
|
||||
for (civ in civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it != otherCiv()}) {
|
||||
for (unique in civ.getMatchingUniques("Influence of all other civilizations with all city-states degrades []% faster")) {
|
||||
modifier *= 1f + unique.params[0].toFloat() / 100f
|
||||
}
|
||||
}
|
||||
|
||||
return max(0f, decrement) * max(0f, modifier)
|
||||
}
|
||||
@ -243,7 +261,7 @@ class DiplomacyManager() {
|
||||
return goldPerTurnForUs
|
||||
}
|
||||
|
||||
fun sciencefromResearchAgreement() {
|
||||
fun scienceFromResearchAgreement() {
|
||||
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
||||
val scienceFromResearchAgreement = min(totalOfScienceDuringRA, otherCivDiplomacy().totalOfScienceDuringRA)
|
||||
civInfo.tech.scienceFromResearchAgreements += scienceFromResearchAgreement
|
||||
@ -288,7 +306,7 @@ class DiplomacyManager() {
|
||||
//endregion
|
||||
|
||||
//region state-changing functions
|
||||
fun removeUntenebleTrades() {
|
||||
fun removeUntenableTrades() {
|
||||
|
||||
for (trade in trades.toList()) {
|
||||
|
||||
@ -329,7 +347,7 @@ class DiplomacyManager() {
|
||||
|
||||
fun nextTurn() {
|
||||
nextTurnTrades()
|
||||
removeUntenebleTrades()
|
||||
removeUntenableTrades()
|
||||
updateHasOpenBorders()
|
||||
nextTurnDiplomaticModifiers()
|
||||
nextTurnFlags()
|
||||
@ -403,7 +421,7 @@ class DiplomacyManager() {
|
||||
when (flag) {
|
||||
DiplomacyFlags.ResearchAgreement.name -> {
|
||||
if (!otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement))
|
||||
sciencefromResearchAgreement()
|
||||
scienceFromResearchAgreement()
|
||||
}
|
||||
// This is confusingly named - in fact, the civ that has the flag set is the MAJOR civ
|
||||
DiplomacyFlags.ProvideMilitaryUnit.name -> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.models.ruleset
|
||||
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.civilization.CivFlags
|
||||
import com.unciv.logic.civilization.CivilizationInfo
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.getPlaceholderParameters
|
||||
@ -104,6 +105,23 @@ object UniqueTriggerActivation {
|
||||
unit.promotions.addPromotion(promotion, isFree = true)
|
||||
}
|
||||
}
|
||||
"Allied City-States will occasionally gift Great People" ->
|
||||
civInfo.addFlag(CivFlags.cityStateGreatPersonGift.name, civInfo.turnsForGreatPersonFromCityState() / 2)
|
||||
// The mechanics for granting great people are wonky, but basically the following happens:
|
||||
// Based on the game speed, a timer with some amount of turns is set, 40 on regular speed
|
||||
// Every turn, 1 is subtracted from this timer, as long as you have at least 1 city state ally
|
||||
// So no, the number of city-state allies does not matter for this. You have a global timer for all of them combined.
|
||||
// If the timer reaches the amount of city-state allies you have (or 10, whichever is lower), it is reset.
|
||||
// You will then receive a random great person from a random city-state you are allied to
|
||||
// The very first time after acquiring this policy, the timer is set to half of its normal value
|
||||
// This is the basics, and apart from this, there is some randomness in the exact turn count, but I don't know how much
|
||||
|
||||
// There is surprisingly little information findable online about this policy, and the civ 5 source files are
|
||||
// also quite though to search through, so this might all be incorrect.
|
||||
// For now this mechanic seems decent enough that this is fine.
|
||||
|
||||
// Note that the way this is implemented now, this unique does NOT stack
|
||||
// I could parametrize the [Allied], but eh.
|
||||
}
|
||||
}
|
||||
}
|
@ -320,6 +320,14 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
* [Religion](https://thenounproject.com/term/religion/1307794/) By Ben Avery for Free Religion
|
||||
* [Flame](https://thenounproject.com/term/flame/633228/) By Ian Shoobridge for Mandate Of Heaven
|
||||
|
||||
### Patronage
|
||||
|
||||
* Adapted from [Gold](https://thenounproject.com/term/gold/842351) by Aneeque Ahmed for Philantropy
|
||||
* [Ornament](https://thenounproject.com/term/ornament/3945298) by Tommy Suhartomo for Aesthetics
|
||||
* [Book Gift](https://thenounproject.com/term/book-gift/671626) by Wolf Böse for Scholasticism
|
||||
* [agreement](https://thenounproject.com/term/agreement/1828960) by RomanP for Cultural Diplomacy
|
||||
* [professor](https://thenounproject.com/term/professor/232239) by Andrew Doane for Educated Elite
|
||||
|
||||
### Commerce
|
||||
|
||||
* [Trade](https://thenounproject.com/term/trade/686718/) By Gregor Cresnar for Trade Unions
|
||||
|