Created Order branch with G&K policies (#4158)

* Created Order branch with G&K policies

* Implemented requested changes
This commit is contained in:
Xander Lenstra
2021-06-20 20:39:14 +02:00
committed by GitHub
parent da455f10b5
commit 3d1836a081
18 changed files with 573 additions and 462 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 KiB

After

Width:  |  Height:  |  Size: 988 KiB

View File

@ -687,7 +687,7 @@
"isWonder": true,
"greatPersonPoints": {"production": 2},
"providesFreeBuilding": "Castle",
"uniques": ["+[15]% combat bonus for units fighting in [Friendly Land]"],
"uniques": ["+[15]% Strength for units fighting in [Friendly Land]"],
"requiredTech": "Gunpowder",
"quote": "'Bushido is realized in the presence of death. This means choosing death whenever there is a choice between life and death. There is no other reasoning.' - Yamamoto Tsunetomo"
},

View File

@ -129,7 +129,7 @@
},
{
"name": "Honor Complete",
"uniques": ["Earn [10]% of killed [Military] unit's [Cost] as [Gold]"],
"uniques": ["Earn [10]% of killed [Military] unit's [Cost] as [Gold]"]
}
]
},{
@ -311,46 +311,10 @@
}
]
},
/*{
"name": "Order",
"era": "Industrial era",
"policies": [
{
"name": "Nationalism",
"row": 1,
"column": 1
},
{
"name": "United Front",
"row": 1,
"column": 3
},
{
"name": "Planned Economy",
"row": 2,
"column": 5
},
{
"name": "Socialism",
"requires": ["Planned Economy"],
"row": 2,
"column": 3
},
{
"name": "Communism",
"requires": ["Socialism"],
"row": 3,
"column": 3
},
{
"name": "Order Complete", Gold and Culture per city"
}
]
},*/
{
"name": "Freedom",
"era": "Renaissance era",
"uniques": ["+[25]% great person generation in all cities"],
"uniques": ["+[25]% great person generation in all cities", "Incompatible with [Autocracy]", "Incompatible with [Order]"],
"policies": [
{
"name": "Constitution",
@ -393,7 +357,8 @@
{
"name": "Autocracy",
"era": "Industrial era",
"uniques": ["-[33]% unit upkeep costs", "Upon capturing a city, receive [10] times its [Culture] production as [Culture] immediately"],
"uniques": ["-[33]% unit upkeep costs", "Upon capturing a city, receive [10] times its [Culture] production as [Culture] immediately",
"Incompatible with [Order]", "Incompatible with [Freedom]"],
"policies": [
{
"name": "Populism",
@ -434,5 +399,48 @@
"uniques": ["+[25]% attack strength to all [Military] units for [50] turns"]
}
]
}
},
{
"name": "Order",
"era": "Industrial era",
"uniques": ["[+1 Happiness] [in all cities]", "Incompatible with [Autocracy]", "Incompatible with [Freedom]"],
"policies": [
{
"name": "United Front",
"uniques": ["Militaristic City-States grant units [2] times as fast when you are at war with a common nation"],
"row": 1,
"column": 1
},
{
"name": "Planned Economy",
"uniques": ["+[25]% [Science] from every [Factory]", "+[100]% Production when constructing a [Factory]"],
"row": 1,
"column": 3
},
{
"name": "Nationalism",
"uniques": ["+[15]% Strength for units fighting in [Friendly Land]"],
"row": 1,
"column": 5
},
{
"name": "Socialism",
"requires": ["Planned Economy"],
"uniques": ["-[15]% maintenance cost for buildings [in all cities]"],
"row": 2,
"column": 3
},
{
"name": "Communism",
"requires": ["Socialism"],
"uniques": ["[+1 Production] [in all cities]", "[+1 Production] from every [Mine]", "[+1 Production] from every [Quarry]"],
"row": 3,
"column": 3
},
{
"name": "Order Complete",
"uniques": ["[+2 Food, +2 Production, +2 Science, +2 Gold, +2 Culture] [in all cities]"]
}
]
}
]

View File

@ -84,13 +84,13 @@ object BattleDamage {
modifiers["vs [City-States]"] = 30
// Deprecated since 3.14.17
if (civInfo.hasUnique("+15% combat strength for melee units which have another military unit in an adjacent tile")
&& combatant.isMelee()
&& combatant.getTile().neighbors.flatMap { it.getUnits() }
.any { it.civInfo == civInfo && !it.type.isCivilian() && !it.type.isAirUnit() }
)
modifiers["Discipline"] = 15
if (civInfo.hasUnique("+15% combat strength for melee units which have another military unit in an adjacent tile")
&& combatant.isMelee()
&& combatant.getTile().neighbors.flatMap { it.getUnits() }
.any { it.civInfo == civInfo && !it.type.isCivilian() && !it.type.isAirUnit() }
)
modifiers["Discipline"] = 15
//
}
if (enemy.getCivInfo().isBarbarian()) {
@ -226,12 +226,19 @@ object BattleDamage {
for (unique in unit.unit.getMatchingUniques("+[]% Strength in []")
+ unit.getCivInfo()
.getMatchingUniques("+[]% combat bonus for units fighting in []")) {
.getMatchingUniques("+[]% Strength for units fighting in []")) {
val filter = unique.params[1]
if (tile.matchesUniqueFilter(filter, unit.getCivInfo()))
modifiers.add(filter, unique.params[0].toInt())
}
// Deprecated since 3.15
for (unique in unit.getCivInfo().getMatchingUniques("+[]% combat bonus for units fighting in []")) {
val filter = unique.params[1]
if (tile.matchesUniqueFilter(filter, unit.getCivInfo()))
modifiers.add(filter, unique.params[0].toInt())
}
//
for (unique in unit.getCivInfo()
.getMatchingUniques("+[]% Strength if within [] tiles of a []")) {

View File

@ -182,7 +182,7 @@ class CityStats {
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)
}
@ -190,8 +190,8 @@ class CityStats {
if (civInfo.hasUnique("Specialists produce half normal unhappiness"))
unhappinessFromSpecialists *= 0.5f
//
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists().toFloat() - unhappinessFromSpecialists
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists().toFloat() - unhappinessFromSpecialists
if (cityInfo.isPuppet)
unhappinessFromCitizens *= 1.5f
@ -200,14 +200,14 @@ class CityStats {
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)
newHappinessList["Population"] = -unhappinessFromCitizens * unhappinessModifier
var happinessFromPolicies = getStatsFromUniques(civInfo.policies.policyUniques.getAllUniques()).happiness
val happinessFromPolicies = getStatsFromUniques(civInfo.policies.policyUniques.getAllUniques()).happiness
newHappinessList["Policies"] = happinessFromPolicies
@ -306,11 +306,16 @@ class CityStats {
for (unique in uniques.filter { it.placeholderText == "+[]% [] []"})
if (cityInfo.matchesFilter(unique.params[2]))
stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
for (unique in uniques.filter { it.placeholderText == "+[]% Production when constructing []" }) {
if (constructionMatchesFilter(currentConstruction, unique.params[1]))
stats.production += unique.params[0].toInt()
}
// Used for specific buildings (ex.: +100% Production when constructing a Factory)
for (unique in uniques.filter { it.placeholderText == "+[]% Production when constructing a []" }) {
if (constructionMatchesFilter(currentConstruction, unique.params[1]))
stats.production += unique.params[0].toInt()
}
// "+[amount]% Production when constructing [constructionFilter] [cityFilter]"
for (unique in uniques.filter { it.placeholderText == "+[]% Production when constructing [] []" }) {
@ -320,29 +325,27 @@ class CityStats {
// "+[amount]% Production when constructing [unitFilter] units [cityFilter]"
for (unique in uniques.filter { it.placeholderText == "+[]% Production when constructing [] units []" }) {
if (currentConstruction is BaseUnit && currentConstruction.matchesFilter(unique.params[1])
&& cityInfo.matchesFilter(unique.params[2]))
if (constructionMatchesFilter(currentConstruction, unique.params[1]) && cityInfo.matchesFilter(unique.params[2]))
stats.production += unique.params[0].toInt()
}
if (cityInfo.civInfo.getHappiness() >= 0) {
for (unique in uniques.filter { it.placeholderText == "+[]% [] while the empire is happy"})
stats.add(Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
// Deprecated since 3.15.0
for (unique in uniques.filter { it.placeholderText == "+15% science while the empire is happy"})
stats.science += 15f
//
}
}
return stats
}
fun constructionMatchesFilter(construction: IConstruction, filter: String): Boolean {
return construction.name == filter
|| filter == "Buildings" && construction is Building && !(construction.isWonder || construction.isNationalWonder)
|| filter == "Wonders" && construction is Building && (construction.isWonder || construction.isNationalWonder)
|| construction is Building && construction.uniques.contains(filter)
private fun constructionMatchesFilter(construction: IConstruction, filter: String): Boolean {
if (construction is Building) return construction.matchesFilter(filter)
if (construction is BaseUnit) return construction.matchesFilter(filter)
return false
}
fun isConnectedToCapital(roadType: RoadStatus): Boolean {
@ -354,7 +357,7 @@ class CityStats {
}
//endregion
fun updateBaseStatList() {
private fun updateBaseStatList() {
val newBaseStatList = LinkedHashMap<String, Stats>() // we don't edit the existing baseStatList directly, in order to avoid concurrency exceptions
val civInfo = cityInfo.civInfo
@ -375,7 +378,7 @@ class CityStats {
}
fun updateStatPercentBonusList(currentConstruction: IConstruction, citySpecificUniques: Sequence<Unique>) {
private fun updateStatPercentBonusList(currentConstruction: IConstruction, citySpecificUniques: Sequence<Unique>) {
val newStatPercentBonusList = LinkedHashMap<String, Stats>()
newStatPercentBonusList["Golden Age"] = getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge())
newStatPercentBonusList["Policies"] = getStatPercentBonusesFromUniques(currentConstruction, cityInfo.civInfo.policies.policyUniques.getAllUniques())
@ -397,9 +400,10 @@ class CityStats {
}
fun update(currentConstruction: IConstruction = cityInfo.cityConstructions.getCurrentConstruction()) {
// We calculate this here for concurrency reasons
// If something needs this, we pass this through as a parameter
val citySpecificUniques = getCitySpecificUniques()
val citySpecificUniques: Sequence<Unique> = cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
.filter { it.params.isNotEmpty() && it.params.last() == "in this city" }
// We need to compute Tile yields before happiness
updateBaseStatList()
updateCityHappiness()
@ -482,20 +486,32 @@ class CityStats {
newFinalStatList["Maintenance"] = Stats().apply { gold -= buildingsMaintenance.toInt() }
if (totalFood > 0 && currentConstruction is BaseUnit
&& currentConstruction.uniques.contains("Excess Food converted to Production when under construction")) {
newFinalStatList["Excess food to production"] =
Stats().apply { production = totalFood; food = -totalFood }
if (totalFood > 0 && constructionMatchesFilter(currentConstruction, "Excess Food converted to Production when under construction")) {
newFinalStatList["Excess food to production"] = Stats().apply { production = totalFood; food = -totalFood }
}
if (cityInfo.isInResistance())
newFinalStatList.clear() // NOPE
if (newFinalStatList.values.map { it.production }.sum() < 1) // Minimum production for things to progress
newFinalStatList["Production"] = Stats().apply { production = 1F }
newFinalStatList["Production"] = Stats().apply { production = 1f }
finalStatList = newFinalStatList
}
private fun getCitySpecificUniques(): Sequence<Unique> {
return cityInfo.cityConstructions.builtBuildingUniqueMap.getAllUniques()
.filter { it.params.isNotEmpty() && it.params.last() == "in this city" }
}
private fun getUniquesForThisCity(
unique: String,
// We might have to cached to avoid concurrency problems, so if we don't, just get it directly
citySpecificUniques: Sequence<Unique> = getCitySpecificUniques()
): Sequence<Unique> {
return citySpecificUniques.filter { it.placeholderText == unique } +
cityInfo.civInfo.getMatchingUniques(unique).filter { cityInfo.matchesFilter(it.params[1]) }
}
private fun getBuildingMaintenanceCosts(citySpecificUniques: Sequence<Unique>): Float {
// Same here - will have a different UI display.
var buildingsMaintenance = cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
@ -503,26 +519,32 @@ class CityStats {
buildingsMaintenance *= cityInfo.civInfo.gameInfo.getDifficulty().aiBuildingMaintenanceModifier
}
// e.g. "-[50]% Maintenance costs [in this city]"
val maintenanceUniqueTemplate = "-[]% building maintenance costs []"
val maintenanceUniques = citySpecificUniques.filter { it.placeholderText == maintenanceUniqueTemplate } +
cityInfo.civInfo.getMatchingUniques(maintenanceUniqueTemplate).filter { cityInfo.matchesFilter(it.params[1]) }
for (unique in maintenanceUniques) buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
// e.g. "-[50]% maintenance costs for buildings [in this city]"
for (unique in getUniquesForThisCity("-[]% maintenance cost for buildings []", citySpecificUniques)) {
buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
}
// Deprecated since 3.15
for (unique in getUniquesForThisCity("-[]% building maintenance costs []", citySpecificUniques)) {
buildingsMaintenance *= (1f - unique.params[0].toFloat() / 100)
}
//
return buildingsMaintenance
}
private fun updateFoodEaten() {
foodEaten = cityInfo.population.population.toFloat() * 2
var foodEatenBySpecialists = 2f * cityInfo.population.getNumberOfSpecialists()
for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists"))
for (unique in cityInfo.civInfo.getMatchingUniques("-[]% food consumption by specialists"))
foodEatenBySpecialists *= 1f - unique.params[0].toFloat() / 100f
// Deprecated since 3.15
if (cityInfo.civInfo.hasUnique("-50% food consumption by specialists"))
foodEatenBySpecialists *= 0.5f
//
foodEaten -= 2f * cityInfo.population.getNumberOfSpecialists() - foodEatenBySpecialists
}
}

View File

@ -380,6 +380,19 @@ class DiplomacyManager() {
// No need to decrement negative countdown flags: they do not expire
if (flagsCountdown[flag]!! > 0)
flagsCountdown[flag] = flagsCountdown[flag]!! - 1
// If we have uniques that make city states grant military units faster when at war with a common enemy, add higher numbers to this flag
if (flag == DiplomacyFlags.ProvideMilitaryUnit.name && civInfo.isMajorCiv() && otherCiv().isCityState() &&
civInfo.gameInfo.civilizations.filter { civInfo.isAtWarWith(it) && otherCiv().isAtWarWith(it) }.any()) {
for (unique in civInfo.getMatchingUniques("Militaristic City-States grant units [] times as fast when you are at war with a common nation")) {
flagsCountdown[DiplomacyFlags.ProvideMilitaryUnit.name] =
flagsCountdown[DiplomacyFlags.ProvideMilitaryUnit.name]!! - unique.params[0].toInt() + 1
if (flagsCountdown[DiplomacyFlags.ProvideMilitaryUnit.name]!! <= 0) {
flagsCountdown[DiplomacyFlags.ProvideMilitaryUnit.name] = 0
break
}
}
}
// At the end of every turn
if (flag == DiplomacyFlags.ResearchAgreement.name)

View File

@ -276,7 +276,7 @@ open class TileInfo {
}
fun getImprovementStats(improvement: TileImprovement, observingCiv: CivilizationInfo, city: CityInfo?): Stats {
val stats = improvement.clone()
val stats = improvement.clone() // clones the stats of the improvement, not the improvement itself
if (hasViewableResource(observingCiv) && getTileResource().improvement == improvement.name)
stats.add(getTileResource().improvementStats!!.clone()) // resource-specific improvement
@ -316,16 +316,16 @@ open class TileInfo {
}
stats.add(unique.stats.times(numberOfBonuses.toFloat()))
}
for (unique in observingCiv.getMatchingUniques("+[]% yield from every []"))
if (improvement.matchesFilter(unique.params[1]))
stats.timesInPlace(1f + unique.params[0].toFloat() / 100f)
// Deprecated since 3.15
if (containsGreatImprovement() && observingCiv.hasUnique("Tile yield from Great Improvements +100%"))
if (containsGreatImprovement() && observingCiv.hasUnique("Tile yield from Great Improvements +100%"))
stats.timesInPlace(2f)
//
return stats
}
@ -393,10 +393,10 @@ open class TileInfo {
}
/**
* Implementation of _`tileFilter`_
* Implementation of _`tileFilter`_
* @see <a href="https://github.com/yairm210/Unciv/wiki/uniques#user-content-tilefilter">tileFilter</a>
*/
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
fun matchesUniqueFilter(filter: String, civInfo: CivilizationInfo? = null): Boolean {
return when (filter) {
"All" -> true
baseTerrain -> true

View File

@ -446,6 +446,19 @@ class Building : NamedStats(), IConstruction {
return true
}
fun matchesFilter(filter: String): Boolean {
return when (filter) {
"All" -> true
name -> true
"Building", "Buildings" -> !(isWonder || isNationalWonder)
"Wonder", "Wonders" -> isWonder || isNationalWonder
else -> {
if (uniques.contains(filter)) return true
return false
}
}
}
fun isStatRelated(stat: Stat): Boolean {
if (get(stat) > 0) return true

View File

@ -46,13 +46,20 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
if (!UncivGame.Current.worldScreen.canChangeState)
rightSideButton.disable()
topTable.row().pad(30f)
topTable.row().pad(10f)
for (branch in viewingCiv.gameInfo.ruleSet.policyBranches.values) {
if (branch.name == "Commerce") topTable.addSeparator()
val branches = viewingCiv.gameInfo.ruleSet.policyBranches
val rowChangeIndex = (branches.size + 1) / 2
var wrapper = Table()
for ( (index, branch) in branches.values.withIndex()) {
if (index == rowChangeIndex) {
topTable.add(wrapper)
topTable.addSeparator()
wrapper = Table()
}
val branchGroup = Table()
branchGroup.row().pad(20f)
branchGroup.add(getPolicyButton(branch, false)).row()
branchGroup.add(getPolicyButton(branch, false)).minWidth(160f).row()
var currentRow = 1
var currentColumn = 1
@ -60,7 +67,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
for (policy in branch.policies) {
if (policy.name.endsWith("Complete")) continue
if (policy.row > currentRow) {
branchTable.row()
branchTable.row().pad(2.5f)
currentRow++
currentColumn = 1
}
@ -73,10 +80,11 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
branchTable.pack()
branchGroup.add(branchTable).height(150f).row()
branchGroup.add(getPolicyButton(branch.policies.last(), false)) // finisher
branchGroup.add(getPolicyButton(branch.policies.last(), false)).pad(15f,0f) // finisher
topTable.add(branchGroup)
wrapper.add(branchGroup).pad(0f, 10f)
}
topTable.add(wrapper)
topTable.pack()
}

View File

@ -325,7 +325,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Trade](https://thenounproject.com/term/trade/686718/) By Gregor Cresnar for Trade Unions
* [Pie Chart](https://thenounproject.com/term/pie-chart/1284359/) By Adrien Coquet for Protectionism
* [Coins](https://thenounproject.com/term/coins/1915881/) By icon 54 for Mercantilism
* [Sextant](https://thenounproject.com/term/sextant/313438 ) By lastspark for Sextant
* [Sextant](https://thenounproject.com/term/sextant/313438) By lastspark for Naval Tradition
* [Merchant Navy Icon](https://www.pngkit.com/view/u2w7i1i1o0t4a9y3_png-file-merchant-navy-icon/) for Merchant Navy
### Rationalism
@ -352,7 +352,12 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
* [Newspaper](https://thenounproject.com/term/newspaper/1207487/) By Trishul for Populism
* [Riot Police](https://thenounproject.com/term/riot-police/43117/) By Dan Hetteix for Police State
### Order
* Adapted from [Plan](https://thenounproject.com/term/plan/2973572) by Cattaleeya Thongsriphong for Planned Economy
* [Flag](https://thenounproject.com/term/flag/2712405) by Muhammad Tajudin for Nationalism
* [Communism](https://thenounproject.com/term/communism/142765) By Valerio Poltrini for Socialism
* [Hammer and Sickle](https://thenounproject.com/term/hammer-and-sickle/1367670) by Dmitry Baranovskiy for Communism
* [United](https://thenounproject.com/term/united/3433531) by Izwar Muis for United Front
## Technologies