Added Game Speed option - part of #559

This commit is contained in:
Yair Morgenstern 2019-07-24 18:35:06 +03:00
parent 7d38841eb8
commit 994e313101
14 changed files with 274 additions and 214 deletions

View file

@ -41,16 +41,6 @@
}
*/
"World size":{ //not duplicate,the other one is wrong.
Italian:"Dimensione della mappa"
Russian:"Размер мира"
French:"Taille du monde"
Romanian:"Mărime pământ"
Spanish:"Tamaño del mundo"
Simplified_Chinese:"世界大小"
Portuguese:"Tamanho do mundo"
German:"Kartengröße"
}
"Start game!":{
@ -99,16 +89,6 @@
German:"Anzahl der Gegner"
}
"Difficulty":{
Italian:"Difficoltà"
Russian:"Сложность"
French:"Difficulté"
Romanian:"Dificultate"
Spanish:"Dificultad"
Simplified_Chinese:"难度"
Portuguese:"Dificuldade"
German:"Schwierigkeitsgrad"
}
"Number of city-states":{
Italian:"Numero di Città-Stato"
@ -140,6 +120,196 @@
French: "Culturelle"
}
// Map sizes
"World size":{ //not duplicate,the other one is wrong.
Italian:"Dimensione della mappa"
Russian:"Размер мира"
French:"Taille du monde"
Romanian:"Mărime pământ"
Spanish:"Tamaño del mundo"
Simplified_Chinese:"世界大小"
Portuguese:"Tamanho do mundo"
German:"Kartengröße"
}
"Tiny":{
Italian:"Minuscola"
Romanian:"Micuț"
Spanish:"Micro"
Simplified_Chinese:"极小"
German:"Winzig"
Russian:"крошечный"
Portuguese:"Minúsculo"
French:"Minuscule"
}
"Small":{
Italian:"Piccola"
Russian:"Маленький"
French:"Petit"
Romanian:"Mic"
Spanish:"Pequeño"
Simplified_Chinese:"小"
Portuguese:"Pequeno"
German:"Klein"
}
"Medium":{
Italian:"Media"
Russian:"Средний"
French:"Moyen"
Romanian:"Mediu"
Spanish:"Mediano"
Simplified_Chinese:"中"
Portuguese:"Médio"
German:"Mittel"
}
"Large":{
Italian:"Grande"
Russian:"Большой"
French:"Grand"
Romanian:"Mare"
Spanish:"Grande"
Simplified_Chinese:"大"
Portuguese:"Grande"
German:"Groß"
}
"Huge":{
Italian:"Enorme"
Russian:"огромный"
French:"Énorme"
Romanian:"Imens"
Spanish:"Enorme"
Simplified_Chinese:"巨大"
Portuguese:"Imenso"
German:"Enorm"
}
// Difficulties
"Difficulty":{
Italian:"Difficoltà"
Russian:"Сложность"
French:"Difficulté"
Romanian:"Dificultate"
Spanish:"Dificultad"
Simplified_Chinese:"难度"
Portuguese:"Dificuldade"
German:"Schwierigkeitsgrad"
}
"Settler":{
Italian:"Colono"
Russian:"Поселенец"
French:"Colon"
Romanian:"Colonist"
Spanish:"Colono"
Simplified_Chinese:"移民"
Portuguese:"Colonizador"
German:"Siedler"
}
"Chieftain":{
Italian:"Capo"
Russian:"Вождь"
French:"Chef de clan"
Romanian:"Șef de trib"
Spanish:"Cacique"
Simplified_Chinese:"酋长"
Portuguese:"Cacique"
German:"Häuptling"
}
"Warlord":{
Italian:"Condottiero"
Russian:"Военачальник"
French:"Chef de guerre"
Romanian:"Comandant"
Spanish:"Señor de la guerra"
Simplified_Chinese:"军阀"
Portuguese:"General"
German:"Kriegsherr"
}
"Prince":{
Italian:"Principe"
Russian:"Принц"
French:"Prince"
Romanian:"Prinţ"
Spanish:"Príncipe"
Simplified_Chinese:"王子"
Portuguese:"Príncipe"
German:"Prinz"
}
"King":{
Italian:"Re"
Russian:"Король"
French:"Roi"
Romanian:"Rege"
Spanish:"Rey"
Simplified_Chinese:"国王"
Portuguese:"Rei"
German:"König"
}
"Emperor":{
Italian:"Imperatore"
Russian:"Император"
French:"Empereur"
Romanian:"Împărat"
Spanish:"Emperador"
Simplified_Chinese:"皇帝"
Portuguese:"Imperador"
German:"Kaiser"
}
"Immortal":{
Italian:"Immortale"
Russian:"Бессмертный"
French:"Immortel"
Romanian:"Nemuritor"
Spanish:"Inmortal"
Simplified_Chinese:"不朽"
Portuguese:"Imortal"
German:"Unsterblicher"
}
"Deity":{
Italian:"Divinità"
Russian:"Божество"
French:"Déité" //or Divinité
Romanian:"Zeitate"
Spanish:"Deidad"
Simplified_Chinese:"天神"
Portuguese:"Semi-Deus"
German:"Gott"
}
// Game speeds
"Game Speed":{
}
"Quick":{
}
"Standard":{
}
"Epic":{
}
"Marathon":{
}
////////////// Save and load game

View file

@ -1324,153 +1324,6 @@
}
//////// Difficulty
"Settler":{
Italian:"Colono"
Russian:"Поселенец"
French:"Colon"
Romanian:"Colonist"
Spanish:"Colono"
Simplified_Chinese:"移民"
Portuguese:"Colonizador"
German:"Siedler"
}
"Chieftain":{
Italian:"Capo"
Russian:"Вождь"
French:"Chef de clan"
Romanian:"Șef de trib"
Spanish:"Cacique"
Simplified_Chinese:"酋长"
Portuguese:"Cacique"
German:"Häuptling"
}
"Warlord":{
Italian:"Condottiero"
Russian:"Военачальник"
French:"Chef de guerre"
Romanian:"Comandant"
Spanish:"Señor de la guerra"
Simplified_Chinese:"军阀"
Portuguese:"General"
German:"Kriegsherr"
}
"Prince":{
Italian:"Principe"
Russian:"Принц"
French:"Prince"
Romanian:"Prinţ"
Spanish:"Príncipe"
Simplified_Chinese:"王子"
Portuguese:"Príncipe"
German:"Prinz"
}
"King":{
Italian:"Re"
Russian:"Король"
French:"Roi"
Romanian:"Rege"
Spanish:"Rey"
Simplified_Chinese:"国王"
Portuguese:"Rei"
German:"König"
}
"Emperor":{
Italian:"Imperatore"
Russian:"Император"
French:"Empereur"
Romanian:"Împărat"
Spanish:"Emperador"
Simplified_Chinese:"皇帝"
Portuguese:"Imperador"
German:"Kaiser"
}
"Immortal":{
Italian:"Immortale"
Russian:"Бессмертный"
French:"Immortel"
Romanian:"Nemuritor"
Spanish:"Inmortal"
Simplified_Chinese:"不朽"
Portuguese:"Imortal"
German:"Unsterblicher"
}
"Deity":{
Italian:"Divinità"
Russian:"Божество"
French:"Déité" //or Divinité
Romanian:"Zeitate"
Spanish:"Deidad"
Simplified_Chinese:"天神"
Portuguese:"Semi-Deus"
German:"Gott"
}
////// world size
"Tiny":{
Italian:"Minuscola"
Romanian:"Micuț"
Spanish:"Micro"
Simplified_Chinese:"极小"
German:"Winzig"
Russian:"крошечный"
Portuguese:"Minúsculo"
French:"Minuscule"
}
"Small":{
Italian:"Piccola"
Russian:"Маленький"
French:"Petit"
Romanian:"Mic"
Spanish:"Pequeño"
Simplified_Chinese:"小"
Portuguese:"Pequeno"
German:"Klein"
}
"Medium":{
Italian:"Media"
Russian:"Средний"
French:"Moyen"
Romanian:"Mediu"
Spanish:"Mediano"
Simplified_Chinese:"中"
Portuguese:"Médio"
German:"Mittel"
}
"Large":{
Italian:"Grande"
Russian:"Большой"
French:"Grand"
Romanian:"Mare"
Spanish:"Grande"
Simplified_Chinese:"大"
Portuguese:"Grande"
German:"Groß"
}
"Huge":{
Italian:"Enorme"
Russian:"огромный"
French:"Énorme"
Romanian:"Imens"
Spanish:"Enorme"
Simplified_Chinese:"巨大"
Portuguese:"Imenso"
German:"Enorm"
}
////// Overview screen

View file

@ -14,8 +14,23 @@ import com.unciv.models.gamebasics.VictoryType
import java.util.*
import kotlin.collections.ArrayList
enum class GameSpeed{
Quick,
Standard,
Epic;
fun getModifier(): Float {
when(this) {
Quick -> return 0.67f
Standard -> return 1f
Epic -> return 1.5f
}
}
}
class GameParameters{
var difficulty="Prince"
var gameSpeed = GameSpeed.Standard
var mapRadius=20
var numberOfHumanPlayers=1
var humanNations=ArrayList<String>().apply { add("Babylon") } // Good default starting civ

View file

@ -92,7 +92,7 @@ class NextTurnAutomation{
val construction = city.cityConstructions.getCurrentConstruction()
if (construction.canBePurchased()
&& city.civInfo.gold / 3 >= construction.getGoldCost(civInfo) ) {
city.cityConstructions.purchaseBuilding(construction.name)
city.cityConstructions.purchaseConstruction(construction.name)
}
}
}

View file

@ -176,7 +176,7 @@ class Battle(val gameInfo:GameInfo) {
if(defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()
&& attacker.getCivInfo().policies.isAdopted("Honor Complete"))
attacker.getCivInfo().gold += defender.unit.baseUnit.getGoldCost(attacker.getCivInfo(), true) / 10
attacker.getCivInfo().gold += defender.unit.baseUnit.getProductionCost(attacker.getCivInfo()) / 10
if(attacker is MapUnitCombatant && attacker.unit.action!=null && attacker.unit.action!!.startsWith("moveTo"))
attacker.unit.action=null

View file

@ -113,7 +113,7 @@ class CityConstructions {
}
fun getRemainingWork(constructionName: String) =
getConstruction(constructionName).getProductionCost(cityInfo.civInfo.policies.adoptedPolicies) - getWorkDone(constructionName)
getConstruction(constructionName).getProductionCost(cityInfo.civInfo) - getWorkDone(constructionName)
fun turnsToConstruction(constructionName: String): Int {
val workLeft = getRemainingWork(constructionName)
@ -158,7 +158,7 @@ class CityConstructions {
val construction = getConstruction(currentConstruction)
if(construction is SpecialConstruction) chooseNextConstruction() // check every turn if we could be doing something better, because this doesn't end by itself
else {
val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
val productionCost = construction.getProductionCost(cityInfo.civInfo)
if (inProgressConstructions.containsKey(currentConstruction)
&& inProgressConstructions[currentConstruction]!! >= productionCost) {
constructionComplete(construction)
@ -217,14 +217,14 @@ class CityConstructions {
builtBuildings.remove(buildingName)
}
fun purchaseBuilding(buildingName: String) {
cityInfo.civInfo.gold -= getConstruction(buildingName).getGoldCost(cityInfo.civInfo)
getConstruction(buildingName).postBuildEvent(this)
if (currentConstruction == buildingName)
fun purchaseConstruction(constructionName: String) {
cityInfo.civInfo.gold -= getConstruction(constructionName).getGoldCost(cityInfo.civInfo)
getConstruction(constructionName).postBuildEvent(this)
if (currentConstruction == constructionName)
cancelCurrentConstruction()
cityInfo.cityStats.update()
cityInfo.civInfo.updateDetailedCivResources() // this building could be a resource-requiring one
cityInfo.civInfo.updateDetailedCivResources() // this building/unit could be a resource-requiring one
}
fun addCultureBuilding() {

View file

@ -5,8 +5,8 @@ import com.unciv.models.gamebasics.ICivilopedia
import com.unciv.models.stats.INamed
interface IConstruction : INamed, ICivilopedia {
fun getProductionCost(adoptedPolicies: HashSet<String>): Int
fun getGoldCost(civInfo: CivilizationInfo, baseCost: Boolean = false): Int
fun getProductionCost(civInfo: CivilizationInfo): Int
fun getGoldCost(civInfo: CivilizationInfo): Int
fun isBuildable(construction: CityConstructions): Boolean
fun shouldBeDisplayed(construction: CityConstructions): Boolean
fun postBuildEvent(construction: CityConstructions) // Yes I'm hilarious.
@ -45,11 +45,11 @@ open class SpecialConstruction(override var name: String, override val descripti
return false
}
override fun getProductionCost(adoptedPolicies: HashSet<String>): Int {
override fun getProductionCost(civInfo: CivilizationInfo): Int {
throw Exception("Impossible!")
}
override fun getGoldCost(civInfo: CivilizationInfo, baseCost: Boolean): Int {
override fun getGoldCost(civInfo: CivilizationInfo): Int {
throw Exception("Impossible!")
}

View file

@ -4,6 +4,9 @@ import com.unciv.Constants
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Policy
import com.unciv.models.gamebasics.VictoryType
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToInt
class PolicyManager {
@ -21,12 +24,15 @@ class PolicyManager {
// from https://forums.civfanatics.com/threads/the-number-crunching-thread.389702/
// round down to nearest 5
fun getCultureNeededForNextPolicy(): Int {
var baseCost = 25 + Math.pow((numberOfAdoptedPolicies * 6).toDouble(), 1.7)
var policyCultureCost = 25 + (numberOfAdoptedPolicies * 6).toDouble().pow(1.7)
var cityModifier = 0.3 * (civInfo.cities.size - 1)
if (isAdopted("Representation")) cityModifier *= (2 / 3f).toDouble()
if (isAdopted("Piety Complete")) baseCost *= 0.9
if (civInfo.containsBuildingUnique("Culture cost of adopting new Policies reduced by 10%")) baseCost *= 0.9
val cost: Int = Math.round(baseCost * (1 + cityModifier)).toInt()
if (isAdopted("Piety Complete")) policyCultureCost *= 0.9
if (civInfo.containsBuildingUnique("Culture cost of adopting new Policies reduced by 10%"))
policyCultureCost *= 0.9
policyCultureCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
val cost: Int = (policyCultureCost * (1 + cityModifier)).roundToInt()
return cost - (cost % 5)
}
@ -73,7 +79,7 @@ class PolicyManager {
"Representation", "Reformation" -> civInfo.goldenAges.enterGoldenAge()
"Scientific Revolution" -> civInfo.tech.freeTechs += 2
"Legalism" ->
for (city in civInfo.cities.subList(0, Math.min(4, civInfo.cities.size)))
for (city in civInfo.cities.subList(0, min(4, civInfo.cities.size)))
city.cityConstructions.addCultureBuilding()
"Free Religion" -> freePolicies++
"Liberty Complete" -> {

View file

@ -40,7 +40,10 @@ class TechManager {
}
fun costOfTech(techName: String): Int {
return (GameBasics.Technologies[techName]!!.cost * civInfo.getDifficulty().researchCostModifier).toInt()
var techCost = GameBasics.Technologies[techName]!!.cost.toFloat()
techCost *= civInfo.getDifficulty().researchCostModifier
techCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
return techCost.toInt()
}
fun currentTechnology(): Technology? = currentTechnologyName()?.let {

View file

@ -185,26 +185,25 @@ class Building : NamedStats(), IConstruction{
return !isWonder && !isNationalWonder
}
override fun getProductionCost(adoptedPolicies: HashSet<String>): Int {
if (!isWonder && culture != 0f && adoptedPolicies.contains("Piety"))
return (cost * 0.85).toInt()
else return cost
override fun getProductionCost(civInfo: CivilizationInfo): Int {
var productionCost = cost.toFloat()
if (!isWonder && culture != 0f && civInfo.policies.isAdopted("Piety"))
productionCost *= 0.85f
productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
return productionCost.toInt()
}
override fun getGoldCost(civInfo: CivilizationInfo, baseCost: Boolean): Int {
override fun getGoldCost(civInfo: CivilizationInfo): Int {
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
var cost: Double
if (baseCost) {
cost = Math.pow((30 * getProductionCost(hashSetOf())).toDouble(), 0.75) * (1 + hurryCostModifier / 100)
} else {
cost = Math.pow((30 * getProductionCost(civInfo.policies.adoptedPolicies)).toDouble(), 0.75) * (1 + hurryCostModifier / 100)
if (civInfo.policies.adoptedPolicies.contains("Mercantilism")) cost *= 0.75
cost = Math.pow((30 * getProductionCost(civInfo)).toDouble(), 0.75) * (1 + hurryCostModifier / 100)
if (civInfo.policies.isAdopted("Mercantilism")) cost *= 0.75
if (civInfo.containsBuildingUnique("-15% to purchasing items in cities")) cost *= 0.85
if (civInfo.policies.adoptedPolicies.contains("Patronage")
if (civInfo.policies.isAdopted("Patronage")
&& listOf("Monument", "Temple", "Opera House", "Museum", "Broadcast Tower")
.map{civInfo.getEquivalentBuilding(it).name}.contains(name))
cost *= 0.5
}
return (cost / 10).toInt() * 10
}

View file

@ -97,17 +97,19 @@ class BaseUnit : INamed, IConstruction, ICivilopedia {
return true
}
override fun getProductionCost(adoptedPolicies: HashSet<String>): Int = cost
override fun getProductionCost(civInfo: CivilizationInfo): Int {
var productionCost = cost.toFloat()
productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
return productionCost.toInt()
}
fun getBaseGoldCost() = Math.pow((30 * cost).toDouble(), 0.75) * (1 + hurryCostModifier / 100)
override fun getGoldCost(civInfo: CivilizationInfo, baseCost: Boolean): Int {
override fun getGoldCost(civInfo: CivilizationInfo): Int {
var cost = getBaseGoldCost()
if (!baseCost) {
if(civInfo.policies.adoptedPolicies.contains("Mercantilism")) cost *= 0.75
if(civInfo.policies.adoptedPolicies.contains("Militarism")) cost *= 0.66f
if (civInfo.policies.adoptedPolicies.contains("Mercantilism")) cost *= 0.75
if (civInfo.policies.adoptedPolicies.contains("Militarism")) cost *= 0.66f
if (civInfo.containsBuildingUnique("-15% to purchasing items in cities")) cost *= 0.85
}
return (cost / 10).toInt() * 10 // rounded down o nearest ten
}

View file

@ -5,6 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
import com.badlogic.gdx.utils.Array
import com.unciv.GameSpeed
import com.unciv.GameStarter
import com.unciv.UnCivGame
import com.unciv.logic.GameInfo
@ -76,6 +77,7 @@ class NewGameScreen: PickerScreen(){
addMapTypeSizeAndFile(newGameOptionsTable)
addNumberOfHumansAndEnemies(newGameOptionsTable)
addDifficultySelectBox(newGameOptionsTable)
addGameSpeedSelectBox(newGameOptionsTable)
addVictoryTypeCheckboxes(newGameOptionsTable)
addBarbariansCheckbox(newGameOptionsTable)
@ -229,6 +231,17 @@ class NewGameScreen: PickerScreen(){
newGameOptionsTable.add(difficultySelectBox).pad(10f).row()
}
private fun addGameSpeedSelectBox(newGameOptionsTable: Table) {
newGameOptionsTable.add("{Game Speed}:".tr())
val gameSpeedSelectBox = TranslatedSelectBox(GameSpeed.values().map { it.name }, newGameParameters.gameSpeed.name, skin)
gameSpeedSelectBox.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
newGameParameters.gameSpeed = GameSpeed.valueOf(gameSpeedSelectBox.selected.value)
}
})
newGameOptionsTable.add(gameSpeedSelectBox).pad(10f).row()
}
private fun addVictoryTypeCheckboxes(newGameOptionsTable: Table) {
newGameOptionsTable.add("{Victory conditions}:".tr()).colspan(2).row()

View file

@ -150,7 +150,7 @@ class ConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScre
purchaseConstructionButton = TextButton("Buy for [$buildingGoldCost] gold".tr(), CameraStageBaseScreen.skin)
purchaseConstructionButton.onClick("coin") {
YesNoPopupTable("Would you like to purchase [${construction.name}] for [$buildingGoldCost] gold?".tr(), {
cityConstructions.purchaseBuilding(construction.name)
cityConstructions.purchaseConstruction(construction.name)
if(lastConstruction!="" && cityConstructions.getConstruction(lastConstruction).isBuildable(cityConstructions))
city.cityConstructions.currentConstruction = lastConstruction
cityScreen.update() // since the list of available buildings needs to be updated too, so we can "see" that the building we bought now exists in the city

View file

@ -180,11 +180,10 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
label.pack()
group.addActor(label)
val adoptedPolicies = cityConstructions.cityInfo.civInfo.policies.adoptedPolicies
val constructionPercentage = cityConstructions.getWorkDone(cityCurrentConstruction.name) /
cityCurrentConstruction.getProductionCost(adoptedPolicies).toFloat()
val productionBar = ImageGetter.getProgressBarVertical(2f, groupHeight, constructionPercentage
, Color.BROWN.cpy().lerp(Color.WHITE, 0.5f), Color.BLACK)
cityCurrentConstruction.getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
val productionBar = ImageGetter.getProgressBarVertical(2f, groupHeight, constructionPercentage,
Color.BROWN.cpy().lerp(Color.WHITE, 0.5f), Color.BLACK)
productionBar.x = 10f
label.x = productionBar.x - label.width - 3
group.addActor(productionBar)