Moddable game speeds (#6856)

* Move GameSpeed definition to JSON files

* Add game speeds civilopedia page
This commit is contained in:
OptimizedForDensity
2022-06-18 17:27:46 -04:00
committed by GitHub
parent 06198f2e2c
commit c922f134e6
40 changed files with 526 additions and 150 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -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}
]
}
]

View File

@ -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}
]
}
]

View File

@ -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] =

View File

@ -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()
}
}

View File

@ -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()

View File

@ -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())
}
}

View File

@ -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

View File

@ -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<String> = 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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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, ""))

View File

@ -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)
}

View File

@ -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 {

View File

@ -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()

View File

@ -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() {

View File

@ -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

View File

@ -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)

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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<Player>().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<String> = arrayListOf()
var victoryTypes: ArrayList<String> = arrayListOf()
var startingEra = "Ancient era"
var isOnlineMultiplayer = false
var baseRuleset: String = BaseRuleset.Civ_V_GnK.fullName
var mods = LinkedHashSet<String>()
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<String> {
return mods.toHashSet().apply { add(baseRuleset) }
}
}
}

View File

@ -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);
}

View File

@ -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()
}

View File

@ -84,6 +84,7 @@ class Ruleset {
val buildings = LinkedHashMap<String, Building>()
val difficulties = LinkedHashMap<String, Difficulty>()
val eras = LinkedHashMap<String, Era>()
val speeds = LinkedHashMap<String, Speed>()
var globalUniques = GlobalUniques()
val nations = LinkedHashMap<String, Nation>()
val policies = LinkedHashMap<String, Policy>()
@ -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<Speed>::class.java, speedsFile))
}
val unitTypesFile = folderHandle.child("UnitTypes.json")
if (unitTypesFile.exists()) unitTypes += createHashmap(json().fromJsonFile(Array<UnitType>::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)
}

View File

@ -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<HashMap<String, Float>> = ArrayList()
val yearsPerTurn: ArrayList<YearsPerTurn> by lazy {
ArrayList<YearsPerTurn>().apply {
turns.forEach { this.add(YearsPerTurn(it["yearsPerTurn"]!!, it["untilTurn"]!!.toInt())) }
}
}
val statCostModifiers: HashMap<Stat, Float> by lazy {
HashMap<Stat, Float>().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
}
}

View File

@ -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)

View File

@ -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(

View File

@ -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),

View File

@ -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()
}

View File

@ -456,6 +456,7 @@ object TranslationFileWriter {
"Buildings" -> emptyArray<Building>().javaClass
"Difficulties" -> emptyArray<Difficulty>().javaClass
"Eras" -> emptyArray<Era>().javaClass
"Speeds" -> emptyArray<Speed>().javaClass
"GlobalUniques" -> GlobalUniques().javaClass
"Nations" -> emptyArray<Nation>().javaClass
"Policies" -> emptyArray<PolicyBranch>().javaClass

View File

@ -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]

View File

@ -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()) {

View File

@ -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() {

View File

@ -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())

View File

@ -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<Player>().apply {
add(Player().apply {

View File

@ -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

View File

@ -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
<!-- [Link to original](https://github.com/yairm210/Unciv/tree/master/android/assets/jsons/Civ%20V%20-%20Gods%20&%20Kings/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

View File

@ -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

View File

@ -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)