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",
|
"name": "Piety",
|
||||||
"era": "Classical era",
|
"era": "Classical era",
|
||||||
"uniques": ["+[15]% Production when constructing [Culture] buildings"],
|
"uniques": ["+[15]% Production when constructing [Culture] buildings", "Incompatible with [Rationalism]"],
|
||||||
"policies": [
|
"policies": [
|
||||||
{
|
{
|
||||||
"name": "Organized Religion",
|
"name": "Organized Religion",
|
||||||
@ -177,8 +177,15 @@
|
|||||||
"uniques": ["Culture cost of adopting new Policies reduced by [10]%"]
|
"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",
|
"era": "Classical era",
|
||||||
"uniques": ["City-State Influence degrades [25]% slower"],
|
"uniques": ["City-State Influence degrades [25]% slower"],
|
||||||
"policies": [
|
"policies": [
|
||||||
@ -196,14 +203,15 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Scholasticism",
|
"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"],
|
"requires": ["Philantropy"],
|
||||||
"row": 2,
|
"row": 2,
|
||||||
"column": 2
|
"column": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Cultural Diplomacy",
|
"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"],
|
"requires": ["Scholasticism"],
|
||||||
"row": 3,
|
"row": 3,
|
||||||
"column": 2
|
"column": 2
|
||||||
@ -211,14 +219,19 @@
|
|||||||
{
|
{
|
||||||
"name": "Educated Elite",
|
"name": "Educated Elite",
|
||||||
"requires": ["Scholasticism","Aesthetics"],
|
"requires": ["Scholasticism","Aesthetics"],
|
||||||
|
"uniques": ["Allied City-States will occasionally gift Great People"],
|
||||||
"row": 3,
|
"row": 3,
|
||||||
"column": 4
|
"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",
|
"name": "Commerce",
|
||||||
"uniques": ["+[25]% [Gold] [in capital]"],
|
"uniques": ["+[25]% [Gold] [in capital]"],
|
||||||
@ -269,7 +282,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Rationalism",
|
"name": "Rationalism",
|
||||||
"era": "Renaissance era",
|
"era": "Renaissance era",
|
||||||
"uniques": ["+[15]% [Science] while the empire is happy"],
|
"uniques": ["+[15]% [Science] while the empire is happy", "Incompatible with [Piety]"],
|
||||||
"policies": [
|
"policies": [
|
||||||
{
|
{
|
||||||
"name": "Secularism",
|
"name": "Secularism",
|
||||||
|
@ -483,6 +483,9 @@ Clearing a [forest] has created [amount] Production for [cityName] =
|
|||||||
The resistance in [cityName] has ended! =
|
The resistance in [cityName] has ended! =
|
||||||
Our [name] took [tileDamage] tile damage and was destroyed =
|
Our [name] took [tileDamage] tile damage and was destroyed =
|
||||||
Our [name] took [tileDamage] tile damage =
|
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
|
# World Screen UI
|
||||||
|
|
||||||
|
@ -103,13 +103,26 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
|
|||||||
statMap.add("City-States", cultureBonus)
|
statMap.add("City-States", cultureBonus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (otherCiv.isCityState())
|
||||||
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() >= RelationshipLevel.Ally) {
|
for (unique in civInfo.getMatchingUniques("Allied City-States provide [] equal to []% of what they produce for themselves")) {
|
||||||
val sciencePercentage = civInfo
|
if (otherCiv.diplomacy[civInfo.civName]!!.matchesCityStateRelationshipFilter(unique.params[0]) && otherCiv.cities.isNotEmpty()) {
|
||||||
.getMatchingUniques("Allied City-States provide Science equal to []% of what they produce for themselves")
|
statMap.add(
|
||||||
.sumBy { it.params[0].toInt() }
|
"City-States",
|
||||||
statMap.add("City-States", Stats().apply { science = otherCiv.statsForNextTurn.science * (sciencePercentage / 100f) })
|
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() }
|
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"))
|
for (unique in civInfo.getMatchingUniques("+1 happiness from each type of luxury resource"))
|
||||||
happinessPerUniqueLuxury += 1
|
happinessPerUniqueLuxury += 1
|
||||||
//
|
//
|
||||||
|
|
||||||
statMap["Luxury resources"] = civInfo.getCivResources().map { it.resource }
|
statMap["Luxury resources"] = civInfo.getCivResources().map { it.resource }
|
||||||
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury
|
.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) {
|
for (city in civInfo.cities) {
|
||||||
// There appears to be a concurrency problem? In concurrent thread in ConstructionsTable.getConstructionButtonDTOs
|
// 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.map.TileInfo
|
||||||
import com.unciv.logic.trade.TradeEvaluation
|
import com.unciv.logic.trade.TradeEvaluation
|
||||||
import com.unciv.logic.trade.TradeRequest
|
import com.unciv.logic.trade.TradeRequest
|
||||||
|
import com.unciv.models.metadata.GameSpeed
|
||||||
import com.unciv.models.ruleset.*
|
import com.unciv.models.ruleset.*
|
||||||
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
import com.unciv.models.ruleset.tile.ResourceSupplyList
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
@ -27,6 +28,7 @@ import java.util.*
|
|||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
class CivilizationInfo {
|
class CivilizationInfo {
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ class CivilizationInfo {
|
|||||||
|
|
||||||
/** See DiplomacyManager.flagsCountdown to why not eEnum */
|
/** See DiplomacyManager.flagsCountdown to why not eEnum */
|
||||||
private var flagsCountdown = HashMap<String, Int>()
|
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
|
* 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
|
* 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) {
|
if (resource.resourceType == ResourceType.Strategic) {
|
||||||
resourceModifier *= 1f + getMatchingUniques("Quantity of strategic resources produced by the empire +[]%")
|
resourceModifier *= 1f + getMatchingUniques("Quantity of strategic resources produced by the empire +[]%")
|
||||||
.map { it.params[0].toFloat() / 100f }.sum()
|
.map { it.params[0].toFloat() / 100f }.sum()
|
||||||
|
|
||||||
// Deprecated since 3.15
|
// Deprecated since 3.15
|
||||||
if (hasUnique("Quantity of strategic resources produced by the empire increased by 100%")) {
|
if (hasUnique("Quantity of strategic resources produced by the empire increased by 100%")) {
|
||||||
resourceModifier *= 2f
|
resourceModifier *= 2f
|
||||||
@ -386,7 +388,7 @@ class CivilizationInfo {
|
|||||||
* Returns a civilization caption suitable for greetings including player type info:
|
* 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
|
* 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.
|
* " (AI)", " (Human - Hotseat)", or " (Human - Multiplayer)" if the game is multiplayer.
|
||||||
*/
|
*/
|
||||||
fun getLeaderDisplayName(): String {
|
fun getLeaderDisplayName(): String {
|
||||||
val severalHumans = gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
|
val severalHumans = gameInfo.civilizations.count { it.playerType == PlayerType.Human } > 1
|
||||||
val online = gameInfo.gameParameters.isOnlineMultiplayer
|
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
|
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
|
||||||
transients().updateCitiesConnectedToCapital()
|
transients().updateCitiesConnectedToCapital()
|
||||||
|
turnStartFlags()
|
||||||
for (city in cities) city.startTurn()
|
for (city in cities) city.startTurn()
|
||||||
|
|
||||||
for (unit in getCivUnits()) unit.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
|
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()
|
city.endTurn()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update turn counter for temporary uniques
|
// Update turn counter for temporary uniques
|
||||||
for (unique in temporaryUniques.toList()) {
|
for (unique in temporaryUniques.toList()) {
|
||||||
temporaryUniques.remove(unique)
|
temporaryUniques.remove(unique)
|
||||||
@ -575,8 +578,34 @@ class CivilizationInfo {
|
|||||||
updateHasActiveGreatWall()
|
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.
|
/** 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) {
|
fun addGold(delta: Int) {
|
||||||
// not using Long.coerceIn - this stays in 32 bits
|
// not using Long.coerceIn - this stays in 32 bits
|
||||||
@ -586,7 +615,7 @@ class CivilizationInfo {
|
|||||||
else -> gold + delta
|
else -> gold + delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addStat(stat: Stat, amount: Int) {
|
fun addStat(stat: Stat, amount: Int) {
|
||||||
when (stat) {
|
when (stat) {
|
||||||
Stat.Culture -> policies.addCulture(amount)
|
Stat.Culture -> policies.addCulture(amount)
|
||||||
@ -673,8 +702,8 @@ class CivilizationInfo {
|
|||||||
|
|
||||||
fun influenceGainedByGift(cityState: CivilizationInfo, giftAmount: Int): Int {
|
fun influenceGainedByGift(cityState: CivilizationInfo, giftAmount: Int): Int {
|
||||||
var influenceGained = giftAmount / 10f
|
var influenceGained = giftAmount / 10f
|
||||||
for (unique in cityState.getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
for (unique in getMatchingUniques("Gifts of Gold to City-States generate []% more Influence"))
|
||||||
influenceGained *= (100f + unique.params[0].toInt()) / 100
|
influenceGained *= 1f + unique.params[0].toFloat() / 100f
|
||||||
return influenceGained.toInt()
|
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)
|
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 getAllyCiv() = allyCivName
|
||||||
|
|
||||||
fun getProtectorCivs() : List<CivilizationInfo> {
|
fun getProtectorCivs() : List<CivilizationInfo> {
|
||||||
@ -786,3 +831,7 @@ class CivilizationInfoPreview {
|
|||||||
var playerId = ""
|
var playerId = ""
|
||||||
fun isPlayerCivilization() = playerType == PlayerType.Human
|
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.Unique
|
||||||
import com.unciv.models.ruleset.UniqueMap
|
import com.unciv.models.ruleset.UniqueMap
|
||||||
import com.unciv.models.ruleset.UniqueTriggerActivation
|
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.min
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.math.roundToInt
|
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)
|
for (unique in policy.uniqueObjects)
|
||||||
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
UniqueTriggerActivation.triggerCivwideUnique(unique, civInfo)
|
||||||
|
|
||||||
@ -238,4 +248,21 @@ class PolicyManager {
|
|||||||
}
|
}
|
||||||
return freeBuildings
|
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
|
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.
|
// To be run from City-State DiplomacyManager, which holds the influence. Resting point for every major civ can be different.
|
||||||
fun getCityStateInfluenceRestingPoint(): Float {
|
fun getCityStateInfluenceRestingPoint(): Float {
|
||||||
var restingPoint = 0f
|
var restingPoint = 0f
|
||||||
for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []"))
|
for (unique in otherCiv().getMatchingUniques("Resting point for Influence with City-States is increased by []"))
|
||||||
restingPoint += unique.params[0].toInt()
|
restingPoint += unique.params[0].toInt()
|
||||||
if(diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5
|
if (diplomaticStatus == DiplomaticStatus.Protector) restingPoint += 5
|
||||||
return restingPoint
|
return restingPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +215,13 @@ class DiplomacyManager() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unique in otherCiv().getMatchingUniques("City-State Influence degrades []% slower"))
|
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)
|
return max(0f, decrement) * max(0f, modifier)
|
||||||
}
|
}
|
||||||
@ -243,7 +261,7 @@ class DiplomacyManager() {
|
|||||||
return goldPerTurnForUs
|
return goldPerTurnForUs
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sciencefromResearchAgreement() {
|
fun scienceFromResearchAgreement() {
|
||||||
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
// https://forums.civfanatics.com/resources/research-agreements-bnw.25568/
|
||||||
val scienceFromResearchAgreement = min(totalOfScienceDuringRA, otherCivDiplomacy().totalOfScienceDuringRA)
|
val scienceFromResearchAgreement = min(totalOfScienceDuringRA, otherCivDiplomacy().totalOfScienceDuringRA)
|
||||||
civInfo.tech.scienceFromResearchAgreements += scienceFromResearchAgreement
|
civInfo.tech.scienceFromResearchAgreements += scienceFromResearchAgreement
|
||||||
@ -288,7 +306,7 @@ class DiplomacyManager() {
|
|||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region state-changing functions
|
//region state-changing functions
|
||||||
fun removeUntenebleTrades() {
|
fun removeUntenableTrades() {
|
||||||
|
|
||||||
for (trade in trades.toList()) {
|
for (trade in trades.toList()) {
|
||||||
|
|
||||||
@ -329,7 +347,7 @@ class DiplomacyManager() {
|
|||||||
|
|
||||||
fun nextTurn() {
|
fun nextTurn() {
|
||||||
nextTurnTrades()
|
nextTurnTrades()
|
||||||
removeUntenebleTrades()
|
removeUntenableTrades()
|
||||||
updateHasOpenBorders()
|
updateHasOpenBorders()
|
||||||
nextTurnDiplomaticModifiers()
|
nextTurnDiplomaticModifiers()
|
||||||
nextTurnFlags()
|
nextTurnFlags()
|
||||||
@ -403,7 +421,7 @@ class DiplomacyManager() {
|
|||||||
when (flag) {
|
when (flag) {
|
||||||
DiplomacyFlags.ResearchAgreement.name -> {
|
DiplomacyFlags.ResearchAgreement.name -> {
|
||||||
if (!otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement))
|
if (!otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement))
|
||||||
sciencefromResearchAgreement()
|
scienceFromResearchAgreement()
|
||||||
}
|
}
|
||||||
// This is confusingly named - in fact, the civ that has the flag set is the MAJOR civ
|
// This is confusingly named - in fact, the civ that has the flag set is the MAJOR civ
|
||||||
DiplomacyFlags.ProvideMilitaryUnit.name -> {
|
DiplomacyFlags.ProvideMilitaryUnit.name -> {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.unciv.models.ruleset
|
package com.unciv.models.ruleset
|
||||||
|
|
||||||
import com.unciv.logic.city.CityInfo
|
import com.unciv.logic.city.CityInfo
|
||||||
|
import com.unciv.logic.civilization.CivFlags
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
import com.unciv.models.stats.Stats
|
import com.unciv.models.stats.Stats
|
||||||
import com.unciv.models.translations.getPlaceholderParameters
|
import com.unciv.models.translations.getPlaceholderParameters
|
||||||
@ -104,6 +105,23 @@ object UniqueTriggerActivation {
|
|||||||
unit.promotions.addPromotion(promotion, isFree = true)
|
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
|
* [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
|
* [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
|
### Commerce
|
||||||
|
|
||||||
* [Trade](https://thenounproject.com/term/trade/686718/) By Gregor Cresnar for Trade Unions
|
* [Trade](https://thenounproject.com/term/trade/686718/) By Gregor Cresnar for Trade Unions
|
||||||
|