mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 05:46:43 -04:00
Made unhappiness effects moddable by adding a global uniques json; added revolts when < -20 happiness (#5932)
* Added a json file for unhappiness effects * Change existing code to handle these effects * Made a weird and unexpendable way to add unhappiness effects to the civilopedia * Add the default unhappinesseffects to mods without the json * Added revolts when at very low happiness * Renamed a few often-used functions * Added a file for uniques that are always active * Fixed tests * Nullifies [Food] -> Nullifies Growth
This commit is contained in:
parent
40cd2ba24b
commit
f6cb2bd0d7
25
android/assets/jsons/Civ V - Gods & Kings/GlobalUniques.json
Normal file
25
android/assets/jsons/Civ V - Gods & Kings/GlobalUniques.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "Global uniques",
|
||||
"uniques": [
|
||||
"[-75]% growth [in all cities] <when between [-10] and [0] Happiness>",
|
||||
"Nullifies Growth [in all cities] <when below [-10] Happiness>",
|
||||
"[-50]% [Production] [in all cities] <when below [-10] Happiness>",
|
||||
"[-33]% Strength <for [All] units> <when below [-10] Happiness>",
|
||||
"Cannot build [Settler] units <when below [-10] Happiness>",
|
||||
"Rebel units may spawn <when below [-20] Happiness>"
|
||||
|
||||
// TODO: Implement the uniques below
|
||||
// "[+20]% [Culture] [in all cities] <during a golden age>",
|
||||
// "[+20]% [Production] [in all cities] <during a golden age>",
|
||||
|
||||
// "[+10]% growth [in all cities] <during We Love The King Day>",
|
||||
|
||||
// "Nullifies All Yield <while is in resistance>",
|
||||
|
||||
// "[-25]% [Science] [in pupetted cities]" -- Imo cityFilters should ideally become conditionals anyway
|
||||
// "[-25]% [Culture] [in pupetted cities]"
|
||||
|
||||
// "[+20]% [Production] [in cities connected via railroad]"
|
||||
// something something unit supply
|
||||
]
|
||||
}
|
25
android/assets/jsons/Civ V - Vanilla/GlobalUniques.json
Normal file
25
android/assets/jsons/Civ V - Vanilla/GlobalUniques.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "Global uniques",
|
||||
"uniques": [
|
||||
"[-75]% growth [in all cities] <when between [-10] and [0] Happiness>",
|
||||
"Nullifies Growth [in all cities] <when below [-10] Happiness>",
|
||||
"[-50]% [Production] [in all cities] <when below [-10] Happiness>",
|
||||
"[-33]% Strength <for [All] units> <when below [-10] Happiness>",
|
||||
"Cannot build [Settler] units <when below [-10] Happiness>",
|
||||
"Rebel units may spawn <when below [-20] Happiness>"
|
||||
|
||||
// TODO: Implement the uniques below
|
||||
// "[+20]% [Culture] [in all cities] <during a golden age>",
|
||||
// "[+20]% [Production] [in all cities] <during a golden age>",
|
||||
|
||||
// "[+10]% growth [in all cities] <during We Love The King Day>",
|
||||
|
||||
// "Nullifies All Yield <while is in resistance>",
|
||||
|
||||
// "[-25]% [Science] [in pupetted cities]" -- Imo cityFilters should ideally become conditionals anyway
|
||||
// "[-25]% [Culture] [in pupetted cities]"
|
||||
|
||||
// "[+20]% [Production] [in cities connected via railroad]"
|
||||
// something something unit supply
|
||||
]
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
"This means that it is very difficult to expand quickly in Unciv.\nIt isn’t impossible, but as a new player you probably shouldn't do it.\nSo what should you do? Chill out, scout, and improve the land that you do have by building Workers.\nOnly build new cities once you have found a spot that you believe is appropriate."
|
||||
],
|
||||
Unhappiness: [
|
||||
"It seems that your citizens are unhappy!\nWhile unhappy, cities will grow at 1/4 the speed, and your units will suffer a 2% penalty for each unhappiness",
|
||||
"It seems that your citizens are unhappy!\nWhile unhappy, your civilization will suffer many detrimental effects, increasing in severity as unhappiness gets higher.",
|
||||
"Unhappiness has two main causes: Population and cities.\n Each city causes 3 unhappiness, and each population, 1",
|
||||
"There are 2 main ways to combat unhappiness:\n by building happiness buildings for your population\n or by having improved luxury resources within your borders."
|
||||
],
|
||||
|
@ -754,6 +754,7 @@ Force =
|
||||
GOLDEN AGE =
|
||||
Golden Age =
|
||||
We Love The King Day =
|
||||
Global Effect =
|
||||
[year] BC =
|
||||
[year] AD =
|
||||
Civilopedia =
|
||||
@ -811,7 +812,6 @@ Specialist Allocation =
|
||||
Specialists =
|
||||
[specialist] slots =
|
||||
Food eaten =
|
||||
Growth bonus =
|
||||
Unassigned population =
|
||||
[turnsToExpansion] turns to expansion =
|
||||
Stopped expansion =
|
||||
|
@ -66,13 +66,13 @@ class MainMenuScreen: BaseScreen() {
|
||||
|
||||
// If we were in a mod, some of the resource images for the background map we're creating
|
||||
// will not exist unless we reset the ruleset and images
|
||||
ImageGetter.ruleset = RulesetCache.getBaseRuleset()
|
||||
ImageGetter.ruleset = RulesetCache.getVanillaRuleset()
|
||||
|
||||
crashHandlingThread(name = "ShowMapBackground") {
|
||||
val newMap = MapGenerator(RulesetCache.getBaseRuleset())
|
||||
val newMap = MapGenerator(RulesetCache.getVanillaRuleset())
|
||||
.generateMap(MapParameters().apply { mapSize = MapSizeNew(MapSize.Small); type = MapType.default })
|
||||
postCrashHandlingRunnable { // for GL context
|
||||
ImageGetter.setNewRuleset(RulesetCache.getBaseRuleset())
|
||||
ImageGetter.setNewRuleset(RulesetCache.getVanillaRuleset())
|
||||
val mapHolder = EditorMapHolder(MapEditorScreen(), newMap)
|
||||
backgroundTable.addAction(Actions.sequence(
|
||||
Actions.fadeOut(0f),
|
||||
|
@ -117,7 +117,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
|
||||
postCrashHandlingRunnable {
|
||||
musicController.chooseTrack(suffix = MusicMood.Menu)
|
||||
|
||||
ImageGetter.ruleset = RulesetCache.getBaseRuleset() // so that we can enter the map editor without having to load a game first
|
||||
ImageGetter.ruleset = RulesetCache.getVanillaRuleset() // so that we can enter the map editor without having to load a game first
|
||||
|
||||
if (settings.isFreshlyCreated) {
|
||||
setScreen(LanguagePickerScreen())
|
||||
|
@ -40,7 +40,7 @@ object GameStarter {
|
||||
gameSetupInfo.gameParameters.baseRuleset = baseRulesetInMods
|
||||
|
||||
if (!RulesetCache.containsKey(gameSetupInfo.gameParameters.baseRuleset))
|
||||
gameSetupInfo.gameParameters.baseRuleset = RulesetCache.getBaseRuleset().name
|
||||
gameSetupInfo.gameParameters.baseRuleset = RulesetCache.getVanillaRuleset().name
|
||||
|
||||
gameInfo.gameParameters = gameSetupInfo.gameParameters
|
||||
val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters.mods, gameInfo.gameParameters.baseRuleset)
|
||||
|
@ -2,6 +2,7 @@ package com.unciv.logic.battle
|
||||
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.ruleset.GlobalUniques
|
||||
import com.unciv.models.ruleset.unique.StateForConditionals
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
@ -17,9 +18,10 @@ import kotlin.math.roundToInt
|
||||
object BattleDamage {
|
||||
|
||||
private fun getModifierStringFromUnique(unique: Unique): String {
|
||||
val source = when (unique.sourceObjectType) {
|
||||
val source = when (unique.sourceObjectType) {
|
||||
UniqueTarget.Unit -> "Unit ability"
|
||||
UniqueTarget.Nation -> "National ability"
|
||||
UniqueTarget.Global -> GlobalUniques.getUniqueSourceDescription(unique)
|
||||
else -> "[${unique.sourceObjectName}] ([${unique.sourceObjectType?.name}])"
|
||||
}
|
||||
if (unique.conditionals.isEmpty()) return source
|
||||
@ -58,19 +60,6 @@ object BattleDamage {
|
||||
}
|
||||
|
||||
//https://www.carlsguides.com/strategy/civilization5/war/combatbonuses.php
|
||||
val civHappiness = if (civInfo.isCityState() && civInfo.getAllyCiv() != null)
|
||||
// If we are a city state with an ally we are vulnerable to their unhappiness.
|
||||
min(
|
||||
civInfo.gameInfo.getCivilization(civInfo.getAllyCiv()!!).getHappiness(),
|
||||
civInfo.getHappiness()
|
||||
)
|
||||
else civInfo.getHappiness()
|
||||
if (civHappiness < 0)
|
||||
modifiers["Unhappiness"] = max(
|
||||
2 * civHappiness,
|
||||
-90
|
||||
) // otherwise it could exceed -100% and start healing enemy units...
|
||||
|
||||
val adjacentUnits = combatant.getTile().neighbors.flatMap { it.getUnits() }
|
||||
|
||||
// Deprecated since 3.18.17
|
||||
|
@ -282,7 +282,7 @@ class CityInfo {
|
||||
fun hasFlag(flag: CityFlags) = flagsCountdown.containsKey(flag.name)
|
||||
fun getFlag(flag: CityFlags) = flagsCountdown[flag.name]!!
|
||||
|
||||
fun isWeLoveTheKingDay() = hasFlag(CityFlags.WeLoveTheKing)
|
||||
fun isWeLoveTheKingDayActive() = hasFlag(CityFlags.WeLoveTheKing)
|
||||
fun isInResistance() = hasFlag(CityFlags.Resistance)
|
||||
|
||||
/** @return the number of tiles 4 out from this city that could hold a city, ie how lonely this city is */
|
||||
|
@ -6,9 +6,9 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.logic.map.RoadStatus
|
||||
import com.unciv.models.Counter
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.GlobalUniques
|
||||
import com.unciv.models.ruleset.ModOptionsConstants
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unique.*
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.stats.StatMap
|
||||
@ -167,15 +167,21 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
return stats
|
||||
}
|
||||
|
||||
private fun getGrowthBonusFromPoliciesAndWonders(): Float {
|
||||
var bonus = 0f
|
||||
private fun getGrowthBonus(totalFood: Float): StatMap {
|
||||
val growthSources = StatMap()
|
||||
val stateForConditionals = StateForConditionals(cityInfo.civInfo, cityInfo)
|
||||
// "[amount]% growth [cityFilter]"
|
||||
for (unique in cityInfo.getMatchingUniques(UniqueType.GrowthPercentBonus)) {
|
||||
if (!unique.conditionalsApply(cityInfo.civInfo, cityInfo)) continue
|
||||
if (cityInfo.matchesFilter(unique.params[1]))
|
||||
bonus += unique.params[0].toFloat()
|
||||
for (unique in cityInfo.getMatchingUniques(UniqueType.GrowthPercentBonus, stateForConditionals = stateForConditionals)) {
|
||||
if (!cityInfo.matchesFilter(unique.params[1])) continue
|
||||
|
||||
val uniqueSource =
|
||||
if (unique.sourceObjectType == UniqueTarget.Global && unique.conditionals.any())
|
||||
GlobalUniques.getUniqueSourceDescription(unique)
|
||||
else unique.sourceObjectType?.name ?: ""
|
||||
|
||||
growthSources.add(uniqueSource, Stats(food = unique.params[0].toFloat()/100f * totalFood))
|
||||
}
|
||||
return bonus / 100
|
||||
return growthSources
|
||||
}
|
||||
|
||||
fun hasExtraAnnexUnhappiness(): Boolean {
|
||||
@ -206,8 +212,13 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
|
||||
private fun getStatsFromUniquesBySource(): StatTreeNode {
|
||||
val sourceToStats = StatTreeNode()
|
||||
fun addUniqueStats(unique:Unique) =
|
||||
sourceToStats.addStats(unique.stats, unique.sourceObjectType?.name ?: "", unique.sourceObjectName ?: "")
|
||||
fun addUniqueStats(unique:Unique) {
|
||||
val uniqueSource =
|
||||
if (unique.sourceObjectType == UniqueTarget.Global && unique.conditionals.any())
|
||||
GlobalUniques.getUniqueSourceDescription(unique)
|
||||
else unique.sourceObjectType?.name ?: ""
|
||||
sourceToStats.addStats(unique.stats, uniqueSource, unique.sourceObjectName ?: "")
|
||||
}
|
||||
|
||||
for (unique in cityInfo.getMatchingUniques(UniqueType.Stats))
|
||||
addUniqueStats(unique)
|
||||
@ -278,9 +289,14 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
|
||||
private fun getStatsPercentBonusesFromUniquesBySource(currentConstruction: IConstruction):StatMap {
|
||||
val sourceToStats = StatMap()
|
||||
fun addUniqueStats(unique: Unique, stat:Stat, amount:Float) =
|
||||
sourceToStats.add(unique.sourceObjectType?.name ?: "",
|
||||
Stats().add(stat, amount))
|
||||
fun addUniqueStats(unique: Unique, stat:Stat, amount:Float) {
|
||||
val uniqueSource =
|
||||
if (unique.sourceObjectType == UniqueTarget.Global && unique.conditionals.any())
|
||||
GlobalUniques.getUniqueSourceDescription(unique)
|
||||
else unique.sourceObjectType?.name ?: ""
|
||||
|
||||
sourceToStats.add(uniqueSource, Stats().add(stat, amount))
|
||||
}
|
||||
|
||||
for (unique in cityInfo.getMatchingUniques(UniqueType.StatPercentBonus)) {
|
||||
addUniqueStats(unique, Stat.valueOf(unique.params[1]), unique.params[0].toFloat())
|
||||
@ -294,14 +310,14 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
|
||||
|
||||
val uniquesToCheck =
|
||||
if (currentConstruction is Building && currentConstruction.isAnyWonder()) {
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionWonders)
|
||||
} else if (currentConstruction is Building && !currentConstruction.isAnyWonder()) {
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionBuildings)
|
||||
} else if (currentConstruction is BaseUnit) {
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionUnits)
|
||||
} else { // Science/Gold production
|
||||
sequenceOf()
|
||||
when {
|
||||
currentConstruction is BaseUnit ->
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionUnits)
|
||||
currentConstruction is Building && currentConstruction.isAnyWonder() ->
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionWonders)
|
||||
currentConstruction is Building && !currentConstruction.isAnyWonder() ->
|
||||
cityInfo.getMatchingUniques(UniqueType.PercentProductionBuildings)
|
||||
else -> sequenceOf() // Science/Gold production
|
||||
}
|
||||
|
||||
for (unique in uniquesToCheck) {
|
||||
@ -321,9 +337,11 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
|
||||
if (currentConstruction is Building
|
||||
&& cityInfo.civInfo.cities.isNotEmpty()
|
||||
&& cityInfo.civInfo.getCapital().cityConstructions.builtBuildings.contains(currentConstruction.name))
|
||||
for(unique in cityInfo.getMatchingUniques("+25% Production towards any buildings that already exist in the Capital"))
|
||||
addUniqueStats(unique, Stat.Production, 25f)
|
||||
&& cityInfo.civInfo.getCapital().cityConstructions.builtBuildings.contains(currentConstruction.name)
|
||||
) {
|
||||
for (unique in cityInfo.getMatchingUniques("+25% Production towards any buildings that already exist in the Capital"))
|
||||
addUniqueStats(unique, Stat.Production, 25f)
|
||||
}
|
||||
|
||||
renameStatmapKeys(sourceToStats)
|
||||
|
||||
@ -462,8 +480,8 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
private fun updateBaseStatList(statsFromBuildings: StatTreeNode) {
|
||||
val newBaseStatTree = StatTreeNode()
|
||||
|
||||
val newBaseStatList =
|
||||
StatMap() // we don't edit the existing baseStatList directly, in order to avoid concurrency exceptions
|
||||
// We don't edit the existing baseStatList directly, in order to avoid concurrency exceptions
|
||||
val newBaseStatList = StatMap()
|
||||
|
||||
newBaseStatTree.addStats(Stats(
|
||||
science = cityInfo.population.population.toFloat(),
|
||||
@ -576,6 +594,20 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
entry.science *= statPercentBonusesSum.science.toPercent()
|
||||
}
|
||||
|
||||
for ((unique, statToBeRemoved) in cityInfo.getMatchingUniques(UniqueType.NullifiesStat)
|
||||
.map { it to Stat.valueOf(it.params[0]) }
|
||||
.distinct()
|
||||
) {
|
||||
val removedAmount = newFinalStatList.values.sumOf { it[statToBeRemoved].toDouble() }
|
||||
|
||||
val uniqueSource =
|
||||
if (unique.sourceObjectType == UniqueTarget.Global && unique.conditionals.any())
|
||||
GlobalUniques.getUniqueSourceDescription(unique)
|
||||
else unique.sourceObjectType?.name ?: ""
|
||||
|
||||
newFinalStatList.add(uniqueSource, Stats().apply { this[statToBeRemoved] = -removedAmount.toFloat() })
|
||||
}
|
||||
|
||||
/* Okay, food calculation is complicated.
|
||||
First we see how much food we generate. Then we apply production bonuses to it.
|
||||
Up till here, business as usual.
|
||||
@ -592,15 +624,12 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
if (totalFood > 0) {
|
||||
// Since growth bonuses are special, (applied afterwards) they will be displayed separately in the user interface as well.
|
||||
// All bonuses except We Love The King do apply even when unhappy
|
||||
val foodFromGrowthBonuses = Stats(food = getGrowthBonusFromPoliciesAndWonders() * totalFood)
|
||||
newFinalStatList.add("Growth bonus", foodFromGrowthBonuses)
|
||||
val happiness = cityInfo.civInfo.getHappiness()
|
||||
if (happiness < 0) {
|
||||
// Unhappiness -75% to -100%
|
||||
val foodReducedByUnhappiness = if (happiness <= -10) Stats(food = totalFood * -1)
|
||||
else Stats(food = (totalFood * -3) / 4)
|
||||
newFinalStatList.add("Unhappiness", foodReducedByUnhappiness)
|
||||
} else if (cityInfo.isWeLoveTheKingDay()) {
|
||||
val growthBonuses = getGrowthBonus(totalFood)
|
||||
renameStatmapKeys(growthBonuses)
|
||||
for (growthBonus in growthBonuses) {
|
||||
newFinalStatList.add("${growthBonus.key} (Growth)", growthBonus.value)
|
||||
}
|
||||
if (cityInfo.isWeLoveTheKingDayActive() && cityInfo.civInfo.getHappiness() >= 0) {
|
||||
// We Love The King Day +25%, only if not unhappy
|
||||
val weLoveTheKingFood = Stats(food = totalFood / 4)
|
||||
newFinalStatList.add("We Love The King Day", weLoveTheKingFood)
|
||||
@ -619,10 +648,20 @@ class CityStats(val cityInfo: CityInfo) {
|
||||
) {
|
||||
newFinalStatList["Excess food to production"] = Stats(production = totalFood, food = -totalFood)
|
||||
}
|
||||
|
||||
val growthNullifyingUnique = cityInfo.getMatchingUniques(UniqueType.NullifiesGrwoth).firstOrNull()
|
||||
if (growthNullifyingUnique != null) {
|
||||
val uniqueSource =
|
||||
if (growthNullifyingUnique.sourceObjectType == UniqueTarget.Global && growthNullifyingUnique.conditionals.any())
|
||||
GlobalUniques.getUniqueSourceDescription(growthNullifyingUnique)
|
||||
else growthNullifyingUnique.sourceObjectType?.name ?: ""
|
||||
val amountToRemove = -newFinalStatList.values.sumOf { it[Stat.Food].toDouble() }
|
||||
newFinalStatList[uniqueSource] = Stats().apply { this[Stat.Food] = amountToRemove.toFloat() }
|
||||
}
|
||||
|
||||
if (cityInfo.isInResistance())
|
||||
newFinalStatList.clear() // NOPE
|
||||
|
||||
|
||||
if (newFinalStatList.values.map { it.production }.sum() < 1) // Minimum production for things to progress
|
||||
newFinalStatList["Production"] = Stats(production = 1f)
|
||||
finalStatList = newFinalStatList
|
||||
|
@ -382,7 +382,8 @@ class CivilizationInfo {
|
||||
else city.getAllUniquesWithNonLocalEffects()
|
||||
}
|
||||
|
||||
fun hasUnique(uniqueType: UniqueType, stateForConditionals: StateForConditionals? = null) = getMatchingUniques(uniqueType, stateForConditionals).any()
|
||||
fun hasUnique(uniqueType: UniqueType, stateForConditionals: StateForConditionals? =
|
||||
StateForConditionals(this)) = getMatchingUniques(uniqueType, stateForConditionals).any()
|
||||
fun hasUnique(unique: String) = getMatchingUniques(unique).any()
|
||||
|
||||
// Does not return local uniques, only global ones.
|
||||
@ -402,6 +403,9 @@ class CivilizationInfo {
|
||||
yieldAll(getEra().getMatchingUniques(uniqueType, stateForConditionals))
|
||||
if (religionManager.religion != null)
|
||||
yieldAll(religionManager.religion!!.getFounderUniques().filter { it.isOfType(uniqueType) })
|
||||
|
||||
yieldAll(gameInfo.ruleSet.globalUniques.getMatchingUniques(uniqueType, stateForConditionals))
|
||||
|
||||
}.filter {
|
||||
it.conditionalsApply(stateForConditionals)
|
||||
}
|
||||
@ -424,8 +428,10 @@ class CivilizationInfo {
|
||||
.asSequence()
|
||||
.filter { it.placeholderText == uniqueTemplate }
|
||||
)
|
||||
|
||||
yieldAll(gameInfo.ruleSet.globalUniques.getMatchingUniques(uniqueTemplate))
|
||||
}
|
||||
|
||||
|
||||
//region Units
|
||||
fun getCivUnitsSize(): Int = units.size
|
||||
fun getCivUnits(): Sequence<MapUnit> = units.asSequence()
|
||||
@ -827,6 +833,7 @@ class CivilizationInfo {
|
||||
updateViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
|
||||
transients().updateCitiesConnectedToCapital()
|
||||
startTurnFlags()
|
||||
updateRevolts()
|
||||
for (city in cities) city.startTurn() // Most expensive part of startTurn
|
||||
|
||||
for (unit in getCivUnits()) unit.startTurn()
|
||||
@ -921,6 +928,11 @@ class CivilizationInfo {
|
||||
if (flagsCountdown[flag]!! > 0)
|
||||
flagsCountdown[flag] = flagsCountdown[flag]!! - 1
|
||||
|
||||
if (flagsCountdown[flag] != 0) continue
|
||||
|
||||
when (flag) {
|
||||
CivFlags.RevoltSpawning.name -> doRevoltSpawn()
|
||||
}
|
||||
}
|
||||
handleDiplomaticVictoryFlags()
|
||||
}
|
||||
@ -947,8 +959,8 @@ class CivilizationInfo {
|
||||
}
|
||||
|
||||
fun addFlag(flag: String, count: Int) = flagsCountdown.set(flag, count)
|
||||
|
||||
fun removeFlag(flag: String) = flagsCountdown.remove(flag)
|
||||
fun hasFlag(flag: String) = flagsCountdown.contains(flag)
|
||||
|
||||
fun getTurnsBetweenDiplomaticVotings() = (15 * gameInfo.gameParameters.gameSpeed.modifier).toInt() // Dunno the exact calculation, hidden in Lua files
|
||||
|
||||
@ -975,6 +987,65 @@ class CivilizationInfo {
|
||||
fun shouldCheckForDiplomaticVictory() =
|
||||
shouldShowDiplomaticVotingResults()
|
||||
|
||||
private fun updateRevolts() {
|
||||
if (!hasUnique(UniqueType.SpawnRebels)) {
|
||||
removeFlag(CivFlags.RevoltSpawning.name)
|
||||
return
|
||||
}
|
||||
|
||||
if (!hasFlag(CivFlags.RevoltSpawning.name)) {
|
||||
addFlag(CivFlags.RevoltSpawning.name, max(getTurnsBeforeRevolt(),1))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun doRevoltSpawn() {
|
||||
val random = Random()
|
||||
val rebelCount = 1 + random.nextInt(100 + 20 * (cities.size - 1)) / 100
|
||||
val spawnCity = cities.maxByOrNull { random.nextInt(it.population.population + 10) } ?: return
|
||||
val spawnTile = spawnCity.getTiles().maxByOrNull { rateTileForRevoltSpawn(it) } ?: return
|
||||
val unitToSpawn = gameInfo.ruleSet.units.values.asSequence().filter {
|
||||
it.uniqueTo == null && it.isMelee() && it.isLandUnit()
|
||||
&& !it.hasUnique(UniqueType.CannotAttack) && it.isBuildable(this)
|
||||
}.maxByOrNull {
|
||||
random.nextInt(1000)
|
||||
} ?: return
|
||||
|
||||
repeat(rebelCount) {
|
||||
gameInfo.tileMap.placeUnitNearTile(
|
||||
spawnTile.position,
|
||||
unitToSpawn.name,
|
||||
gameInfo.getBarbarianCivilization()
|
||||
)
|
||||
}
|
||||
|
||||
// Will be automatically added again as long as unhappiness is still low enough
|
||||
removeFlag(CivFlags.RevoltSpawning.name)
|
||||
|
||||
addNotification("Your citizens are revolting due to very high unhappiness!", spawnTile.position, unitToSpawn.name, "StatIcons/Malcontent")
|
||||
}
|
||||
|
||||
// Higher is better
|
||||
private fun rateTileForRevoltSpawn(tile: TileInfo): Int {
|
||||
if (tile.isWater || tile.militaryUnit != null || tile.civilianUnit != null || tile.isCityCenter() || tile.isImpassible())
|
||||
return -1;
|
||||
var score = 10
|
||||
if (tile.improvement == null) {
|
||||
score += 4
|
||||
if (tile.resource != null) {
|
||||
score += 3
|
||||
}
|
||||
}
|
||||
if (tile.getDefensiveBonus() > 0)
|
||||
score += 4
|
||||
return score
|
||||
}
|
||||
|
||||
private fun getTurnsBeforeRevolt(): Int {
|
||||
val score = ((4 + Random().nextInt(3)) * max(gameInfo.gameParameters.gameSpeed.modifier, 1f)).toInt()
|
||||
return score
|
||||
}
|
||||
|
||||
/** Modify gold by a given amount making sure it does neither overflow nor underflow.
|
||||
* @param delta the amount to add (can be negative)
|
||||
*/
|
||||
@ -1198,7 +1269,7 @@ class CivilizationInfo {
|
||||
|
||||
return proximity
|
||||
}
|
||||
|
||||
|
||||
//////////////////////// City State wrapper functions ////////////////////////
|
||||
|
||||
/** Gain a random great person from the city state */
|
||||
@ -1252,4 +1323,5 @@ enum class CivFlags {
|
||||
ShouldResetDiplomaticVotes,
|
||||
RecentlyBullied,
|
||||
TurnsTillCallForBarbHelp,
|
||||
RevoltSpawning,
|
||||
}
|
||||
|
25
core/src/com/unciv/models/ruleset/GlobalUniques.kt
Normal file
25
core/src/com/unciv/models/ruleset/GlobalUniques.kt
Normal file
@ -0,0 +1,25 @@
|
||||
package com.unciv.models.ruleset
|
||||
|
||||
import com.unciv.models.ruleset.unique.Unique
|
||||
import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
|
||||
class GlobalUniques: RulesetObject() {
|
||||
override var name = ""
|
||||
override fun getUniqueTarget() = UniqueTarget.Global
|
||||
override fun makeLink() = "" // No own category on Civilopedia screen
|
||||
|
||||
companion object {
|
||||
fun getUniqueSourceDescription(unique: Unique): String {
|
||||
if (unique.conditionals.none())
|
||||
return "Global Effect"
|
||||
|
||||
return when (unique.conditionals.first().type) {
|
||||
UniqueType.ConditionalGoldenAge -> "Golden Age"
|
||||
UniqueType.ConditionalHappy -> "Happiness"
|
||||
UniqueType.ConditionalBetweenHappiness, UniqueType.ConditionalBelowHappiness -> "Unhappiness"
|
||||
else -> "Global Effect"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -65,13 +65,12 @@ class Ruleset {
|
||||
|
||||
private val jsonParser = JsonParser()
|
||||
|
||||
var modWithReligionLoaded = false
|
||||
|
||||
var name = ""
|
||||
val beliefs = LinkedHashMap<String, Belief>()
|
||||
val buildings = LinkedHashMap<String, Building>()
|
||||
val difficulties = LinkedHashMap<String, Difficulty>()
|
||||
val eras = LinkedHashMap<String, Era>()
|
||||
var globalUniques = GlobalUniques()
|
||||
val nations = LinkedHashMap<String, Nation>()
|
||||
val policies = LinkedHashMap<String, Policy>()
|
||||
val policyBranches = LinkedHashMap<String, PolicyBranch>()
|
||||
@ -104,15 +103,16 @@ class Ruleset {
|
||||
}
|
||||
|
||||
fun add(ruleset: Ruleset) {
|
||||
beliefs.putAll(ruleset.beliefs)
|
||||
buildings.putAll(ruleset.buildings)
|
||||
for (buildingToRemove in ruleset.modOptions.buildingsToRemove) buildings.remove(buildingToRemove)
|
||||
difficulties.putAll(ruleset.difficulties)
|
||||
eras.putAll(ruleset.eras)
|
||||
globalUniques = GlobalUniques().apply { uniques.addAll(globalUniques.uniques); uniques.addAll(ruleset.globalUniques.uniques) }
|
||||
nations.putAll(ruleset.nations)
|
||||
for (nationToRemove in ruleset.modOptions.nationsToRemove) nations.remove(nationToRemove)
|
||||
policyBranches.putAll(ruleset.policyBranches)
|
||||
policies.putAll(ruleset.policies)
|
||||
beliefs.putAll(ruleset.beliefs)
|
||||
quests.putAll(ruleset.quests)
|
||||
religions.addAll(ruleset.religions)
|
||||
ruinRewards.putAll(ruleset.ruinRewards)
|
||||
@ -127,7 +127,6 @@ class Ruleset {
|
||||
unitTypes.putAll(ruleset.unitTypes)
|
||||
for (unitToRemove in ruleset.modOptions.unitsToRemove) units.remove(unitToRemove)
|
||||
mods += ruleset.mods
|
||||
modWithReligionLoaded = modWithReligionLoaded || ruleset.modWithReligionLoaded
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
@ -135,14 +134,15 @@ class Ruleset {
|
||||
buildings.clear()
|
||||
difficulties.clear()
|
||||
eras.clear()
|
||||
policyBranches.clear()
|
||||
specialists.clear()
|
||||
globalUniques = GlobalUniques()
|
||||
mods.clear()
|
||||
nations.clear()
|
||||
policies.clear()
|
||||
policyBranches.clear()
|
||||
quests.clear()
|
||||
religions.clear()
|
||||
ruinRewards.clear()
|
||||
quests.clear()
|
||||
specialists.clear()
|
||||
technologies.clear()
|
||||
terrains.clear()
|
||||
tileImprovements.clear()
|
||||
@ -150,7 +150,6 @@ class Ruleset {
|
||||
unitPromotions.clear()
|
||||
units.clear()
|
||||
unitTypes.clear()
|
||||
modWithReligionLoaded = false
|
||||
}
|
||||
|
||||
|
||||
@ -201,7 +200,7 @@ class Ruleset {
|
||||
if (erasFile.exists()) eras += createHashmap(jsonParser.getFromJson(Array<Era>::class.java, erasFile))
|
||||
// While `eras.values.toList()` might seem more logical, eras.values is a MutableCollection and
|
||||
// therefore does not guarantee keeping the order of elements like a LinkedHashMap does.
|
||||
// Using a map sidesteps this problem
|
||||
// Using map{} sidesteps this problem
|
||||
eras.map { it.value }.withIndex().forEach { it.value.eraNumber = it.index }
|
||||
|
||||
val unitTypesFile = folderHandle.child("UnitTypes.json")
|
||||
@ -254,8 +253,14 @@ class Ruleset {
|
||||
}
|
||||
|
||||
val difficultiesFile = folderHandle.child("Difficulties.json")
|
||||
if (difficultiesFile.exists()) difficulties += createHashmap(jsonParser.getFromJson(Array<Difficulty>::class.java, difficultiesFile))
|
||||
if (difficultiesFile.exists())
|
||||
difficulties += createHashmap(jsonParser.getFromJson(Array<Difficulty>::class.java, difficultiesFile))
|
||||
|
||||
val globalUniquesFile = folderHandle.child("GlobalUniques.json")
|
||||
if (globalUniquesFile.exists()) {
|
||||
globalUniques = jsonParser.getFromJson(GlobalUniques::class.java, globalUniquesFile)
|
||||
}
|
||||
|
||||
val gameBasicsLoadTime = System.currentTimeMillis() - gameBasicsStartTime
|
||||
if (printOutput) println("Loading ruleset - " + gameBasicsLoadTime + "ms")
|
||||
}
|
||||
@ -274,9 +279,7 @@ class Ruleset {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hasReligion() = beliefs.any() && modWithReligionLoaded
|
||||
|
||||
|
||||
/** Used for displaying a RuleSet's name */
|
||||
override fun toString() = when {
|
||||
name.isNotEmpty() -> name
|
||||
@ -476,7 +479,7 @@ class Ruleset {
|
||||
// Quit here when no base ruleset is loaded - references cannot be checked
|
||||
if (!modOptions.isBaseRuleset) return lines
|
||||
|
||||
val baseRuleset = RulesetCache.getBaseRuleset() // for UnitTypes fallback
|
||||
val baseRuleset = RulesetCache.getVanillaRuleset() // for UnitTypes fallback
|
||||
|
||||
for (unit in units.values) {
|
||||
if (unit.requiredTech != null && !technologies.containsKey(unit.requiredTech!!))
|
||||
@ -697,7 +700,7 @@ object RulesetCache : HashMap<String,Ruleset>() {
|
||||
}
|
||||
|
||||
|
||||
fun getBaseRuleset() = this[BaseRuleset.Civ_V_Vanilla.fullName]!!.clone() // safeguard, so no-one edits the base ruleset by mistake
|
||||
fun getVanillaRuleset() = this[BaseRuleset.Civ_V_Vanilla.fullName]!!.clone() // safeguard, so no-one edits the base ruleset by mistake
|
||||
|
||||
fun getSortedBaseRulesets(): List<String> {
|
||||
val baseRulesets = values
|
||||
@ -729,7 +732,7 @@ object RulesetCache : HashMap<String,Ruleset>() {
|
||||
|
||||
val baseRuleset =
|
||||
if (containsKey(optionalBaseRuleset) && this[optionalBaseRuleset]!!.modOptions.isBaseRuleset) this[optionalBaseRuleset]!!
|
||||
else getBaseRuleset()
|
||||
else getVanillaRuleset()
|
||||
|
||||
|
||||
val loadedMods = mods
|
||||
@ -744,20 +747,20 @@ object RulesetCache : HashMap<String,Ruleset>() {
|
||||
if (mod.modOptions.isBaseRuleset) {
|
||||
newRuleset.modOptions = mod.modOptions
|
||||
}
|
||||
if (mod.beliefs.any()) {
|
||||
newRuleset.modWithReligionLoaded = true
|
||||
}
|
||||
}
|
||||
newRuleset.updateBuildingCosts() // only after we've added all the mods can we calculate the building costs
|
||||
|
||||
// This one should be temporary
|
||||
if (newRuleset.unitTypes.isEmpty()) {
|
||||
newRuleset.unitTypes.putAll(getBaseRuleset().unitTypes)
|
||||
newRuleset.unitTypes.putAll(getVanillaRuleset().unitTypes)
|
||||
}
|
||||
|
||||
// This one should be permanent
|
||||
// These should be permanent
|
||||
if (newRuleset.ruinRewards.isEmpty()) {
|
||||
newRuleset.ruinRewards.putAll(getBaseRuleset().ruinRewards)
|
||||
newRuleset.ruinRewards.putAll(getVanillaRuleset().ruinRewards)
|
||||
}
|
||||
if (newRuleset.globalUniques.uniques.isEmpty()) {
|
||||
newRuleset.globalUniques = getVanillaRuleset().globalUniques
|
||||
}
|
||||
|
||||
return newRuleset
|
||||
|
@ -58,6 +58,12 @@ class Unique(val text: String, val sourceObjectType: UniqueTarget? = null, val s
|
||||
UniqueType.ConditionalNotWar -> state.civInfo?.isAtWar() == false
|
||||
UniqueType.ConditionalHappy ->
|
||||
state.civInfo != null && state.civInfo.statsForNextTurn.happiness >= 0
|
||||
UniqueType.ConditionalBetweenHappiness ->
|
||||
state.civInfo != null
|
||||
&& condition.params[0].toInt() <= state.civInfo.happinessForNextTurn
|
||||
&& state.civInfo.happinessForNextTurn < condition.params[1].toInt()
|
||||
UniqueType.ConditionalBelowHappiness ->
|
||||
state.civInfo != null && state.civInfo.happinessForNextTurn < condition.params[0].toInt()
|
||||
UniqueType.ConditionalGoldenAge ->
|
||||
state.civInfo != null && state.civInfo.goldenAges.isGoldenAge()
|
||||
UniqueType.ConditionalBeforeEra ->
|
||||
|
@ -87,6 +87,7 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
|
||||
// Stat percentage boosts
|
||||
StatPercentBonus("[amount]% [stat]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
StatPercentBonusCities("[amount]% [stat] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
StatPercentFromObject("[amount]% [stat] from every [tileFilter/specialist/buildingName]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
@Deprecated("As of 3.18.17", ReplaceWith("[amount]% [stat] from every [tileFilter/specialist/buildingName]"))
|
||||
StatPercentSignedFromObject("+[amount]% [stat] from every [tileFilter/specialist/buildingName]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
@ -95,7 +96,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
AllStatsSignedPercentFromObject("+[amount]% yield from every [tileFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
StatPercentFromReligionFollowers("[amount]% [stat] from every follower, up to [amount]%", UniqueTarget.FollowerBelief),
|
||||
BonusStatsFromCityStates("[amount]% [stat] from City-States", UniqueTarget.Global),
|
||||
StatPercentBonusCities("[amount]% [stat] [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
NullifiesStat("Nullifies [stat] [cityFilter]", UniqueTarget.Global),
|
||||
NullifiesGrwoth("Nullifies Growth [cityFilter]", UniqueTarget.Global),
|
||||
|
||||
PercentProductionWonders("[amount]% Production when constructing [buildingFilter] wonders [cityFilter]", UniqueTarget.Global, UniqueTarget.Resource, UniqueTarget.FollowerBelief),
|
||||
PercentProductionBuildings("[amount]% Production when constructing [buildingFilter] buildings [cityFilter]", UniqueTarget.Global, UniqueTarget.FollowerBelief),
|
||||
@ -266,6 +268,8 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
StartsWithTech("Starts with [tech]", UniqueTarget.Nation),
|
||||
ResearchableMultipleTimes("Can be continually researched", UniqueTarget.Global),
|
||||
|
||||
SpawnRebels("Rebel units may spawn", UniqueTarget.Global),
|
||||
|
||||
//endregion
|
||||
|
||||
//endregion Global uniques
|
||||
@ -514,8 +518,11 @@ enum class UniqueType(val text: String, vararg targets: UniqueTarget, val flags:
|
||||
/////// civ conditionals
|
||||
ConditionalWar("when at war", UniqueTarget.Conditional),
|
||||
ConditionalNotWar("when not at war", UniqueTarget.Conditional),
|
||||
ConditionalHappy("while the empire is happy", UniqueTarget.Conditional),
|
||||
ConditionalGoldenAge("during a Golden Age", UniqueTarget.Conditional),
|
||||
|
||||
ConditionalHappy("while the empire is happy", UniqueTarget.Conditional),
|
||||
ConditionalBetweenHappiness("when between [amount] and [amount] Happiness", UniqueTarget.Conditional),
|
||||
ConditionalBelowHappiness("when below [amount] Happiness", UniqueTarget.Conditional),
|
||||
|
||||
ConditionalDuringEra("during the [era]", UniqueTarget.Conditional),
|
||||
ConditionalBeforeEra("before the [era]", UniqueTarget.Conditional),
|
||||
|
@ -238,7 +238,7 @@ object TranslationFileWriter {
|
||||
|
||||
private fun generateStringsFromJSONs(jsonsFolder: FileHandle): LinkedHashMap<String, MutableSet<String>> {
|
||||
// build maps identifying parameters as certain types of filters - unitFilter etc
|
||||
val ruleset = RulesetCache.getBaseRuleset()
|
||||
val ruleset = RulesetCache.getVanillaRuleset()
|
||||
val tileFilterMap = ruleset.terrains.keys.toMutableSet().apply { addAll(sequenceOf(
|
||||
"Friendly Land",
|
||||
"Foreign Land",
|
||||
@ -422,6 +422,7 @@ object TranslationFileWriter {
|
||||
"Buildings" -> emptyArray<Building>().javaClass
|
||||
"Difficulties" -> emptyArray<Difficulty>().javaClass
|
||||
"Eras" -> emptyArray<Era>().javaClass
|
||||
"GlobalUniques" -> GlobalUniques().javaClass
|
||||
"Nations" -> emptyArray<Nation>().javaClass
|
||||
"Policies" -> emptyArray<PolicyBranch>().javaClass
|
||||
"Quests" -> emptyArray<Quest>().javaClass
|
||||
|
@ -87,7 +87,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
tableWithIcons.add(ImageGetter.getImage("StatIcons/Resistance")).size(20f)
|
||||
tableWithIcons.add("In resistance for another [${cityInfo.getFlag(CityFlags.Resistance)}] turns".toLabel()).row()
|
||||
}
|
||||
if (cityInfo.isWeLoveTheKingDay()) {
|
||||
if (cityInfo.isWeLoveTheKingDayActive()) {
|
||||
tableWithIcons.add(ImageGetter.getStatIcon("Food")).size(20f)
|
||||
tableWithIcons.add("We Love The King Day for another [${cityInfo.getFlag(CityFlags.WeLoveTheKing)}] turns".toLabel()).row()
|
||||
} else if (cityInfo.demandedResource != "") {
|
||||
|
@ -196,7 +196,7 @@ class CivilopediaScreen(
|
||||
CivilopediaCategories.Technology -> ruleset.technologies.values
|
||||
CivilopediaCategories.Promotion -> ruleset.unitPromotions.values
|
||||
CivilopediaCategories.Policy -> ruleset.policies.values
|
||||
CivilopediaCategories.Tutorial -> tutorialController.getCivilopediaTutorials()
|
||||
CivilopediaCategories.Tutorial -> tutorialController.getCivilopediaTutorials(ruleset)
|
||||
CivilopediaCategories.Difficulty -> ruleset.difficulties.values
|
||||
CivilopediaCategories.Belief -> (ruleset.beliefs.values.asSequence() +
|
||||
Belief.getCivilopediaReligionEntry(ruleset)).toList()
|
||||
|
@ -22,7 +22,7 @@ import com.unciv.ui.utils.*
|
||||
class MapEditorScreen(): BaseScreen() {
|
||||
var mapName = ""
|
||||
var tileMap = TileMap()
|
||||
var ruleset = Ruleset().apply { add(RulesetCache.getBaseRuleset()) }
|
||||
var ruleset = Ruleset().apply { add(RulesetCache.getVanillaRuleset()) }
|
||||
|
||||
var gameSetupInfo = GameSetupInfo()
|
||||
lateinit var mapHolder: EditorMapHolder
|
||||
|
@ -23,7 +23,7 @@ import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
/** New map generation screen */
|
||||
class NewMapScreen(val mapParameters: MapParameters = getDefaultParameters()) : PickerScreen() {
|
||||
|
||||
private val ruleset = RulesetCache.getBaseRuleset()
|
||||
private val ruleset = RulesetCache.getVanillaRuleset()
|
||||
private var generatedMap: TileMap? = null
|
||||
private val mapParametersTable: MapParametersTable
|
||||
private val modCheckBoxes: ModCheckboxTable
|
||||
|
@ -4,6 +4,7 @@ import com.badlogic.gdx.utils.Array
|
||||
import com.unciv.JsonParser
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.Tutorial
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.ui.civilopedia.FormattedLine
|
||||
import com.unciv.ui.civilopedia.SimpleCivilopediaText
|
||||
@ -70,10 +71,13 @@ class TutorialController(screen: BaseScreen) {
|
||||
/** Get all Tutorials intended to be displayed in the Civilopedia
|
||||
* as a List of wrappers supporting INamed and ICivilopediaText
|
||||
*/
|
||||
fun getCivilopediaTutorials() =
|
||||
tutorials.filter {
|
||||
fun getCivilopediaTutorials(ruleset: Ruleset): List<CivilopediaTutorial> {
|
||||
val civilopediaTutorials = tutorials.filter {
|
||||
Tutorial.findByName(it.key)!!.isCivilopedia
|
||||
}.map {
|
||||
CivilopediaTutorial(it.key, it.value)
|
||||
}.map { tutorial ->
|
||||
val lines = tutorial.value
|
||||
CivilopediaTutorial(tutorial.key, lines)
|
||||
}
|
||||
return civilopediaTutorials
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,11 @@ Example: "[20]% [Culture]"
|
||||
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% [stat] [cityFilter]
|
||||
Example: "[20]% [Culture] [in all cities]"
|
||||
|
||||
Applicable to: Global, FollowerBelief
|
||||
|
||||
#### [amount]% [stat] from every [tileFilter/specialist/buildingName]
|
||||
Example: "[20]% [Culture] from every [tileFilter/specialist/buildingName]"
|
||||
|
||||
@ -91,10 +96,15 @@ Example: "[20]% [Culture] from City-States"
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### [amount]% [stat] [cityFilter]
|
||||
Example: "[20]% [Culture] [in all cities]"
|
||||
#### Nullifies [stat] [cityFilter]
|
||||
Example: "Nullifies [Culture] [in all cities]"
|
||||
|
||||
Applicable to: Global, FollowerBelief
|
||||
Applicable to: Global
|
||||
|
||||
#### Nullifies Growth [cityFilter]
|
||||
Example: "Nullifies Growth [in all cities]"
|
||||
|
||||
Applicable to: Global
|
||||
|
||||
#### [amount]% Production when constructing [buildingFilter] wonders [cityFilter]
|
||||
Example: "[20]% Production when constructing [Culture] wonders [in all cities]"
|
||||
@ -388,6 +398,9 @@ Applicable to: Global
|
||||
#### Can be continually researched
|
||||
Applicable to: Global
|
||||
|
||||
#### Rebel units may spawn
|
||||
Applicable to: Global
|
||||
|
||||
#### [amount]% Strength
|
||||
Example: "[20]% Strength"
|
||||
|
||||
@ -1206,10 +1219,20 @@ Applicable to: Conditional
|
||||
#### <when not at war>
|
||||
Applicable to: Conditional
|
||||
|
||||
#### <during a Golden Age>
|
||||
Applicable to: Conditional
|
||||
|
||||
#### <while the empire is happy>
|
||||
Applicable to: Conditional
|
||||
|
||||
#### <during a Golden Age>
|
||||
#### <when between [amount] and [amount] Happiness>
|
||||
Example: "<when between [20] and [20] Happiness>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
#### <when below [amount] Happiness>
|
||||
Example: "<when below [20] Happiness>"
|
||||
|
||||
Applicable to: Conditional
|
||||
|
||||
#### <during the [era]>
|
||||
|
@ -31,7 +31,7 @@ class TileImprovementConstructionTests {
|
||||
@Before
|
||||
fun initTheWorld() {
|
||||
RulesetCache.loadRulesets()
|
||||
ruleSet = RulesetCache.getBaseRuleset()
|
||||
ruleSet = RulesetCache.getVanillaRuleset()
|
||||
civInfo.tech.researchedTechnologies.addAll(ruleSet.technologies.values)
|
||||
civInfo.tech.techsResearched.addAll(ruleSet.technologies.keys)
|
||||
city.civInfo = civInfo
|
||||
|
@ -22,7 +22,7 @@ class TileMapTests {
|
||||
@Before
|
||||
fun initTheWorld() {
|
||||
RulesetCache.loadRulesets()
|
||||
ruleSet = RulesetCache.getBaseRuleset()
|
||||
ruleSet = RulesetCache.getVanillaRuleset()
|
||||
map = TileMap()
|
||||
|
||||
tile1.position = Vector2(0f, 0f)
|
||||
|
@ -28,7 +28,7 @@ class UnitMovementAlgorithmsTests {
|
||||
@Before
|
||||
fun initTheWorld() {
|
||||
RulesetCache.loadRulesets()
|
||||
ruleSet = RulesetCache.getBaseRuleset()
|
||||
ruleSet = RulesetCache.getVanillaRuleset()
|
||||
tile.ruleset = ruleSet
|
||||
tile.baseTerrain = Constants.grassland
|
||||
civInfo.tech.techsResearched.addAll(ruleSet.technologies.keys)
|
||||
|
@ -28,7 +28,7 @@ class BasicTests {
|
||||
@Before
|
||||
fun loadTranslations() {
|
||||
RulesetCache.loadRulesets()
|
||||
ruleset = RulesetCache.getBaseRuleset()
|
||||
ruleset = RulesetCache.getVanillaRuleset()
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -31,7 +31,7 @@ class TranslationTests {
|
||||
}))
|
||||
translations.readAllLanguagesTranslation()
|
||||
RulesetCache.loadRulesets()
|
||||
ruleset = RulesetCache.getBaseRuleset()
|
||||
ruleset = RulesetCache.getVanillaRuleset()
|
||||
System.setOut(outputChannel)
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ class GlobalUniquesTests {
|
||||
|
||||
// Create a new ruleset we can easily edit, and set the important variables of gameInfo
|
||||
RulesetCache.loadRulesets()
|
||||
ruleSet = RulesetCache.getBaseRuleset()
|
||||
ruleSet = RulesetCache.getVanillaRuleset()
|
||||
gameInfo.ruleSet = ruleSet
|
||||
gameInfo.difficultyObject = ruleSet.difficulties["Prince"]!!
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user