added feature to select specific city states

created MultiNationSelectPopup to reuse for the city states
This commit is contained in:
alexban011
2023-01-23 13:35:37 +02:00
parent 52c3f14bde
commit 4a1e6964b0
5 changed files with 225 additions and 160 deletions

View File

@ -336,8 +336,11 @@ Promotions =
Load copied data =
Reset to defaults =
Select nations =
Select city states =
Random nations pool =
Random city states pool =
Blacklist random nations pool =
Blacklist random city states pool =
Are you sure you want to reset all game options to defaults? =
Start game! =
Map Options =

View File

@ -291,16 +291,25 @@ object GameStarter {
gameInfo.civilizations.add(playerCiv)
}
val availableCityStatesNames = Stack<String>()
var availableCityStatesNames = Stack<String>()
// since we shuffle and then order by, we end up with all the City-States with starting tiles first in a random order,
// and then all the other City-States in a random order! Because the sortedBy function is stable!
availableCityStatesNames.addAll( ruleset.nations
.filter {
it.value.isCityState() &&
!it.value.hasUnique(UniqueType.CityStateDeprecated)
}.keys
.shuffled()
.sortedBy { it in civNamesWithStartingLocations } ) // pop() gets the last item, so sort ascending
val selectedCityStatesPoolNames = Stack<String>()
for (selectedCityState in gameSetupInfo.gameParameters.randomCityStates)
selectedCityStatesPoolNames.add(selectedCityState.name)
if (gameSetupInfo.gameParameters.blacklistRandomCityStatesPool) {
availableCityStatesNames.addAll( ruleset.nations
.filter {
it.value.isCityState() &&
!it.value.hasUnique(UniqueType.CityStateDeprecated)
}.keys
.shuffled()
.sortedBy { it in civNamesWithStartingLocations } ) // pop() gets the last item, so sort ascending
availableCityStatesNames.removeAll(selectedCityStatesPoolNames)
} else {
availableCityStatesNames = selectedCityStatesPoolNames
}
val numberOfCityStates = if (newGameParameters.randomNumberOfCityStates) {
// This swaps min and max if the user accidentally swapped min and max

View File

@ -29,8 +29,11 @@ class GameParameters : IsPartOfGameInfoSerialization { // Default values are the
var numberOfCityStates = 6
var enableRandomNationsPool = false
var enableRandomCityStatesPool = false
var blacklistRandomNationsPool = false
var blacklistRandomCityStatesPool = false
var randomNations = arrayListOf<Nation>()
var randomCityStates = arrayListOf<Nation>()
var noCityRazing = false
var noBarbarians = false

View File

@ -1,34 +1,21 @@
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
@ -107,12 +94,17 @@ class GameOptionsTable(
it.addEnableEspionageCheckbox()
it.addNoStartBiasCheckbox()
it.addRandomPlayersCheckbox()
it.addRandomCityStatesCheckbox()
it.addRandomNrCityStatesCheckbox()
it.addRandomNationsPoolCheckbox()
if (gameParameters.enableRandomNationsPool) {
it.addBlacklistRandomPool()
it.addBlacklistRandomNationsPool()
it.addNationsSelectTextButton()
}
it.addRandomCityStatesPoolCheckbox()
if (gameParameters.enableRandomCityStatesPool){
it.addBlacklistRandomCityStatesPool()
it.addCityStatesSelectTextButton()
}
}
add(expander).pad(10f).padTop(10f).growX().row()
@ -177,19 +169,40 @@ class GameOptionsTable(
update()
}
private fun Table.addBlacklistRandomPool() =
private fun Table.addRandomCityStatesPoolCheckbox() =
addCheckbox("Random city states pool", gameParameters.enableRandomCityStatesPool) {
gameParameters.enableRandomCityStatesPool = it
update()
}
private fun Table.addBlacklistRandomNationsPool() =
addCheckbox("Blacklist random nations pool", gameParameters.blacklistRandomNationsPool) {
gameParameters.blacklistRandomNationsPool = it
}
private fun Table.addBlacklistRandomCityStatesPool() =
addCheckbox("Blacklist random city states pool", gameParameters.blacklistRandomCityStatesPool) {
gameParameters.blacklistRandomCityStatesPool = it
}
private fun Table.addNationsSelectTextButton() {
val button = "Select nations".toTextButton()
button.onClick {
val popup = RandomNationPickerPopup(previousScreen, gameParameters)
val popup = MultiNationSelectPopup(previousScreen, gameParameters, true)
popup.open()
popup.update()
}
add(button)
add(button).row()
}
private fun Table.addCityStatesSelectTextButton() {
val button = "Select city states".toTextButton()
button.onClick {
val popup = MultiNationSelectPopup(previousScreen, gameParameters, false)
popup.open()
popup.update()
}
add(button).row()
}
private fun numberOfPlayable() = ruleset.nations.values.count {
@ -212,7 +225,7 @@ class GameOptionsTable(
update()
}
private fun Table.addRandomCityStatesCheckbox() =
private fun Table.addRandomNrCityStatesCheckbox() =
addCheckbox("Random number of City-States", gameParameters.randomNumberOfCityStates)
{
gameParameters.randomNumberOfCityStates = it
@ -439,136 +452,3 @@ class GameOptionsTable(
updatePlayerPickerTable(desiredCiv)
}
}
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

@ -0,0 +1,170 @@
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.nation.Nation
import com.unciv.models.translations.tr
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
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.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
class MultiNationSelectPopup(
previousScreen: IPreviousScreen,
val gameParameters: GameParameters,
val majorCivs: Boolean
) : 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 }
}
private val blockWidth: Float = 0f
private 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 += if(majorCivs) {
previousScreen.ruleset.nations.values.asSequence()
.filter { it.isMajorCiv() }
} else {
previousScreen.ruleset.nations.values.asSequence()
.filter { it.isCityState() }
}
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 = if (majorCivs) {
gameParameters.randomNations
} else {
gameParameters.randomCityStates
}
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()
if (majorCivs)
gameParameters.randomNations = selectedNations
else
gameParameters.randomCityStates = selectedNations
}
}