mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-13 01:08:25 +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 =
|
||||
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 =
|
||||
|
@ -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) }
|
||||
|
@ -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
|
||||
|
@ -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??
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user