mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-14 09:48:12 +07:00
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:
@ -335,6 +335,9 @@ Uniques =
|
|||||||
Promotions =
|
Promotions =
|
||||||
Load copied data =
|
Load copied data =
|
||||||
Reset to defaults =
|
Reset to defaults =
|
||||||
|
Select nations =
|
||||||
|
Random nations pool =
|
||||||
|
Blacklist random nations pool =
|
||||||
Are you sure you want to reset all game options to defaults? =
|
Are you sure you want to reset all game options to defaults? =
|
||||||
Start game! =
|
Start game! =
|
||||||
Map Options =
|
Map Options =
|
||||||
|
@ -222,7 +222,18 @@ object GameStarter {
|
|||||||
private fun addCivilizations(newGameParameters: GameParameters, gameInfo: GameInfo, ruleset: Ruleset, existingMap: Boolean) {
|
private fun addCivilizations(newGameParameters: GameParameters, gameInfo: GameInfo, ruleset: Ruleset, existingMap: Boolean) {
|
||||||
val availableCivNames = Stack<String>()
|
val availableCivNames = Stack<String>()
|
||||||
// CityState or Spectator civs are not available for Random pick
|
// 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())
|
availableCivNames.removeAll(newGameParameters.players.map { it.chosenCiv }.toSet())
|
||||||
|
|
||||||
val startingTechs = ruleset.technologies.values.filter { it.hasUnique(UniqueType.StartingTech) }
|
val startingTechs = ruleset.technologies.values.filter { it.hasUnique(UniqueType.StartingTech) }
|
||||||
|
@ -3,6 +3,7 @@ package com.unciv.models.metadata
|
|||||||
import com.unciv.logic.IsPartOfGameInfoSerialization
|
import com.unciv.logic.IsPartOfGameInfoSerialization
|
||||||
import com.unciv.logic.civilization.PlayerType
|
import com.unciv.logic.civilization.PlayerType
|
||||||
import com.unciv.models.ruleset.Speed
|
import com.unciv.models.ruleset.Speed
|
||||||
|
import com.unciv.models.ruleset.nation.Nation
|
||||||
|
|
||||||
enum class BaseRuleset(val fullName:String){
|
enum class BaseRuleset(val fullName:String){
|
||||||
Civ_V_Vanilla("Civ V - Vanilla"),
|
Civ_V_Vanilla("Civ V - Vanilla"),
|
||||||
@ -27,6 +28,10 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
|
|||||||
var maxNumberOfCityStates = 6
|
var maxNumberOfCityStates = 6
|
||||||
var numberOfCityStates = 6
|
var numberOfCityStates = 6
|
||||||
|
|
||||||
|
var enableRandomNationsPool = false
|
||||||
|
var blacklistRandomNationsPool = false
|
||||||
|
var randomNations = arrayListOf<Nation>()
|
||||||
|
|
||||||
var noCityRazing = false
|
var noCityRazing = false
|
||||||
var noBarbarians = false
|
var noBarbarians = false
|
||||||
var ragingBarbarians = false
|
var ragingBarbarians = false
|
||||||
|
@ -168,7 +168,7 @@ class MapEditorGenerateTab(
|
|||||||
private val parent: MapEditorGenerateTab
|
private val parent: MapEditorGenerateTab
|
||||||
): Table(BaseScreen.skin) {
|
): Table(BaseScreen.skin) {
|
||||||
val generateButton = "".toTextButton()
|
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??
|
parent.replacePage(0, this) // A kludge to get the ScrollPanes to recognize changes in vertical layout??
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,37 @@
|
|||||||
package com.unciv.ui.newgamescreen
|
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.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
|
import com.unciv.models.metadata.GameParameters
|
||||||
import com.unciv.models.ruleset.RulesetCache
|
import com.unciv.models.ruleset.RulesetCache
|
||||||
|
import com.unciv.models.ruleset.nation.Nation
|
||||||
import com.unciv.models.ruleset.unique.UniqueType
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.audio.MusicMood
|
import com.unciv.ui.audio.MusicMood
|
||||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.multiplayer.MultiplayerHelpers
|
import com.unciv.ui.multiplayer.MultiplayerHelpers
|
||||||
|
import com.unciv.ui.popup.Popup
|
||||||
import com.unciv.ui.popup.ToastPopup
|
import com.unciv.ui.popup.ToastPopup
|
||||||
|
import com.unciv.ui.utils.AutoScrollPane
|
||||||
import com.unciv.ui.utils.BaseScreen
|
import com.unciv.ui.utils.BaseScreen
|
||||||
import com.unciv.ui.utils.ExpanderTab
|
import com.unciv.ui.utils.ExpanderTab
|
||||||
|
import com.unciv.ui.utils.KeyCharAndCode
|
||||||
import com.unciv.ui.utils.UncivSlider
|
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.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.toCheckBox
|
||||||
import com.unciv.ui.utils.extensions.toLabel
|
import com.unciv.ui.utils.extensions.toLabel
|
||||||
|
import com.unciv.ui.utils.extensions.toTextButton
|
||||||
|
|
||||||
class GameOptionsTable(
|
class GameOptionsTable(
|
||||||
val previousScreen: IPreviousScreen,
|
val previousScreen: IPreviousScreen,
|
||||||
@ -93,6 +108,11 @@ class GameOptionsTable(
|
|||||||
it.addNoStartBiasCheckbox()
|
it.addNoStartBiasCheckbox()
|
||||||
it.addRandomPlayersCheckbox()
|
it.addRandomPlayersCheckbox()
|
||||||
it.addRandomCityStatesCheckbox()
|
it.addRandomCityStatesCheckbox()
|
||||||
|
it.addRandomNationsPoolCheckbox()
|
||||||
|
if (gameParameters.enableRandomNationsPool) {
|
||||||
|
it.addBlacklistRandomPool()
|
||||||
|
it.addNationsSelectTextButton()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
add(expander).pad(10f).padTop(10f).growX().row()
|
add(expander).pad(10f).padTop(10f).growX().row()
|
||||||
|
|
||||||
@ -151,6 +171,26 @@ class GameOptionsTable(
|
|||||||
addCheckbox("Enable Espionage", gameParameters.espionageEnabled)
|
addCheckbox("Enable Espionage", gameParameters.espionageEnabled)
|
||||||
{ gameParameters.espionageEnabled = it }
|
{ 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 {
|
private fun numberOfPlayable() = ruleset.nations.values.count {
|
||||||
it.isMajorCiv()
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() {
|
|||||||
|
|
||||||
private val mapParameters = newGameScreen.gameSetupInfo.mapParameters
|
private val mapParameters = newGameScreen.gameSetupInfo.mapParameters
|
||||||
private var mapTypeSpecificTable = Table()
|
private var mapTypeSpecificTable = Table()
|
||||||
val generatedMapOptionsTable = MapParametersTable(mapParameters, MapGeneratedMainType.generated)
|
val generatedMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.generated)
|
||||||
private val randomMapOptionsTable = MapParametersTable(mapParameters, MapGeneratedMainType.randomGenerated)
|
private val randomMapOptionsTable = MapParametersTable(newGameScreen, mapParameters, MapGeneratedMainType.randomGenerated)
|
||||||
private val savedMapOptionsTable = Table()
|
private val savedMapOptionsTable = Table()
|
||||||
lateinit var mapTypeSelectBox: TranslatedSelectBox
|
lateinit var mapTypeSelectBox: TranslatedSelectBox
|
||||||
private val mapFileSelectBox = createMapFileSelectBox()
|
private val mapFileSelectBox = createMapFileSelectBox()
|
||||||
|
@ -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
|
* @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(
|
class MapParametersTable(
|
||||||
|
private val previousScreen: IPreviousScreen? = null,
|
||||||
private val mapParameters: MapParameters,
|
private val mapParameters: MapParameters,
|
||||||
private val mapGeneratedMainType: String,
|
private val mapGeneratedMainType: String,
|
||||||
private val forMapEditor: Boolean = false,
|
private val forMapEditor: Boolean = false,
|
||||||
@ -67,6 +68,12 @@ class MapParametersTable(
|
|||||||
private val advancedSliders = HashMap<UncivSlider, ()->Float>()
|
private val advancedSliders = HashMap<UncivSlider, ()->Float>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
update()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
clear()
|
||||||
|
|
||||||
skin = BaseScreen.skin
|
skin = BaseScreen.skin
|
||||||
defaults().pad(5f, 10f)
|
defaults().pad(5f, 10f)
|
||||||
if (mapGeneratedMainType == MapGeneratedMainType.randomGenerated) {
|
if (mapGeneratedMainType == MapGeneratedMainType.randomGenerated) {
|
||||||
@ -354,6 +361,13 @@ class MapParametersTable(
|
|||||||
return slider
|
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)
|
addSlider("Map Elevation", {mapParameters.elevationExponent}, 0.6f, 0.8f)
|
||||||
{ mapParameters.elevationExponent = it }
|
{ mapParameters.elevationExponent = it }
|
||||||
|
|
||||||
@ -381,13 +395,11 @@ class MapParametersTable(
|
|||||||
addSlider("Water level", {mapParameters.waterThreshold}, -0.1f, 0.1f)
|
addSlider("Water level", {mapParameters.waterThreshold}, -0.1f, 0.1f)
|
||||||
{ mapParameters.waterThreshold = it }
|
{ mapParameters.waterThreshold = it }
|
||||||
|
|
||||||
val resetToDefaultButton = "Reset to defaults".toTextButton()
|
addTextButton("Reset to defaults", true) {
|
||||||
resetToDefaultButton.onClick {
|
|
||||||
mapParameters.resetAdvancedSettings()
|
mapParameters.resetAdvancedSettings()
|
||||||
seedTextField.text = mapParameters.seed.toString()
|
seedTextField.text = mapParameters.seed.toString()
|
||||||
for (entry in advancedSliders)
|
for (entry in advancedSliders)
|
||||||
entry.key.value = entry.value()
|
entry.key.value = entry.value()
|
||||||
}
|
}
|
||||||
table.add(resetToDefaultButton).colspan(2).padTop(10f).row()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user