Add options to use random number of players and city states. (#8394)

* Add option to use random number of players and city states.

* Fix spaces after =

* Update clone() and toString() of GameParameters

* Make sure at least one AI player when using random players.

* Fix typo in random players initial values.

* Fix for if user chooses random of 0 or 1 city states.

* Move random player and city state toggles to advanced. Move random city state choice to where it will not cache and reveal on next game. Change random city states to use min and max sliders that can be used inverted.

* Add random players min and max sliders.

* Change random players option to use min and max sliders that can be used inverted.
This commit is contained in:
Philip Keiter
2023-01-19 04:21:39 -06:00
committed by GitHub
parent 4267816880
commit 2ba79d85db
4 changed files with 144 additions and 5 deletions

View File

@ -360,6 +360,12 @@ Three Continents =
Four Corners =
Archipelago =
Inner Sea =
Random number of Civilizations =
Min number of Civilizations =
Max number of Civilizations =
Random number of City-States =
Min number of City-States =
Max number of City-States =
Number of City-States =
One City Challenge =
No City Razing =

View File

@ -13,6 +13,7 @@ import com.unciv.logic.map.TileMap
import com.unciv.logic.map.mapgenerator.MapGenerator
import com.unciv.models.metadata.GameParameters
import com.unciv.models.metadata.GameSetupInfo
import com.unciv.models.metadata.Player
import com.unciv.models.ruleset.ModOptionsConstants
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
@ -236,6 +237,33 @@ object GameStarter {
val presetMajors = Stack<String>()
presetMajors.addAll(availableCivNames.filter { it in civNamesWithStartingLocations })
if (newGameParameters.randomNumberOfPlayers) {
// This swaps min and max if the user accidentally swapped min and max
val min = newGameParameters.minNumberOfPlayers.coerceAtMost(newGameParameters.maxNumberOfPlayers)
val max = newGameParameters.maxNumberOfPlayers.coerceAtLeast(newGameParameters.minNumberOfPlayers)
var playerCount = (min..max).random()
val humanPlayerCount = newGameParameters.players.filter {
it.playerType === PlayerType.Human
}.count()
val spectatorCount = newGameParameters.players.filter {
it.chosenCiv === Constants.spectator
}.count()
playerCount = playerCount.coerceAtLeast(humanPlayerCount + spectatorCount)
if (newGameParameters.players.size < playerCount) {
val neededPlayers = playerCount - newGameParameters.players.size
for (i in 1..neededPlayers) newGameParameters.players.add(Player())
} else if (newGameParameters.players.size > playerCount) {
val extraPlayers = newGameParameters.players.size - playerCount
val playersToRemove = newGameParameters.players.filter {
it.playerType === PlayerType.AI
}.shuffled().subList(0, extraPlayers)
newGameParameters.players.removeAll(playersToRemove)
}
}
for (player in newGameParameters.players.sortedBy { it.chosenCiv == Constants.random }) {
val nationName = when {
player.chosenCiv != Constants.random -> player.chosenCiv
@ -263,9 +291,17 @@ object GameStarter {
.shuffled()
.sortedBy { it in civNamesWithStartingLocations } ) // pop() gets the last item, so sort ascending
val numberOfCityStates = if (newGameParameters.randomNumberOfCityStates) {
// This swaps min and max if the user accidentally swapped min and max
val min = newGameParameters.minNumberOfCityStates.coerceAtMost(newGameParameters.maxNumberOfCityStates)
val max = newGameParameters.maxNumberOfCityStates.coerceAtLeast(newGameParameters.minNumberOfCityStates)
(min..max).random()
} else {
newGameParameters.numberOfCityStates
}
var addedCityStates = 0
// Keep trying to add city states until we reach the target number.
while (addedCityStates < newGameParameters.numberOfCityStates) {
while (addedCityStates < numberOfCityStates) {
if (availableCityStatesNames.isEmpty()) // We ran out of city-states somehow
break

View File

@ -15,10 +15,16 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
@Deprecated("Since 4.1.11")
var gameSpeed = ""
var randomNumberOfPlayers = false
var minNumberOfPlayers = 3
var maxNumberOfPlayers = 3
var players = ArrayList<Player>().apply {
add(Player().apply { playerType = PlayerType.Human })
for (i in 1..3) add(Player())
}
var randomNumberOfCityStates = false
var minNumberOfCityStates = 6
var maxNumberOfCityStates = 6
var numberOfCityStates = 6
var noCityRazing = false
@ -47,6 +53,12 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
parameters.difficulty = difficulty
parameters.speed = speed
parameters.players = ArrayList(players)
parameters.randomNumberOfPlayers = randomNumberOfPlayers
parameters.minNumberOfPlayers = minNumberOfPlayers
parameters.maxNumberOfPlayers = maxNumberOfPlayers
parameters.randomNumberOfCityStates = randomNumberOfCityStates
parameters.minNumberOfCityStates = minNumberOfCityStates
parameters.maxNumberOfCityStates = maxNumberOfCityStates
parameters.numberOfCityStates = numberOfCityStates
parameters.noBarbarians = noBarbarians
parameters.ragingBarbarians = ragingBarbarians
@ -67,7 +79,11 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
yield("$difficulty $speed $startingEra")
yield("${players.count { it.playerType == PlayerType.Human }} ${PlayerType.Human}")
yield("${players.count { it.playerType == PlayerType.AI }} ${PlayerType.AI}")
yield("$minNumberOfCityStates Min CS")
yield("$maxNumberOfCityStates Max CS")
yield("$numberOfCityStates CS")
if (randomNumberOfPlayers) yield("Random number of Players")
if (randomNumberOfCityStates) yield("Random number of City-States")
if (isOnlineMultiplayer) yield("Online Multiplayer")
if (noBarbarians) yield("No barbs")
if (ragingBarbarians) yield("Raging barbs")

View File

@ -60,7 +60,16 @@ class GameOptionsTable(
val turnSlider = addMaxTurnsSlider()
if (turnSlider != null)
add(turnSlider).padTop(10f).row()
addCityStatesSlider()
if (gameParameters.randomNumberOfPlayers) {
addMinPlayersSlider()
addMaxPlayersSlider()
}
if (gameParameters.randomNumberOfCityStates) {
addMinCityStatesSlider()
addMaxCityStatesSlider()
} else {
addCityStatesSlider()
}
}).colspan(2).fillX().row()
}).row()
addVictoryTypeCheckboxes()
@ -82,6 +91,8 @@ class GameOptionsTable(
if (UncivGame.Current.settings.enableEspionageOption)
it.addEnableEspionageCheckbox()
it.addNoStartBiasCheckbox()
it.addRandomPlayersCheckbox()
it.addRandomCityStatesCheckbox()
}
add(expander).pad(10f).padTop(10f).growX().row()
@ -141,6 +152,10 @@ class GameOptionsTable(
{ gameParameters.espionageEnabled = it }
private fun numberOfPlayable() = ruleset.nations.values.count {
it.isMajorCiv()
}
private fun numberOfCityStates() = ruleset.nations.values.count {
it.isCityState()
&& !it.hasUnique(UniqueType.CityStateDeprecated)
@ -150,12 +165,78 @@ class GameOptionsTable(
addCheckbox("Disable starting bias", gameParameters.noStartBias)
{ gameParameters.noStartBias = it }
private fun Table.addRandomPlayersCheckbox() =
addCheckbox("Random number of Civilizations", gameParameters.randomNumberOfPlayers)
{
gameParameters.randomNumberOfPlayers = it
update()
}
private fun Table.addRandomCityStatesCheckbox() =
addCheckbox("Random number of City-States", gameParameters.randomNumberOfCityStates)
{
gameParameters.randomNumberOfCityStates = it
update()
}
private fun Table.addMinPlayersSlider() {
val playableAvailable = numberOfPlayable()
if (playableAvailable == 0) return
add("{Min number of Civilizations}:".toLabel()).left().expandX()
val slider = UncivSlider(2f, playableAvailable.toFloat(), 1f, initial = gameParameters.minNumberOfPlayers.toFloat()) {
gameParameters.minNumberOfPlayers = it.toInt()
}
slider.permanentTip = true
slider.isDisabled = locked
add(slider).padTop(10f).row()
}
private fun Table.addMaxPlayersSlider() {
val playableAvailable = numberOfPlayable()
if (playableAvailable == 0) return
add("{Max number of Civilizations}:".toLabel()).left().expandX()
val slider = UncivSlider(2f, playableAvailable.toFloat(), 1f, initial = gameParameters.maxNumberOfPlayers.toFloat()) {
gameParameters.maxNumberOfPlayers = it.toInt()
}
slider.permanentTip = true
slider.isDisabled = locked
add(slider).padTop(10f).row()
}
private fun Table.addMinCityStatesSlider() {
val cityStatesAvailable = numberOfCityStates()
if (cityStatesAvailable == 0) return
add("{Min number of City-States}:".toLabel()).left().expandX()
val slider = UncivSlider(0f, cityStatesAvailable.toFloat(), 1f, initial = gameParameters.minNumberOfCityStates.toFloat()) {
gameParameters.minNumberOfCityStates = it.toInt()
}
slider.permanentTip = true
slider.isDisabled = locked
add(slider).padTop(10f).row()
}
private fun Table.addMaxCityStatesSlider() {
val cityStatesAvailable = numberOfCityStates()
if (cityStatesAvailable == 0) return
add("{Max number of City-States}:".toLabel()).left().expandX()
val slider = UncivSlider(0f, cityStatesAvailable.toFloat(), 1f, initial = gameParameters.maxNumberOfCityStates.toFloat()) {
gameParameters.maxNumberOfCityStates = it.toInt()
}
slider.permanentTip = true
slider.isDisabled = locked
add(slider).padTop(10f).row()
}
private fun Table.addCityStatesSlider() {
val maxCityStates = numberOfCityStates()
if (maxCityStates == 0) return
val cityStatesAvailable = numberOfCityStates()
if (cityStatesAvailable == 0) return
add("{Number of City-States}:".toLabel()).left().expandX()
val slider = UncivSlider(0f, maxCityStates.toFloat(), 1f, initial = gameParameters.numberOfCityStates.toFloat()) {
val slider = UncivSlider(0f, cityStatesAvailable.toFloat(), 1f, initial = gameParameters.numberOfCityStates.toFloat()) {
gameParameters.numberOfCityStates = it.toInt()
}
slider.permanentTip = true