diff --git a/android/build.gradle b/android/build.gradle index bd2a267e..8e798eec 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,8 +21,8 @@ android { applicationId "com.unciv.app" minSdkVersion 14 targetSdkVersion 29 - versionCode 307 - versionName "3.1.4-patch1" + versionCode 308 + versionName "3.1.5" } // Had to add this crap for Travis to build, it wanted to sign the app diff --git a/core/src/com/unciv/logic/GameStarter.kt b/core/src/com/unciv/logic/GameStarter.kt index 22288935..fd4a2e98 100644 --- a/core/src/com/unciv/logic/GameStarter.kt +++ b/core/src/com/unciv/logic/GameStarter.kt @@ -10,8 +10,10 @@ import com.unciv.models.gamebasics.GameBasics import com.unciv.models.metadata.GameParameters import java.util.* import kotlin.collections.ArrayList +import kotlin.math.max class GameStarter{ + fun startNewGame(newGameParameters: GameParameters): GameInfo { val gameInfo = GameInfo() @@ -21,6 +23,32 @@ class GameStarter{ gameInfo.difficulty = newGameParameters.difficulty + addCivilizations(newGameParameters, gameInfo) + + gameInfo.setTransients() // needs to be before placeBarbarianUnit because it depends on the tilemap having its gameinfo set + + // Add Civ Technologies + for (civInfo in gameInfo.civilizations.filter {!it.isBarbarian()}) { + + if (!civInfo.isPlayerCivilization()) + for (tech in gameInfo.getDifficulty().aiFreeTechs) + civInfo.tech.addTechnology(tech) + + for (tech in GameBasics.Technologies.values + .filter { it.era() < newGameParameters.startingEra }) + if (!civInfo.tech.isResearched(tech.name)) + civInfo.tech.addTechnology(tech.name) + + civInfo.popupAlerts.clear() // Since adding technologies generates popups... + } + + // and only now do we add units for everyone, because otherwise both the gameInfo.setTransients() and the placeUnit will both add the unit to the civ's unit list! + addCivStartingUnits(gameInfo) + + return gameInfo + } + + private fun addCivilizations(newGameParameters: GameParameters, gameInfo: GameInfo) { val availableCivNames = Stack() availableCivNames.addAll(GameBasics.Nations.filter { !it.value.isCityState() }.keys.shuffled()) availableCivNames.removeAll(newGameParameters.players.map { it.chosenCiv }) @@ -30,8 +58,8 @@ class GameStarter{ val barbarianCivilization = CivilizationInfo("Barbarians") gameInfo.civilizations.add(barbarianCivilization) - for(player in newGameParameters.players.sortedBy { it.chosenCiv=="Random" }) { - val nationName = if(player.chosenCiv!="Random") player.chosenCiv + for (player in newGameParameters.players.sortedBy { it.chosenCiv == "Random" }) { + val nationName = if (player.chosenCiv != "Random") player.chosenCiv else availableCivNames.pop() val playerCiv = CivilizationInfo(nationName) @@ -42,8 +70,8 @@ class GameStarter{ val cityStatesWithStartingLocations = - gameInfo.tileMap.values.filter { it.improvement!=null && it.improvement!!.startsWith("StartingLocation ") } - .map { it.improvement!!.replace("StartingLocation ","") } + gameInfo.tileMap.values.filter { it.improvement != null && it.improvement!!.startsWith("StartingLocation ") } + .map { it.improvement!!.replace("StartingLocation ", "") } val availableCityStatesNames = Stack() // since we shuffle and then order by, we end up with all the city states with starting locations first in a random order, @@ -55,39 +83,41 @@ class GameStarter{ val civ = CivilizationInfo(cityStateName) gameInfo.civilizations.add(civ) } + } - gameInfo.setTransients() // needs to be before placeBarbarianUnit because it depends on the tilemap having its gameinfo set - - for (civInfo in gameInfo.civilizations.filter {!it.isBarbarian() && !it.isPlayerCivilization()}) { - for (tech in gameInfo.getDifficulty().aiFreeTechs) - civInfo.tech.addTechnology(tech) - } - - // and only now do we add units for everyone, because otherwise both the gameInfo.setTransients() and the placeUnit will both add the unit to the civ's unit list! - + private fun addCivStartingUnits(gameInfo: GameInfo) { val startingLocations = getStartingLocations( gameInfo.civilizations.filter { !it.isBarbarian() }, gameInfo.tileMap) + // For later starting eras, or for civs like Polynesia with a different Warrior, we need different starting units + fun getWarriorEquivalent(civ: CivilizationInfo): String { + val availableMilitaryUnits = GameBasics.Units.values.filter { + it.isBuildable(civ) + && it.unitType.isLandUnit() + && !it.unitType.isCivilian() + } + return availableMilitaryUnits.maxBy { max(it.strength, it.rangedStrength) }!!.name + } + for (civ in gameInfo.civilizations.filter { !it.isBarbarian() }) { val startingLocation = startingLocations[civ]!! civ.placeUnitNearTile(startingLocation.position, Constants.settler) - civ.placeUnitNearTile(startingLocation.position, civ.getEquivalentUnit("Warrior").name) + civ.placeUnitNearTile(startingLocation.position, getWarriorEquivalent(civ)) civ.placeUnitNearTile(startingLocation.position, "Scout") if (!civ.isPlayerCivilization() && civ.isMajorCiv()) { for (unit in gameInfo.getDifficulty().aiFreeUnits) { - civ.placeUnitNearTile(startingLocation.position, civ.getEquivalentUnit(unit).name) + val unitToAdd = if (unit == "Warrior") getWarriorEquivalent(civ) else unit + civ.placeUnitNearTile(startingLocation.position, unitToAdd) } } } - - return gameInfo } - fun getStartingLocations(civs:List,tileMap: TileMap): HashMap { + private fun getStartingLocations(civs:List, tileMap: TileMap): HashMap { var landTiles = tileMap.values .filter { it.isLand && !it.getBaseTerrain().impassable } @@ -148,7 +178,7 @@ class GameStarter{ throw Exception("Didn't manage to get starting locations even with distance of 1?") } - fun vectorIsAtLeastNTilesAwayFromEdge(vector: Vector2, n:Int, tileMap: TileMap): Boolean { + private fun vectorIsAtLeastNTilesAwayFromEdge(vector: Vector2, n:Int, tileMap: TileMap): Boolean { // Since all maps are HEXAGONAL, the easiest way of checking if a tile is n steps away from the // edge is checking the distance to the CENTER POINT // Can't believe we used a dumb way of calculating this before! @@ -156,5 +186,4 @@ class GameStarter{ val distanceFromCenter = HexMath().getDistance(vector, Vector2.Zero) return hexagonalRadius-distanceFromCenter >= n } - } \ No newline at end of file diff --git a/core/src/com/unciv/models/metadata/GameParameters.kt b/core/src/com/unciv/models/metadata/GameParameters.kt index 35231aaf..a5c8c682 100644 --- a/core/src/com/unciv/models/metadata/GameParameters.kt +++ b/core/src/com/unciv/models/metadata/GameParameters.kt @@ -3,6 +3,7 @@ package com.unciv.models.metadata import com.unciv.logic.civilization.PlayerType import com.unciv.logic.map.MapType import com.unciv.models.gamebasics.VictoryType +import com.unciv.models.gamebasics.tech.TechEra class GameParameters { // Default values are the default new game var difficulty = "Prince" @@ -17,6 +18,7 @@ class GameParameters { // Default values are the default new game var noBarbarians = false var mapFileName: String? = null var victoryTypes: ArrayList = VictoryType.values().toCollection(ArrayList()) // By default, all victory types + var startingEra = TechEra.Ancient var isOnlineMultiplayer = false } \ No newline at end of file diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt index 57e918ea..110d3c3e 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt @@ -10,6 +10,7 @@ import com.unciv.logic.MapSaver import com.unciv.logic.map.MapType import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.VictoryType +import com.unciv.models.gamebasics.tech.TechEra import com.unciv.models.gamebasics.tr import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.GameSpeed @@ -22,11 +23,11 @@ class NewGameScreenOptionsTable(val newGameParameters: GameParameters, val onMul addMapTypeSizeAndFile() addDifficultySelectBox() addGameSpeedSelectBox() + addEraSelectBox() addCityStatesSelectBox() addVictoryTypeCheckboxes() addBarbariansCheckbox() - addIsOnlineMultiplayerCheckbox() pack() @@ -140,6 +141,17 @@ class NewGameScreenOptionsTable(val newGameParameters: GameParameters, val onMul add(gameSpeedSelectBox).pad(10f).row() } + private fun addEraSelectBox() { + add("{Starting Era}:".tr()) + val eraSelectBox = TranslatedSelectBox(TechEra.values().map { it.name }, newGameParameters.startingEra.name, CameraStageBaseScreen.skin) + eraSelectBox.addListener(object : ChangeListener() { + override fun changed(event: ChangeEvent?, actor: Actor?) { + newGameParameters.startingEra = TechEra.valueOf(eraSelectBox.selected.value) + } + }) + add(eraSelectBox).pad(10f).row() + } + private fun addVictoryTypeCheckboxes() { add("{Victory conditions}:".tr()).colspan(2).row() diff --git a/docs/Credits.md b/docs/Credits.md index a06e10f3..652c9f4b 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -20,6 +20,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https: * [Flag](https://thenounproject.com/search/?q=Flag&i=50114) By Melvin Poppelaars for Settler * [Eagle](https://thenounproject.com/search/?q=Eagle&i=1619932) By anggun for Scout * [Axe](https://thenounproject.com/search/?q=Axe&i=1688143) By ehab.abdullah for Warrior +* [Haka](https://thenounproject.com/search/?q=haka&i=379655) By Josh for Maori Warrior * [Spiked Club](https://thenounproject.com/search/?q=spiked%20club&i=831793) by Hamish * [Bow And Arrow](https://thenounproject.com/search/?q=Bow%20and%20Arrow&i=338261) By Viktor Ostrovsky for Archer * [Bow](https://thenounproject.com/search/?q=bow&i=101736) By Arthur Shlain for Bowman