Update and generalize Siam UP (#5237)

* refactor and generalize Siam UP, display correct values in diplo screen

* enable preferred diplomatic victory

* allow compatibility mode

* revisions, restore timesInPlace

* don't change game.png

* don't change game.png

* objectify and enum city state bonuses

* objectify and enum city state bonuses

* template.properties

* refactored city state bonuses into Unique

* further enumization, fix toStringWithDecimals

* reviews
This commit is contained in:
SimonCeder 2021-09-19 05:28:10 +02:00 committed by GitHub
parent ba679191f8
commit 027057874d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 239 additions and 176 deletions

View File

@ -13,17 +13,17 @@
"baseUnitBuyCost": 200,
"startPercent": 0,
"friendBonus": {
"Cultured": ["Provides [3] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [2] Happiness"],
"Religious": ["Provides [3] [Faith] per turn"],
"Cultured": ["Provides [+3 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+2] Happiness"],
"Religious": ["Provides [+3 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [6] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [2] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [6] [Faith] per turn"],
"Cultured": ["Provides [+6 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+2] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+6 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [255, 87, 35]
@ -41,17 +41,17 @@
"baseUnitBuyCost": 200,
"startPercent": 10,
"friendBonus": {
"Cultured": ["Provides [3] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [2] Happiness"],
"Religious": ["Provides [3] [Faith] per turn"],
"Cultured": ["Provides [+3 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+2] Happiness"],
"Religious": ["Provides [+3 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [6] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [2] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [6] [Faith] per turn"],
"Cultured": ["Provides [+6 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+2] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+6 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [233, 31, 99]
@ -71,17 +71,17 @@
"baseUnitBuyCost": 200,
"startPercent": 25,
"friendBonus": {
"Cultured": ["Provides [6] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [6] [Faith] per turn"],
"Cultured": ["Provides [+6 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+6 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [12] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [12] [Faith] per turn"],
"Cultured": ["Provides [+12 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+12 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [157, 39, 176]
@ -102,17 +102,17 @@
"baseUnitBuyCost": 300,
"startPercent": 37,
"friendBonus": {
"Cultured": ["Provides [6] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [6] [Faith] per turn"],
"Cultured": ["Provides [+6 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+6 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [12] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [12] [Faith] per turn"],
"Cultured": ["Provides [+12 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+12 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [104, 58, 183]
@ -134,17 +134,17 @@
"baseUnitBuyCost": 400,
"startPercent": 50,
"friendBonus": {
"Cultured": ["Provides [13] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [13] [Faith] per turn"],
"Cultured": ["Provides [+13 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+13 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [26] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [26] [Faith] per turn"],
"Cultured": ["Provides [+26 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+26 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [63, 81, 182],
@ -171,18 +171,17 @@
"baseUnitBuyCost": 600,
"startPercent": 65,
"friendBonus": {
"Cultured": ["Provides [13] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [13] [Faith] per turn"],
"Cultured": ["Provides [+13 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+13 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [26] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [26] [Faith] per turn"],
"Cultured": ["Provides [+26 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+26 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [33, 150, 243],
@ -210,17 +209,17 @@
"baseUnitBuyCost": 800,
"startPercent": 65,
"friendBonus": {
"Cultured": ["Provides [13] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [13] [Faith] per turn"],
"Cultured": ["Provides [+13 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+13 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [26] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [26] [Faith] per turn"],
"Cultured": ["Provides [+26 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+26 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
"iconRGB": [0, 150, 136],
@ -252,17 +251,17 @@
// But where is the modularity? The excluding of very specific wonders? That is no fun.
// So we just write down the entire long list (sorted by era!) instead.
"friendBonus": {
"Cultured": ["Provides [13] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [13] [Faith] per turn"],
"Cultured": ["Provides [+13 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+13 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [26] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [26] [Faith] per turn"],
"Cultured": ["Provides [+26 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+26 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},
@ -294,18 +293,17 @@
"baseUnitBuyCost": 1000,
"startPercent": 80,
"friendBonus": {
"Cultured": ["Provides [13] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]"],
"Mercantile": ["Provides [3] Happiness"],
"Religious": ["Provides [13] [Faith] per turn"],
"Cultured": ["Provides [+13 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]"],
"Mercantile": ["Provides [+3] Happiness"],
"Religious": ["Provides [+13 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[20] turns"]
},
"allyBonus": {
"Cultured": ["Provides [26] [Culture] per turn"],
"Maritime": ["Provides [2] [Food] [in capital]", "Provides [1] [Food] [in all cities]"],
"Mercantile": ["Provides [3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [26] [Faith] per turn"],
"Cultured": ["Provides [+26 Culture] per turn"],
"Maritime": ["Provides [+2 Food] [in capital]", "Provides [+1 Food] [in all cities]"],
"Mercantile": ["Provides [+3] Happiness", "Provides a unique luxury"],
"Religious": ["Provides [+26 Faith] per turn"],
"Militaristic": ["Provides military units every ≈[17] turns"]
},

View File

@ -125,7 +125,7 @@
"leaderName": "Elizabeth",
"adjective": ["English"],
"startBias": ["Coast"],
// "preferredVictoryType": "Diplomatic",
"preferredVictoryType": "Diplomatic",
"startIntroPart1": "Praises upon her serene highness, Queen Elizabeth Gloriana. You lead and protect the celebrated maritime nation of England. England is an ancient land, settled as early as 35,000 years ago. The island has seen countless waves of invaders, each in turn becoming a part of the fabric of the people. Although England is a small island, for many years your people dominated the world stage. Their matchless navy, brilliant artists and shrewd merchants, giving them power and influence far in excess of their mere numbers.",
"startIntroPart2": "Queen Elizabeth, will you bring about a new golden age for the English people? They look to you once more to return peace and prosperity to the nation. Will you take up the mantle of greatness? Can you build a civilization that will stand the test of time?",
@ -482,7 +482,7 @@
"leaderName": "Ramkhamhaeng",
"adjective": ["Siamese"],
"startBias": ["Avoid [Forest]"],
// "preferredVictoryType":"Diplomatic",
"preferredVictoryType":"Diplomatic",
"startIntroPart1": "Greetings to you, Great King Ramkhamhaeng, leader of the glorious Siamese people! O mighty King, your people bow down before you in awe and fear! You are the ruler of Siam, an ancient country in the heart of Southeast Asia, a beautiful and mysterious land. Surrounded by foes, beset by bloody war and grinding poverty, the clever and loyal Siamese people have endured and triumphed. King Ramkhamhaeng, your empire was once part of the Khmer Empire, until the 13th century AD, when your ancestors revolted, forming the small Sukhothai kingdom. Through successful battle and cunning diplomacy, the tiny kingdom grew into a mighty empire, an empire which would dominate South East Asia for more than a century!",
"startIntroPart2": "Oh, wise and puissant King Ramkhamhaeng, your people need you to once again lead them to greatness! Can you use your wits and strength of arms to protect your people and defeat your foes? Can you build a civilization that will stand the test of time?",
@ -496,7 +496,7 @@
"outerColor": [228,208,43],
"innerColor": [193,21,17],
"uniqueName": "Father Governs Children",
"uniques": ["Food and Culture from Friendly City-States are increased by 50%","Military Units gifted from City-States start with [+10] XP"],
"uniques": ["[+50]% [Food] from City-States","[+50]% [Culture] from City-States","[+50]% [Faith] from City-States","Military Units gifted from City-States start with [+10] XP"],
"cities": ["Sukhothai","Si Satchanalai","Muang Saluang","Lampang","Phitsanulok","Kamphaeng Pet","Nakhom Chum","Vientiane",
"Nakhon Si Thammarat","Martaban","Nakhon Sawan","Chainat","Luang Prabang","Uttaradit","Chiang Thong","Phrae",
"Nan","Tak","Suphanburi","Hongsawadee","Thawaii","Ayutthaya","Taphan Hin","Uthai Thani","Lap Buri","Ratchasima",

View File

@ -215,6 +215,11 @@ Reach highest influence above 60 for alliance. =
When Friends: =
When Allies: =
The unique luxury is one of: =
Provides [stats] [cityFilter] =
Provides [stats] per turn =
Provides [amount] Happiness =
Provides military units every ≈[amount] turns =
Provides a unique luxury =
Demand Tribute =
Tribute Willingness =

View File

@ -12,8 +12,6 @@ import com.unciv.models.ruleset.UniqueType
import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.utils.toPercent
import kotlin.math.min
@ -114,34 +112,26 @@ class CityStats(val cityInfo: CityInfo) {
val stats = Stats()
for (otherCiv in cityInfo.civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() >= RelationshipLevel.Friend) {
val relationshipLevel = otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel()
if (otherCiv.isCityState() && relationshipLevel >= RelationshipLevel.Friend) {
val eraInfo = cityInfo.civInfo.getEra()
if (eraInfo.friendBonus[otherCiv.cityStateType.name] == null || eraInfo.allyBonus[otherCiv.cityStateType.name] == null) {
if (eraInfo.undefinedCityStateBonuses()) {
// Deprecated, assume Civ V values for compatibility
if (otherCiv.cityStateType == CityStateType.Maritime && otherCiv.getDiplomacyManager(cityInfo.civInfo).relationshipLevel() == RelationshipLevel.Ally)
if (otherCiv.cityStateType == CityStateType.Maritime && relationshipLevel == RelationshipLevel.Ally)
stats.food += 1
if (otherCiv.cityStateType == CityStateType.Maritime && cityInfo.isCapital())
stats.food += 2
if (cityInfo.civInfo.hasUnique("Food and Culture from Friendly City-States are increased by 50%"))
stats.food *= 1.5f
return stats
}
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())
} else {
for (bonus in eraInfo.getCityStateBonuses(otherCiv.cityStateType, relationshipLevel)) {
if (bonus.isOfType(UniqueType.CityStateStatsPerCity) && cityInfo.matchesFilter(bonus.params[1])) {
stats.add(bonus.stats)
}
}
}
if (cityInfo.civInfo.hasUnique("Food and Culture from Friendly City-States are increased by 50%")) {
stats.food *= 1.5f
stats.culture *= 1.5f
for (unique in cityInfo.civInfo.getMatchingUniques("[]% [] from City-States")) {
stats[Stat.valueOf(unique.params[1])] *= unique.params[0].toPercent()
}
}
}

View File

@ -5,9 +5,9 @@ import com.unciv.logic.automation.NextTurnAutomation
import com.unciv.logic.civilization.diplomacy.*
import com.unciv.models.metadata.GameSpeed
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.UniqueType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.victoryscreen.RankingType
import java.util.*
import kotlin.collections.HashMap
@ -28,29 +28,32 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
for (tech in startingTechs)
civInfo.tech.techsResearched.add(tech.name) // can't be .addTechnology because the civInfo isn't assigned yet
val allMercantileResources = ruleset.tileResources.values.filter { it.unique == "Can only be created by Mercantile City-States" }.map { it.name }
val allPossibleBonuses = HashSet<String>() // We look through these to determine what kind of city state we are
val allMercantileResources = ruleset.tileResources.values.filter { it.hasUnique("Can only be created by Mercantile City-States") }.map { it.name }
val allPossibleBonuses = HashSet<Unique>() // We look through these to determine what kind of city state we are
var fallback = false
for (era in ruleset.eras.values) {
val allyBonuses = era.allyBonus[cityStateType.name]
val friendBonuses = era.friendBonus[cityStateType.name]
if (allyBonuses != null)
allPossibleBonuses.addAll(allyBonuses)
if (friendBonuses != null)
allPossibleBonuses.addAll(friendBonuses)
if (era.undefinedCityStateBonuses()) {
fallback = true
break
}
val allyBonuses = era.getCityStateBonuses(cityStateType, RelationshipLevel.Ally)
val friendBonuses = era.getCityStateBonuses(cityStateType, RelationshipLevel.Friend)
allPossibleBonuses.addAll(allyBonuses)
allPossibleBonuses.addAll(friendBonuses)
}
// CS Personality
civInfo.cityStatePersonality = CityStatePersonality.values().random()
// Mercantile bonus resources
if ("Provides a unique luxury" in allPossibleBonuses
|| (allPossibleBonuses.isEmpty() && cityStateType == CityStateType.Mercantile)) { // Fallback for badly defined Eras.json
if (allPossibleBonuses.any { it.isOfType(UniqueType.CityStateUniqueLuxury) }
|| (fallback && cityStateType == CityStateType.Mercantile)) { // Fallback for badly defined Eras.json
civInfo.cityStateResource = allMercantileResources.random()
}
// Unique unit for militaristic city-states
if (allPossibleBonuses.any { it.getPlaceholderText() == "Provides military units every ≈[] turns" }
|| (allPossibleBonuses.isEmpty() && cityStateType == CityStateType.Militaristic)) { // Fallback for badly defined Eras.json
if (allPossibleBonuses.any { it.isOfType(UniqueType.CityStateMilitaryUnits) }
|| (fallback && cityStateType == CityStateType.Militaristic)) { // Fallback for badly defined Eras.json
val possibleUnits = ruleset.units.values.filter { it.requiredTech != null
&& ruleset.eras[ruleset.technologies[it.requiredTech!!]!!.era()]!!.eraNumber > ruleset.eras[startingEra]!!.eraNumber // Not from the start era or before
@ -400,19 +403,12 @@ class CityStateFunctions(val civInfo: CivilizationInfo) {
if (!civInfo.isCityState())
return false
val eraInfo = civInfo.getEra()
val allyBonuses = eraInfo.allyBonus[civInfo.cityStateType.name]
if (allyBonuses != null) {
if (!eraInfo.undefinedCityStateBonuses()) {
// Defined city states in json
val bonuses = allyBonuses + eraInfo.friendBonus[civInfo.cityStateType.name]!!
for (bonus in bonuses) {
if (statType == Stat.Happiness && bonus.getPlaceholderText() == "Provides [] Happiness")
return true
if (bonus.getPlaceholderText() == "Provides [] [] per turn" && bonus.getPlaceholderParameters()[1] == statType.name)
return true
if (bonus.getPlaceholderText() == "Provides [] [] []" && bonus.getPlaceholderParameters()[1] == statType.name)
for (bonus in eraInfo.getCityStateBonuses(civInfo.cityStateType, RelationshipLevel.Ally)) {
if (bonus.stats[statType] > 0 || (bonus.isOfType(UniqueType.CityStateHappiness) && statType == Stat.Happiness))
return true
}
} else {
// compatibility mode
return when {

View File

@ -11,8 +11,7 @@ import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.stats.Stat
import com.unciv.models.stats.StatMap
import com.unciv.models.stats.Stats
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.utils.toPercent
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
@ -122,25 +121,15 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
//City-States bonuses
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo.civName)
.relationshipLevel() >= RelationshipLevel.Friend
) {
val relationshipLevel = otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel()
if (otherCiv.isCityState() && relationshipLevel >= RelationshipLevel.Friend) {
val cityStateBonus = Stats()
val eraInfo = civInfo.getEra()
val relevantBonuses =
if (otherCiv.getDiplomacyManager(civInfo.civName).relationshipLevel() == RelationshipLevel.Friend)
eraInfo.friendBonus[otherCiv.cityStateType.name]
else eraInfo.allyBonus[otherCiv.cityStateType.name]
if (relevantBonuses != null) {
for (bonus in relevantBonuses) {
val unique = Unique(bonus)
if (unique.placeholderText == "Provides [] [] per turn")
cityStateBonus.add(
Stat.valueOf(unique.params[1]),
unique.params[0].toFloat()
)
if (!eraInfo.undefinedCityStateBonuses()) {
for (bonus in eraInfo.getCityStateBonuses(otherCiv.cityStateType, relationshipLevel)) {
if (bonus.isOfType(UniqueType.CityStateStatsPerTurn))
cityStateBonus.add(bonus.stats)
}
} else {
// Deprecated, assume Civ V values for compatibility
@ -151,15 +140,14 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
civInfo.getEraNumber() in 2..3 -> 6f
else -> 13f
}
if (otherCiv.getDiplomacyManager(civInfo.civName)
.relationshipLevel() == RelationshipLevel.Ally
)
if (relationshipLevel == RelationshipLevel.Ally)
cityStateBonus.culture *= 2f
}
}
if (civInfo.hasUnique("Food and Culture from Friendly City-States are increased by 50%"))
cityStateBonus.culture *= 1.5f
for (unique in civInfo.getMatchingUniques("[]% [] from City-States")) {
cityStateBonus[Stat.valueOf(unique.params[1])] *= unique.params[0].toPercent()
}
statMap.add("City-States", cityStateBonus)
}
@ -327,24 +315,18 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
//From city-states
for (otherCiv in civInfo.getKnownCivs()) {
if (otherCiv.isCityState() && otherCiv.getDiplomacyManager(civInfo)
.relationshipLevel() >= RelationshipLevel.Friend
) {
val relationshipLevel = otherCiv.getDiplomacyManager(civInfo).relationshipLevel()
if (otherCiv.isCityState() && relationshipLevel >= RelationshipLevel.Friend) {
val eraInfo = civInfo.getEra()
val relevantBonuses =
if (otherCiv.getDiplomacyManager(civInfo).relationshipLevel() == RelationshipLevel.Friend)
eraInfo.friendBonus[otherCiv.cityStateType.name]
else eraInfo.allyBonus[otherCiv.cityStateType.name]
if (relevantBonuses != null) {
for (bonus in relevantBonuses) {
if (bonus.getPlaceholderText() == "Provides [] Happiness") {
if (!eraInfo.undefinedCityStateBonuses()) {
for (bonus in eraInfo.getCityStateBonuses(otherCiv.cityStateType, relationshipLevel)) {
if (bonus.isOfType(UniqueType.CityStateHappiness)) {
if (statMap.containsKey("City-States"))
statMap["City-States"] =
statMap["City-States"]!! + bonus.getPlaceholderParameters()[0].toFloat()
statMap["City-States"]!! + bonus.params[0].toFloat()
else
statMap["City-States"] =
bonus.getPlaceholderParameters()[0].toFloat()
statMap["City-States"] = bonus.params[0].toFloat()
}
}
} else {
@ -360,6 +342,14 @@ class CivInfoStats(val civInfo: CivilizationInfo) {
}
}
// Just in case
if (statMap.containsKey("City-States")) {
for (unique in civInfo.getMatchingUniques("[]% [] from City-States")) {
if (unique.params[1] == Stat.Happiness.name)
statMap["City-States"] = statMap["City-States"]!! * unique.params[0].toPercent()
}
}
return statMap
}

View File

@ -6,9 +6,8 @@ import com.unciv.logic.civilization.*
import com.unciv.logic.trade.Trade
import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeType
import com.unciv.models.ruleset.UniqueType
import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.utils.toPercent
import kotlin.math.ceil
import kotlin.math.max
@ -586,13 +585,8 @@ class DiplomacyManager() {
if (hasFlag(DiplomacyFlags.ProvideMilitaryUnit)) removeFlag(DiplomacyFlags.ProvideMilitaryUnit)
} else {
val variance = listOf(-1, 0, 1).random()
val relevantBonuses =
if (relationshipLevel() == RelationshipLevel.Friend)
eraInfo.friendBonus[otherCiv().cityStateType.name]
else eraInfo.allyBonus[otherCiv().cityStateType.name]
if (relevantBonuses == null && otherCiv().cityStateType == CityStateType.Militaristic) {
if (eraInfo.undefinedCityStateBonuses() && otherCiv().cityStateType == CityStateType.Militaristic) {
// Deprecated, assume Civ V values for compatibility
if (!hasFlag(DiplomacyFlags.ProvideMilitaryUnit) && relationshipLevel() == RelationshipLevel.Friend)
setFlag(DiplomacyFlags.ProvideMilitaryUnit, 20 + variance)
@ -601,13 +595,13 @@ class DiplomacyManager() {
&& relationshipLevel() == RelationshipLevel.Ally)
setFlag(DiplomacyFlags.ProvideMilitaryUnit, 17 + variance)
}
if (relevantBonuses == null) return
if (eraInfo.undefinedCityStateBonuses()) return
for (bonus in relevantBonuses) {
for (bonus in eraInfo.getCityStateBonuses(otherCiv().cityStateType, relationshipLevel())) {
// Reset the countdown if it has ended, or if we have longer to go than the current maximum (can happen when going from friend to ally)
if (bonus.getPlaceholderText() == "Provides military units every ≈[] turns" &&
(!hasFlag(DiplomacyFlags.ProvideMilitaryUnit) || getFlag(DiplomacyFlags.ProvideMilitaryUnit) > bonus.getPlaceholderParameters()[0].toInt()))
setFlag(DiplomacyFlags.ProvideMilitaryUnit, bonus.getPlaceholderParameters()[0].toInt() + variance)
if (bonus.isOfType(UniqueType.CityStateMilitaryUnits) &&
(!hasFlag(DiplomacyFlags.ProvideMilitaryUnit) || getFlag(DiplomacyFlags.ProvideMilitaryUnit) > bonus.params[0].toInt()))
setFlag(DiplomacyFlags.ProvideMilitaryUnit, bonus.params[0].toInt() + variance)
}
}
}

View File

@ -2,7 +2,12 @@ package com.unciv.models.ruleset
import com.badlogic.gdx.graphics.Color
import com.unciv.logic.civilization.CityStateType
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
import com.unciv.models.stats.INamed
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.getPlaceholderParameters
import com.unciv.models.translations.getPlaceholderText
import com.unciv.ui.utils.colorFromRGB
class Era : INamed, IHasUniques {
@ -22,12 +27,36 @@ class Era : INamed, IHasUniques {
var startingObsoleteWonders = ArrayList<String>()
var baseUnitBuyCost = 200
var startPercent = 0
var friendBonus = HashMap<String, List<String>>()
var allyBonus = HashMap<String, List<String>>()
val friendBonusObjects: Map<CityStateType, List<Unique>> by lazy { initBonuses(friendBonus) }
val allyBonusObjects: Map<CityStateType, List<Unique>> by lazy { initBonuses(allyBonus) }
var iconRGB: List<Int>? = null
override var uniques: ArrayList<String> = arrayListOf()
override val uniqueObjects: List<Unique> by lazy { uniques.map { Unique(it) } }
private fun initBonuses(bonusMap: Map<String, List<String>>): Map<CityStateType, List<Unique>> {
val objectMap = HashMap<CityStateType, List<Unique>>()
for ((cityStateType, bonusList) in bonusMap) {
objectMap[CityStateType.valueOf(cityStateType)] = bonusList.map { Unique(it) }
}
return objectMap
}
fun getCityStateBonuses(cityStateType: CityStateType, relationshipLevel: RelationshipLevel): List<Unique> {
return when (relationshipLevel) {
RelationshipLevel.Ally -> allyBonusObjects[cityStateType] ?: emptyList()
RelationshipLevel.Friend -> friendBonusObjects[cityStateType] ?: emptyList()
else -> emptyList()
}
}
fun undefinedCityStateBonuses(): Boolean {
return friendBonus.isEmpty() || allyBonus.isEmpty()
}
fun getStartingUnits(): List<String> {
val startingUnits = mutableListOf<String>()
repeat(startingSettlerCount) { startingUnits.add(startingSettlerUnit) }

View File

@ -21,7 +21,12 @@ enum class UniqueType(val text:String, val replacedBy: UniqueType? = null) {
@Deprecated("As of 3.16.16")
DecreasedUnitMaintenanceCostsGlobally("-[amount]% unit upkeep costs", UnitMaintenanceDiscount),
StatBonusForNumberOfSpecialists("[stats] if this city has at least [amount] specialists"),
StatsPerCity("[stats] [cityFilter]")
StatsPerCity("[stats] [cityFilter]"),
CityStateStatsPerTurn("Provides [stats] per turn"), // Should not be Happiness!
CityStateStatsPerCity("Provides [stats] [cityFilter]"),
CityStateHappiness("Provides [amount] Happiness"),
CityStateMilitaryUnits("Provides military units every ≈[amount] turns"),
CityStateUniqueLuxury("Provides a unique luxury"),
;
/** For uniques that have "special" parameters that can accept multiple types, we can override them manually

View File

@ -135,6 +135,13 @@ open class Stats(
}
}
// For display in diplomacy window
fun toStringWithDecimals(): String {
return this.joinToString {
(if (it.value > 0) "+" else "") + it.value.toString().removeSuffix(".0") + " " + it.key.toString().tr()
}
}
/** Represents one [key][Stat]/[value][Float] pair returned by the [iterator] */
data class StatValuePair (val key: Stat, val value: Float)

View File

@ -15,7 +15,11 @@ import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeType
import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.Quest
import com.unciv.models.ruleset.Unique
import com.unciv.models.ruleset.UniqueType
import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.stats.Stat
import com.unciv.models.translations.fillPlaceholders
import com.unciv.models.translations.tr
import com.unciv.ui.civilopedia.CivilopediaScreen
import com.unciv.ui.tilegroups.CityButton
@ -189,12 +193,14 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
val eraInfo = viewingCiv.getEra()
var friendBonusText = "{When Friends:} ".tr()
val friendBonuses = eraInfo.friendBonus[otherCiv.cityStateType.name]
friendBonusText += friendBonuses?.joinToString(separator = ", ") { it.tr() } ?: ""
val friendBonusObjects = eraInfo.getCityStateBonuses(otherCiv.cityStateType, RelationshipLevel.Friend)
val friendBonusStrings = getAdjustedBonuses(friendBonusObjects)
friendBonusText += friendBonusStrings.joinToString(separator = ", ") { it.tr() } ?: ""
var allyBonusText = "{When Allies:} ".tr()
val allyBonuses = eraInfo.allyBonus[otherCiv.cityStateType.name]
allyBonusText += allyBonuses?.joinToString(separator = ", ") { it.tr() } ?: ""
val allyBonusObjects = eraInfo.getCityStateBonuses(otherCiv.cityStateType, RelationshipLevel.Ally)
val allyBonusStrings = getAdjustedBonuses(allyBonusObjects)
allyBonusText += allyBonusStrings.joinToString(separator = ", ") { it.tr() } ?: ""
val relationLevel = otherCivDiplomacyManager.relationshipLevel()
if (relationLevel >= RelationshipLevel.Friend) {
@ -223,6 +229,49 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() {
return diplomacyTable
}
/** Given a list of [bonuses], returns a list of pretty strings with updated values for Siam-like uniques
* Assumes that each bonus contains only one stat type */
private fun getAdjustedBonuses(bonuses: List<Unique>): List<String> {
val bonusStrings = ArrayList<String>()
for (bonus in bonuses) {
var improved = false
for (unique in viewingCiv.getMatchingUniques("[]% [] from City-States")) {
val boostAmount = unique.params[0].toPercent()
val boostedStat = Stat.valueOf(unique.params[1])
when (bonus.type) {
UniqueType.CityStateStatsPerTurn -> { // "Provides [stats] per turn"
if (bonus.stats[boostedStat] > 0) {
bonusStrings.add(
bonus.text.fillPlaceholders(
(bonus.stats * boostAmount).toStringWithDecimals()))
improved = true
}
}
UniqueType.CityStateStatsPerCity -> { // "Provides [stats] [cityFilter]"
if (bonus.stats[boostedStat] > 0) {
bonusStrings.add(
bonus.text.fillPlaceholders(
(bonus.stats * boostAmount).toStringWithDecimals(), bonus.params[1]))
improved = true
}
}
UniqueType.CityStateHappiness -> { // "Provides [amount] Happiness"
if (boostedStat == Stat.Happiness) {
bonusStrings.add(
bonus.text.fillPlaceholders(
(bonus.params[0].toFloat() * boostAmount).toString().removeSuffix(".0")))
improved = true
}
}
}
}
// No matching unique, add it unmodified
if (!improved)
bonusStrings.add(bonus.text)
}
return bonusStrings
}
private fun getCityStateDiplomacyTable(otherCiv: CivilizationInfo): Table {
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)