diff --git a/android/Images/OtherIcons/Timer.png b/android/Images/OtherIcons/Timer.png new file mode 100644 index 0000000000..b5fb7a9f64 Binary files /dev/null and b/android/Images/OtherIcons/Timer.png differ diff --git a/android/assets/jsons/Civ V - Gods & Kings/Speeds.json b/android/assets/jsons/Civ V - Gods & Kings/Speeds.json new file mode 100644 index 0000000000..9c6aeba13d --- /dev/null +++ b/android/assets/jsons/Civ V - Gods & Kings/Speeds.json @@ -0,0 +1,113 @@ +[ + { + "name": "Quick", + "modifier": 0.67, + "productionCostModifier": 0.67, + "goldCostModifier": 0.67, + "scienceCostModifier": 0.67, + "cultureCostModifier": 0.67, + "faithCostModifier": 0.67, + "improvementBuildLengthModifier": 0.67, + "barbarianModifier": 0.67, + "goldGiftModifier": 1.25, + "cityStateTributeScalingInterval": 5.0, + "goldenAgeLengthModifier": 0.80, + "religiousPressureAdjacentCity": 9, + "peaceDealDuration": 10, + "dealDuration": 25, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 60, "untilTurn": 50}, + {"yearsPerTurn": 40, "untilTurn": 80}, + {"yearsPerTurn": 30, "untilTurn": 100}, + {"yearsPerTurn": 20, "untilTurn": 130}, + {"yearsPerTurn": 10, "untilTurn": 155}, + {"yearsPerTurn": 5, "untilTurn": 195}, + {"yearsPerTurn": 2, "untilTurn": 260}, + {"yearsPerTurn": 1, "untilTurn": 330} + ] + }, + { + "name": "Standard", + "modifier": 1.0, + "productionCostModifier": 1.0, + "goldCostModifier": 1.0, + "scienceCostModifier": 1.0, + "cultureCostModifier": 1.0, + "faithCostModifier": 1.0, + "improvementBuildLengthModifier": 1.0, + "barbarianModifier": 1.0, + "goldGiftModifier": 1.0, + "cityStateTributeScalingInterval": 6.5, + "goldenAgeLengthModifier": 1.0, + "religiousPressureAdjacentCity": 6, + "peaceDealDuration": 10, + "dealDuration": 30, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 40, "untilTurn": 75}, + {"yearsPerTurn": 25, "untilTurn": 135}, + {"yearsPerTurn": 20, "untilTurn": 160}, + {"yearsPerTurn": 10, "untilTurn": 210}, + {"yearsPerTurn": 5, "untilTurn": 270}, + {"yearsPerTurn": 2, "untilTurn": 320}, + {"yearsPerTurn": 1, "untilTurn": 440}, + {"yearsPerTurn": 0.5, "untilTurn": 500} + ] + }, + { + "name": "Epic", + "modifier": 1.5, + "productionCostModifier": 1.5, + "goldCostModifier": 1.5, + "scienceCostModifier": 1.5, + "cultureCostModifier": 1.5, + "faithCostModifier": 1.5, + "improvementBuildLengthModifier": 1.5, + "barbarianModifier": 1.5, + "goldGiftModifier": 0.75, + "cityStateTributeScalingInterval": 14.0, + "goldenAgeLengthModifier": 1.25, + "religiousPressureAdjacentCity": 4, + "peaceDealDuration": 15, + "dealDuration": 45, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 25, "untilTurn": 140}, + {"yearsPerTurn": 15, "untilTurn": 230}, + {"yearsPerTurn": 10, "untilTurn": 270}, + {"yearsPerTurn": 5, "untilTurn": 360}, + {"yearsPerTurn": 2, "untilTurn": 430}, + {"yearsPerTurn": 1, "untilTurn": 530}, + {"yearsPerTurn": 0.5, "untilTurn": 750} + ] + }, + { + "name": "Marathon", + "modifier": 3.0, + "productionCostModifier": 3.0, + "goldCostModifier": 3.0, + "scienceCostModifier": 3.0, + "cultureCostModifier": 3.0, + "faithCostModifier": 3.0, + "improvementBuildLengthModifier": 3.0, + "barbarianModifier": 4.0, + "goldGiftModifier": 0.67, + "cityStateTributeScalingInterval": 32.0, + "goldenAgeLengthModifier": 2.0, + "religiousPressureAdjacentCity": 2, + "peaceDealDuration": 30, + "dealDuration": 90, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 15, "untilTurn": 100}, + {"yearsPerTurn": 10, "untilTurn": 400}, + {"yearsPerTurn": 5, "untilTurn": 570}, + {"yearsPerTurn": 2, "untilTurn": 771}, + {"yearsPerTurn": 1, "untilTurn": 900}, + {"yearsPerTurn": 0.5, "untilTurn": 1080}, + {"yearsPerTurn": 0.25, "untilTurn": 1344}, + {"yearsPerTurn": 0.083333, "untilTurn": 1500} + ] + } +] diff --git a/android/assets/jsons/Civ V - Vanilla/Speeds.json b/android/assets/jsons/Civ V - Vanilla/Speeds.json new file mode 100644 index 0000000000..9c6aeba13d --- /dev/null +++ b/android/assets/jsons/Civ V - Vanilla/Speeds.json @@ -0,0 +1,113 @@ +[ + { + "name": "Quick", + "modifier": 0.67, + "productionCostModifier": 0.67, + "goldCostModifier": 0.67, + "scienceCostModifier": 0.67, + "cultureCostModifier": 0.67, + "faithCostModifier": 0.67, + "improvementBuildLengthModifier": 0.67, + "barbarianModifier": 0.67, + "goldGiftModifier": 1.25, + "cityStateTributeScalingInterval": 5.0, + "goldenAgeLengthModifier": 0.80, + "religiousPressureAdjacentCity": 9, + "peaceDealDuration": 10, + "dealDuration": 25, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 60, "untilTurn": 50}, + {"yearsPerTurn": 40, "untilTurn": 80}, + {"yearsPerTurn": 30, "untilTurn": 100}, + {"yearsPerTurn": 20, "untilTurn": 130}, + {"yearsPerTurn": 10, "untilTurn": 155}, + {"yearsPerTurn": 5, "untilTurn": 195}, + {"yearsPerTurn": 2, "untilTurn": 260}, + {"yearsPerTurn": 1, "untilTurn": 330} + ] + }, + { + "name": "Standard", + "modifier": 1.0, + "productionCostModifier": 1.0, + "goldCostModifier": 1.0, + "scienceCostModifier": 1.0, + "cultureCostModifier": 1.0, + "faithCostModifier": 1.0, + "improvementBuildLengthModifier": 1.0, + "barbarianModifier": 1.0, + "goldGiftModifier": 1.0, + "cityStateTributeScalingInterval": 6.5, + "goldenAgeLengthModifier": 1.0, + "religiousPressureAdjacentCity": 6, + "peaceDealDuration": 10, + "dealDuration": 30, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 40, "untilTurn": 75}, + {"yearsPerTurn": 25, "untilTurn": 135}, + {"yearsPerTurn": 20, "untilTurn": 160}, + {"yearsPerTurn": 10, "untilTurn": 210}, + {"yearsPerTurn": 5, "untilTurn": 270}, + {"yearsPerTurn": 2, "untilTurn": 320}, + {"yearsPerTurn": 1, "untilTurn": 440}, + {"yearsPerTurn": 0.5, "untilTurn": 500} + ] + }, + { + "name": "Epic", + "modifier": 1.5, + "productionCostModifier": 1.5, + "goldCostModifier": 1.5, + "scienceCostModifier": 1.5, + "cultureCostModifier": 1.5, + "faithCostModifier": 1.5, + "improvementBuildLengthModifier": 1.5, + "barbarianModifier": 1.5, + "goldGiftModifier": 0.75, + "cityStateTributeScalingInterval": 14.0, + "goldenAgeLengthModifier": 1.25, + "religiousPressureAdjacentCity": 4, + "peaceDealDuration": 15, + "dealDuration": 45, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 25, "untilTurn": 140}, + {"yearsPerTurn": 15, "untilTurn": 230}, + {"yearsPerTurn": 10, "untilTurn": 270}, + {"yearsPerTurn": 5, "untilTurn": 360}, + {"yearsPerTurn": 2, "untilTurn": 430}, + {"yearsPerTurn": 1, "untilTurn": 530}, + {"yearsPerTurn": 0.5, "untilTurn": 750} + ] + }, + { + "name": "Marathon", + "modifier": 3.0, + "productionCostModifier": 3.0, + "goldCostModifier": 3.0, + "scienceCostModifier": 3.0, + "cultureCostModifier": 3.0, + "faithCostModifier": 3.0, + "improvementBuildLengthModifier": 3.0, + "barbarianModifier": 4.0, + "goldGiftModifier": 0.67, + "cityStateTributeScalingInterval": 32.0, + "goldenAgeLengthModifier": 2.0, + "religiousPressureAdjacentCity": 2, + "peaceDealDuration": 30, + "dealDuration": 90, + "startYear": -4000, + "turns": [ + {"yearsPerTurn": 15, "untilTurn": 100}, + {"yearsPerTurn": 10, "untilTurn": 400}, + {"yearsPerTurn": 5, "untilTurn": 570}, + {"yearsPerTurn": 2, "untilTurn": 771}, + {"yearsPerTurn": 1, "untilTurn": 900}, + {"yearsPerTurn": 0.5, "untilTurn": 1080}, + {"yearsPerTurn": 0.25, "untilTurn": 1344}, + {"yearsPerTurn": 0.083333, "untilTurn": 1500} + ] + } +] diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 1eed6d8f1f..d4759f8198 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -1321,6 +1321,22 @@ Eras = Embarked strength: [amount]† = Base unit buy cost: [amount]¤ = Research agreement cost: [amount]¤ = +Game Speeds = +General speed modifier: [amount]%⏳ = +Production cost modifier: [amount]%⚙ = +Gold cost modifier: [amount]%¤ = +Science cost modifier: [amount]%⍾ = +Culture cost modifier: [amount]%♪ = +Faith cost modifier: [amount]%☮ = +Improvement build length modifier: [amount]%⏳ = +Diplomatic deal duration: [amount] turns⏳ = +Gold gift influence gain modifier: [amount]%¤ = +City-state tribute scaling interval: [amount] turns⏳ = +Barbarian spawn modifier: [amount]%† = +Golden age length modifier: [amount]%⌣ = +Adjacent city religious pressure: [amount]☮ = +Peace deal duration: [amount] turns⏳ = +Start year: [comment] = Pillaging this improvement yields [stats] = Pillaging this improvement yields approximately [stats] = diff --git a/core/src/com/unciv/logic/BarbarianManager.kt b/core/src/com/unciv/logic/BarbarianManager.kt index 1692271e4b..e2b57a5605 100644 --- a/core/src/com/unciv/logic/BarbarianManager.kt +++ b/core/src/com/unciv/logic/BarbarianManager.kt @@ -6,7 +6,6 @@ import com.unciv.json.HashMapVector2 import com.unciv.logic.civilization.NotificationIcon import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileMap -import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.utils.extensions.randomWeighted import java.util.* @@ -288,12 +287,6 @@ class Encampment() { // Quicker if this camp has already spawned units countdown -= min(3, spawnedUnits) - countdown *= when (gameInfo.gameParameters.gameSpeed) { - GameSpeed.Quick -> 67 - GameSpeed.Standard -> 100 - GameSpeed.Epic -> 150 - GameSpeed.Marathon -> 400 // sic! - } - countdown /= 100 + countdown = (countdown * gameInfo.speed.barbarianModifier).toInt() } } diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 3cf107771f..959a2b30cd 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -16,12 +16,12 @@ import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileMap import com.unciv.models.Religion import com.unciv.models.metadata.GameParameters -import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.* import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags import java.util.* +import kotlin.NoSuchElementException class GameInfo { @@ -55,6 +55,9 @@ class GameInfo { @Transient lateinit var difficultyObject: Difficulty // Since this is static game-wide, and was taking a large part of nextTurn + @Transient + lateinit var speed: Speed + @Transient lateinit var currentPlayerCiv: CivilizationInfo // this is called thousands of times, no reason to search for it with a find{} every time @@ -152,40 +155,20 @@ class GameInfo { } private fun getEquivalentTurn(): Int { - val totalTurns = 500f * gameParameters.gameSpeed.modifier + val totalTurns = speed.numTotalTurns() val startPercent = ruleSet.eras[gameParameters.startingEra]!!.startPercent - return turns + ((totalTurns * startPercent).toInt() / 100) - } - private class YearsToTurn( - // enum class with lists for each value group potentially more efficient? - val toTurn: Int, - val yearInterval: Float - ) { - companion object { - // Best to initialize these once only - val marathon = listOf(YearsToTurn(100, 15f), YearsToTurn(400, 10f), YearsToTurn(570, 5f), YearsToTurn(771, 2f), YearsToTurn(900, 1f), YearsToTurn(1080, 0.5f), YearsToTurn(1344, 0.25f), YearsToTurn(1500, 0.083333f)) - val epic = listOf(YearsToTurn(140, 25f), YearsToTurn(230, 15f), YearsToTurn(270, 10f), YearsToTurn(360, 5f), YearsToTurn(430, 2f), YearsToTurn(530, 1f), YearsToTurn(1500, 0.5f)) - val standard = listOf(YearsToTurn(75, 40f), YearsToTurn(135, 25f), YearsToTurn(160, 20f), YearsToTurn(210, 10f), YearsToTurn(270, 5f), YearsToTurn(320, 2f), YearsToTurn(440, 1f), YearsToTurn(500, 0.5f)) - val quick = listOf(YearsToTurn(50, 60f), YearsToTurn(80, 40f), YearsToTurn(100, 30f), YearsToTurn(130, 20f), YearsToTurn(155, 10f), YearsToTurn(195, 5f), YearsToTurn(260, 2f), YearsToTurn(310, 1f)) - fun getList(gameSpeed: GameSpeed) = when (gameSpeed) { - GameSpeed.Marathon -> marathon - GameSpeed.Epic -> epic - GameSpeed.Standard -> standard - GameSpeed.Quick -> quick - } - } + return turns + (totalTurns * startPercent / 100) } fun getYear(turnOffset: Int = 0): Int { val turn = getEquivalentTurn() + turnOffset - val yearToTurnList = YearsToTurn.getList(gameParameters.gameSpeed) - var year: Float = -4000f + val yearsToTurn = speed.yearsPerTurn + var year = speed.startYear var i = 0 var yearsPerTurn: Float - // if macros are ever added to kotlin, this is one hell of a place for em' while (i < turn) { - yearsPerTurn = yearToTurnList.firstOrNull { i < it.toTurn }?.yearInterval ?: 0.5f + yearsPerTurn = (yearsToTurn.firstOrNull { i < it.untilTurn }?.yearInterval ?: yearsToTurn.last().yearInterval) year += yearsPerTurn ++i } @@ -431,6 +414,8 @@ class GameInfo { difficultyObject = ruleSet.difficulties[difficulty]!! + speed = ruleSet.speeds[gameParameters.speed]!! + for (religion in religions.values) religion.setTransients(this) for (civInfo in civilizations) civInfo.setTransients() diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 917e1e2efa..6c7a441797 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -46,6 +46,11 @@ object GameStarter { val ruleset = RulesetCache.getComplexRuleset(gameInfo.gameParameters) val mapGen = MapGenerator(ruleset) + // Make sure that a valid game speed is loaded (catches a base ruleset not using the default game speed) + if (!ruleset.speeds.containsKey(gameSetupInfo.gameParameters.speed)) { + gameSetupInfo.gameParameters.speed = ruleset.speeds.keys.first() + } + if (gameSetupInfo.mapParameters.name != "") runAndMeasure("loadMap") { tileMap = MapSaver.loadMap(gameSetupInfo.mapFile!!) // Don't override the map parameters - this can include if we world wrap or not! @@ -202,8 +207,8 @@ object GameStarter { val startingEra = gameInfo.gameParameters.startingEra val era = ruleSet.eras[startingEra]!! for (civInfo in gameInfo.civilizations.filter { !it.isBarbarian() }) { - civInfo.addGold((era.startingGold * gameInfo.gameParameters.gameSpeed.modifier).toInt()) - civInfo.policies.addCulture((era.startingCulture * gameInfo.gameParameters.gameSpeed.modifier).toInt()) + civInfo.addGold((era.startingGold * gameInfo.speed.goldCostModifier).toInt()) + civInfo.policies.addCulture((era.startingCulture * gameInfo.speed.cultureCostModifier).toInt()) } } diff --git a/core/src/com/unciv/logic/automation/Automation.kt b/core/src/com/unciv/logic/automation/Automation.kt index 0d9a7ee65a..d95cc2f6f1 100644 --- a/core/src/com/unciv/logic/automation/Automation.kt +++ b/core/src/com/unciv/logic/automation/Automation.kt @@ -193,19 +193,18 @@ object Automation { if (civInfo.isCityState() || civInfo.isBarbarian()) return false - // If there are no barbarians we are not afraid if (civInfo.gameInfo.gameParameters.noBarbarians) - return false + return false // If there are no barbarians we are not afraid - // Very late in the game we are not afraid - if (civInfo.gameInfo.turns > 200 * civInfo.gameInfo.gameParameters.gameSpeed.modifier) - return false + val speed = civInfo.gameInfo.speed + if (civInfo.gameInfo.turns > 200 * speed.barbarianModifier) + return false // Very late in the game we are not afraid var multiplier = if (civInfo.gameInfo.gameParameters.ragingBarbarians) 1.3f else 1f // We're slightly more afraid of raging barbs // Past the early game we are less afraid - if (civInfo.gameInfo.turns > 120 * civInfo.gameInfo.gameParameters.gameSpeed.modifier * multiplier) + if (civInfo.gameInfo.turns > 120 * speed.barbarianModifier * multiplier) multiplier /= 2 // If we have a lot of, or no cities we are not afraid diff --git a/core/src/com/unciv/logic/city/CityReligion.kt b/core/src/com/unciv/logic/city/CityReligion.kt index bee03ae21d..a1ad1808f5 100644 --- a/core/src/com/unciv/logic/city/CityReligion.kt +++ b/core/src/com/unciv/logic/city/CityReligion.kt @@ -4,7 +4,6 @@ import com.unciv.Constants import com.unciv.logic.civilization.NotificationIcon import com.unciv.models.Counter import com.unciv.models.Religion -import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.utils.extensions.toPercent @@ -23,14 +22,7 @@ class CityInfoReligionManager { private val followers: Counter = Counter() @delegate:Transient - private val pressureFromAdjacentCities: Int by lazy { - when (cityInfo.civInfo.gameInfo.gameParameters.gameSpeed) { - GameSpeed.Quick -> 9 - GameSpeed.Standard -> 6 - GameSpeed.Epic -> 4 - GameSpeed.Marathon -> 2 - } - } + private val pressureFromAdjacentCities: Int by lazy { cityInfo.civInfo.gameInfo.speed.religiousPressureAdjacentCity } var religionThisIsTheHolyCityOf: String? = null diff --git a/core/src/com/unciv/logic/civilization/CityStateFunctions.kt b/core/src/com/unciv/logic/civilization/CityStateFunctions.kt index cfd9bee780..ed80c7c8c3 100644 --- a/core/src/com/unciv/logic/civilization/CityStateFunctions.kt +++ b/core/src/com/unciv/logic/civilization/CityStateFunctions.kt @@ -3,7 +3,6 @@ package com.unciv.logic.civilization import com.unciv.Constants 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.tile.ResourceSupplyList import com.unciv.models.ruleset.unique.Unique @@ -134,14 +133,10 @@ class CityStateFunctions(val civInfo: CivilizationInfo) { // https://github.com/Gedemon/Civ5-DLL/blob/aa29e80751f541ae04858b6d2a2c7dcca454201e/CvGameCoreDLL_Expansion1/CvMinorCivAI.cpp // line 8681 and below var influenceGained = giftAmount.toFloat().pow(1.01f) / 9.8f - val gameProgressApproximate = min(civInfo.gameInfo.turns / (400f * civInfo.gameInfo.gameParameters.gameSpeed.modifier), 1f) + val speed = civInfo.gameInfo.speed + val gameProgressApproximate = min(civInfo.gameInfo.turns / (400f * speed.modifier), 1f) influenceGained *= 1 - (2/3f) * gameProgressApproximate - influenceGained *= when (civInfo.gameInfo.gameParameters.gameSpeed) { - GameSpeed.Quick -> 1.25f - GameSpeed.Standard -> 1f - GameSpeed.Epic -> 0.75f - GameSpeed.Marathon -> 0.67f - } + influenceGained *= speed.goldGiftModifier for (unique in donorCiv.getMatchingUniques(UniqueType.CityStateGoldGiftsProvideMoreInfluence)) influenceGained *= 1f + unique.params[0].toFloat() / 100f @@ -273,7 +268,7 @@ class CityStateFunctions(val civInfo: CivilizationInfo) { fun getDiplomaticMarriageCost(): Int { // https://github.com/Gedemon/Civ5-DLL/blob/master/CvGameCoreDLL_Expansion1/CvMinorCivAI.cpp, line 7812 - var cost = (500 * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + var cost = (500 * civInfo.gameInfo.speed.goldCostModifier).toInt() // Plus disband value of all units for (unit in civInfo.getCivUnits()) { cost += unit.baseUnit.getDisbandGold(civInfo) @@ -393,18 +388,8 @@ class CityStateFunctions(val civInfo: CivilizationInfo) { fun goldGainedByTribute(): Int { // These values are close enough, linear increase throughout the game - var gold = when (civInfo.gameInfo.gameParameters.gameSpeed) { - GameSpeed.Quick -> 60 - GameSpeed.Standard -> 50 - GameSpeed.Epic -> 35 - GameSpeed.Marathon -> 30 - } - val turnsToIncrement = when (civInfo.gameInfo.gameParameters.gameSpeed) { - GameSpeed.Quick -> 5f - GameSpeed.Standard -> 6.5f - GameSpeed.Epic -> 14f - GameSpeed.Marathon -> 32f - } + var gold = (10 * civInfo.gameInfo.speed.goldGiftModifier).toInt() * 5 // rounding down to nearest 5 + val turnsToIncrement = civInfo.gameInfo.speed.cityStateTributeScalingInterval gold += 5 * (civInfo.gameInfo.turns / turnsToIncrement).toInt() return gold diff --git a/core/src/com/unciv/logic/civilization/CivInfoStats.kt b/core/src/com/unciv/logic/civilization/CivInfoStats.kt index 04ee0d76de..fc26eff242 100644 --- a/core/src/com/unciv/logic/civilization/CivInfoStats.kt +++ b/core/src/com/unciv/logic/civilization/CivInfoStats.kt @@ -3,7 +3,6 @@ package com.unciv.logic.civilization import com.unciv.Constants import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.RoadStatus -import com.unciv.models.metadata.BASE_GAME_DURATION_TURNS import com.unciv.models.ruleset.BeliefType import com.unciv.models.ruleset.Policy import com.unciv.models.ruleset.tile.ResourceType @@ -62,7 +61,7 @@ class CivInfoStats(val civInfo: CivilizationInfo) { val numberOfUnitsToPayFor = max(0.0, costsToPay.asSequence().drop(freeUnits).sumOf { it.toDouble() } ).toFloat() // as game progresses Maintenance cost rises - val turnLimit = BASE_GAME_DURATION_TURNS * civInfo.gameInfo.gameParameters.gameSpeed.modifier + val turnLimit = civInfo.gameInfo.speed.numTotalTurns().toFloat() val gameProgress = min(civInfo.gameInfo.turns / turnLimit, 1f) var cost = baseUnitCost * numberOfUnitsToPayFor * (1 + gameProgress) diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index cdee21094a..acea5e4586 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -1025,7 +1025,7 @@ class CivilizationInfo { fun removeFlag(flag: String) = flagsCountdown.remove(flag) fun hasFlag(flag: String) = flagsCountdown.contains(flag) - fun getTurnsBetweenDiplomaticVotes() = (15 * gameInfo.gameParameters.gameSpeed.modifier).toInt() // Dunno the exact calculation, hidden in Lua files + fun getTurnsBetweenDiplomaticVotes() = (15 * gameInfo.speed.modifier).toInt() // Dunno the exact calculation, hidden in Lua files fun getTurnsTillNextDiplomaticVote() = flagsCountdown[CivFlags.TurnsTillNextDiplomaticVote.name] @@ -1115,7 +1115,7 @@ class CivilizationInfo { } private fun getTurnsBeforeRevolt() = - ((4 + Random().nextInt(3)) * max(gameInfo.gameParameters.gameSpeed.modifier, 1f)).toInt() + ((4 + Random().nextInt(3)) * max(gameInfo.speed.modifier, 1f)).toInt() /** Modify gold by a given amount making sure it does neither overflow nor underflow. * @param delta the amount to add (can be negative) @@ -1265,7 +1265,7 @@ class CivilizationInfo { fun getResearchAgreementCost(): Int { // https://forums.civfanatics.com/resources/research-agreements-bnw.25568/ return ( - getEra().researchAgreementCost * gameInfo.gameParameters.gameSpeed.modifier + getEra().researchAgreementCost * gameInfo.speed.goldCostModifier ).toInt() } @@ -1367,7 +1367,7 @@ class CivilizationInfo { fun receiveGoldGift(donorCiv: CivilizationInfo, giftAmount: Int) = cityStateFunctions.receiveGoldGift(donorCiv, giftAmount) - fun turnsForGreatPersonFromCityState(): Int = ((37 + Random().nextInt(7)) * gameInfo.gameParameters.gameSpeed.modifier).toInt() + fun turnsForGreatPersonFromCityState(): Int = ((37 + Random().nextInt(7)) * gameInfo.speed.modifier).toInt() fun getProtectorCivs() = cityStateFunctions.getProtectorCivs() fun addProtectorCiv(otherCiv: CivilizationInfo) = cityStateFunctions.addProtectorCiv(otherCiv) diff --git a/core/src/com/unciv/logic/civilization/GoldenAgeManager.kt b/core/src/com/unciv/logic/civilization/GoldenAgeManager.kt index c6cf293de9..c8d1d5c83e 100644 --- a/core/src/com/unciv/logic/civilization/GoldenAgeManager.kt +++ b/core/src/com/unciv/logic/civilization/GoldenAgeManager.kt @@ -29,7 +29,7 @@ class GoldenAgeManager { var turnsToGoldenAge = unmodifiedNumberOfTurns.toFloat() for (unique in civInfo.getMatchingUniques(UniqueType.GoldenAgeLength)) turnsToGoldenAge *= unique.params[0].toPercent() - turnsToGoldenAge *= civInfo.gameInfo.gameParameters.gameSpeed.modifier + turnsToGoldenAge *= civInfo.gameInfo.speed.goldenAgeLengthModifier turnsLeftForCurrentGoldenAge += turnsToGoldenAge.toInt() civInfo.addNotification("You have entered a Golden Age!", "StatIcons/Happiness") civInfo.popupAlerts.add(PopupAlert(AlertType.GoldenAge, "")) diff --git a/core/src/com/unciv/logic/civilization/PolicyManager.kt b/core/src/com/unciv/logic/civilization/PolicyManager.kt index f3588c39b5..3cb39579d4 100644 --- a/core/src/com/unciv/logic/civilization/PolicyManager.kt +++ b/core/src/com/unciv/logic/civilization/PolicyManager.kt @@ -144,7 +144,7 @@ class PolicyManager { for (unique in civInfo.getMatchingUniques(UniqueType.LessPolicyCostFromCities)) cityModifier *= 1 - unique.params[0].toFloat() / 100 for (unique in civInfo.getMatchingUniques(UniqueType.LessPolicyCost)) policyCultureCost *= unique.params[0].toPercent() if (civInfo.isPlayerCivilization()) policyCultureCost *= civInfo.getDifficulty().policyCostModifier - policyCultureCost *= civInfo.gameInfo.gameParameters.gameSpeed.modifier + policyCultureCost *= civInfo.gameInfo.speed.cultureCostModifier val cost: Int = (policyCultureCost * (1 + cityModifier)).roundToInt() return cost - (cost % 5) } diff --git a/core/src/com/unciv/logic/civilization/QuestManager.kt b/core/src/com/unciv/logic/civilization/QuestManager.kt index 6e832afdb1..ac3203190f 100644 --- a/core/src/com/unciv/logic/civilization/QuestManager.kt +++ b/core/src/com/unciv/logic/civilization/QuestManager.kt @@ -144,7 +144,7 @@ class QuestManager { else GLOBAL_QUEST_MIN_TURNS_BETWEEN + Random.nextInt(GLOBAL_QUEST_RAND_TURNS_BETWEEN) - globalQuestCountdown = (countdown * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + globalQuestCountdown = (countdown * civInfo.gameInfo.speed.modifier).toInt() } private fun seedIndividualQuestsCountdown() { @@ -164,7 +164,7 @@ class QuestManager { else INDIVIDUAL_QUEST_MIN_TURNS_BETWEEN + Random.nextInt(INDIVIDUAL_QUEST_RAND_TURNS_BETWEEN) - individualQuestCountdown[challenger.civName] = (countdown * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + individualQuestCountdown[challenger.civName] = (countdown * civInfo.gameInfo.speed.modifier).toInt() } private fun tryStartNewGlobalQuest() { @@ -905,7 +905,7 @@ class AssignedQuest(val questName: String = "", fun doesExpire(): Boolean = gameInfo.ruleSet.quests[questName]!!.duration > 0 fun isExpired(): Boolean = doesExpire() && getRemainingTurns() == 0 @Suppress("MemberVisibilityCanBePrivate") - fun getDuration(): Int = (gameInfo.gameParameters.gameSpeed.modifier * gameInfo.ruleSet.quests[questName]!!.duration).toInt() + fun getDuration(): Int = (gameInfo.speed.modifier * gameInfo.ruleSet.quests[questName]!!.duration).toInt() fun getRemainingTurns(): Int = max(0, (assignedOnTurn + getDuration()) - gameInfo.turns) fun getDescription(): String { diff --git a/core/src/com/unciv/logic/civilization/ReligionManager.kt b/core/src/com/unciv/logic/civilization/ReligionManager.kt index 28c757e34b..6d4b260a54 100644 --- a/core/src/com/unciv/logic/civilization/ReligionManager.kt +++ b/core/src/com/unciv/logic/civilization/ReligionManager.kt @@ -110,7 +110,7 @@ class ReligionManager { var faithCost = (200 + 100 * greatProphetsEarned * (greatProphetsEarned + 1) / 2f) * - civInfo.gameInfo.gameParameters.gameSpeed.modifier + civInfo.gameInfo.speed.faithCostModifier for (unique in civInfo.getMatchingUniques(UniqueType.FaithCostOfGreatProphetChange)) faithCost *= unique.params[0].toPercent() diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 4220e5508a..11e79b0e20 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -86,7 +86,7 @@ class TechManager { var techCost = getRuleset().technologies[techName]!!.cost.toFloat() if (civInfo.isPlayerCivilization()) techCost *= civInfo.getDifficulty().researchCostModifier - techCost *= civInfo.gameInfo.gameParameters.gameSpeed.modifier + techCost *= civInfo.gameInfo.speed.scienceCostModifier val techsResearchedKnownCivs = civInfo.getKnownCivs() .count { it.isMajorCiv() && it.tech.isResearched(techName) } val undefeatedCivs = civInfo.gameInfo.civilizations @@ -132,13 +132,13 @@ class TechManager { val tech = getRuleset().technologies[techName]!! if (tech.uniqueObjects.any { it.type == UniqueType.OnlyAvailableWhen && !it.conditionalsApply(civInfo) }) return false - + if (tech.getMatchingUniques(UniqueType.IncompatibleWith).any { isResearched(it.params[0]) }) return false - + if (isResearched(tech.name) && !tech.isContinuallyResearchable()) return false - + return tech.prerequisites.all { isResearched(it) } } @@ -167,7 +167,7 @@ class TechManager { fun getScienceFromGreatScientist(): Int { // https://civilization.fandom.com/wiki/Great_Scientist_(Civ5) - return (scienceOfLast8Turns.sum() * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + return (scienceOfLast8Turns.sum() * civInfo.gameInfo.speed.scienceCostModifier).toInt() } private fun addCurrentScienceToScienceOfLast8Turns() { diff --git a/core/src/com/unciv/logic/map/MapUnit.kt b/core/src/com/unciv/logic/map/MapUnit.kt index ffac2e530b..35a94756f4 100644 --- a/core/src/com/unciv/logic/map/MapUnit.kt +++ b/core/src/com/unciv/logic/map/MapUnit.kt @@ -959,10 +959,15 @@ class MapUnit { val gainedStats = Stats() for (unique in civInfo.getMatchingUniques(UniqueType.ProvidesGoldWheneverGreatPersonExpended)) { - gainedStats.gold += (100 * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + gainedStats.gold += (100 * civInfo.gameInfo.speed.goldCostModifier).toInt() } for (unique in civInfo.getMatchingUniques(UniqueType.ProvidesStatsWheneverGreatPersonExpended)) { - gainedStats.add(unique.stats) + val uniqueStats = unique.stats + val speedModifiers = civInfo.gameInfo.speed.statCostModifiers + for (stat in uniqueStats) { + uniqueStats[stat.key] = stat.value * speedModifiers[stat.key]!! + } + gainedStats.add(uniqueStats) } if (gainedStats.isEmpty()) return @@ -1030,7 +1035,7 @@ class MapUnit { .forEach { it.questManager.barbarianCampCleared(civInfo, tile.position) } var goldGained = - civInfo.getDifficulty().clearBarbarianCampReward * civInfo.gameInfo.gameParameters.gameSpeed.modifier + civInfo.getDifficulty().clearBarbarianCampReward * civInfo.gameInfo.speed.goldCostModifier if (civInfo.hasUnique(UniqueType.TripleGoldFromEncampmentsAndCities)) goldGained *= 3f diff --git a/core/src/com/unciv/logic/trade/TradeEvaluation.kt b/core/src/com/unciv/logic/trade/TradeEvaluation.kt index 98aaafbc3d..72b2cf06c1 100644 --- a/core/src/com/unciv/logic/trade/TradeEvaluation.kt +++ b/core/src/com/unciv/logic/trade/TradeEvaluation.kt @@ -118,7 +118,7 @@ class TradeEvaluation { TradeType.Technology -> // Currently unused return (sqrt(civInfo.gameInfo.ruleSet.technologies[offer.name]!!.cost.toDouble()) - * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() * 20 + * civInfo.gameInfo.speed.scienceCostModifier).toInt() * 20 TradeType.Introduction -> return introductionValue(civInfo.gameInfo.ruleSet) TradeType.WarDeclaration -> { val civToDeclareWarOn = civInfo.gameInfo.getCivilization(offer.name) diff --git a/core/src/com/unciv/logic/trade/TradeOffer.kt b/core/src/com/unciv/logic/trade/TradeOffer.kt index 9909c4cafc..45748aa1a0 100644 --- a/core/src/com/unciv/logic/trade/TradeOffer.kt +++ b/core/src/com/unciv/logic/trade/TradeOffer.kt @@ -2,7 +2,7 @@ package com.unciv.logic.trade import com.unciv.Constants import com.unciv.UncivGame -import com.unciv.models.metadata.GameSpeed +import com.unciv.models.ruleset.Speed import com.unciv.models.translations.tr import com.unciv.ui.utils.Fonts import com.unciv.logic.trade.TradeType.TradeTypeNumberType @@ -13,13 +13,12 @@ data class TradeOffer(val name: String, val type: TradeType, var amount: Int = 1 name: String, type: TradeType, amount: Int = 1, - gameSpeed: GameSpeed = UncivGame.Current.gameInfo!!.gameParameters.gameSpeed + speed: Speed = UncivGame.Current.gameInfo!!.speed ) : this(name, type, amount, duration = -1) { duration = when { type.isImmediate -> -1 // -1 for offers that are immediate (e.g. gold transfer) - name == Constants.peaceTreaty -> 10 - gameSpeed == GameSpeed.Quick -> 25 - else -> (30 * gameSpeed.modifier).toInt() + name == Constants.peaceTreaty -> speed.peaceDealDuration + else -> speed.dealDuration } } diff --git a/core/src/com/unciv/models/ModConstants.kt b/core/src/com/unciv/models/ModConstants.kt index d329c7a9f5..33848a1b16 100644 --- a/core/src/com/unciv/models/ModConstants.kt +++ b/core/src/com/unciv/models/ModConstants.kt @@ -6,9 +6,9 @@ class ModConstants { var maxXPfromBarbarians = 30 // Formula for city Strength: - // Strength = baseStrength + strengthPerPop + strengthFromTiles + - // ((%techs * multiplier) ^ exponent) * fullMultiplier + - // (garrisonBonus * garrisonUnitStrength * garrisonUnitHealth/100) + + // Strength = baseStrength + strengthPerPop + strengthFromTiles + + // ((%techs * multiplier) ^ exponent) * fullMultiplier + + // (garrisonBonus * garrisonUnitStrength * garrisonUnitHealth/100) + // defensiveBuildingStrength // where %techs is the percentage of techs in the tech tree that are complete // If no techs exist in this ruleset, %techs = 0.5 (=50%) @@ -18,10 +18,10 @@ class ModConstants { var cityStrengthFromTechsExponent = 2.8 var cityStrengthFromTechsFullMultiplier = 1.0 var cityStrengthFromGarrison = 0.2 - + // Formula for Unit Supply: // Supply = unitSupplyBase (difficulties.json) - // unitSupplyPerCity * amountOfCities + (difficulties.json) + // unitSupplyPerCity * amountOfCities + (difficulties.json) // unitSupplyPerPopulation * amountOfPopulationInAllCities // unitSupplyBase and unitSupplyPerCity can be found in difficulties.json // unitSupplyBase, unitSupplyPerCity and unitSupplyPerPopulation can also be increased through uniques @@ -38,7 +38,7 @@ class ModConstants { class UnitUpgradeCost { val base = 10f val perProduction = 2f - val eraMultiplier = 0f // 0.3 in Civ5 cpp sources but 0 in xml + val eraMultiplier = 0f // 0.3 in Civ5 cpp sources but 0 in xml val exponent = 1f val roundTo = 5 } diff --git a/core/src/com/unciv/models/metadata/GameParameters.kt b/core/src/com/unciv/models/metadata/GameParameters.kt index 29ace901ad..f523459fbf 100644 --- a/core/src/com/unciv/models/metadata/GameParameters.kt +++ b/core/src/com/unciv/models/metadata/GameParameters.kt @@ -1,6 +1,7 @@ package com.unciv.models.metadata import com.unciv.logic.civilization.PlayerType +import com.unciv.models.ruleset.Speed enum class BaseRuleset(val fullName:String){ Civ_V_Vanilla("Civ V - Vanilla"), @@ -9,7 +10,7 @@ enum class BaseRuleset(val fullName:String){ class GameParameters { // Default values are the default new game var difficulty = "Prince" - var gameSpeed = GameSpeed.Standard + var speed = Speed.DEFAULT var players = ArrayList().apply { add(Player().apply { playerType = PlayerType.Human }) for (i in 1..3) add(Player()) @@ -22,20 +23,20 @@ class GameParameters { // Default values are the default new game var godMode = false var nuclearWeaponsEnabled = true var religionEnabled = false - - var victoryTypes: ArrayList = arrayListOf() + + var victoryTypes: ArrayList = arrayListOf() var startingEra = "Ancient era" var isOnlineMultiplayer = false var baseRuleset: String = BaseRuleset.Civ_V_GnK.fullName var mods = LinkedHashSet() - + var maxTurns = 500 fun clone(): GameParameters { val parameters = GameParameters() parameters.difficulty = difficulty - parameters.gameSpeed = gameSpeed + parameters.speed = speed parameters.players = ArrayList(players) parameters.numberOfCityStates = numberOfCityStates parameters.noBarbarians = noBarbarians @@ -54,7 +55,7 @@ class GameParameters { // Default values are the default new game // For debugging and GameStarter console output override fun toString() = sequence { - yield("$difficulty $gameSpeed $startingEra") + yield("$difficulty $speed $startingEra") yield("${players.count { it.playerType == PlayerType.Human }} ${PlayerType.Human}") yield("${players.count { it.playerType == PlayerType.AI }} ${PlayerType.AI}") yield("$numberOfCityStates CS") @@ -69,8 +70,8 @@ class GameParameters { // Default values are the default new game yield(baseRuleset) yield(if (mods.isEmpty()) "no mods" else mods.joinToString(",", "mods=(", ")", 6) ) }.joinToString(prefix = "(", postfix = ")") - + fun getModsAndBaseRuleset(): HashSet { return mods.toHashSet().apply { add(baseRuleset) } } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/models/metadata/GameSpeed.kt b/core/src/com/unciv/models/metadata/GameSpeed.kt deleted file mode 100644 index 34ad815f67..0000000000 --- a/core/src/com/unciv/models/metadata/GameSpeed.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.unciv.models.metadata - -const val BASE_GAME_DURATION_TURNS = 500f - -/** Game speed - * - * @param modifier cost modifier - * */ -enum class GameSpeed(val modifier: Float) { - Quick(0.67f), - Standard(1f), - Epic(1.5f), - Marathon(3f); -} \ No newline at end of file diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index b09822ffc1..005ddfaa5e 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -354,7 +354,7 @@ class Building : RulesetStatsObject(), INonPerpetualConstruction { civInfo.gameInfo.getDifficulty().aiBuildingCostModifier } - productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.modifier + productionCost *= civInfo.gameInfo.speed.productionCostModifier return productionCost.toInt() } diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index ed2bf7f5c2..5af736a3fc 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -84,6 +84,7 @@ class Ruleset { val buildings = LinkedHashMap() val difficulties = LinkedHashMap() val eras = LinkedHashMap() + val speeds = LinkedHashMap() var globalUniques = GlobalUniques() val nations = LinkedHashMap() val policies = LinkedHashMap() @@ -123,6 +124,7 @@ class Ruleset { for (buildingToRemove in ruleset.modOptions.buildingsToRemove) buildings.remove(buildingToRemove) difficulties.putAll(ruleset.difficulties) eras.putAll(ruleset.eras) + speeds.putAll(ruleset.speeds) 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) @@ -152,6 +154,7 @@ class Ruleset { buildings.clear() difficulties.clear() eras.clear() + speeds.clear() globalUniques = GlobalUniques() mods.clear() nations.clear() @@ -176,6 +179,7 @@ class Ruleset { buildings.values.asSequence() + //difficulties is only INamed eras.values.asSequence() + + speeds.values.asSequence() + sequenceOf(globalUniques) + nations.values.asSequence() + policies.values.asSequence() + @@ -245,6 +249,11 @@ class Ruleset { // Using map{} sidesteps this problem eras.map { it.value }.withIndex().forEach { it.value.eraNumber = it.index } + val speedsFile = folderHandle.child("Speeds.json") + if (speedsFile.exists()) { + speeds += createHashmap(json().fromJsonFile(Array::class.java, speedsFile)) + } + val unitTypesFile = folderHandle.child("UnitTypes.json") if (unitTypesFile.exists()) unitTypes += createHashmap(json().fromJsonFile(Array::class.java, unitTypesFile)) @@ -343,6 +352,10 @@ class Ruleset { if (victories.isEmpty()) { victories.putAll(RulesetCache.getVanillaRuleset().victories) } + + if (speeds.isEmpty()) { + speeds.putAll(RulesetCache.getVanillaRuleset().speeds) + } } debug("Loading ruleset - %sms", System.currentTimeMillis() - gameBasicsStartTime) @@ -795,6 +808,13 @@ class Ruleset { checkUniques(era, lines, rulesetSpecific, forOptionsPopup) } + for (speed in speeds.values) { + if (speed.modifier < 0f) + lines += "Negative speed modifier for game speed ${speed.name}" + if (speed.yearsPerTurn.isEmpty()) + lines += "Empty turn increment list for game speed ${speed.name}" + } + for (belief in beliefs.values) { checkUniques(belief, lines, rulesetSpecific, forOptionsPopup) } diff --git a/core/src/com/unciv/models/ruleset/Speed.kt b/core/src/com/unciv/models/ruleset/Speed.kt new file mode 100644 index 0000000000..949e2a815a --- /dev/null +++ b/core/src/com/unciv/models/ruleset/Speed.kt @@ -0,0 +1,83 @@ +package com.unciv.models.ruleset + +import com.unciv.models.ruleset.unique.UniqueTarget +import com.unciv.models.stats.Stat +import com.unciv.models.translations.tr +import com.unciv.ui.civilopedia.FormattedLine +import com.unciv.ui.utils.Fonts +import kotlin.math.abs + +class Speed : RulesetObject() { + var modifier: Float = 1f + var goldCostModifier: Float = modifier + var productionCostModifier: Float = modifier + var scienceCostModifier: Float = modifier + var cultureCostModifier: Float = modifier + var faithCostModifier: Float = modifier + var goldGiftModifier: Float = modifier + var cityStateTributeScalingInterval: Float = 6.5f + var barbarianModifier: Float = modifier + var improvementBuildLengthModifier: Float = modifier + var goldenAgeLengthModifier: Float = modifier + var religiousPressureAdjacentCity: Int = 6 + var peaceDealDuration: Int = 10 + var dealDuration: Int = 30 + var startYear: Float = -4000f + var turns: ArrayList> = ArrayList() + + val yearsPerTurn: ArrayList by lazy { + ArrayList().apply { + turns.forEach { this.add(YearsPerTurn(it["yearsPerTurn"]!!, it["untilTurn"]!!.toInt())) } + } + } + + val statCostModifiers: HashMap by lazy { + HashMap().apply { + this[Stat.Faith] = 1f; + this[Stat.Production] = productionCostModifier; + this[Stat.Gold] = goldCostModifier; + this[Stat.Science] = scienceCostModifier; + this[Stat.Faith] = faithCostModifier; + this[Stat.Happiness] = 1f; + } + } + + companion object { + const val DEFAULT: String = "Quick" + const val DEFAULTFORSIMULATION: String = "Standard" + } + + override fun getUniqueTarget(): UniqueTarget = UniqueTarget.Speed + + override fun makeLink(): String = "GameSpeed/$name" + override fun getCivilopediaTextHeader() = FormattedLine(name, header = 2) + override fun getCivilopediaTextLines(ruleset: Ruleset) = sequence { + yield(FormattedLine("General speed modifier: [${modifier * 100}]%${Fonts.turn}")) + yield(FormattedLine("Production cost modifier: [${productionCostModifier * 100}]%${Fonts.production}")) + yield(FormattedLine("Gold cost modifier: [${goldCostModifier * 100}]%${Fonts.gold}")) + yield(FormattedLine("Science cost modifier: [${scienceCostModifier * 100}]%${Fonts.science}")) + yield(FormattedLine("Culture cost modifier: [${cultureCostModifier * 100}]%${Fonts.culture}")) + yield(FormattedLine("Faith cost modifier: [${faithCostModifier * 100}]%${Fonts.faith}")) + yield(FormattedLine("Improvement build length modifier: [${improvementBuildLengthModifier * 100}]%${Fonts.turn}")) + yield(FormattedLine("Diplomatic deal duration: [$dealDuration] turns${Fonts.turn}")) + yield(FormattedLine("Gold gift influence gain modifier: [${goldGiftModifier * 100}]%${Fonts.gold}")) + yield(FormattedLine("City-state tribute scaling interval: [${cityStateTributeScalingInterval}] turns${Fonts.turn}")) + yield(FormattedLine("Barbarian spawn modifier: [${barbarianModifier * 100}]%${Fonts.strength}")) + yield(FormattedLine("Golden age length modifier: [${goldenAgeLengthModifier * 100}]%${Fonts.happiness}")) + yield(FormattedLine("Adjacent city religious pressure: [$religiousPressureAdjacentCity]${Fonts.faith}")) + yield(FormattedLine("Peace deal duration: [$peaceDealDuration] turns${Fonts.turn}")) + yield(FormattedLine("Start year: " + ("[${abs(startYear).toInt()}] " + (if (startYear < 0) "BC" else "AD")).tr())) + }.toList() + + fun numTotalTurns(): Int = yearsPerTurn.last().untilTurn +} + +class YearsPerTurn { + var yearInterval: Float = 0f + var untilTurn: Int = 0 + + constructor(yearsPerTurn: Float, turnsPerIncrement: Int) { + this.yearInterval = yearsPerTurn + this.untilTurn = turnsPerIncrement + } +} diff --git a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt index 7ab86606a6..adc56c8d05 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt @@ -31,7 +31,7 @@ class TileImprovement : RulesetStatsObject() { fun getTurnsToBuild(civInfo: CivilizationInfo, unit: MapUnit): Int { val state = StateForConditionals(civInfo, unit = unit) return unit.getMatchingUniques(UniqueType.TileImprovementTime, state, checkCivInfoUniques = true) - .fold(turnsToBuild.toFloat() * civInfo.gameInfo.gameParameters.gameSpeed.modifier) { it, unique -> + .fold(turnsToBuild.toFloat() * civInfo.gameInfo.speed.improvementBuildLengthModifier) { it, unique -> it * unique.params[0].toPercent() }.roundToInt() .coerceAtLeast(1) diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt index 4e5bb82502..90d46efc6b 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueTriggerActivation.kt @@ -339,7 +339,7 @@ object UniqueTriggerActivation { val foundStatAmount = (tileBasedRandom.nextInt(unique.params[0].toInt(), unique.params[1].toInt()) * - civInfo.gameInfo.gameParameters.gameSpeed.modifier + civInfo.gameInfo.speed.statCostModifiers[stat]!! ).toInt() civInfo.addStat( diff --git a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt index 17e1c79952..8e4742e4e1 100644 --- a/core/src/com/unciv/models/ruleset/unique/UniqueType.kt +++ b/core/src/com/unciv/models/ruleset/unique/UniqueType.kt @@ -20,6 +20,7 @@ enum class UniqueTarget(val inheritsFrom: UniqueTarget? = null) { // Civilization-specific Nation(Global), Era(Global), + Speed(Global), Tech(Global), Policy(Global), FounderBelief(Global), diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index b9c4aa8c8f..17dac036a7 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -253,7 +253,7 @@ class BaseUnit : RulesetObject(), INonPerpetualConstruction { civInfo.getDifficulty().unitCostModifier else civInfo.gameInfo.getDifficulty().aiUnitCostModifier - productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.modifier + productionCost *= civInfo.gameInfo.speed.productionCostModifier return productionCost.toInt() } diff --git a/core/src/com/unciv/models/translations/TranslationFileWriter.kt b/core/src/com/unciv/models/translations/TranslationFileWriter.kt index 613f507725..336506f336 100644 --- a/core/src/com/unciv/models/translations/TranslationFileWriter.kt +++ b/core/src/com/unciv/models/translations/TranslationFileWriter.kt @@ -456,6 +456,7 @@ object TranslationFileWriter { "Buildings" -> emptyArray().javaClass "Difficulties" -> emptyArray().javaClass "Eras" -> emptyArray().javaClass + "Speeds" -> emptyArray().javaClass "GlobalUniques" -> GlobalUniques().javaClass "Nations" -> emptyArray().javaClass "Policies" -> emptyArray().javaClass diff --git a/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt b/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt index 9f35579d8d..f4c25f803b 100644 --- a/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt +++ b/core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt @@ -188,6 +188,11 @@ enum class CivilopediaCategories ( getImage = null, KeyCharAndCode('D'), "OtherIcons/Tyrannosaurus" + ), + Speed ("Speeds", false, + getImage = null, + KeyCharAndCode('S'), + "OtherIcons/Timer" ); fun getByOffset(offset: Int) = values()[(ordinal + count + offset) % count] diff --git a/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt b/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt index 5d2d5c5994..7ea8a830e2 100644 --- a/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt +++ b/core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt @@ -213,6 +213,7 @@ class CivilopediaScreen( CivilopediaCategories.Belief -> (ruleset.beliefs.values.asSequence() + Belief.getCivilopediaReligionEntry(ruleset)).toList() CivilopediaCategories.Era -> ruleset.eras.values + CivilopediaCategories.Speed -> ruleset.speeds.values } for (loopCategory in CivilopediaCategories.values()) { diff --git a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index f9d3cd2b5b..fdfefe01a4 100644 --- a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -1,13 +1,8 @@ package com.unciv.ui.newgamescreen -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.scenes.scene2d.ui.CheckBox -import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.UncivGame import com.unciv.logic.civilization.CityStateType -import com.unciv.logic.multiplayer.OnlineMultiplayer -import com.unciv.models.metadata.GameSpeed import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr @@ -15,7 +10,6 @@ import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags import com.unciv.ui.images.ImageGetter import com.unciv.ui.multiplayer.MultiplayerHelpers -import com.unciv.ui.popup.Popup import com.unciv.ui.popup.ToastPopup import com.unciv.ui.utils.BaseScreen import com.unciv.ui.utils.UncivSlider @@ -224,8 +218,8 @@ class GameOptionsTable( } private fun Table.addGameSpeedSelectBox() { - addSelectBox("{Game Speed}:", GameSpeed.values().map { it.name }, gameParameters.gameSpeed.name) - { gameParameters.gameSpeed = GameSpeed.valueOf(it); null } + addSelectBox("{Game Speed}:", ruleset.speeds.values.map { it.name }, gameParameters.speed) + { gameParameters.speed = it; null } } private fun Table.addEraSelectBox() { diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 5209c2769e..41f912c496 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -518,7 +518,7 @@ object UnitActions { action = { tile.getCity()!!.cityConstructions.apply { //http://civilization.wikia.com/wiki/Great_engineer_(Civ5) - addProductionPoints(((300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt()) + addProductionPoints(((300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier).toInt()) constructIfEnough() } @@ -539,7 +539,7 @@ object UnitActions { //http://civilization.wikia.com/wiki/Great_engineer_(Civ5) val productionPointsToAdd = min( - (300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.gameParameters.gameSpeed.modifier, + (300 + 30 * tile.getCity()!!.population.population) * unit.civInfo.gameInfo.speed.productionCostModifier, cityConstructions.getRemainingWork(cityConstructions.currentConstructionFromQueue).toFloat() - 1 ).toInt() if (productionPointsToAdd <= 0) continue @@ -563,7 +563,7 @@ object UnitActions { actionList += UnitAction(UnitActionType.ConductTradeMission, action = { // http://civilization.wikia.com/wiki/Great_Merchant_(Civ5) - var goldEarned = (350 + 50 * unit.civInfo.getEraNumber()) * unit.civInfo.gameInfo.gameParameters.gameSpeed.modifier + var goldEarned = (350 + 50 * unit.civInfo.getEraNumber()) * unit.civInfo.gameInfo.speed.goldCostModifier for (goldUnique in unit.civInfo.getMatchingUniques(UniqueType.PercentGoldFromTradeMissions)) goldEarned *= goldUnique.params[0].toPercent() unit.civInfo.addGold(goldEarned.toInt()) diff --git a/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt b/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt index c96a0bb26d..4afaa50c34 100644 --- a/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/ConsoleLauncher.kt @@ -11,12 +11,12 @@ import com.unciv.logic.map.MapSize import com.unciv.logic.map.MapSizeNew import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.GameSettings -import com.unciv.models.metadata.GameSpeed import com.unciv.models.metadata.Player import com.unciv.models.ruleset.RulesetCache import com.unciv.models.simulation.Simulation import com.unciv.models.tilesets.TileSetCache import com.unciv.models.metadata.GameSetupInfo +import com.unciv.models.ruleset.Speed import kotlin.time.ExperimentalTime internal object ConsoleLauncher { @@ -69,7 +69,7 @@ internal object ConsoleLauncher { private fun getGameParameters(civilization1: String, civilization2: String): GameParameters { return GameParameters().apply { difficulty = "Chieftain" - gameSpeed = GameSpeed.Quick + speed = Speed.DEFAULT noBarbarians = true players = ArrayList().apply { add(Player().apply { diff --git a/docs/Credits.md b/docs/Credits.md index 7a229d7817..d0c46ea318 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -698,6 +698,50 @@ Unless otherwise specified, all the following are from [the Noun Project](https: - [Santa beard vector](https://www.freepik.com/free-vector/positive-santa-ringing-bell-waving-hand_3636285.htm) by katemangostar - [Funny christmas vector](https://www.freepik.com/free-vector/snowman-wearing-santa-hat-scarf-mittens_3636292.htm) by katemangostar +- [Circle](https://thenounproject.com/term/circle/1841891/) By Aybige +- [Arrow](https://thenounproject.com/term/arrow/18123/) By Joe Mortell for movement +- [Swap](https://thenounproject.com/search/?q=swap&i=1259600) By iconomania for swapping units +- [Connection](https://thenounproject.com/search/?q=connection&i=1521886) By Travis Avery +- [Skull](https://thenounproject.com/search/?q=Skull&i=1030702) By Vladimir Belochkin for disbanding units +- [Crosshair](https://thenounproject.com/search/?q=crosshairs&i=916030) By Bakunetsu Kaito for selecting enemies to attack +- [City](https://thenounproject.com/search/?q=city&i=571332) By Felix Westphal +- [Fire](https://thenounproject.com/search/?q=Fire&i=96564) By Lloyd Humphreys for "city being razed" icon +- [Sleep](https://thenounproject.com/search/?q=sleep&i=1760085) By Saeful Muslim +- [Banner](https://thenounproject.com/term/banner/866282/) By Emir Palavan for embarked units +- [Arrow](https://thenounproject.com/term/arrow/18123/) By uzeir syarief for moving between idle units +- [Replace](https://thenounproject.com/search/?q=replace&i=17858) By Mike Rowe for switching tiles between cities +- [Resistance](https://thenounproject.com/term/revolution/1315305/) By HeadsOfBirds +- [Viking Hat](https://thenounproject.com/search/?q=pillage&i=185405) By my name is mud for pillaging improvements +- [Aim](https://thenounproject.com/search/?q=aim&i=2034920) By Kaviashri for ranged strength +- [Capitol](https://thenounproject.com/search/?q=capitol&i=160031) By Loren Klein for City-States +- [Aircraft](https://thenounproject.com/search/?q=aircraft&i=1629000) By Tom Fricker for aircraft icon in city button +- [radar scan](https://thenounproject.com/search/?q=range&i=1500234) By icon 54 for Range +- [short range radar](https://thenounproject.com/search/?q=air%20range&i=2612731) by Vectors Point for Intercept range +- [Puppet](https://thenounproject.com/search/?q=puppet&i=285735) By Ben Davis for puppeted cities +- [City](https://thenounproject.com/search/?q=city&i=1765370) By Muhajir ila Robbi in the Icon center +- [Lock](https://thenounproject.com/search/?q=lock&i=3217613) by Vadim Solomakhin for locked tiles +- [Hourglass](https://thenounproject.com/search/?q=hourglass&i=142268) by I Create Stuff for the 'Turn' icon +- [Shield](https://thenounproject.com/search/?q=shield&i=813568) by Gregor Cresnar for Religious Strength +- [skill sword flame](https://thenounproject.com/term/skill-sword-flame/2360212/) by Maxicons) for Remove Heresy +- [Pencil](https://thenounproject.com/search/?q=pencil&i=4195852) by Muhamad Aldi Maulana for Enter Text Prompt Button / Pencil +- [Parchment](https://thenounproject.com/term/parchment/1516378/) by hans draiman for Cultured City-States +- [connection](https://thenounproject.com/term/connection/1365233/) by Popular for Mercantile City-States +- [crossed sword](https://thenounproject.com/term/crossed-sword/2427559/) by ProSymbols for Militaristic City-States +- [ship helm](https://thenounproject.com/term/ship-helm/2170591/) by Vectors Market for Maritime City-States +- [Magnifying Glass](https://thenounproject.com/term/magnifying-glass/1311/) by John Caserta for Mod filter +- [tick](https://thenounproject.com/term/tick/3968142/) by Adrien Coquet on Nation picker +- [people](https://thenounproject.com/term/people/458671) by Wilson Joseph as base for Civilopedia category Nations +- [Mountains ](https://thenounproject.com/term/mountains/15616/) by Andrew J. Young as base for Civilopedia category Terrains +- [File:Maya.svg](https://en.wikipedia.org/wiki/File:Maya.svg) for Mayan numerals +- [East side of stela C, Quirigua](https://en.wikipedia.org/wiki/File:East_side_of_stela_C,_Quirigua.PNG) for Mayan calendar symbols +- [Footprints](https://thenounproject.com/icon/footprints-1393611/) by Abdul Wahhab for movement overlay toggle, slightly modified. Currently unused. +- Arrows.svg by Intralexical (@will-ca), CC0. +- [favor](https://thenounproject.com/icon/favor-1029350/) by MICHAEL G BROWN for WLTK marker on City Overview +- [Party](https://thenounproject.com/icon/party-1784941/) by Adrien Coquet for WLTK header on City Overview +- [Party](https://thenounproject.com/icon/party-2955155/) by Lars Meiertoberens as additional WLKT decoration +- [turn right](https://thenounproject.com/icon/turn-right-1920867/) by Alice Design for Resource Overview +- [Tyrannosaurus Rex](https://thenounproject.com/icon/tyrannosaurus-rex-4130976/) by Amethyst Studio for Civilopedia Eras header +- [Timer](https://www.flaticon.com/free-icons/timer) created by Gregor Cresnar Premium - Flaticon ### Main menu diff --git a/docs/Other/Miscellaneous-JSON-files.md b/docs/Other/Miscellaneous-JSON-files.md index ad84a897f5..661b788f1b 100644 --- a/docs/Other/Miscellaneous-JSON-files.md +++ b/docs/Other/Miscellaneous-JSON-files.md @@ -60,6 +60,43 @@ Each era can have the following attributes: | settlerBuildings | List of Strings | defaults to none | Buildings that should automatically be built whenever a city is settled when starting a game in this era | | startingObsoleteWonders | List of Strings | defaults to none | Wonders (and technically buildings) that should be impossible to built when starting a game in this era. Used in the base game to remove all wonders older than 2 era's | +## Speeds.json + +[Link to original](https://github.com/yairm210/Unciv/tree/master/android/assets/jsons/Civ%20V%20-%20Gods%20&%20Kings/Speeds.json) + +This file should contain all the speeds you want to use in your mod. + +Each speed can have the following attributes: + +| Attribute | Type | Optional | Notes | +| --------- | ---- | -------- | ----- | +| name | String | required | Name of the speed | +| modifier | Float (≥0) | defaults to 1.0 | Overall game speed modifier | +| productionCostModifier | Float (≥0) | defaults to the value of `modifier` | Scales production cost of units and buildings | +| goldCostModifier | Float (≥0) | defaults to the value of `modifier` | Scales gold costs | +| scienceCostModifier | Float (≥0) | defaults to the value of `modifier` | Scales science costs | +| cultureCostModifier | Float (≥0) | defaults to the value of `modifier` | Scales culture costs | +| faithCostModifier | Float (≥0) | defaults to the value of `modifier` | Scales faith costs | +| improvementBuildLengthModifier | Float (≥0) | defaults to the value of `modifier` | Scales the time it takes for a worker to build tile improvements | +| barbarianModifier | Float (≥0) | defaults to the value of `modifier` | Scales the time between barbarian spawns | +| goldGiftModifier | Float (≥0) | defaults to the value of `modifier` | Scales the influence gained from gifting gold to city-states | +| cityStateTributeScalingInterval | Float (≥0) | defaults to 6.5 | The number of turns it takes for the amount of gold a player demands from city-states to increase by 5 gold | +| goldenAgeLengthModifier | Float (≥0) | defaults to the value of `modifier` | Scales the length of golden ages | +| religiousPressureAdjacentCity | Integer (≥0) | defaults to 6 | Defines how much religious pressure a city exerts on nearby cities | +| peaceDealDuration | Integer (≥0) | defaults to 10 | The number of turns a peace deal lasts | +| dealDuration | Integer (≥0) | defaults to 30 | The number of turns a non-peace deal (research agreement, open borders, etc.) lasts | +| startYear | Float | defaults to -4000 | The start year of the game (negative is BC/BCE) | +| turns | List of HashMaps | required | The amount of time passed between turns ("yearsPerTurn") and the range of turn numbers ("untilTurn") that this duration applies to | + +The below code is an example of a valid "turns" definition and it specifies that the first 50 turns of a game last for 60 years each, then the next 30 turns (and any played after the 80th) last for 40 years each. + +```json +"turns": [ +{"yearsPerTurn": 60, "untilTurn": 50}, +{"yearsPerTurn": 40, "untilTurn": 80} +] +``` + ## ModOptions.json @@ -185,13 +222,13 @@ Currently the following milestones are supported: | --------- | ----------- | | Build [building] | Build the building [building] in any city | | Anyone build [building] | Anyone must build the building [building] for all players to have this milestone | -| Add all [comment] in capital | Add all units in the `requiredSpaceshipParts` field of this victory to the capital | +| Add all [comment] in capital | Add all units in the `requiredSpaceshipParts` field of this victory to the capital | | Destroy all players | You must be the only major civilization with any cities left | | Capture all capitals | Capture all the original capitals of major civilizations in the game | | Complete [amount] Policy branches | Fully complete at least [amount] policy branches | | Win diplomatic vote | At any point in the game win a diplomatic vote (UN). You may lose afterwards and still retain this milestone | | Become the world religion | Have your religion be the majority religion in a majority of cities of all major civs | -| Have highest score after max turns | Basically time victory. Enables the 'max turn' slider and calculates score when that amount is reached | +| Have highest score after max turns | Basically time victory. Enables the 'max turn' slider and calculates score when that amount is reached | ## Civilopedia text diff --git a/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt b/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt index dee8d73cab..e430920747 100644 --- a/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt +++ b/tests/src/com/unciv/logic/map/UnitMovementAlgorithmsTests.kt @@ -7,10 +7,7 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomaticStatus -import com.unciv.models.ruleset.Difficulty -import com.unciv.models.ruleset.Nation -import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.RulesetCache +import com.unciv.models.ruleset.* import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.testing.GdxTestRunner import org.junit.Assert @@ -35,10 +32,11 @@ class UnitMovementAlgorithmsTests { civInfo.tech.techsResearched.addAll(ruleSet.technologies.keys) civInfo.tech.embarkedUnitsCanEnterOcean = true civInfo.tech.unitsCanEmbark = true - civInfo.nation = Nation().apply { name = "My nation" } civInfo.gameInfo = GameInfo() civInfo.gameInfo.ruleSet = ruleSet civInfo.gameInfo.difficultyObject = Difficulty() + civInfo.gameInfo.speed = ruleSet.speeds[Speed.DEFAULTFORSIMULATION]!! + civInfo.nation = Nation().apply { name = "My nation" } civInfo.gameInfo.civilizations.add(civInfo) unit.civInfo = civInfo unit.owner = civInfo.civName diff --git a/tests/src/com/unciv/uniques/TestGame.kt b/tests/src/com/unciv/uniques/TestGame.kt index d7dd1e4ce8..ee65013f13 100644 --- a/tests/src/com/unciv/uniques/TestGame.kt +++ b/tests/src/com/unciv/uniques/TestGame.kt @@ -39,6 +39,7 @@ class TestGame { ruleset = RulesetCache[BaseRuleset.Civ_V_GnK.fullName]!! gameInfo.ruleSet = ruleset gameInfo.difficultyObject = ruleset.difficulties["Prince"]!! + gameInfo.speed = ruleset.speeds[Speed.DEFAULTFORSIMULATION]!! // Create a tilemap, needed for city centers gameInfo.tileMap = TileMap(1, ruleset, false)