mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-16 02:40:41 +07:00
Spruced up Civilopedia - phase 1 - linking and category Enum (#3975)
This commit is contained in:
@ -1,198 +0,0 @@
|
||||
package com.unciv.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.tilegroups.TileGroup
|
||||
import com.unciv.ui.tilegroups.TileSetStrings
|
||||
import com.unciv.ui.utils.*
|
||||
import java.util.*
|
||||
|
||||
class CivilopediaScreen(ruleset: Ruleset) : CameraStageBaseScreen() {
|
||||
class CivilopediaEntry(var name: String, var description: String, var image: Actor? = null)
|
||||
|
||||
private val categoryToEntries = LinkedHashMap<String, Collection<CivilopediaEntry>>()
|
||||
private val categoryToButtons = LinkedHashMap<String, Button>()
|
||||
|
||||
private val entrySelectTable = Table().apply { defaults().pad(6f).left() }
|
||||
val description = "".toLabel()
|
||||
|
||||
|
||||
fun select(category: String) {
|
||||
entrySelectTable.clear()
|
||||
|
||||
for (button in categoryToButtons.values) button.color = Color.WHITE
|
||||
categoryToButtons[category]!!.color = Color.BLUE
|
||||
|
||||
var entries = categoryToEntries[category]!!
|
||||
if (category != "Difficulty levels") // this is the only case where we need them in order
|
||||
entries = entries.sortedBy { it.name.tr() } // Alphabetical order of localized names
|
||||
for (entry in entries) {
|
||||
val entryButton = Table().apply {
|
||||
background = ImageGetter.getBackground(colorFromRGB(50, 75, 125))
|
||||
touchable = Touchable.enabled
|
||||
}
|
||||
if (entry.image != null)
|
||||
if (category == "Terrains")
|
||||
entryButton.add(entry.image).padLeft(20f).padRight(10f)
|
||||
else
|
||||
entryButton.add(entry.image).padLeft(10f)
|
||||
entryButton.left().add(entry.name.toLabel(Color.WHITE, 25)).pad(10f)
|
||||
entryButton.onClick {
|
||||
description.setText(entry.description)
|
||||
entrySelectTable.children.forEach { it.color = Color.WHITE }
|
||||
entryButton.color = Color.BLUE
|
||||
}
|
||||
entrySelectTable.add(entryButton).height(75f).expandX().fillX().row()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val imageSize = 50f
|
||||
onBackButtonClicked { UncivGame.Current.setWorldScreen() }
|
||||
|
||||
categoryToEntries["Buildings"] = ruleset.buildings.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques && !(it.isWonder || it.isNationalWonder) }
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(false, null, ruleset),
|
||||
ImageGetter.getConstructionImage(it.name).surroundWithCircle(imageSize))
|
||||
}
|
||||
categoryToEntries["Wonders"] = ruleset.buildings.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques && (it.isWonder || it.isNationalWonder) }
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(false, null, ruleset),
|
||||
ImageGetter.getConstructionImage(it.name).surroundWithCircle(imageSize))
|
||||
}
|
||||
categoryToEntries["Resources"] = ruleset.tileResources.values
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(ruleset),
|
||||
ImageGetter.getResourceImage(it.name, imageSize))
|
||||
}
|
||||
categoryToEntries["Terrains"] = ruleset.terrains.values
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(ruleset),
|
||||
terrainImage(it, ruleset, imageSize))
|
||||
}
|
||||
categoryToEntries["Tile Improvements"] = ruleset.tileImprovements.values
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(ruleset, false),
|
||||
ImageGetter.getImprovementIcon(it.name, imageSize))
|
||||
}
|
||||
categoryToEntries["Units"] = ruleset.units.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques }
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(false),
|
||||
ImageGetter.getConstructionImage(it.name).surroundWithCircle(imageSize))
|
||||
}
|
||||
categoryToEntries["Nations"] = ruleset.nations.values
|
||||
.filter { it.isMajorCiv() }
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getUniqueString(ruleset, false),
|
||||
ImageGetter.getNationIndicator(it, imageSize))
|
||||
}
|
||||
categoryToEntries["Technologies"] = ruleset.technologies.values
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(ruleset),
|
||||
ImageGetter.getTechIconGroup(it.name, imageSize))
|
||||
}
|
||||
categoryToEntries["Promotions"] = ruleset.unitPromotions.values
|
||||
.map {
|
||||
CivilopediaEntry(it.name, it.getDescription(ruleset.unitPromotions.values, true, ruleset),
|
||||
ImageGetter.getPromotionIcon(it.name, imageSize))
|
||||
}
|
||||
|
||||
categoryToEntries["Tutorials"] = tutorialController.getCivilopediaTutorials()
|
||||
.map { CivilopediaEntry(it.key.replace("_", " "), it.value.joinToString("\n\n") { line -> line.tr() }) }
|
||||
|
||||
categoryToEntries["Difficulty levels"] = ruleset.difficulties.values
|
||||
.map { CivilopediaEntry(it.name, it.getDescription()) }
|
||||
|
||||
val buttonTable = Table()
|
||||
buttonTable.pad(15f)
|
||||
buttonTable.defaults().pad(10f)
|
||||
|
||||
for (category in categoryToEntries.keys) {
|
||||
val button = category.toTextButton()
|
||||
button.style = TextButton.TextButtonStyle(button.style)
|
||||
categoryToButtons[category] = button
|
||||
button.onClick { select(category) }
|
||||
buttonTable.add(button)
|
||||
}
|
||||
|
||||
buttonTable.pack()
|
||||
buttonTable.width = stage.width
|
||||
val buttonTableScroll = ScrollPane(buttonTable)
|
||||
buttonTableScroll.setScrollingDisabled(false, true)
|
||||
|
||||
val goToGameButton = Constants.close.toTextButton()
|
||||
goToGameButton.onClick {
|
||||
game.setWorldScreen()
|
||||
dispose()
|
||||
}
|
||||
|
||||
val topTable = Table()
|
||||
topTable.add(goToGameButton).pad(10f)
|
||||
topTable.add(buttonTableScroll)
|
||||
topTable.pack()
|
||||
|
||||
val entryTable = Table()
|
||||
val splitPane = SplitPane(topTable, entryTable, true, skin)
|
||||
splitPane.splitAmount = topTable.prefHeight / stage.height
|
||||
entryTable.height = stage.height - topTable.prefHeight
|
||||
splitPane.setFillParent(true)
|
||||
|
||||
stage.addActor(splitPane)
|
||||
|
||||
description.wrap = true
|
||||
|
||||
val entrySelectScroll = ScrollPane(entrySelectTable)
|
||||
entrySelectTable.top()
|
||||
entrySelectScroll.setOverscroll(false, false)
|
||||
val descriptionTable = Table()
|
||||
descriptionTable.add(description).width(stage.width * 0.5f)
|
||||
val entrySplitPane = SplitPane(entrySelectScroll, ScrollPane(descriptionTable), false, skin)
|
||||
entrySplitPane.splitAmount = 0.3f
|
||||
entryTable.addActor(entrySplitPane)
|
||||
entrySplitPane.setFillParent(true)
|
||||
|
||||
select("Tutorials")
|
||||
}
|
||||
|
||||
private fun terrainImage(terrain: Terrain, ruleset: Ruleset, imageSize: Float): Actor {
|
||||
val tileInfo = TileInfo()
|
||||
tileInfo.ruleset = ruleset
|
||||
when (terrain.type) {
|
||||
TerrainType.NaturalWonder -> {
|
||||
tileInfo.naturalWonder = terrain.name
|
||||
tileInfo.baseTerrain = terrain.turnsInto ?: Constants.grassland
|
||||
}
|
||||
TerrainType.TerrainFeature -> {
|
||||
tileInfo.terrainFeatures.add(terrain.name)
|
||||
tileInfo.baseTerrain = terrain.occursOn.lastOrNull() ?: Constants.grassland
|
||||
}
|
||||
else ->
|
||||
tileInfo.baseTerrain = terrain.name
|
||||
}
|
||||
tileInfo.setTransients()
|
||||
val group = TileGroup(tileInfo, TileSetStrings(), imageSize)
|
||||
group.showEntireMap = true
|
||||
group.forMapEditorIcon = true
|
||||
group.update()
|
||||
return group
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) {
|
||||
game.setScreen(CivilopediaScreen(game.worldScreen.gameInfo.ruleSet))
|
||||
}
|
||||
}
|
||||
}
|
107
core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt
Normal file
107
core/src/com/unciv/ui/civilopedia/CivilopediaCategories.kt
Normal file
@ -0,0 +1,107 @@
|
||||
package com.unciv.ui.civilopedia
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.tile.Terrain
|
||||
import com.unciv.models.ruleset.tile.TerrainType
|
||||
import com.unciv.ui.tilegroups.TileGroup
|
||||
import com.unciv.ui.tilegroups.TileSetStrings
|
||||
import com.unciv.ui.utils.ImageGetter
|
||||
import com.unciv.ui.utils.surroundWithCircle
|
||||
import java.io.File
|
||||
|
||||
/** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */
|
||||
object CivilopediaImageGetters {
|
||||
private const val policyIconFolder = "PolicyIcons"
|
||||
|
||||
// Todo: potential synergy with map editor
|
||||
fun terrainImage(terrain: Terrain, ruleset: Ruleset, imageSize: Float): Actor {
|
||||
val tileInfo = TileInfo()
|
||||
tileInfo.ruleset = ruleset
|
||||
when (terrain.type) {
|
||||
TerrainType.NaturalWonder -> {
|
||||
tileInfo.naturalWonder = terrain.name
|
||||
tileInfo.baseTerrain = terrain.turnsInto ?: Constants.grassland
|
||||
}
|
||||
TerrainType.TerrainFeature -> {
|
||||
tileInfo.terrainFeatures.add(terrain.name)
|
||||
tileInfo.baseTerrain = terrain.occursOn.lastOrNull() ?: Constants.grassland
|
||||
}
|
||||
else ->
|
||||
tileInfo.baseTerrain = terrain.name
|
||||
}
|
||||
tileInfo.setTerrainTransients()
|
||||
val group = TileGroup(tileInfo, TileSetStrings(), imageSize * 36f/54f) // TileGroup normally spills out of its bounding box
|
||||
group.showEntireMap = true
|
||||
group.forMapEditorIcon = true
|
||||
group.update()
|
||||
return group
|
||||
}
|
||||
|
||||
val construction = { name: String, size: Float ->
|
||||
ImageGetter.getConstructionImage(name)
|
||||
.surroundWithCircle(size, color = Color.WHITE)
|
||||
}
|
||||
val improvement = { name: String, size: Float ->
|
||||
ImageGetter.getImprovementIcon(name, size)
|
||||
}
|
||||
val nation = { name: String, size: Float ->
|
||||
val nation = ImageGetter.ruleset.nations[name]
|
||||
if (nation == null) null
|
||||
else ImageGetter.getNationIndicator(nation, size)
|
||||
}
|
||||
val policy = { name: String, size: Float ->
|
||||
ImageGetter.getImage(policyIconFolder + File.separator + name)
|
||||
.apply { setSize(size,size) }
|
||||
}
|
||||
val resource = { name: String, size: Float ->
|
||||
ImageGetter.getResourceImage(name, size)
|
||||
}
|
||||
val technology = { name: String, size: Float ->
|
||||
ImageGetter.getTechIconGroup(name, size)
|
||||
}
|
||||
val promotion = { name: String, size: Float ->
|
||||
ImageGetter.getPromotionIcon(name, size)
|
||||
}
|
||||
val terrain = { name: String, size: Float ->
|
||||
val terrain = ImageGetter.ruleset.terrains[name]
|
||||
if (terrain == null) null
|
||||
else terrainImage(terrain, ImageGetter.ruleset, size)
|
||||
}
|
||||
}
|
||||
|
||||
/** Enum used as keys for Civilopedia "pages" (categories).
|
||||
*
|
||||
* Note names are singular on purpose - a "link" allows both key and label
|
||||
*
|
||||
* @param label Translatable caption for the Civilopedia button
|
||||
*/
|
||||
enum class CivilopediaCategories (
|
||||
val label: String,
|
||||
val hide: Boolean, // Omitted on CivilopediaScreen
|
||||
val getImage: ((name: String, size: Float) -> Actor?)?
|
||||
) {
|
||||
Building ("Buildings", false, CivilopediaImageGetters.construction ),
|
||||
Wonder ("Wonders", false, CivilopediaImageGetters.construction ),
|
||||
Resource ("Resources", false, CivilopediaImageGetters.resource ),
|
||||
Terrain ("Terrains", false, CivilopediaImageGetters.terrain ),
|
||||
Improvement ("Tile Improvements", false, CivilopediaImageGetters.improvement ),
|
||||
Unit ("Units", false, CivilopediaImageGetters.construction ),
|
||||
Nation ("Nations", false, CivilopediaImageGetters.nation ),
|
||||
Technology ("Technologies", false, CivilopediaImageGetters.technology ),
|
||||
Promotion ("Promotions", false, CivilopediaImageGetters.promotion ),
|
||||
Policy ("Policies", true, CivilopediaImageGetters.policy ),
|
||||
Tutorial ("Tutorials", false, null ),
|
||||
Difficulty ("Difficulty levels", false, null ),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromLink(name: String): CivilopediaCategories? =
|
||||
values().firstOrNull { it.name == name }
|
||||
?: values().firstOrNull { it.label == name }
|
||||
|
||||
}
|
||||
}
|
303
core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt
Normal file
303
core/src/com/unciv/ui/civilopedia/CivilopediaScreen.kt
Normal file
@ -0,0 +1,303 @@
|
||||
package com.unciv.ui.civilopedia
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.utils.*
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
|
||||
/** Screen displaying the Civilopedia
|
||||
* @param ruleset [Ruleset] to display items from
|
||||
* @param category [CivilopediaCategories] key to select category
|
||||
* @param link alternate selector to select category and/or entry. Can have the form `category/entry`
|
||||
* overriding the [category] parameter, or just `entry` to complement it.
|
||||
*/
|
||||
class CivilopediaScreen(
|
||||
val ruleset: Ruleset
|
||||
, category: CivilopediaCategories = CivilopediaCategories.Tutorial
|
||||
, link: String = ""
|
||||
) : CameraStageBaseScreen() {
|
||||
|
||||
/** Container collecting data per Civilopedia entry
|
||||
* @param name From [Ruleset] object [INamed.name]
|
||||
* @param description Multiline text
|
||||
* @param image Icon for button
|
||||
* @param y Y coordinate for scrolling to
|
||||
* @param height Cell height
|
||||
*/
|
||||
private class CivilopediaEntry (
|
||||
val name: String,
|
||||
val description: String,
|
||||
val image: Actor? = null,
|
||||
val y: Float = 0f, // coordinates of button cell used to scroll to entry
|
||||
val height: Float = 0f
|
||||
) {
|
||||
fun withCoordinates(y: Float, height: Float) = CivilopediaEntry(name, description, image, y, height)
|
||||
}
|
||||
|
||||
private val categoryToEntries = LinkedHashMap<CivilopediaCategories, Collection<CivilopediaEntry>>()
|
||||
private val categoryToButtons = LinkedHashMap<CivilopediaCategories, Button>()
|
||||
private val entryIndex = LinkedHashMap<String, CivilopediaEntry>()
|
||||
|
||||
private val entrySelectTable = Table().apply { defaults().pad(6f).left() }
|
||||
private val entrySelectScroll: ScrollPane
|
||||
private val descriptionLabel = "".toLabel()
|
||||
|
||||
private var currentCategory: CivilopediaCategories = CivilopediaCategories.Tutorial
|
||||
private var currentEntry: String = ""
|
||||
|
||||
/** Jump to a "link" selecting both category and entry
|
||||
*
|
||||
* Calls [selectCategory] with the substring before the first '/',
|
||||
*
|
||||
* and [selectEntry] with the substring after the first '/'
|
||||
*
|
||||
* @param link Link in the form Category/Entry
|
||||
*/
|
||||
private fun selectLink(link: String) {
|
||||
val parts = link.split('/', limit = 2)
|
||||
if (parts.isEmpty()) return
|
||||
selectCategory(parts[0])
|
||||
if (parts.size >= 2) selectEntry(parts[1], noScrollAnimation = true)
|
||||
}
|
||||
|
||||
/** Select a specified category
|
||||
* @param name Category name or label
|
||||
*/
|
||||
fun selectCategory(name: String) {
|
||||
val category = CivilopediaCategories.fromLink(name)
|
||||
?: return // silently ignore unknown category names in links
|
||||
selectCategory(category)
|
||||
}
|
||||
|
||||
/** Select a specified category - unselects entry, rebuilds left side buttons.
|
||||
* @param category Category key
|
||||
*/
|
||||
fun selectCategory(category: CivilopediaCategories) {
|
||||
currentCategory = category
|
||||
entrySelectTable.clear()
|
||||
entryIndex.clear()
|
||||
descriptionLabel.setText("")
|
||||
|
||||
for (button in categoryToButtons.values) button.color = Color.WHITE
|
||||
if (category !in categoryToButtons) return // defense against being passed a bad selector
|
||||
categoryToButtons[category]!!.color = Color.BLUE
|
||||
|
||||
if (category !in categoryToEntries) return // defense, allowing buggy panes to remain emtpy while others work
|
||||
var entries = categoryToEntries[category]!!
|
||||
if (category != CivilopediaCategories.Difficulty) // this is the only case where we need them in order
|
||||
entries = entries.sortedBy { it.name.tr() } // Alphabetical order of localized names
|
||||
var currentY = -1f
|
||||
|
||||
for (entry in entries) {
|
||||
val entryButton = Table().apply {
|
||||
background = ImageGetter.getBackground(colorFromRGB(50, 75, 125))
|
||||
touchable = Touchable.enabled
|
||||
}
|
||||
if (entry.image != null)
|
||||
if (category == CivilopediaCategories.Terrain)
|
||||
entryButton.add(entry.image).padLeft(20f).padRight(10f)
|
||||
else
|
||||
entryButton.add(entry.image).padLeft(10f)
|
||||
entryButton.left().add(entry.name.toLabel(Color.WHITE, 25)).pad(10f)
|
||||
entryButton.onClick { selectEntry(entry) }
|
||||
entryButton.name = entry.name // make button findable
|
||||
val cell = entrySelectTable.add(entryButton).height(75f).expandX().fillX()
|
||||
entrySelectTable.row()
|
||||
if (currentY < 0f) currentY = cell.padTop
|
||||
entryIndex[entry.name] = entry.withCoordinates(currentY, cell.prefHeight)
|
||||
currentY += cell.padBottom + cell.prefHeight + cell.padTop
|
||||
}
|
||||
|
||||
entrySelectScroll.layout() // necessary for positioning in selectRow to work
|
||||
}
|
||||
|
||||
/** Select a specified entry within the current category. Unknown strings are ignored!
|
||||
* @param name Entry (Ruleset object) name
|
||||
* @param noScrollAnimation Disable scroll animation
|
||||
*/
|
||||
fun selectEntry(name: String, noScrollAnimation: Boolean = false) {
|
||||
val entry = entryIndex[name] ?: return
|
||||
// fails: entrySelectScroll.scrollTo(0f, entry.y, 0f, entry.h, false, true)
|
||||
entrySelectScroll.let {
|
||||
it.scrollY = (entry.y + (entry.height - it.height) / 2).coerceIn(0f, it.maxY)
|
||||
}
|
||||
if (noScrollAnimation)
|
||||
entrySelectScroll.updateVisualScroll() // snap without animation on fresh pedia open
|
||||
selectEntry(entry)
|
||||
}
|
||||
private fun selectEntry(entry: CivilopediaEntry) {
|
||||
currentEntry = entry.name
|
||||
descriptionLabel.setText(entry.description)
|
||||
entrySelectTable.children.forEach {
|
||||
it.color = if (it.name == entry.name) Color.BLUE else Color.WHITE
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val imageSize = 50f
|
||||
onBackButtonClicked { UncivGame.Current.setWorldScreen() }
|
||||
|
||||
categoryToEntries[CivilopediaCategories.Building] = ruleset.buildings.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques && !(it.isWonder || it.isNationalWonder) }
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(false, null, ruleset),
|
||||
CivilopediaCategories.Building.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Wonder] = ruleset.buildings.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques && (it.isWonder || it.isNationalWonder) }
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(false, null, ruleset),
|
||||
CivilopediaCategories.Wonder.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Resource] = ruleset.tileResources.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(ruleset),
|
||||
CivilopediaCategories.Resource.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Terrain] = ruleset.terrains.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(ruleset),
|
||||
CivilopediaCategories.Terrain.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Improvement] = ruleset.tileImprovements.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(ruleset, false),
|
||||
CivilopediaCategories.Improvement.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Unit] = ruleset.units.values
|
||||
.filter { "Will not be displayed in Civilopedia" !in it.uniques }
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(false),
|
||||
CivilopediaCategories.Unit.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Nation] = ruleset.nations.values
|
||||
.filter { it.isMajorCiv() }
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getUniqueString(ruleset, false),
|
||||
CivilopediaCategories.Nation.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Technology] = ruleset.technologies.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(ruleset),
|
||||
CivilopediaCategories.Technology.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
categoryToEntries[CivilopediaCategories.Promotion] = ruleset.unitPromotions.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(ruleset.unitPromotions.values, true, ruleset),
|
||||
CivilopediaCategories.Promotion.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
|
||||
categoryToEntries[CivilopediaCategories.Tutorial] = tutorialController.getCivilopediaTutorials()
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.key.replace("_", " "),
|
||||
it.value.joinToString("\n\n") { line -> line.tr() },
|
||||
// CivilopediaCategories.Tutorial.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
|
||||
categoryToEntries[CivilopediaCategories.Difficulty] = ruleset.difficulties.values
|
||||
.map {
|
||||
CivilopediaEntry(
|
||||
it.name,
|
||||
it.getDescription(),
|
||||
// CivilopediaCategories.Difficulty.getImage?.invoke(it.name, imageSize)
|
||||
)
|
||||
}
|
||||
|
||||
val buttonTable = Table()
|
||||
buttonTable.pad(15f)
|
||||
buttonTable.defaults().pad(10f)
|
||||
|
||||
for (categoryKey in categoryToEntries.keys) {
|
||||
val button = categoryKey.label.toTextButton()
|
||||
button.style = TextButton.TextButtonStyle(button.style)
|
||||
categoryToButtons[categoryKey] = button
|
||||
button.onClick { selectCategory(categoryKey) }
|
||||
buttonTable.add(button)
|
||||
}
|
||||
|
||||
buttonTable.pack()
|
||||
buttonTable.width = stage.width
|
||||
val buttonTableScroll = ScrollPane(buttonTable)
|
||||
buttonTableScroll.setScrollingDisabled(false, true)
|
||||
|
||||
val goToGameButton = Constants.close.toTextButton()
|
||||
goToGameButton.onClick {
|
||||
game.setWorldScreen()
|
||||
dispose()
|
||||
}
|
||||
|
||||
val topTable = Table()
|
||||
topTable.add(goToGameButton).pad(10f)
|
||||
topTable.add(buttonTableScroll)
|
||||
topTable.pack()
|
||||
|
||||
val entryTable = Table()
|
||||
val splitPane = SplitPane(topTable, entryTable, true, skin)
|
||||
splitPane.splitAmount = topTable.prefHeight / stage.height
|
||||
entryTable.height = stage.height - topTable.prefHeight
|
||||
splitPane.setFillParent(true)
|
||||
|
||||
stage.addActor(splitPane)
|
||||
|
||||
entrySelectScroll = ScrollPane(entrySelectTable)
|
||||
entrySelectTable.top()
|
||||
entrySelectScroll.setOverscroll(false, false)
|
||||
val descriptionTable = Table()
|
||||
descriptionLabel.wrap = true // requires explicit cell width!
|
||||
descriptionTable.add(descriptionLabel).width(stage.width * 0.5f).padTop(10f).row()
|
||||
val entrySplitPane = SplitPane(entrySelectScroll, ScrollPane(descriptionTable), false, skin)
|
||||
entrySplitPane.splitAmount = 0.3f
|
||||
entryTable.addActor(entrySplitPane)
|
||||
entrySplitPane.setFillParent(true)
|
||||
|
||||
if (link.isEmpty() || '/' !in link)
|
||||
selectCategory(category)
|
||||
if (link.isNotEmpty())
|
||||
if ('/' in link)
|
||||
selectLink(link)
|
||||
else
|
||||
selectEntry(link, noScrollAnimation = true)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) {
|
||||
game.setScreen(CivilopediaScreen(game.worldScreen.gameInfo.ruleSet, currentCategory, currentEntry))
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ import com.unciv.models.UncivSound
|
||||
import com.unciv.models.ruleset.tile.ResourceType
|
||||
import com.unciv.models.ruleset.unit.UnitType
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.CivilopediaScreen
|
||||
import com.unciv.ui.civilopedia.CivilopediaScreen
|
||||
import com.unciv.ui.cityscreen.CityScreen
|
||||
import com.unciv.ui.overviewscreen.EmpireOverviewScreen
|
||||
import com.unciv.ui.pickerscreens.GreatPersonPickerScreen
|
||||
@ -40,19 +40,38 @@ import com.unciv.ui.victoryscreen.VictoryScreen
|
||||
import com.unciv.ui.worldscreen.bottombar.BattleTable
|
||||
import com.unciv.ui.worldscreen.bottombar.TileInfoTable
|
||||
import com.unciv.ui.worldscreen.mainmenu.OnlineMultiplayer
|
||||
import com.unciv.ui.worldscreen.mainmenu.OptionsPopup
|
||||
import com.unciv.ui.worldscreen.unit.UnitActionsTable
|
||||
import com.unciv.ui.worldscreen.unit.UnitTable
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.concurrent.timer
|
||||
|
||||
/**
|
||||
* Unciv's world screen
|
||||
* @param gameInfo The game state the screen should represent
|
||||
* @param viewingCiv The currently active [civilization][CivilizationInfo]
|
||||
* @see [shouldUpdate]
|
||||
* @see [isPlayersTurn]
|
||||
* @see [selectedCiv]
|
||||
* @see [canChangeState]
|
||||
* @see [mapHolder]
|
||||
* @see [bottomUnitTable]
|
||||
* @see [enableNextTurnButtonAfterOptions]
|
||||
* @property shouldUpdate When set, causes the screen to update in the next [render][CameraStageBaseScreen.render] event
|
||||
* @property isPlayersTurn (readonly) Indicates it's the player's ([viewingCiv]) turn
|
||||
* @property selectedCiv Selected civilization, used in spectator and replay mode, equals viewingCiv in ordinary games
|
||||
* @property canChangeState (readonly) `true` when it's the player's turn unless he is a spectator
|
||||
* @property mapHolder A [MinimapHolder] instance
|
||||
* @property bottomUnitTable Bottom left widget holding information about a selected unit or city
|
||||
*/
|
||||
class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
|
||||
|
||||
var isPlayersTurn = viewingCiv == gameInfo.currentPlayerCiv
|
||||
var selectedCiv = viewingCiv // Selected civilization, used in spectator and replay mode, equals viewingCiv in ordinary games
|
||||
private set // only this class is allowed to make changes
|
||||
var selectedCiv = viewingCiv
|
||||
private var fogOfWar = true
|
||||
val canChangeState = isPlayersTurn && !viewingCiv.isSpectator()
|
||||
val canChangeState
|
||||
get() = isPlayersTurn && !viewingCiv.isSpectator()
|
||||
private var waitingForAutosave = false
|
||||
|
||||
val mapHolder = WorldMapHolder(this, gameInfo.tileMap)
|
||||
@ -140,9 +159,9 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Cam
|
||||
|
||||
// Don't select unit and change selectedCiv when centering as spectator
|
||||
if (viewingCiv.isSpectator())
|
||||
mapHolder.setCenterPosition(tileToCenterOn, true, false)
|
||||
mapHolder.setCenterPosition(tileToCenterOn, immediately = true, selectUnit = false)
|
||||
else
|
||||
mapHolder.setCenterPosition(tileToCenterOn, true, true)
|
||||
mapHolder.setCenterPosition(tileToCenterOn, immediately = true, selectUnit = true)
|
||||
|
||||
|
||||
tutorialController.allTutorialsShowedCallback = { shouldUpdate = true }
|
||||
@ -544,7 +563,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Cam
|
||||
}
|
||||
|
||||
|
||||
fun createNewWorldScreen(gameInfo: GameInfo) {
|
||||
private fun createNewWorldScreen(gameInfo: GameInfo) {
|
||||
|
||||
game.gameInfo = gameInfo
|
||||
val newWorldScreen = WorldScreen(gameInfo, gameInfo.getPlayerToViewAs())
|
||||
@ -596,7 +615,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Cam
|
||||
|
||||
val shouldAutoSave = gameInfoClone.turns % game.settings.turnsBetweenAutosaves == 0
|
||||
|
||||
// create a new worldscreen to show the new stuff we've changed, and switch out the current screen.
|
||||
// create a new WorldScreen to show the new stuff we've changed, and switch out the current screen.
|
||||
// do this on main thread - it's the only one that has a GL context to create images from
|
||||
Gdx.app.postRunnable {
|
||||
|
||||
@ -635,6 +654,10 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Cam
|
||||
nextTurnButton.setPosition(stage.width - nextTurnButton.width - 10f, topBar.y - nextTurnButton.height - 10f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by [OptionsPopup][com.unciv.ui.worldscreen.mainmenu.OptionsPopup]
|
||||
* to re-enable the next turn button within its Close button action
|
||||
*/
|
||||
fun enableNextTurnButtonAfterOptions() {
|
||||
nextTurnButton.isEnabled = isPlayersTurn && !waitingForAutosave
|
||||
}
|
||||
@ -647,7 +670,7 @@ class WorldScreen(val gameInfo: GameInfo, val viewingCiv:CivilizationInfo) : Cam
|
||||
NextTurnAction("Next unit", Color.LIGHT_GRAY) {
|
||||
val nextDueUnit = viewingCiv.getNextDueUnit()
|
||||
if (nextDueUnit != null) {
|
||||
mapHolder.setCenterPosition(nextDueUnit.currentTile.position, false, false)
|
||||
mapHolder.setCenterPosition(nextDueUnit.currentTile.position, immediately = false, selectUnit = false)
|
||||
bottomUnitTable.selectUnit(nextDueUnit)
|
||||
shouldUpdate = true
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.Constants
|
||||
import com.unciv.MainMenuScreen
|
||||
import com.unciv.ui.CivilopediaScreen
|
||||
import com.unciv.ui.civilopedia.CivilopediaScreen
|
||||
import com.unciv.ui.newgamescreen.GameSetupInfo
|
||||
import com.unciv.ui.newgamescreen.NewGameScreen
|
||||
import com.unciv.ui.saves.LoadGameScreen
|
||||
|
Reference in New Issue
Block a user