Added difficulty settings!

This commit is contained in:
Yair Morgenstern 2018-07-25 22:56:25 +03:00
parent 7af1a89913
commit 06c68302ce
14 changed files with 160 additions and 32 deletions

View file

@ -0,0 +1,82 @@
[
{
name:"Settler",
baseHappiness:15,
researchCostModifier:0.9,
unhappinessModifier:0.4,
aiCityGrowthModifier:1.6, // that is to say it'll take them 1.6 times as long to grow the city
aiUnitMaintainanceModifier:1,
aiConstructionModifier:0.6, // Replaces "Construction rate" and "Create rate" in original config
aiFreeTechs:[]
},
{
name:"Chieftain",
baseHappiness:12,
researchCostModifier:0.95,
unhappinessModifier:0.6,
aiCityGrowthModifier:1.3,
aiUnitMaintainanceModifier:1,
aiConstructionModifier:0.75,
aiFreeTechs:[]
},
{
name:"Warlord",
baseHappiness:12,
researchCostModifier:1,
unhappinessModifier:0.75,
aiCityGrowthModifier:1.1,
aiUnitMaintainanceModifier:1,
aiConstructionModifier:0.9,
aiFreeTechs:[]
},
{
name:"Prince",
baseHappiness:9,
researchCostModifier:1,
unhappinessModifier:1
aiCityGrowthModifier:1,
aiUnitMaintainanceModifier:0.85,
aiConstructionModifier:1,
aiFreeTechs:[]
},
{
name:"King",
baseHappiness:9,
researchCostModifier:1,
unhappinessModifier:1
aiCityGrowthModifier:0.9,
aiUnitMaintainanceModifier:0.8,
aiConstructionModifier:1.15,
aiFreeTechs:["Pottery"]
},
{
name:"Emperor",
baseHappiness:9,
researchCostModifier:1,
unhappinessModifier:1
aiCityGrowthModifier:0.85,
aiUnitMaintainanceModifier:0.75,
aiConstructionModifier:1.25,
aiFreeTechs:["Pottery","Animal Husbandry"]
},
{
name:"Immortal",
baseHappiness:9,
researchCostModifier:1,
unhappinessModifier:1
aiCityGrowthModifier:0.75,
aiUnitMaintainanceModifier:0.65,
aiConstructionModifier:1.5,
aiFreeTechs:["Pottery","Animal Husbandry","Mining"]
},
{
name:"Deity",
baseHappiness:9,
researchCostModifier:1,
unhappinessModifier:1
aiCityGrowthModifier:0.6,
aiUnitMaintainanceModifier:0.5,
aiConstructionModifier:2,
aiFreeTechs:["Pottery","Animal Husbandry","Mining","The Wheel"]
}
]

View file

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.game"
minSdkVersion 14
targetSdkVersion 26
versionCode 105
versionName "2.6.7"
versionCode 106
versionName "2.6.8"
}
buildTypes {
release {

View file

@ -8,7 +8,7 @@ import com.unciv.models.gamebasics.GameBasics
import com.unciv.ui.utils.getRandom
class GameStarter(){
fun startNewGame(mapRadius: Int, numberOfCivs: Int, civilization: String): GameInfo {
fun startNewGame(mapRadius: Int, numberOfCivs: Int, civilization: String, difficulty:String): GameInfo {
val gameInfo = GameInfo()
gameInfo.tileMap = TileMap(mapRadius)
@ -24,7 +24,9 @@ class GameStarter(){
val freeTiles = gameInfo.tileMap.values.toMutableList().filter { vectorIsWithinNTilesOfEdge(it.position,3)}.toMutableList()
val playerPosition = freeTiles.getRandom().position
gameInfo.civilizations.add(CivilizationInfo(civilization, playerPosition, gameInfo)) // first one is player civ
val playerCiv = CivilizationInfo(civilization, playerPosition, gameInfo)
playerCiv.difficulty=difficulty
gameInfo.civilizations.add(playerCiv) // first one is player civ
freeTiles.removeAll(gameInfo.tileMap.getTilesInDistance(playerPosition,6))
@ -33,7 +35,9 @@ class GameStarter(){
for (civname in GameBasics.Civilizations.keys.filterNot { it=="Barbarians" || it==civilization }.take(numberOfCivs)) {
val startingLocation = freeTiles.toList().getRandom().position
gameInfo.civilizations.add(CivilizationInfo(civname, startingLocation, gameInfo))
val civ = CivilizationInfo(civname, startingLocation, gameInfo)
civ.tech.techsResearched.addAll(playerCiv.getDifficulty().aiFreeTechs)
gameInfo.civilizations.add(civ)
freeTiles.removeAll(gameInfo.tileMap.getTilesInDistance(startingLocation, 6))
}

View file

@ -45,7 +45,7 @@ class UnCivGame : Game() {
}
fun startNewGame(saveTutorialState:Boolean = false) {
val newGame = GameStarter().startNewGame(20, 3, "Babylon")
val newGame = GameStarter().startNewGame(20, 3, "Babylon","Chieftain")
if(saveTutorialState) {
newGame.tutorial = gameInfo.tutorial
}

View file

@ -102,6 +102,9 @@ class CityConstructions {
} else
currentConstruction = saveCurrentConstruction
var productionToAdd = cityStats.production
if(!cityInfo.civInfo.isPlayerCivilization())
productionToAdd *= cityInfo.civInfo.gameInfo.getPlayerCivilization().getDifficulty().aiConstructionModifier
addConstruction(Math.round(cityStats.production))
val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
if (inProgressConstructions[currentConstruction]!! >= productionCost) {

View file

@ -99,8 +99,11 @@ class CityStats {
// in order to determine how much food is produced in a city!
// -3 happiness per city
fun getCityHappiness(): LinkedHashMap<String, Float> {
happinessList["Cities"] = -3f
val civInfo = cityInfo.civInfo
var unhappinessModifier = civInfo.getDifficulty().unhappinessModifier
happinessList["Cities"] = -3f * unhappinessModifier
var unhappinessFromCitizens = cityInfo.population.population.toFloat()
if (civInfo.policies.isAdopted("Democracy"))
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists() * 0.5f
@ -109,7 +112,7 @@ class CityStats {
if (civInfo.policies.isAdopted("Meritocracy"))
unhappinessFromCitizens *= 0.95f
happinessList["Population"] = -unhappinessFromCitizens
happinessList["Population"] = -unhappinessFromCitizens * unhappinessModifier
var happinessFromPolicies = 0f
if (civInfo.policies.isAdopted("Aristocracy"))

View file

@ -36,8 +36,11 @@ class PopulationManager {
fun getFoodToNextPopulation(): Int {
// civ v math,civilization.wikia
return 15 + 6 * (population - 1) + Math.floor(Math.pow((population - 1).toDouble(), 1.8)).toInt()
// civ v math, civilization.wikia
var foodRequired = 15 + 6 * (population - 1) + Math.floor(Math.pow((population - 1).toDouble(), 1.8))
if(!cityInfo.civInfo.isPlayerCivilization())
foodRequired *= cityInfo.civInfo.gameInfo.getPlayerCivilization().getDifficulty().aiCityGrowthModifier
return foodRequired.toInt()
}

View file

@ -8,7 +8,6 @@ import com.unciv.logic.map.MapUnit
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.Counter
import com.unciv.models.gamebasics.Civilization
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tech.TechEra
import com.unciv.models.gamebasics.tile.ResourceType
@ -19,6 +18,7 @@ import com.unciv.ui.utils.getRandom
import com.unciv.ui.utils.tr
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
class CivilizationInfo {
@ -28,6 +28,7 @@ class CivilizationInfo {
var gold = 0
var happiness = 15
var difficulty = "Chieftain"
var civName = "Babylon"
var tech = TechManager()
@ -40,7 +41,8 @@ class CivilizationInfo {
var cities = ArrayList<CityInfo>()
var exploredTiles = HashSet<Vector2>()
fun getCivilization(): Civilization {return GameBasics.Civilizations[civName]!!}
fun getDifficulty() = GameBasics.Difficulties[difficulty]!!
fun getCivilization() = GameBasics.Civilizations[civName]!!
fun getCapital()=cities.first { it.isCapital() }
@ -97,9 +99,11 @@ class CivilizationInfo {
if(policies.isAdopted("Oligarchy")) unitsToPayFor = unitsToPayFor.filterNot { it.getTile().isCityCenter() }
val totalPaidUnits = max(0,unitsToPayFor.count()-freeUnits)
val gameProgress = gameInfo.turns/400f // as game progresses maintainance cost rises
val cost = baseUnitCost*totalPaidUnits*(1+gameProgress)
val finalCost = cost.pow(1+gameProgress/3) // Why 3? No reason.
return finalCost.toInt()
var cost = baseUnitCost*totalPaidUnits*(1+gameProgress)
cost = cost.pow(1+gameProgress/3) // Why 3? To spread 1 to 1.33
if(!isPlayerCivilization())
cost *= gameInfo.getPlayerCivilization().getDifficulty().aiUnitMaintainanceModifier
return cost.toInt()
}
private fun getTransportationUpkeep(): Int {
@ -115,11 +119,11 @@ class CivilizationInfo {
}
// base happiness
fun getHappinessForNextTurn(): HashMap<String, Int> {
val statMap = HashMap<String,Int>()
statMap["Base happiness"] = 15
fun getHappinessForNextTurn(): HashMap<String, Float> {
val statMap = HashMap<String,Float>()
statMap["Base happiness"] = getDifficulty().baseHappiness.toFloat()
var happinessPerUniqueLuxury = 5
var happinessPerUniqueLuxury = 5f
if (policies.isAdopted("Protectionism")) happinessPerUniqueLuxury += 1
statMap["Luxury resources"]= getCivResources().keys
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury
@ -127,13 +131,13 @@ class CivilizationInfo {
for(city in cities){
for(keyvalue in city.cityStats.getCityHappiness()){
if(statMap.containsKey(keyvalue.key))
statMap[keyvalue.key] = statMap[keyvalue.key]!!+keyvalue.value.toInt()
else statMap[keyvalue.key] = keyvalue.value.toInt()
statMap[keyvalue.key] = statMap[keyvalue.key]!!+keyvalue.value
else statMap[keyvalue.key] = keyvalue.value
}
}
if (buildingUniques.contains("Provides 1 happiness per social policy"))
statMap["Policies"] = policies.getAdoptedPolicies().count { !it.endsWith("Complete") }
statMap["Policies"] = policies.getAdoptedPolicies().count { !it.endsWith("Complete") }.toFloat()
return statMap
}
@ -227,7 +231,7 @@ class CivilizationInfo {
getViewableTiles() // adds explored tiles so that the units will be able to perform automated actions better
for (city in cities)
city.cityStats.update()
happiness = getHappinessForNextTurn().values.sum()
happiness = getHappinessForNextTurn().values.sum().roundToInt()
getCivUnits().forEach { it.startTurn() }
}

View file

@ -21,6 +21,7 @@ class DiplomacyManager() {
civInfo=civilizationInfo
otherCivName=OtherCivName
}
// var status:DiplomaticStatus = DiplomaticStatus.War
var trades = ArrayList<Trade>()

View file

@ -20,10 +20,9 @@ class TechManager {
private fun getCurrentTechnology(): Technology = GameBasics.Technologies[currentTechnology()]!!
fun getAmountResearchedText(): String =
if (currentTechnology() == null) ""
else "(" + researchOfTech(currentTechnology()!!) + "/" + getCurrentTechnology().cost + ")"
fun costOfTech(techName: String): Int {
return (GameBasics.Technologies[techName]!!.cost * civInfo.getDifficulty().researchCostModifier).toInt()
}
fun currentTechnology(): String? {
if (techsToResearch.isEmpty()) return null
@ -35,8 +34,8 @@ class TechManager {
else return 0
}
fun turnsToTech(TechName: String): Int {
val remainingScience =GameBasics.Technologies[TechName]!!.cost - researchOfTech(TechName)
fun turnsToTech(techName: String): Int {
val remainingScience = costOfTech(techName) - researchOfTech(techName)
return Math.ceil( remainingScience.toDouble()
/ civInfo.getStatsForNextTurn().science).toInt()
}
@ -51,7 +50,7 @@ class TechManager {
val currentTechnology = currentTechnology()
if (currentTechnology == null) return
techsInProgress[currentTechnology] = researchOfTech(currentTechnology) + scienceForNewTurn
if (techsInProgress[currentTechnology]!! < getCurrentTechnology().cost)
if (techsInProgress[currentTechnology]!! < costOfTech(currentTechnology))
return
val previousEra = civInfo.getEra()

View file

@ -0,0 +1,15 @@
package com.unciv.models.gamebasics
import com.unciv.models.stats.INamed
import java.util.*
class Difficulty: INamed {
override lateinit var name: String
var baseHappiness: Int = 0
var researchCostModifier:Float = 1f
var unhappinessModifier = 1f
var aiCityGrowthModifier = 1f
var aiUnitMaintainanceModifier = 1f
var aiConstructionModifier = 1f
var aiFreeTechs = ArrayList<String>()
}

View file

@ -23,6 +23,7 @@ object GameBasics {
val UnitPromotions = LinkedHashMap<String, Promotion>()
val Civilizations = LinkedHashMap<String, Civilization>()
val PolicyBranches = LinkedHashMap<String, PolicyBranch>()
val Difficulties = LinkedHashMap<String, Difficulty>()
val Tutorials = LinkedHashMap<String, List<String>>()
val Translations = Translations(Gdx.files.internal("jsons/Translations.json").readString())
@ -48,6 +49,7 @@ object GameBasics {
UnitPromotions += createHashmap(getFromJson(Array<Promotion>::class.java, "UnitPromotions"))
PolicyBranches += createHashmap(getFromJson(Array<PolicyBranch>::class.java, "Policies"))
Civilizations += createHashmap(getFromJson(Array<Civilization>::class.java, "Civilizations"))
Difficulties += createHashmap(getFromJson(Array<Difficulty>::class.java, "Difficulties"))
// ...Yes. Total Voodoo. I wish I didn't have to do this.
val x = LinkedHashMap<String,com.badlogic.gdx.utils.Array<com.badlogic.gdx.utils.Array<String>>>()

View file

@ -19,6 +19,7 @@ class NewGameScreen: PickerScreen(){
val table = Table()
table.skin= skin
table.add("Civilization:".tr())
val civSelectBox = SelectBox<String>(skin)
val civArray = Array<String>()
@ -48,6 +49,16 @@ class NewGameScreen: PickerScreen(){
enemiesSelectBox.selected=3
table.add(enemiesSelectBox).pad(10f).row()
table.add("Difficulty:".tr())
val difficultySelectBox = SelectBox<String>(skin)
val difficultyArray = Array<String>()
GameBasics.Difficulties.keys.forEach{difficultyArray.add(it)}
difficultySelectBox.items = difficultyArray
difficultySelectBox.selected = "Chieftain"
table.add(difficultySelectBox).pad(10f).row()
rightSideButton.enable()
rightSideButton.setText("Start game!".tr())
rightSideButton.addClickListener {
@ -57,7 +68,8 @@ class NewGameScreen: PickerScreen(){
kotlin.concurrent.thread { // Creating a new game can tke a while and we don't want ANRs
newGame = GameStarter().startNewGame(
worldSizeToRadius[worldSizeSelectBox.selected]!!, enemiesSelectBox.selected, civSelectBox.selected )
worldSizeToRadius[worldSizeSelectBox.selected]!!, enemiesSelectBox.selected,
civSelectBox.selected, difficultySelectBox.selected )
.apply { tutorial=game.gameInfo.tutorial }
}
}

View file

@ -83,7 +83,7 @@ class WorldScreen : CameraStageBaseScreen() {
fun update() {
kotlin.concurrent.thread { civInfo.happiness = civInfo.getHappinessForNextTurn().values.sum() }
kotlin.concurrent.thread { civInfo.happiness = civInfo.getHappinessForNextTurn().values.sum().toInt() }
if (game.gameInfo.tutorial.contains("CityEntered")) {
displayTutorials("AfterCityEntered")