New Demographics Scoreboard (#6645)

* Healing parity

Adjusted healing values for parity with CV

* New Demographics system for victory screen rankings

Added a new game setup checkbox option to use a ranking system on the victory screen which is more in line with the Civ V Demographics window. Created the UI element and game parameter but the demographics screen still needs to be implemented.

Also removed unnecessary comments from adjustments to healing values in a previous update.

* Demographics table init

Beginning to build structure of Demographics rankings table.

* Update VictoryScreen.kt

Attempt at getting more of the Demographics table implemented

* Update VictoryScreen.kt

Continued building the structure of the Demographics table

* Demographics first implementation

Finished first pass of Demographics screen.

* Minor text formatting

Improved some text formatting in code and comments.

* Update MapUnit.kt

Minor comment cleanup.

* SomeTroglodyte's Feedback, pt. 1

Implemented feedback given by SomeTroglodyte in PR #6645.

* Organized into functions

Split up Rankings table creation and Demographics table creation into new functions

* Update template.properties

Fixed missing space.

* Implementing more PR #6645 feedback

Added needed translation templates, used enum class instead of array for headers, moved checkbox to Options -> Display instead of new game

* Implemented rest of PR #6645 feedback

Simplified logic for finding player's rank, value, best/worst civ value, and filtered out defeated civs from the display and calculations

* Dead Civs get 0 in all categories

Added simple check if a civ is dead when computing score. If they are dead then they get 0 and go to the bottom of the scoreboard.

* Update VictoryScreen.kt

Further cleaned up code for better reuse and simpler logic with fewer loops.

* Update CivilizationInfo.kt

Simplified implementation of return 0 for stats when civ is defeated.

* Update CivilizationInfo.kt

Removed commented-out line of code.

* Fixed duplicate rank bug

Adjusted method of determining best and worst civs so that duplicates don't occur.

* Update VictoryScreen.kt

One-lined the handling of logic in buildDemographicsTable()

* Update VictoryScreen.kt

Moved static header row to new function.
This commit is contained in:
letstalkaboutdune 2022-05-05 05:42:35 -07:00 committed by GitHub
parent b258b34c89
commit 035b6528a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 29 deletions

View File

@ -639,7 +639,8 @@ Show minimap =
off =
Show pixel units =
Show pixel improvements =
Enable nuclear weapons =
Enable Nuclear Weapons =
Experimental Demographics scoreboard =
Show tile yields =
Show unit movement arrows =
Continuous rendering =
@ -1113,6 +1114,13 @@ Global status =
Rankings =
# The \n here means: put a newline (enter) here. If this is omitted, the sidebox in the diplomacy overview will become _really_ wide.
# Feel free to replace it with a space and put it between other words in your translation
Demographics =
Demographic =
Rank =
Value =
Best =
Average =
Worst =
Turns until the next\ndiplomacy victory vote: [amount] =
Choose a civ to vote for =
Choose who should become the world leader and win a Diplomatic Victory! =

View File

@ -653,17 +653,18 @@ class CivilizationInfo {
}
fun getStatForRanking(category: RankingType): Int {
return when (category) {
RankingType.Score -> calculateTotalScore().toInt()
RankingType.Population -> cities.sumOf { it.population.population }
RankingType.Crop_Yield -> statsForNextTurn.food.roundToInt()
RankingType.Production -> statsForNextTurn.production.roundToInt()
RankingType.Gold -> gold
RankingType.Territory -> cities.sumOf { it.tiles.size }
RankingType.Force -> getMilitaryMight()
RankingType.Happiness -> getHappiness()
RankingType.Technologies -> tech.researchedTechnologies.size
RankingType.Culture -> policies.adoptedPolicies.count { !Policy.isBranchCompleteByName(it) }
return if (isDefeated()) 0
else when (category) {
RankingType.Score -> calculateTotalScore().toInt()
RankingType.Population -> cities.sumOf { it.population.population }
RankingType.Crop_Yield -> statsForNextTurn.food.roundToInt()
RankingType.Production -> statsForNextTurn.production.roundToInt()
RankingType.Gold -> gold
RankingType.Territory -> cities.sumOf { it.tiles.size }
RankingType.Force -> getMilitaryMight()
RankingType.Happiness -> getHappiness()
RankingType.Technologies -> tech.researchedTechnologies.size
RankingType.Culture -> policies.adoptedPolicies.count { !Policy.isBranchCompleteByName(it) }
}
}

View File

@ -708,12 +708,12 @@ class MapUnit {
val isFriendlyTerritory = tileInfo.isFriendlyTerritory(civInfo)
var healing = when {
tileInfo.isCityCenter() -> 25 // Increased from 20 for CV parity
tileInfo.isWater && isFriendlyTerritory && (baseUnit.isWaterUnit() || isTransported) -> 20 // Water unit on friendly water, increased from 15 for CV parity
tileInfo.isCityCenter() -> 25
tileInfo.isWater && isFriendlyTerritory && (baseUnit.isWaterUnit() || isTransported) -> 20 // Water unit on friendly water
tileInfo.isWater -> 0 // All other water cases
isFriendlyTerritory -> 20 // Allied territory, increased from 15 for CV parity
isFriendlyTerritory -> 20 // Allied territory
tileInfo.getOwner() == null -> 10 // Neutral territory
else -> 10 // Enemy territory, increased from 5 for CV parity
else -> 10 // Enemy territory
}
val mayHeal = healing > 0 || (tileInfo.isWater && hasUnique(UniqueType.HealsOutsideFriendlyTerritory, checkCivInfoUniques = true))

View File

@ -54,6 +54,7 @@ class GameSettings {
var windowState = WindowState()
var isFreshlyCreated = false
var visualMods = HashSet<String>()
var useDemographics: Boolean = false
var multiplayerServer = Constants.dropboxMultiplayerServer

View File

@ -95,10 +95,9 @@ class GameOptionsTable(
{ gameParameters.oneCityChallenge = it }
private fun Table.addNuclearWeaponsCheckbox() =
addCheckbox("Enable nuclear weapons", gameParameters.nuclearWeaponsEnabled)
addCheckbox("Enable Nuclear Weapons", gameParameters.nuclearWeaponsEnabled)
{ gameParameters.nuclearWeaponsEnabled = it }
private fun Table.addIsOnlineMultiplayerCheckbox() =
addCheckbox("Online Multiplayer", gameParameters.isOnlineMultiplayer)
{

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.translations.tr
import com.unciv.models.metadata.GameSetupInfo
@ -32,7 +33,9 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
if (!playerCivInfo.isSpectator()) tabsTable.add(setMyVictoryButton)
val setGlobalVictoryButton = "Global status".toTextButton().onClick { setGlobalVictoryTable() }
tabsTable.add(setGlobalVictoryButton)
val setCivRankingsButton = "Rankings".toTextButton().onClick { setCivRankingsTable() }
val rankingLabel = if (UncivGame.Current.settings.useDemographics) "Demographics" else "Rankings"
val setCivRankingsButton = rankingLabel.toTextButton().onClick { setCivRankingsTable() }
tabsTable.add(setCivRankingsButton)
topTable.add(tabsTable)
topTable.addSeparator()
@ -175,22 +178,73 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
private fun setCivRankingsTable() {
val majorCivs = gameInfo.civilizations.filter { it.isMajorCiv() }
val civRankingsTable = Table().apply { defaults().pad(5f) }
contentsTable.clear()
if (UncivGame.Current.settings.useDemographics) contentsTable.add(buildDemographicsTable(majorCivs))
else contentsTable.add(buildRankingsTable(majorCivs))
}
enum class RankLabels { Rank, Value, Best, Average, Worst}
private fun buildDemographicsTable(majorCivs: List<CivilizationInfo>): Table {
val demographicsTable = Table().apply { defaults().pad(5f) }
buildDemographicsHeaders(demographicsTable)
for (rankLabel in RankLabels.values()) {
demographicsTable.row()
demographicsTable.add(rankLabel.name.toLabel())
for (category in RankingType.values()) {
val aliveMajorCivsSorted = majorCivs.filter{ it.isAlive() }.sortedByDescending { it.getStatForRanking(category) }
fun addRankCivGroup(civ: CivilizationInfo) { // local function for reuse of getting and formatting civ stats
demographicsTable.add(getCivGroup(civ, ": " + civ.getStatForRanking(category).toString(), playerCivInfo)).fillX()
}
@Suppress("NON_EXHAUSTIVE_WHEN") // RankLabels.Demographic treated above
when (rankLabel) {
RankLabels.Rank -> demographicsTable.add((aliveMajorCivsSorted.indexOfFirst { it == gameInfo.currentPlayerCiv } + 1).toLabel())
RankLabels.Value -> addRankCivGroup(gameInfo.currentPlayerCiv)
RankLabels.Best -> addRankCivGroup(aliveMajorCivsSorted.firstOrNull()!!)
RankLabels.Average -> demographicsTable.add((aliveMajorCivsSorted.sumOf { it.getStatForRanking(category) } / aliveMajorCivsSorted.count()).toLabel())
RankLabels.Worst -> addRankCivGroup(aliveMajorCivsSorted.lastOrNull()!!)
}
}
}
return demographicsTable
}
private fun buildDemographicsHeaders(demographicsTable: Table) {
val demoLabel = Table().apply { defaults().pad(5f) }
demoLabel.add("Demographic".toLabel()).row()
demoLabel.addSeparator().fillX()
demographicsTable.add(demoLabel)
for (category in RankingType.values()) {
val headers = Table().apply { defaults().pad(5f) }
headers.add(category.name.replace('_', ' ').toLabel()).row()
headers.addSeparator().fillX()
demographicsTable.add(headers)
}
}
private fun buildRankingsTable(majorCivs: List<CivilizationInfo>): Table {
val rankingsTable = Table().apply { defaults().pad(5f) }
for (category in RankingType.values()) {
val column = Table().apply { defaults().pad(5f) }
column.add(category.name.replace('_',' ').toLabel()).row()
column.add(category.name.replace('_' , ' ').toLabel()).row()
column.addSeparator()
for (civ in majorCivs.sortedByDescending { it.getStatForRanking(category) }) {
column.add(getCivGroup(civ, ": " + civ.getStatForRanking(category).toString(), playerCivInfo)).fillX().row()
}
civRankingsTable.add(column)
rankingsTable.add(column)
}
contentsTable.clear()
contentsTable.add(civRankingsTable)
return rankingsTable
}
private fun getCivGroup(civ: CivilizationInfo, afterCivNameText: String, currentPlayer: CivilizationInfo): Table {
@ -205,8 +259,8 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
backgroundColor = Color.LIGHT_GRAY
labelColor = Color.BLACK
} else if (currentPlayer == civ // || game.viewEntireMapForDebug
|| currentPlayer.knows(civ)
|| currentPlayer.isDefeated()
|| currentPlayer.knows(civ)
|| currentPlayer.isDefeated()
|| currentPlayer.victoryManager.hasWon()
) {
civGroup.add(ImageGetter.getNationIndicator(civ.nation, 30f))
@ -217,7 +271,6 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
backgroundColor = Color.DARK_GRAY
labelText = Constants.unknownNationName
}
civGroup.background = ImageGetter.getRoundedEdgeRectangle(backgroundColor)
val label = labelText.toLabel(labelColor)

View File

@ -186,7 +186,8 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) {
addCheckbox("Show tutorials", settings.showTutorials, true) { settings.showTutorials = it }
addCheckbox("Show pixel units", settings.showPixelUnits, true) { settings.showPixelUnits = it }
addCheckbox("Show pixel improvements", settings.showPixelImprovements, true) { settings.showPixelImprovements = it }
addCheckbox("Experimental Demographics scoreboard", settings.useDemographics, true) { settings.useDemographics = it }
addMinimapSizeSlider()
addResolutionSelectBox()