Added option to allow players to choose randomly selected civs (#8430)

* Added UI

* random nations are now chosen from the specified random pool

* refactoring

* translations

* compareBy(getCollatorFromLocale) instead of just sorting by english names

* fixed nation popup not remembering the selected nations

* added blacklist feature

fixed bug which made the feature not work if random civilization nr was disabled

* addCheckbox function

* blacklist translation

* added function for textButton

* changed if in gameStarter

* moved button and checkboxes to the GameParameters
This commit is contained in:
alexban011
2023-01-23 11:10:14 +02:00
committed by GitHub
parent c5667d1685
commit c9a4f59566
7 changed files with 210 additions and 7 deletions

View File

@ -335,6 +335,9 @@ Uniques =
Promotions =
Load copied data =
Reset to defaults =
Select nations =
Random nations pool =
Blacklist random nations pool =
Are you sure you want to reset all game options to defaults? =
Start game! =
Map Options =

View File

@ -222,7 +222,18 @@ object GameStarter {
private fun addCivilizations(newGameParameters: GameParameters, gameInfo: GameInfo, ruleset: Ruleset, existingMap: Boolean) {
val availableCivNames = Stack<String>()
// CityState or Spectator civs are not available for Random pick
availableCivNames.addAll(ruleset.nations.filter { it.value.isMajorCiv() }.keys.shuffled())
if (gameSetupInfo.gameParameters.enableRandomNationsPool) {
if (gameSetupInfo.gameParameters.blacklistRandomNationsPool) {
availableCivNames.addAll(ruleset.nations.filter { it.value.isMajorCiv() }.keys.shuffled())
for (nation in gameSetupInfo.gameParameters.randomNations)
availableCivNames.remove(nation.name)
} else {
for (nation in gameSetupInfo.gameParameters.randomNations)
availableCivNames.add(nation.name)
}
} else
availableCivNames.addAll(ruleset.nations.filter { it.value.isMajorCiv() }.keys.shuffled())
availableCivNames.removeAll(newGameParameters.players.map { it.chosenCiv }.toSet())
val startingTechs = ruleset.technologies.values.filter { it.hasUnique(UniqueType.StartingTech) }

View File

@ -3,6 +3,7 @@ package com.unciv.models.metadata
import com.unciv.logic.IsPartOfGameInfoSerialization
import com.unciv.logic.civilization.PlayerType
import com.unciv.models.ruleset.Speed
import com.unciv.models.ruleset.nation.Nation
enum class BaseRuleset(val fullName:String){
Civ_V_Vanilla("Civ V - Vanilla"),
@ -27,6 +28,10 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
var maxNumberOfCityStates = 6
var numberOfCityStates = 6
var enableRandomNationsPool = false
var blacklistRandomNationsPool = false
var randomNations = arrayListOf<Nation>()
var noCityRazing = false
var noBarbarians = false
var ragingBarbarians = false

View File

@ -168,7 +168,7 @@ class MapEditorGenerateTab(
private val parent: MapEditorGenerateTab
): Table(BaseScreen.skin) {
val generateButton = "".toTextButton()
val mapParametersTable = MapParametersTable(parent.editorScreen.newMapParameters, MapGeneratedMainType.generated, forMapEditor = true) {
val mapParametersTable = MapParametersTable(null, parent.editorScreen.newMapParameters, MapGeneratedMainType.generated, forMapEditor = true) {
parent.replacePage(0, this) // A kludge to get the ScrollPanes to recognize changes in vertical layout??
}

View File

@ -1,22 +1,37 @@
package com.unciv.ui.newgamescreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
import com.unciv.models.metadata.GameParameters
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.ruleset.nation.Nation
import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr
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.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.UncivSlider
import com.unciv.ui.utils.extensions.isNarrowerThan4to3
import com.unciv.ui.utils.extensions.keyShortcuts
import com.unciv.ui.utils.extensions.onActivation
import com.unciv.ui.utils.extensions.onChange
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toCheckBox
import com.unciv.ui.utils.extensions.toLabel
import com.unciv.ui.utils.extensions.toTextButton
class GameOptionsTable(
val previousScreen: IPreviousScreen,
@ -93,6 +108,11 @@ class GameOptionsTable(
it.addNoStartBiasCheckbox()
it.addRandomPlayersCheckbox()
it.addRandomCityStatesCheckbox()
it.addRandomNationsPoolCheckbox()
if (gameParameters.enableRandomNationsPool) {
it.addBlacklistRandomPool()
it.addNationsSelectTextButton()
}
}
add(expander).pad(10f).padTop(10f).growX().row()
@ -151,6 +171,26 @@ class GameOptionsTable(
addCheckbox("Enable Espionage", gameParameters.espionageEnabled)
{ gameParameters.espionageEnabled = it }
private fun Table.addRandomNationsPoolCheckbox() =
addCheckbox("Random nations pool", gameParameters.enableRandomNationsPool) {
gameParameters.enableRandomNationsPool = it
update()
}
private fun Table.addBlacklistRandomPool() =
addCheckbox("Blacklist random nations pool", gameParameters.blacklistRandomNationsPool) {
gameParameters.blacklistRandomNationsPool = it
}
private fun Table.addNationsSelectTextButton() {
val button = "Select nations".toTextButton()
button.onClick {
val popup = RandomNationPickerPopup(previousScreen, gameParameters)
popup.open()
popup.update()
}
add(button)
}
private fun numberOfPlayable() = ruleset.nations.values.count {
it.isMajorCiv()
@ -400,3 +440,135 @@ class GameOptionsTable(
}
}
private class RandomNationPickerPopup(
previousScreen: IPreviousScreen,
val gameParameters: GameParameters
) : Popup(previousScreen as BaseScreen) {
companion object {
// These are used for the Close/OK buttons in the lower left/right corners:
const val buttonsCircleSize = 70f
const val buttonsIconSize = 50f
const val buttonsOffsetFromEdge = 5f
val buttonsBackColor: Color = Color.BLACK.cpy().apply { a = 0.67f }
}
val blockWidth: Float = 0f
val civBlocksWidth = if(blockWidth <= 10f) previousScreen.stage.width / 3 - 5f else blockWidth
// This Popup's body has two halves of same size, either side by side or arranged vertically
// depending on screen proportions - determine height for one of those
private val partHeight = stageToShowOn.height * (if (stageToShowOn.isNarrowerThan4to3()) 0.45f else 0.8f)
private val nationListTable = Table()
private val nationListScroll = AutoScrollPane(nationListTable)
private val selectedNationsListTable = Table()
private val selectedNationsListScroll = AutoScrollPane(selectedNationsListTable)
private var selectedNations = gameParameters.randomNations
var nations = arrayListOf<Nation>()
init {
var nationListScrollY = 0f
nations += previousScreen.ruleset.nations.values.asSequence()
.filter { it.isMajorCiv() }
nationListScroll.setOverscroll(false, false)
add(nationListScroll).size( civBlocksWidth + 10f, partHeight )
// +10, because the nation table has a 5f pad, for a total of +10f
if (stageToShowOn.isNarrowerThan4to3()) row()
selectedNationsListScroll.setOverscroll(false, false)
add(selectedNationsListScroll).size(civBlocksWidth + 10f, partHeight) // Same here, see above
update()
nationListScroll.layout()
pack()
if (nationListScrollY > 0f) {
// center the selected nation vertically, getRowHeight safe because nationListScrollY > 0f ensures at least 1 row
nationListScrollY -= (nationListScroll.height - nationListTable.getRowHeight(0)) / 2
nationListScroll.scrollY = nationListScrollY.coerceIn(0f, nationListScroll.maxY)
}
val closeButton = "OtherIcons/Close".toImageButton(Color.FIREBRICK)
closeButton.onActivation { close() }
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft)
innerTable.addActor(closeButton)
val okButton = "OtherIcons/Checkmark".toImageButton(Color.LIME)
okButton.onClick { returnSelected() }
okButton.setPosition(innerTable.width - buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomRight)
innerTable.addActor(okButton)
selectedNationsListTable.touchable = Touchable.enabled
}
fun update() {
nationListTable.clear()
selectedNations = gameParameters.randomNations
nations -= selectedNations.toSet()
nations = nations.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.name.tr() }).toMutableList() as ArrayList<Nation>
var currentY = 0f
for (nation in nations) {
val nationTable = NationTable(nation, civBlocksWidth, 0f) // no need for min height
val cell = nationListTable.add(nationTable)
currentY += cell.padBottom + cell.prefHeight + cell.padTop
cell.row()
nationTable.onClick {
addNationToPool(nation)
}
}
if (selectedNations.isNotEmpty()) {
selectedNationsListTable.clear()
for (currentNation in selectedNations) {
val nationTable = NationTable(currentNation, civBlocksWidth, 0f)
nationTable.onClick { removeNationFromPool(currentNation) }
selectedNationsListTable.add(nationTable).row()
}
}
}
private fun String.toImageButton(overColor: Color): Group {
val style = ImageButton.ImageButtonStyle()
val image = ImageGetter.getDrawable(this)
style.imageUp = image
style.imageOver = image.tint(overColor)
val button = ImageButton(style)
button.setSize(buttonsIconSize, buttonsIconSize)
return button.surroundWithCircle(buttonsCircleSize, false, buttonsBackColor)
}
private fun updateNationListTable() {
selectedNationsListTable.clear()
for (currentNation in selectedNations) {
val nationTable = NationTable(currentNation, civBlocksWidth, 0f)
nationTable.onClick { removeNationFromPool(currentNation) }
selectedNationsListTable.add(nationTable).row()
}
}
private fun addNationToPool(nation: Nation) {
selectedNations.add(nation)
update()
updateNationListTable()
}
private fun removeNationFromPool(nation: Nation) {
nations.add(nation)
selectedNations.remove(nation)
update()
updateNationListTable()
}
private fun returnSelected() {
close()
gameParameters.randomNations = selectedNations
}
}

View File

@ -18,8 +18,8 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {
private val mapParameters = newGameScreen.gameSetupInfo.mapParameters
private var mapTypeSpecificTable = Table()
val generatedMapOptionsTable = MapParametersTable(mapParameters, MapGeneratedMainType.generated)
private val randomMapOptionsTable = MapParametersTable(mapParameters, MapGeneratedMainType.randomGenerated)
val generatedMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.generated)
private val randomMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.randomGenerated)
private val savedMapOptionsTable = Table()
lateinit var mapTypeSelectBox: TranslatedSelectBox
private val mapFileSelectBox = createMapFileSelectBox()

View File

@ -31,6 +31,7 @@ import com.unciv.ui.utils.extensions.toTextButton
* @param forMapEditor whether the [MapType.empty] option should be present. Is used by the Map Editor, but should **never** be used with the New Game
* */
class MapParametersTable(
private val previousScreen: IPreviousScreen? = null,
private val mapParameters: MapParameters,
private val mapGeneratedMainType: String,
private val forMapEditor: Boolean = false,
@ -67,6 +68,12 @@ class MapParametersTable(
private val advancedSliders = HashMap<UncivSlider, ()->Float>()
init {
update()
}
fun update() {
clear()
skin = BaseScreen.skin
defaults().pad(5f, 10f)
if (mapGeneratedMainType == MapGeneratedMainType.randomGenerated) {
@ -354,6 +361,13 @@ class MapParametersTable(
return slider
}
fun addTextButton(text: String, shouldAddToTable: Boolean = false, action: ((Boolean) -> Unit),) {
val button = text.toTextButton()
button.onClick { action.invoke(true) }
if (shouldAddToTable)
table.add(button).colspan(2).padTop(10f).row()
}
addSlider("Map Elevation", {mapParameters.elevationExponent}, 0.6f, 0.8f)
{ mapParameters.elevationExponent = it }
@ -381,13 +395,11 @@ class MapParametersTable(
addSlider("Water level", {mapParameters.waterThreshold}, -0.1f, 0.1f)
{ mapParameters.waterThreshold = it }
val resetToDefaultButton = "Reset to defaults".toTextButton()
resetToDefaultButton.onClick {
addTextButton("Reset to defaults", true) {
mapParameters.resetAdvancedSettings()
seedTextField.text = mapParameters.seed.toString()
for (entry in advancedSliders)
entry.key.value = entry.value()
}
table.add(resetToDefaultButton).colspan(2).padTop(10f).row()
}
}