Huge update of Technology Picker screen UI (Civ 5), new original icons + misc changes (#8188)
* Huge update of Technology Picker screen UI, new original icons + misc changes * Fix possible memory leak * Fix lines Z-Depth, shifted era boundary lines, thicker queue-path lines * Fix lines Z-Depth more correctly * Size checks replaced by truncation * Icons credits Co-authored-by: tunerzinc@gmail.com <vfylfhby>
BIN
android/Images.Construction/OtherIcons/ConvertGold.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
android/Images.Construction/OtherIcons/ConvertNothing.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
android/Images.Construction/OtherIcons/ConvertScience.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
android/Images/ImprovementIcons/Remove Fallout.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
android/Images/ImprovementIcons/Remove Forest.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
android/Images/ImprovementIcons/Remove Jungle.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
android/Images/ImprovementIcons/Remove Marsh.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
android/Images/ImprovementIcons/Remove Railroad.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
android/Images/ImprovementIcons/Remove Road.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
android/Images/OtherIcons/Unique.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
@ -263,6 +263,48 @@ ImprovementIcons/Railroad
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
ImprovementIcons/Remove Fallout
|
||||||
|
rotate: false
|
||||||
|
xy: 250, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
ImprovementIcons/Remove Forest
|
||||||
|
rotate: false
|
||||||
|
xy: 350, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
ImprovementIcons/Remove Jungle
|
||||||
|
rotate: false
|
||||||
|
xy: 350, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
ImprovementIcons/Remove Marsh
|
||||||
|
rotate: false
|
||||||
|
xy: 450, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
ImprovementIcons/Remove Railroad
|
||||||
|
rotate: false
|
||||||
|
xy: 550, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
ImprovementIcons/Remove Road
|
||||||
|
rotate: false
|
||||||
|
xy: 650, 0
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
ImprovementIcons/Repair
|
ImprovementIcons/Repair
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1270, 1720
|
xy: 1270, 1720
|
||||||
@ -361,6 +403,13 @@ StatIcons/Science
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
OtherIcons/ConvertScience
|
||||||
|
rotate: false
|
||||||
|
xy: 622, 886
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
OtherIcons/AirSweep
|
OtherIcons/AirSweep
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 4, 369
|
xy: 4, 369
|
||||||
@ -543,6 +592,13 @@ OtherIcons/Improvements
|
|||||||
orig: 50, 50
|
orig: 50, 50
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
OtherIcons/Unique
|
||||||
|
rotate: false
|
||||||
|
xy: 1921, 1655
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
OtherIcons/Link
|
OtherIcons/Link
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 1004, 906
|
xy: 1004, 906
|
||||||
@ -1194,6 +1250,20 @@ StatIcons/Gold
|
|||||||
orig: 100, 100
|
orig: 100, 100
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
|
OtherIcons/ConvertGold
|
||||||
|
rotate: false
|
||||||
|
xy: 298, 1426
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
OtherIcons/ConvertNothing
|
||||||
|
rotate: false
|
||||||
|
xy: 1923, 1545
|
||||||
|
size: 100, 100
|
||||||
|
orig: 100, 100
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
StatIcons/Happiness
|
StatIcons/Happiness
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 514, 1642
|
xy: 514, 1642
|
||||||
|
Before Width: | Height: | Size: 523 KiB After Width: | Height: | Size: 520 KiB |
@ -18,6 +18,7 @@ import com.badlogic.gdx.utils.Align
|
|||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.json.json
|
import com.unciv.json.json
|
||||||
|
import com.unciv.logic.city.PerpetualConstruction
|
||||||
import com.unciv.models.ruleset.Nation
|
import com.unciv.models.ruleset.Nation
|
||||||
import com.unciv.models.ruleset.Ruleset
|
import com.unciv.models.ruleset.Ruleset
|
||||||
import com.unciv.models.ruleset.tile.ResourceType
|
import com.unciv.models.ruleset.tile.ResourceType
|
||||||
@ -238,17 +239,19 @@ object ImageGetter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun getImprovementIcon(improvementName: String, size: Float = 20f): Group {
|
fun getImprovementIcon(improvementName: String, size: Float = 20f, withCircle: Boolean = true): Group {
|
||||||
if (improvementName.startsWith(Constants.remove) || improvementName == Constants.cancelImprovementOrder)
|
if (improvementName == Constants.cancelImprovementOrder)
|
||||||
return getImage("OtherIcons/Stop").surroundWithCircle(size)
|
return getImage("OtherIcons/Stop").surroundWithCircle(size)
|
||||||
|
|
||||||
val iconGroup = getImage("ImprovementIcons/$improvementName").surroundWithCircle(size)
|
val icon = getImage("ImprovementIcons/$improvementName")
|
||||||
|
|
||||||
|
if (!withCircle) return icon.toGroup(size)
|
||||||
|
|
||||||
|
val group = icon.surroundWithCircle(size)
|
||||||
val improvement = ruleset.tileImprovements[improvementName]
|
val improvement = ruleset.tileImprovements[improvementName]
|
||||||
if (improvement != null)
|
if (improvement != null)
|
||||||
iconGroup.circle.color = getColorFromStats(improvement)
|
group.circle.color = getColorFromStats(improvement)
|
||||||
|
return group.surroundWithThinCircle()
|
||||||
return iconGroup.surroundWithThinCircle()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPortraitImage(construction: String, size: Float): Group {
|
fun getPortraitImage(construction: String, size: Float): Group {
|
||||||
@ -269,8 +272,8 @@ object ImageGetter {
|
|||||||
} else
|
} else
|
||||||
getUnitIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
getUnitIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
||||||
}
|
}
|
||||||
if (construction == "Nothing")
|
if (construction in PerpetualConstruction.perpetualConstructionsMap)
|
||||||
return getImage("OtherIcons/Sleep").surroundWithCircle(size).surroundWithThinCircle()
|
return getImage("OtherIcons/Convert$construction").toGroup(size)
|
||||||
return getStatIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
return getStatIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,35 +1,57 @@
|
|||||||
package com.unciv.ui.pickerscreens
|
package com.unciv.ui.pickerscreens
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
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.Touchable
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||||
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.logic.civilization.TechManager
|
import com.unciv.logic.civilization.TechManager
|
||||||
import com.unciv.models.ruleset.Building
|
import com.unciv.models.ruleset.Building
|
||||||
import com.unciv.models.ruleset.tile.TileImprovement
|
import com.unciv.models.ruleset.tile.TileImprovement
|
||||||
import com.unciv.models.ruleset.tile.TileResource
|
import com.unciv.models.ruleset.tile.TileResource
|
||||||
|
import com.unciv.models.ruleset.unique.UniqueType
|
||||||
import com.unciv.ui.images.IconCircleGroup
|
import com.unciv.ui.images.IconCircleGroup
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.utils.BaseScreen
|
import com.unciv.ui.utils.BaseScreen
|
||||||
import com.unciv.ui.utils.extensions.addBorder
|
import com.unciv.ui.utils.extensions.addBorder
|
||||||
import com.unciv.ui.utils.extensions.brighten
|
import com.unciv.ui.utils.extensions.brighten
|
||||||
import com.unciv.ui.utils.extensions.center
|
import com.unciv.ui.utils.extensions.center
|
||||||
|
import com.unciv.ui.utils.extensions.centerY
|
||||||
import com.unciv.ui.utils.extensions.darken
|
import com.unciv.ui.utils.extensions.darken
|
||||||
|
import com.unciv.ui.utils.extensions.setFontSize
|
||||||
|
import com.unciv.ui.utils.extensions.setSize
|
||||||
import com.unciv.ui.utils.extensions.surroundWithCircle
|
import com.unciv.ui.utils.extensions.surroundWithCircle
|
||||||
import com.unciv.ui.utils.extensions.surroundWithThinCircle
|
import com.unciv.ui.utils.extensions.surroundWithThinCircle
|
||||||
|
import com.unciv.ui.utils.extensions.toGroup
|
||||||
import com.unciv.ui.utils.extensions.toLabel
|
import com.unciv.ui.utils.extensions.toLabel
|
||||||
|
|
||||||
class TechButton(techName:String, private val techManager: TechManager, isWorldScreen: Boolean = true) : Table(BaseScreen.skin) {
|
class TechButton(techName:String, private val techManager: TechManager, isWorldScreen: Boolean = true) : Table(BaseScreen.skin) {
|
||||||
val text = "".toLabel().apply { setAlignment(Align.center) }
|
val text = "".toLabel().apply {
|
||||||
|
wrap = false
|
||||||
|
setFontSize(14)
|
||||||
|
setAlignment(Align.left)
|
||||||
|
setEllipsis(true)
|
||||||
|
}
|
||||||
|
val turns = "".toLabel().apply {
|
||||||
|
setFontSize(14)
|
||||||
|
setAlignment(Align.right)
|
||||||
|
}
|
||||||
var orderIndicator: IconCircleGroup? = null
|
var orderIndicator: IconCircleGroup? = null
|
||||||
|
var bg = Image(BaseScreen.skinStrings.getUiBackground("TechPickerScreen/TechButton", BaseScreen.skinStrings.roundedEdgeRectangleShape))
|
||||||
|
|
||||||
init {
|
init {
|
||||||
touchable = Touchable.enabled
|
touchable = Touchable.enabled
|
||||||
background = BaseScreen.skinStrings.getUiBackground("TechPickerScreen/TechButton", BaseScreen.skinStrings.roundedEdgeRectangleShape)
|
background = BaseScreen.skinStrings.getUiBackground("TechPickerScreen/TechButton", BaseScreen.skinStrings.roundedEdgeRectangleShape,
|
||||||
pad(10f)
|
tintColor = Color.WHITE.darken(0.3f))
|
||||||
|
|
||||||
|
bg.toBack()
|
||||||
|
addActor(bg)
|
||||||
|
|
||||||
|
pad(0f).padBottom(5f).padTop(5f).padLeft(5f).padRight(5f)
|
||||||
|
|
||||||
if (ImageGetter.techIconExists(techName))
|
if (ImageGetter.techIconExists(techName))
|
||||||
add(ImageGetter.getTechIconGroup(techName, 60f)).left()
|
add(ImageGetter.getTechIconGroup(techName, 45f)).padRight(5f).left()
|
||||||
|
|
||||||
val rightSide = Table()
|
val rightSide = Table()
|
||||||
|
|
||||||
@ -45,18 +67,37 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
|||||||
.addColor(Color.BLUE.brighten(0.3f), percentWillBeComplete)
|
.addColor(Color.BLUE.brighten(0.3f), percentWillBeComplete)
|
||||||
.addColor(Color.BLUE.darken(0.5f), percentComplete)
|
.addColor(Color.BLUE.darken(0.5f), percentComplete)
|
||||||
add(progressBar.addBorder(1f, Color.GRAY)).pad(10f)
|
add(progressBar.addBorder(1f, Color.GRAY)).pad(10f)
|
||||||
rightSide.add(text).padBottom(5f).row()
|
}
|
||||||
} else rightSide.add(text).height(25f).padBottom(5f).row()
|
rightSide.add(text).width(145f).top().left().padRight(15f)
|
||||||
|
rightSide.add(turns).width(40f).top().right().padRight(10f).row()
|
||||||
|
|
||||||
addTechEnabledIcons(techName, isWorldScreen, rightSide)
|
addTechEnabledIcons(techName, isWorldScreen, rightSide)
|
||||||
|
|
||||||
add(rightSide)
|
rightSide.centerY(this)
|
||||||
|
add(rightSide).expandX().left()
|
||||||
|
pack()
|
||||||
|
|
||||||
|
bg.setSize(width-3f, height-3f)
|
||||||
|
bg.align = Align.center
|
||||||
|
bg.center(this)
|
||||||
|
|
||||||
|
pack()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setButtonColor(color: Color) {
|
||||||
|
bg.color = color
|
||||||
pack()
|
pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addTechEnabledIcons(techName: String, isWorldScreen: Boolean, rightSide: Table) {
|
private fun addTechEnabledIcons(techName: String, isWorldScreen: Boolean, rightSide: Table) {
|
||||||
val techEnabledIcons = Table()
|
val techEnabledIcons = Table().align(Align.left)
|
||||||
techEnabledIcons.defaults().pad(5f)
|
techEnabledIcons.background = BaseScreen.skinStrings.getUiBackground(
|
||||||
|
"TechPickerScreen/TechButtonIconsOutline",
|
||||||
|
BaseScreen.skinStrings.rectangleWithOutlineShape,
|
||||||
|
tintColor = Color.BLACK.cpy().apply { a = 0.7f }
|
||||||
|
)
|
||||||
|
techEnabledIcons.pad(0f).padLeft(10f).padTop(2f).padBottom(2f)
|
||||||
|
techEnabledIcons.defaults().padRight(5f)
|
||||||
val techIconSize = 30f
|
val techIconSize = 30f
|
||||||
|
|
||||||
val civName = techManager.civInfo.civName
|
val civName = techManager.civInfo.civName
|
||||||
@ -64,11 +105,15 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
|||||||
|
|
||||||
val tech = ruleset.technologies[techName]!!
|
val tech = ruleset.technologies[techName]!!
|
||||||
|
|
||||||
for (unit in tech.getEnabledUnits(ruleset, techManager.civInfo))
|
val icons = ArrayList<Group>()
|
||||||
techEnabledIcons.add(ImageGetter.getPortraitImage(unit.name, techIconSize))
|
|
||||||
|
|
||||||
for (building in tech.getEnabledBuildings(ruleset, techManager.civInfo))
|
for (unit in tech.getEnabledUnits(ruleset, techManager.civInfo)) {
|
||||||
techEnabledIcons.add(ImageGetter.getPortraitImage(building.name, techIconSize))
|
icons.add(ImageGetter.getPortraitImage(unit.name, techIconSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (building in tech.getEnabledBuildings(ruleset, techManager.civInfo)) {
|
||||||
|
icons.add(ImageGetter.getPortraitImage(building.name, techIconSize))
|
||||||
|
}
|
||||||
|
|
||||||
for (obj in tech.getObsoletedObjects(ruleset, techManager.civInfo)) {
|
for (obj in tech.getObsoletedObjects(ruleset, techManager.civInfo)) {
|
||||||
val obsoletedIcon = when (obj) {
|
val obsoletedIcon = when (obj) {
|
||||||
@ -81,34 +126,56 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
|||||||
closeImage.center(it)
|
closeImage.center(it)
|
||||||
it.addActor(closeImage)
|
it.addActor(closeImage)
|
||||||
}
|
}
|
||||||
techEnabledIcons.add(obsoletedIcon)
|
icons.add(obsoletedIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (resource in ruleset.tileResources.values.filter { it.revealedBy == techName }) {
|
||||||
|
icons.add(ImageGetter.getResourceImage(resource.name, techIconSize))
|
||||||
|
}
|
||||||
|
|
||||||
for (improvement in ruleset.tileImprovements.values.asSequence()
|
for (improvement in ruleset.tileImprovements.values.asSequence()
|
||||||
.filter {
|
.filter { it.techRequired == techName }
|
||||||
it.techRequired == techName
|
|
||||||
|| it.uniqueObjects.any { u -> u.allParams.contains(techName) }
|
|
||||||
}
|
|
||||||
.filter { it.uniqueTo == null || it.uniqueTo == civName }
|
.filter { it.uniqueTo == null || it.uniqueTo == civName }
|
||||||
) {
|
) {
|
||||||
techEnabledIcons.add(ImageGetter.getImprovementIcon(improvement.name, techIconSize))
|
icons.add(ImageGetter.getImprovementIcon(improvement.name, techIconSize, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (improvement in ruleset.tileImprovements.values.asSequence()
|
||||||
for (resource in ruleset.tileResources.values.filter { it.revealedBy == techName })
|
.filter { it.uniqueObjects.any { u -> u.allParams.contains(techName) } }
|
||||||
techEnabledIcons.add(ImageGetter.getResourceImage(resource.name, techIconSize))
|
.filter { it.uniqueTo == null || it.uniqueTo == civName }
|
||||||
|
) {
|
||||||
for (unique in tech.uniques)
|
icons.add(
|
||||||
techEnabledIcons.add(
|
ImageGetter.getImage("OtherIcons/Unique")
|
||||||
ImageGetter.getImage("OtherIcons/Star")
|
|
||||||
.apply { color = Color.BLACK }
|
|
||||||
.surroundWithCircle(techIconSize)
|
.surroundWithCircle(techIconSize)
|
||||||
.surroundWithThinCircle())
|
.surroundWithThinCircle())
|
||||||
|
}
|
||||||
|
|
||||||
if (isWorldScreen) rightSide.add(techEnabledIcons)
|
for (unique in tech.uniques) {
|
||||||
else rightSide.add(techEnabledIcons)
|
icons.add(
|
||||||
.minWidth(225f)
|
when (unique) {
|
||||||
|
UniqueType.EnablesCivWideStatProduction.text.replace("civWideStat", "Gold" )
|
||||||
|
-> ImageGetter.getImage("OtherIcons/ConvertGold").toGroup(techIconSize)
|
||||||
|
UniqueType.EnablesCivWideStatProduction.text.replace("civWideStat", "Science" )
|
||||||
|
-> ImageGetter.getImage("OtherIcons/ConvertScience").toGroup(techIconSize)
|
||||||
|
else -> ImageGetter.getImage("OtherIcons/Unique")
|
||||||
|
.surroundWithCircle(techIconSize)
|
||||||
|
.surroundWithThinCircle()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0..4) {
|
||||||
|
val icon = icons.getOrNull(i)
|
||||||
|
if (icon != null)
|
||||||
|
techEnabledIcons.add(icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
rightSide.add(techEnabledIcons)
|
||||||
|
.colspan(2)
|
||||||
|
.minWidth(195f)
|
||||||
|
.prefWidth(195f)
|
||||||
|
.maxWidth(195f)
|
||||||
|
.expandX().left().row()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addOrderIndicator(number:Int){
|
fun addOrderIndicator(number:Int){
|
||||||
@ -119,4 +186,5 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
|||||||
orderIndicator!!.setPosition(0f, height, Align.topLeft)
|
orderIndicator!!.setPosition(0f, height, Align.topLeft)
|
||||||
addActor(orderIndicator)
|
addActor(orderIndicator)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ package com.unciv.ui.pickerscreens
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.badlogic.gdx.utils.Align
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
@ -16,14 +18,17 @@ import com.unciv.ui.civilopedia.CivilopediaCategories
|
|||||||
import com.unciv.ui.civilopedia.CivilopediaScreen
|
import com.unciv.ui.civilopedia.CivilopediaScreen
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.popup.ToastPopup
|
import com.unciv.ui.popup.ToastPopup
|
||||||
|
import com.unciv.ui.utils.BaseScreen
|
||||||
import com.unciv.ui.utils.Fonts
|
import com.unciv.ui.utils.Fonts
|
||||||
import com.unciv.ui.utils.extensions.addBorder
|
import com.unciv.ui.utils.extensions.addBorder
|
||||||
|
import com.unciv.ui.utils.extensions.brighten
|
||||||
import com.unciv.ui.utils.extensions.colorFromRGB
|
import com.unciv.ui.utils.extensions.colorFromRGB
|
||||||
import com.unciv.ui.utils.extensions.darken
|
import com.unciv.ui.utils.extensions.darken
|
||||||
import com.unciv.ui.utils.extensions.disable
|
import com.unciv.ui.utils.extensions.disable
|
||||||
import com.unciv.ui.utils.extensions.onClick
|
import com.unciv.ui.utils.extensions.onClick
|
||||||
import com.unciv.ui.utils.extensions.toLabel
|
import com.unciv.ui.utils.extensions.toLabel
|
||||||
import com.unciv.utils.concurrency.Concurrency
|
import com.unciv.utils.concurrency.Concurrency
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
|
||||||
class TechPickerScreen(
|
class TechPickerScreen(
|
||||||
@ -37,6 +42,7 @@ class TechPickerScreen(
|
|||||||
private var civTech: TechManager = civInfo.tech
|
private var civTech: TechManager = civInfo.tech
|
||||||
private var tempTechsToResearch: ArrayList<String>
|
private var tempTechsToResearch: ArrayList<String>
|
||||||
private var lines = ArrayList<Image>()
|
private var lines = ArrayList<Image>()
|
||||||
|
private var eraLabels = ArrayList<Label>()
|
||||||
|
|
||||||
/** We need this to be a separate table, and NOT the topTable, because *inhales*
|
/** We need this to be a separate table, and NOT the topTable, because *inhales*
|
||||||
* When call setConnectingLines we need to pack() the table so that the lines will align correctly, BUT
|
* When call setConnectingLines we need to pack() the table so that the lines will align correctly, BUT
|
||||||
@ -51,10 +57,10 @@ class TechPickerScreen(
|
|||||||
private var researchableTechs = civInfo.gameInfo.ruleSet.technologies.keys
|
private var researchableTechs = civInfo.gameInfo.ruleSet.technologies.keys
|
||||||
.filter { civTech.canBeResearched(it) }.toHashSet()
|
.filter { civTech.canBeResearched(it) }.toHashSet()
|
||||||
|
|
||||||
private val currentTechColor = colorFromRGB(7, 46, 43)
|
private val currentTechColor = colorFromRGB(72, 147, 175)
|
||||||
private val researchedTechColor = colorFromRGB(133, 112, 39)
|
private val researchedTechColor = colorFromRGB(255, 215, 0)
|
||||||
private val researchableTechColor = colorFromRGB(28, 170, 0)
|
private val researchableTechColor = colorFromRGB(28, 170, 0)
|
||||||
private val queuedTechColor = colorFromRGB(39, 114, 154)
|
private val queuedTechColor = colorFromRGB(7*2, 46*2, 43*2)
|
||||||
|
|
||||||
|
|
||||||
private val turnsToTech = civInfo.gameInfo.ruleSet.technologies.values.associateBy({ it.name }, { civTech.turnsToTech(it.name) })
|
private val turnsToTech = civInfo.gameInfo.ruleSet.technologies.values.associateBy({ it.name }, { civTech.turnsToTech(it.name) })
|
||||||
@ -110,6 +116,10 @@ class TechPickerScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createTechTable() {
|
private fun createTechTable() {
|
||||||
|
|
||||||
|
for (label in eraLabels) label.remove()
|
||||||
|
eraLabels.clear()
|
||||||
|
|
||||||
val allTechs = civInfo.gameInfo.ruleSet.technologies.values
|
val allTechs = civInfo.gameInfo.ruleSet.technologies.values
|
||||||
if (allTechs.isEmpty()) return
|
if (allTechs.isEmpty()) return
|
||||||
val columns = allTechs.maxOf { it.column!!.columnNumber } + 1
|
val columns = allTechs.maxOf { it.column!!.columnNumber } + 1
|
||||||
@ -127,28 +137,55 @@ class TechPickerScreen(
|
|||||||
val columnNumber = tech.column!!.columnNumber
|
val columnNumber = tech.column!!.columnNumber
|
||||||
if (!erasNamesToColumns[era]!!.contains(columnNumber)) erasNamesToColumns[era]!!.add(columnNumber)
|
if (!erasNamesToColumns[era]!!.contains(columnNumber)) erasNamesToColumns[era]!!.add(columnNumber)
|
||||||
}
|
}
|
||||||
var i = 0
|
|
||||||
for ((era, eraColumns) in erasNamesToColumns) {
|
for ((era, eraColumns) in erasNamesToColumns) {
|
||||||
val columnSpan = eraColumns.size
|
val columnSpan = eraColumns.size
|
||||||
val color = if (i % 2 == 0) Color.BLUE else Color.FIREBRICK
|
val color = when {
|
||||||
i++
|
civTech.era.name == era -> queuedTechColor
|
||||||
techTable.add(era.toLabel().addBorder(2f, color)).fill().colspan(columnSpan)
|
civInfo.gameInfo.ruleSet.eras[era]!!.eraNumber < civTech.era.eraNumber -> colorFromRGB(255, 175, 0)
|
||||||
|
else -> Color.BLACK
|
||||||
|
}
|
||||||
|
|
||||||
|
val table1 = Table().pad(1f)
|
||||||
|
val table2 = Table()
|
||||||
|
|
||||||
|
table1.background = skinStrings.getUiBackground("General/Border", tintColor = Color.WHITE)
|
||||||
|
table2.background = skinStrings.getUiBackground("General/Border", tintColor = color)
|
||||||
|
|
||||||
|
val label = era.toLabel().apply {
|
||||||
|
setAlignment(Align.center)
|
||||||
|
if (civInfo.gameInfo.ruleSet.eras[era]!!.eraNumber < civTech.era.eraNumber)
|
||||||
|
this.color = colorFromRGB(120, 46, 16) }
|
||||||
|
|
||||||
|
eraLabels.add(label)
|
||||||
|
|
||||||
|
table2.add(label).growX()
|
||||||
|
table1.add(table2).growX()
|
||||||
|
|
||||||
|
techTable.add(table1).fill().colspan(columnSpan)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (rowIndex in 0 until rows) {
|
for (rowIndex in 0 until rows) {
|
||||||
techTable.row().pad(5f).padRight(40f)
|
|
||||||
|
techTable.row()
|
||||||
|
|
||||||
for (columnIndex in techMatrix.indices) {
|
for (columnIndex in techMatrix.indices) {
|
||||||
val tech = techMatrix[columnIndex][rowIndex]
|
val tech = techMatrix[columnIndex][rowIndex]
|
||||||
if (tech == null)
|
|
||||||
techTable.add() // empty cell
|
|
||||||
|
|
||||||
else {
|
val table = Table().pad(2f).padRight(60f).padLeft(20f)
|
||||||
|
if (rowIndex == 0)
|
||||||
|
table.padTop(7f)
|
||||||
|
|
||||||
|
if (erasNamesToColumns[civTech.era.name]!!.contains(columnIndex))
|
||||||
|
table.background = skinStrings.getUiBackground("TechPickerScreen/Background", tintColor = queuedTechColor.darken(0.5f))
|
||||||
|
|
||||||
|
if (tech == null) {
|
||||||
|
techTable.add(table).fill()
|
||||||
|
} else {
|
||||||
val techButton = TechButton(tech.name, civTech, false)
|
val techButton = TechButton(tech.name, civTech, false)
|
||||||
|
table.add(techButton)
|
||||||
techNameToButton[tech.name] = techButton
|
techNameToButton[tech.name] = techButton
|
||||||
techButton.onClick { selectTechnology(tech, false) }
|
techButton.onClick { selectTechnology(tech, false) }
|
||||||
techTable.add(techButton).fillX()
|
techTable.add(table).fillX()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,19 +194,22 @@ class TechPickerScreen(
|
|||||||
private fun setButtonsInfo() {
|
private fun setButtonsInfo() {
|
||||||
for (techName in techNameToButton.keys) {
|
for (techName in techNameToButton.keys) {
|
||||||
val techButton = techNameToButton[techName]!!
|
val techButton = techNameToButton[techName]!!
|
||||||
techButton.color = when {
|
techButton.setButtonColor(when {
|
||||||
civTech.isResearched(techName) && techName != Constants.futureTech -> researchedTechColor
|
civTech.isResearched(techName) && techName != Constants.futureTech -> researchedTechColor
|
||||||
// if we're here to pick a free tech, show the current tech like the rest of the researchables so it'll be obvious what we can pick
|
// if we're here to pick a free tech, show the current tech like the rest of the researchables so it'll be obvious what we can pick
|
||||||
tempTechsToResearch.firstOrNull() == techName && !freeTechPick -> currentTechColor
|
tempTechsToResearch.firstOrNull() == techName && !freeTechPick -> currentTechColor
|
||||||
researchableTechs.contains(techName) -> researchableTechColor
|
researchableTechs.contains(techName) -> researchableTechColor
|
||||||
tempTechsToResearch.contains(techName) -> queuedTechColor
|
tempTechsToResearch.contains(techName) -> queuedTechColor
|
||||||
else -> Color.GRAY
|
else -> Color.BLACK
|
||||||
|
})
|
||||||
|
|
||||||
|
if (civTech.isResearched(techName) && techName != Constants.futureTech) {
|
||||||
|
techButton.text.color = colorFromRGB(154, 98, 16)
|
||||||
|
techButton.color = researchedTechColor.cpy().darken(0.5f)
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = techName.tr()
|
if (techName == selectedTech?.name && civTech.isResearched(techName)) {
|
||||||
|
techButton.setButtonColor(colorFromRGB(230, 220, 114))
|
||||||
if (techName == selectedTech?.name && techButton.color != currentTechColor) {
|
|
||||||
techButton.color = techButton.color.darken(0.5f)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
techButton.orderIndicator?.remove()
|
techButton.orderIndicator?.remove()
|
||||||
@ -177,10 +217,11 @@ class TechPickerScreen(
|
|||||||
techButton.addOrderIndicator(tempTechsToResearch.indexOf(techName) + 1)
|
techButton.addOrderIndicator(tempTechsToResearch.indexOf(techName) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!civTech.isResearched(techName) || techName == Constants.futureTech)
|
if (!civTech.isResearched(techName) || techName == Constants.futureTech) {
|
||||||
text += "\r\n" + turnsToTech[techName] + "${Fonts.turn}".tr()
|
techButton.turns.setText(turnsToTech[techName] + "${Fonts.turn}".tr())
|
||||||
|
}
|
||||||
|
|
||||||
techButton.text.setText(text)
|
techButton.text.setText(techName.tr())
|
||||||
}
|
}
|
||||||
|
|
||||||
addConnectingLines()
|
addConnectingLines()
|
||||||
@ -193,6 +234,17 @@ class TechPickerScreen(
|
|||||||
for (line in lines) line.remove()
|
for (line in lines) line.remove()
|
||||||
lines.clear()
|
lines.clear()
|
||||||
|
|
||||||
|
for (eraLabel in eraLabels) {
|
||||||
|
val coords = Vector2(0f, 0f)
|
||||||
|
eraLabel.localToStageCoordinates(coords)
|
||||||
|
techTable.stageToLocalCoordinates(coords)
|
||||||
|
val line = ImageGetter.getLine(coords.x-1f, coords.y, coords.x-1f, coords.y - 1000f, 1f)
|
||||||
|
line.color = Color.GRAY.apply { a = 0.6f }
|
||||||
|
line.toBack()
|
||||||
|
techTable.addActor(line)
|
||||||
|
lines.add(line)
|
||||||
|
}
|
||||||
|
|
||||||
for (tech in civInfo.gameInfo.ruleSet.technologies.values) {
|
for (tech in civInfo.gameInfo.ruleSet.technologies.values) {
|
||||||
if (!techNameToButton.containsKey(tech.name)) {
|
if (!techNameToButton.containsKey(tech.name)) {
|
||||||
ToastPopup("Tech ${tech.name} appears to be missing - perhaps two techs have the same row & column", this)
|
ToastPopup("Tech ${tech.name} appears to be missing - perhaps two techs have the same row & column", this)
|
||||||
@ -213,22 +265,110 @@ class TechPickerScreen(
|
|||||||
prerequisiteButton.localToStageCoordinates(prerequisiteCoords)
|
prerequisiteButton.localToStageCoordinates(prerequisiteCoords)
|
||||||
techTable.stageToLocalCoordinates(prerequisiteCoords)
|
techTable.stageToLocalCoordinates(prerequisiteCoords)
|
||||||
|
|
||||||
val line = ImageGetter.getLine(techButtonCoords.x, techButtonCoords.y,
|
|
||||||
prerequisiteCoords.x, prerequisiteCoords.y, 2f)
|
|
||||||
|
|
||||||
val lineColor = when {
|
val lineColor = when {
|
||||||
civTech.isResearched(tech.name) && !tech.isContinuallyResearchable() -> researchedTechColor
|
civTech.isResearched(tech.name) && !tech.isContinuallyResearchable() -> Color.WHITE
|
||||||
civTech.isResearched(prerequisite) -> researchableTechColor
|
civTech.isResearched(prerequisite) -> researchableTechColor
|
||||||
tempTechsToResearch.contains(tech.name) -> queuedTechColor
|
tempTechsToResearch.contains(tech.name) -> currentTechColor
|
||||||
else -> Color.GRAY
|
else -> Color.WHITE
|
||||||
}
|
}
|
||||||
line.color = lineColor
|
|
||||||
|
|
||||||
techTable.addActor(line)
|
val lineSize = when {
|
||||||
line.toBack()
|
tempTechsToResearch.contains(tech.name) && !civTech.isResearched(prerequisite) -> 4f
|
||||||
lines.add(line)
|
else -> 2f
|
||||||
|
}
|
||||||
|
|
||||||
|
if (techButtonCoords.y != prerequisiteCoords.y) {
|
||||||
|
|
||||||
|
val r = 6f
|
||||||
|
|
||||||
|
val deltaX = techButtonCoords.x - prerequisiteCoords.x
|
||||||
|
val deltaY = techButtonCoords.y - prerequisiteCoords.y
|
||||||
|
val halfLength = deltaX / 2f
|
||||||
|
|
||||||
|
val line = ImageGetter.getWhiteDot().apply {
|
||||||
|
width = halfLength - r
|
||||||
|
height = lineSize
|
||||||
|
x = prerequisiteCoords.x
|
||||||
|
y = prerequisiteCoords.y - height / 2
|
||||||
|
}
|
||||||
|
val line1 = ImageGetter.getWhiteDot().apply {
|
||||||
|
width = halfLength - r
|
||||||
|
height = lineSize
|
||||||
|
x = techButtonCoords.x - halfLength + r
|
||||||
|
y = techButtonCoords.y - height / 2
|
||||||
|
}
|
||||||
|
val line2 = ImageGetter.getWhiteDot().apply {
|
||||||
|
width = lineSize
|
||||||
|
height = abs(deltaY) - 2*r
|
||||||
|
x = techButtonCoords.x - halfLength - width / 2
|
||||||
|
y = techButtonCoords.y + (if (deltaY > 0f) -height - r else r + width / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
var line3: Image?
|
||||||
|
var line4: Image?
|
||||||
|
|
||||||
|
if (deltaY < 0) {
|
||||||
|
line3 = ImageGetter.getLine(line2.x, line2.y + line2.height,
|
||||||
|
line.x + line.width, line.y+lineSize/2, lineSize)
|
||||||
|
line4 = ImageGetter.getLine(line2.x, line2.y, line1.x, line1.y+lineSize/2, lineSize)
|
||||||
|
} else {
|
||||||
|
line3 = ImageGetter.getLine(line2.x+lineSize/2, line2.y,
|
||||||
|
line.x + line.width, line.y, lineSize)
|
||||||
|
line4 = ImageGetter.getLine(line2.x, line2.y + line2.height-lineSize/2,
|
||||||
|
line1.x, line1.y+lineSize/2, lineSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
line.color = lineColor
|
||||||
|
line1.color = lineColor
|
||||||
|
line2.color = lineColor
|
||||||
|
line3.color = lineColor
|
||||||
|
line4.color = lineColor
|
||||||
|
|
||||||
|
techTable.addActor(line)
|
||||||
|
techTable.addActor(line1)
|
||||||
|
techTable.addActor(line2)
|
||||||
|
techTable.addActor(line3)
|
||||||
|
techTable.addActor(line4)
|
||||||
|
|
||||||
|
line.toFront()
|
||||||
|
line1.toFront()
|
||||||
|
line2.toFront()
|
||||||
|
line3.toFront()
|
||||||
|
line4.toFront()
|
||||||
|
|
||||||
|
lines.add(line)
|
||||||
|
lines.add(line1)
|
||||||
|
lines.add(line2)
|
||||||
|
lines.add(line3)
|
||||||
|
lines.add(line4)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
val line = ImageGetter.getWhiteDot().apply {
|
||||||
|
width = techButtonCoords.x - prerequisiteCoords.x
|
||||||
|
height = lineSize
|
||||||
|
x = prerequisiteCoords.x
|
||||||
|
y = prerequisiteCoords.y - height / 2
|
||||||
|
}
|
||||||
|
line.color = lineColor
|
||||||
|
|
||||||
|
techTable.addActor(line)
|
||||||
|
|
||||||
|
if (tempTechsToResearch.contains(tech.name))
|
||||||
|
line.zIndex = 200000
|
||||||
|
else
|
||||||
|
line.zIndex = 500
|
||||||
|
|
||||||
|
lines.add(line)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (line in lines) {
|
||||||
|
if (line.color == currentTechColor)
|
||||||
|
line.toFront()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectTechnology(tech: Technology?, center: Boolean = false, switchFromWorldScreen: Boolean = true) {
|
private fun selectTechnology(tech: Technology?, center: Boolean = false, switchFromWorldScreen: Boolean = true) {
|
||||||
|
@ -88,10 +88,11 @@ class TechPolicyDiplomacyButtons(val worldScreen: WorldScreen) : Table(BaseScree
|
|||||||
if (viewingCiv.tech.currentTechnology() != null) {
|
if (viewingCiv.tech.currentTechnology() != null) {
|
||||||
val currentTech = viewingCiv.tech.currentTechnologyName()!!
|
val currentTech = viewingCiv.tech.currentTechnologyName()!!
|
||||||
val innerButton = TechButton(currentTech, viewingCiv.tech)
|
val innerButton = TechButton(currentTech, viewingCiv.tech)
|
||||||
innerButton.color = colorFromRGB(7, 46, 43)
|
innerButton.setButtonColor(colorFromRGB(7, 46, 43))
|
||||||
techButtonHolder.actor = innerButton
|
techButtonHolder.actor = innerButton
|
||||||
val turnsToTech = viewingCiv.tech.turnsToTech(currentTech)
|
val turnsToTech = viewingCiv.tech.turnsToTech(currentTech)
|
||||||
innerButton.text.setText(currentTech.tr() + "\r\n" + turnsToTech + Fonts.turn)
|
innerButton.text.setText(currentTech.tr())
|
||||||
|
innerButton.turns.setText(turnsToTech + Fonts.turn)
|
||||||
} else {
|
} else {
|
||||||
val canResearch = viewingCiv.tech.canResearchTech()
|
val canResearch = viewingCiv.tech.canResearchTech()
|
||||||
if (canResearch || viewingCiv.tech.researchedTechnologies.size != 0) {
|
if (canResearch || viewingCiv.tech.researchedTechnologies.size != 0) {
|
||||||
|
@ -213,6 +213,11 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
- [Village](https://thenounproject.com/search/?q=city+center&i=476338) by Andrey Vasiliev
|
- [Village](https://thenounproject.com/search/?q=city+center&i=476338) by Andrey Vasiliev
|
||||||
- [pumping station](https://thenounproject.com/search/?q=dike&i=555172) by Peter van Driel for Polder
|
- [pumping station](https://thenounproject.com/search/?q=dike&i=555172) by Peter van Driel for Polder
|
||||||
- [Oil Platform](https://thenounproject.com/icon/oil-platform-1364795/) by Georgiana Ionescu for Offshore Platform
|
- [Oil Platform](https://thenounproject.com/icon/oil-platform-1364795/) by Georgiana Ionescu for Offshore Platform
|
||||||
|
- [Broom](https://thenounproject.com/icon/broom-1642644/) by Rakhmat Setiawan for Remove Fallout
|
||||||
|
- [Axe](https://www.flaticon.com/ru/free-icon/axe_803805) by Those Icons for Remove Forest and Remove Jungle
|
||||||
|
- [Machete](https://thenounproject.com/icon/machete-36067/) by Robert A. Di Ieso for Remove Marsh
|
||||||
|
- Icon for Remove Railroad by [vegeta1k95](https://github.com/vegeta1k95)
|
||||||
|
- Icon for Remove Road by [vegeta1k95](https://github.com/vegeta1k95)
|
||||||
|
|
||||||
### Buildings
|
### Buildings
|
||||||
|
|
||||||
@ -756,6 +761,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
- [Political Science](https://www.flaticon.com/premium-icon/political-science_5403775) created by Hilmy Abiyyu A. - Flaticon
|
- [Political Science](https://www.flaticon.com/premium-icon/political-science_5403775) created by Hilmy Abiyyu A. - Flaticon
|
||||||
- [Question](https://thenounproject.com/icon/question-1157126/) created by Aneeque Ahmed for Question Icon
|
- [Question](https://thenounproject.com/icon/question-1157126/) created by Aneeque Ahmed for Question Icon
|
||||||
- [Trade](https://www.flaticon.com/free-icon/trade_4257019) created by Smashicons for Conduct Trade Mission
|
- [Trade](https://www.flaticon.com/free-icon/trade_4257019) created by Smashicons for Conduct Trade Mission
|
||||||
|
- [Nothing](https://www.flaticon.com/free-icon/nothing_5084125) created by Freepik for Nothing construction process
|
||||||
|
- Icon for Unique created by [vegeta1k95](https://github.com/vegeta1k95)
|
||||||
|
|
||||||
### Main menu
|
### Main menu
|
||||||
|
|
||||||
|