Modding: allow custom ResourcePortraits (#8330)
* Modding: allow custom ResourcePortraits * Modding: big generification of the icons/portraits mechanism * Resolve conflict * Fix background fallback, remove dimming of improvement icons Co-authored-by: tunerzinc@gmail.com <vfylfhby>
BIN
android/Images.NationIcons/NationIcons/Random.png
Normal file
After Width: | Height: | Size: 479 B |
BIN
android/Images.NationIcons/NationIcons/Spectator.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
android/Images/ImprovementIcons/Cancel improvement order.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 9.0 KiB |
BIN
android/Images/UniqueIcons/Fallback.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
@ -1,257 +1,271 @@
|
||||
|
||||
NationIcons.png
|
||||
size: 2048, 256
|
||||
size: 2048, 512
|
||||
format: RGBA8888
|
||||
filter: MipMapLinearLinear, MipMapLinearLinear
|
||||
repeat: none
|
||||
NationIcons/America
|
||||
rotate: false
|
||||
xy: 4, 112
|
||||
xy: 4, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Arabia
|
||||
rotate: false
|
||||
xy: 4, 4
|
||||
xy: 4, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Austria
|
||||
rotate: false
|
||||
xy: 112, 112
|
||||
xy: 112, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Aztecs
|
||||
rotate: false
|
||||
xy: 112, 4
|
||||
xy: 4, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Babylon
|
||||
rotate: false
|
||||
xy: 220, 112
|
||||
xy: 112, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Barbarians
|
||||
rotate: false
|
||||
xy: 220, 4
|
||||
xy: 220, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Byzantium
|
||||
rotate: false
|
||||
xy: 328, 112
|
||||
xy: 4, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Carthage
|
||||
rotate: false
|
||||
xy: 328, 4
|
||||
xy: 112, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Celts
|
||||
rotate: false
|
||||
xy: 436, 112
|
||||
xy: 220, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/China
|
||||
rotate: false
|
||||
xy: 436, 4
|
||||
xy: 328, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/CityState
|
||||
rotate: false
|
||||
xy: 544, 112
|
||||
xy: 112, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Denmark
|
||||
rotate: false
|
||||
xy: 544, 4
|
||||
xy: 220, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Egypt
|
||||
rotate: false
|
||||
xy: 652, 112
|
||||
xy: 328, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/England
|
||||
rotate: false
|
||||
xy: 652, 4
|
||||
xy: 436, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Ethiopia
|
||||
rotate: false
|
||||
xy: 760, 112
|
||||
xy: 220, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/France
|
||||
rotate: false
|
||||
xy: 760, 4
|
||||
xy: 328, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Germany
|
||||
rotate: false
|
||||
xy: 868, 112
|
||||
xy: 436, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Greece
|
||||
rotate: false
|
||||
xy: 868, 4
|
||||
xy: 544, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Inca
|
||||
rotate: false
|
||||
xy: 976, 112
|
||||
xy: 328, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/India
|
||||
rotate: false
|
||||
xy: 976, 4
|
||||
xy: 436, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Iroquois
|
||||
rotate: false
|
||||
xy: 1084, 112
|
||||
xy: 544, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Japan
|
||||
rotate: false
|
||||
xy: 1084, 4
|
||||
xy: 652, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Korea
|
||||
rotate: false
|
||||
xy: 1192, 112
|
||||
xy: 436, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Mongolia
|
||||
rotate: false
|
||||
xy: 1192, 4
|
||||
xy: 544, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Persia
|
||||
rotate: false
|
||||
xy: 1300, 112
|
||||
xy: 652, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Polynesia
|
||||
rotate: false
|
||||
xy: 1300, 4
|
||||
xy: 760, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Random
|
||||
rotate: false
|
||||
xy: 544, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Rome
|
||||
rotate: false
|
||||
xy: 1408, 112
|
||||
xy: 652, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Russia
|
||||
rotate: false
|
||||
xy: 1408, 4
|
||||
xy: 760, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Siam
|
||||
rotate: false
|
||||
xy: 1516, 112
|
||||
xy: 868, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Songhai
|
||||
rotate: false
|
||||
xy: 1516, 4
|
||||
xy: 652, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Spain
|
||||
rotate: false
|
||||
xy: 1624, 112
|
||||
xy: 760, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Spectator
|
||||
rotate: false
|
||||
xy: 868, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/Sweden
|
||||
rotate: false
|
||||
xy: 1624, 4
|
||||
xy: 976, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/The Huns
|
||||
rotate: false
|
||||
xy: 1732, 112
|
||||
xy: 760, 4
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/The Maya
|
||||
rotate: false
|
||||
xy: 1732, 4
|
||||
xy: 868, 112
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/The Netherlands
|
||||
rotate: false
|
||||
xy: 1840, 112
|
||||
xy: 976, 220
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
NationIcons/The Ottomans
|
||||
rotate: false
|
||||
xy: 1840, 4
|
||||
xy: 1084, 328
|
||||
size: 100, 100
|
||||
orig: 100, 100
|
||||
offset: 0, 0
|
||||
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 190 KiB |
Before Width: | Height: | Size: 579 KiB After Width: | Height: | Size: 580 KiB |
@ -61,8 +61,8 @@ open class Notification() : IsPartOfGameInfoSerialization {
|
||||
if (icons.isEmpty()) return
|
||||
for (icon in icons.reversed()) {
|
||||
val image: Actor = when {
|
||||
ruleset.technologies.containsKey(icon) -> ImageGetter.getTechIconGroup(icon, iconSize)
|
||||
ruleset.nations.containsKey(icon) -> ImageGetter.getNationIndicator(
|
||||
ruleset.technologies.containsKey(icon) -> ImageGetter.getTechIconPortrait(icon, iconSize)
|
||||
ruleset.nations.containsKey(icon) -> ImageGetter.getNationPortrait(
|
||||
ruleset.nations[icon]!!,
|
||||
iconSize
|
||||
)
|
||||
|
@ -23,22 +23,20 @@ data class UnitAction(
|
||||
val action: (() -> Unit)? = null
|
||||
) {
|
||||
fun getIcon(): Actor {
|
||||
if (type.imageGetter != null) return type.imageGetter.invoke()
|
||||
.surroundWithCircle(20f)
|
||||
.surroundWithThinCircle()
|
||||
if (type.imageGetter != null)
|
||||
return type.imageGetter.invoke()
|
||||
return when (type) {
|
||||
UnitActionType.Create -> {
|
||||
ImageGetter.getImprovementIcon(title.getPlaceholderParameters()[0])
|
||||
ImageGetter.getImprovementPortrait(title.getPlaceholderParameters()[0])
|
||||
}
|
||||
UnitActionType.SpreadReligion -> {
|
||||
val religionName = title.getPlaceholderParameters()[0]
|
||||
ImageGetter.getReligionImage(
|
||||
ImageGetter.getReligionPortrait(
|
||||
if (ImageGetter.religionIconExists(religionName)) religionName
|
||||
else "Pantheon"
|
||||
).apply { color = Color.BLACK }
|
||||
.surroundWithCircle(20f).surroundWithThinCircle()
|
||||
else "Pantheon", 20f
|
||||
)
|
||||
}
|
||||
else -> ImageGetter.getImage("UnitActionIcons/Star").apply { color = Color.BLACK }
|
||||
else -> ImageGetter.getUnitActionPortrait("Star")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,77 +60,77 @@ enum class UnitActionType(
|
||||
val uncivSound: UncivSound = UncivSound.Click
|
||||
) {
|
||||
SwapUnits("Swap units",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Swap") }, 'y', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Swap") }, 'y', false),
|
||||
Automate("Automate",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Automate") }, 'm'),
|
||||
{ ImageGetter.getUnitActionPortrait("Automate") }, 'm'),
|
||||
StopAutomation("Stop automation",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Stop") }, 'm', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, 'm', false),
|
||||
StopMovement("Stop movement",
|
||||
{ ImageGetter.getImage("UnitActionIcons/StopMove") }, '.', false),
|
||||
{ ImageGetter.getUnitActionPortrait("StopMove") }, '.', false),
|
||||
Sleep("Sleep",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Sleep") }, 'f'),
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }, 'f'),
|
||||
SleepUntilHealed("Sleep until healed",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Sleep") }, 'h'),
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }, 'h'),
|
||||
Fortify("Fortify",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Fortify") }, 'f', UncivSound.Fortify),
|
||||
{ ImageGetter.getUnitActionPortrait("Fortify") }, 'f', UncivSound.Fortify),
|
||||
FortifyUntilHealed("Fortify until healed",
|
||||
{ ImageGetter.getImage("UnitActionIcons/FortifyUntilHealed") }, 'h', UncivSound.Fortify),
|
||||
{ ImageGetter.getUnitActionPortrait("FortifyUntilHealed") }, 'h', UncivSound.Fortify),
|
||||
Explore("Explore",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Explore") }, 'x'),
|
||||
{ ImageGetter.getUnitActionPortrait("Explore") }, 'x'),
|
||||
StopExploration("Stop exploration",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Stop") }, 'x', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, 'x', false),
|
||||
Promote("Promote",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Promote") }, 'o', false, UncivSound.Promote),
|
||||
{ ImageGetter.getUnitActionPortrait("Promote") }, 'o', false, UncivSound.Promote),
|
||||
Upgrade("Upgrade",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Upgrade") }, 'u', UncivSound.Upgrade),
|
||||
{ ImageGetter.getUnitActionPortrait("Upgrade") }, 'u', UncivSound.Upgrade),
|
||||
Pillage("Pillage",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Pillage") }, 'p', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Pillage") }, 'p', false),
|
||||
Paradrop("Paradrop",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Paradrop") }, 'p', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Paradrop") }, 'p', false),
|
||||
AirSweep("Air Sweep",
|
||||
{ ImageGetter.getImage("UnitActionIcons/AirSweep") }, 'a', false),
|
||||
{ ImageGetter.getUnitActionPortrait("AirSweep") }, 'a', false),
|
||||
SetUp("Set up",
|
||||
{ ImageGetter.getImage("UnitActionIcons/SetUp") }, 't', false, UncivSound.Setup),
|
||||
{ ImageGetter.getUnitActionPortrait("SetUp") }, 't', false, UncivSound.Setup),
|
||||
FoundCity("Found city",
|
||||
{ ImageGetter.getImage("UnitActionIcons/FoundCity") }, 'c', UncivSound.Silent),
|
||||
{ ImageGetter.getUnitActionPortrait("FoundCity") }, 'c', UncivSound.Silent),
|
||||
ConstructImprovement("Construct improvement",
|
||||
{ ImageGetter.getImage("UnitActionIcons/ConstructImprovement") }, 'i'),
|
||||
{ ImageGetter.getUnitActionPortrait("ConstructImprovement") }, 'i'),
|
||||
Repair(Constants.repair,
|
||||
{ ImageGetter.getImage("UnitActionIcons/Repair") }, 'r', UncivSound.Construction),
|
||||
{ ImageGetter.getUnitActionPortrait("Repair") }, 'r', UncivSound.Construction),
|
||||
Create("Create",
|
||||
null, 'i', UncivSound.Chimes),
|
||||
HurryResearch("Hurry Research",
|
||||
{ ImageGetter.getImage("UnitActionIcons/HurryResearch") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryResearch") }, 'g', UncivSound.Chimes),
|
||||
StartGoldenAge("Start Golden Age",
|
||||
{ ImageGetter.getImage("UnitActionIcons/StartGoldenAge") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("StartGoldenAge") }, 'g', UncivSound.Chimes),
|
||||
HurryWonder("Hurry Wonder",
|
||||
{ ImageGetter.getImage("UnitActionIcons/HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
HurryBuilding("Hurry Construction",
|
||||
{ ImageGetter.getImage("UnitActionIcons/HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
ConductTradeMission("Conduct Trade Mission",
|
||||
{ ImageGetter.getImage("UnitActionIcons/ConductTradeMission") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("ConductTradeMission") }, 'g', UncivSound.Chimes),
|
||||
FoundReligion("Found a Religion",
|
||||
{ ImageGetter.getImage("UnitActionIcons/FoundReligion") }, 'g', UncivSound.Choir),
|
||||
{ ImageGetter.getUnitActionPortrait("FoundReligion") }, 'g', UncivSound.Choir),
|
||||
TriggerUnique("Trigger unique",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Star") }, 'g', false, UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("Star") }, 'g', false, UncivSound.Chimes),
|
||||
SpreadReligion("Spread Religion",
|
||||
null, 'g', UncivSound.Choir),
|
||||
RemoveHeresy("Remove Heresy",
|
||||
{ ImageGetter.getImage("UnitActionIcons/RemoveHeresy") }, 'h', UncivSound.Fire),
|
||||
{ ImageGetter.getUnitActionPortrait("RemoveHeresy") }, 'h', UncivSound.Fire),
|
||||
EnhanceReligion("Enhance a Religion",
|
||||
{ ImageGetter.getImage("UnitActionIcons/EnhanceReligion") }, 'g', UncivSound.Choir),
|
||||
{ ImageGetter.getUnitActionPortrait("EnhanceReligion") }, 'g', UncivSound.Choir),
|
||||
DisbandUnit("Disband unit",
|
||||
{ ImageGetter.getImage("UnitActionIcons/DisbandUnit") }, KeyCharAndCode.DEL, false),
|
||||
{ ImageGetter.getUnitActionPortrait("DisbandUnit") }, KeyCharAndCode.DEL, false),
|
||||
GiftUnit("Gift unit",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Present") }, UncivSound.Silent),
|
||||
{ ImageGetter.getUnitActionPortrait("Present") }, UncivSound.Silent),
|
||||
Wait("Wait",
|
||||
{ ImageGetter.getImage("UnitActionIcons/Wait") }, 'z', UncivSound.Silent),
|
||||
{ ImageGetter.getUnitActionPortrait("Wait") }, 'z', UncivSound.Silent),
|
||||
ShowAdditionalActions("Show more",
|
||||
{ ImageGetter.getImage("UnitActionIcons/ShowMore") }, KeyCharAndCode(Input.Keys.PAGE_DOWN), false),
|
||||
{ ImageGetter.getUnitActionPortrait("ShowMore") }, KeyCharAndCode(Input.Keys.PAGE_DOWN), false),
|
||||
HideAdditionalActions("Back",
|
||||
{ ImageGetter.getImage("UnitActionIcons/HideMore") }, KeyCharAndCode(Input.Keys.PAGE_UP), false),
|
||||
{ ImageGetter.getUnitActionPortrait("HideMore") }, KeyCharAndCode(Input.Keys.PAGE_UP), false),
|
||||
AddInCapital( "Add in capital",
|
||||
{ ImageGetter.getImage("UnitActionIcons/AddInCapital")}, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("AddInCapital")}, 'g', UncivSound.Chimes),
|
||||
;
|
||||
|
||||
// Allow shorter initializations
|
||||
|
@ -302,7 +302,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
table.defaults().pad(2f).minWidth(40f)
|
||||
if (isFirstConstructionOfItsKind) table.add(getProgressBar(constructionName)).minWidth(5f)
|
||||
else table.add().minWidth(5f)
|
||||
table.add(ImageGetter.getPortraitImage(constructionName, 40f)).padRight(10f)
|
||||
table.add(ImageGetter.getConstructionPortrait(constructionName, 40f)).padRight(10f)
|
||||
table.add(text.toLabel()).expandX().fillX().left()
|
||||
|
||||
if (constructionQueueIndex > 0) table.add(getRaisePriorityButton(constructionQueueIndex, constructionName, city)).right()
|
||||
@ -361,7 +361,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) {
|
||||
}
|
||||
|
||||
pickConstructionButton.add(getProgressBar(construction.name)).padRight(5f)
|
||||
pickConstructionButton.add(ImageGetter.getPortraitImage(construction.name, 40f)).padRight(10f)
|
||||
pickConstructionButton.add(ImageGetter.getConstructionPortrait(construction.name, 40f)).padRight(10f)
|
||||
pickConstructionButton.add(constructionButtonDTO.buttonText.toLabel()).expandX().fillX()
|
||||
|
||||
if (!cannotAddConstructionToQueue(construction, cityScreen.city, cityScreen.city.cityConstructions)) {
|
||||
|
@ -8,8 +8,8 @@ import com.unciv.logic.city.CityReligionManager
|
||||
import com.unciv.models.Religion
|
||||
import com.unciv.ui.civilopedia.CivilopediaCategories
|
||||
import com.unciv.ui.civilopedia.CivilopediaScreen
|
||||
import com.unciv.ui.images.IconCircleGroup
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.images.Portrait
|
||||
import com.unciv.ui.overviewscreen.EmpireOverviewCategories
|
||||
import com.unciv.ui.overviewscreen.EmpireOverviewScreen
|
||||
import com.unciv.ui.utils.BaseScreen
|
||||
@ -79,8 +79,8 @@ class CityReligionInfoTable(
|
||||
return if (religion == null) "Religion" to "None"
|
||||
else religion.getIconName() to religion.getReligionDisplayName()
|
||||
}
|
||||
private fun linkedReligionIcon(iconName: String, religion: String?): IconCircleGroup {
|
||||
val icon = ImageGetter.getCircledReligionIcon(iconName, 30f)
|
||||
private fun linkedReligionIcon(iconName: String, religion: String?): Portrait {
|
||||
val icon = ImageGetter.getReligionPortrait(iconName, 30f)
|
||||
if (religion == null) return icon
|
||||
icon.onClick {
|
||||
val newScreen = if (religion == iconName) {
|
||||
@ -98,7 +98,7 @@ class CityReligionInfoTable(
|
||||
return ExpanderTab(
|
||||
title = "Majority Religion: [$label]",
|
||||
fontSize = Constants.defaultFontSize,
|
||||
icon = ImageGetter.getCircledReligionIcon(icon, 30f),
|
||||
icon = ImageGetter.getReligionPortrait(icon, 30f),
|
||||
defaultPad = 0f,
|
||||
persistenceID = "CityStatsTable.Religion",
|
||||
startsOutOpened = false,
|
||||
|
@ -183,7 +183,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
ImageGetter.getStatIcon("Food") to
|
||||
"We Love The King Day for another [${cityInfo.getFlag(CityFlags.WeLoveTheKing)}] turns".toLabel(Color.LIME)
|
||||
cityInfo.demandedResource.isNotEmpty() ->
|
||||
ImageGetter.getResourceImage(cityInfo.demandedResource, 20f) to
|
||||
ImageGetter.getResourcePortrait(cityInfo.demandedResource, 20f) to
|
||||
"Demanding [${cityInfo.demandedResource}]".toLabel(Color.CORAL)
|
||||
else -> null to null
|
||||
}
|
||||
@ -270,7 +270,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
val info = Table()
|
||||
val statsAndSpecialists = Table()
|
||||
|
||||
val icon = ImageGetter.getPortraitImage(building.name, 50f)
|
||||
val icon = ImageGetter.getConstructionPortrait(building.name, 50f)
|
||||
val isFree = building.name in cityScreen.city.civInfo.civConstructions.getFreeBuildings(cityScreen.city.id)
|
||||
val displayName = if (isFree) "{${building.name}} ({Free})" else building.name
|
||||
|
||||
@ -374,7 +374,7 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||
info.add(progressBar).colspan(2).left().expandX().row()
|
||||
|
||||
greatPeopleTable.add(info).growX().top().padBottom(10f)
|
||||
greatPeopleTable.add(ImageGetter.getPortraitImage(greatPersonName, 50f)).row()
|
||||
greatPeopleTable.add(ImageGetter.getConstructionPortrait(greatPersonName, 50f)).row()
|
||||
}
|
||||
|
||||
lowerTable.addCategory("Great People", greatPeopleTable)
|
||||
|
@ -61,7 +61,7 @@ class ConstructionInfoTable(val cityScreen: CityScreen): Table() {
|
||||
selectedConstructionTable.run {
|
||||
pad(10f)
|
||||
|
||||
add(ImageGetter.getPortraitImage(construction.name, 50f).apply {
|
||||
add(ImageGetter.getConstructionPortrait(construction.name, 50f).apply {
|
||||
val link = (construction as? IRulesetObject)?.makeLink() ?: return@apply
|
||||
if (link.isEmpty()) return@apply
|
||||
touchable = Touchable.enabled
|
||||
|
@ -52,15 +52,15 @@ object CivilopediaImageGetters {
|
||||
}
|
||||
|
||||
val construction = { name: String, size: Float ->
|
||||
ImageGetter.getPortraitImage(name, size)
|
||||
ImageGetter.getConstructionPortrait(name, size)
|
||||
}
|
||||
val improvement = { name: String, size: Float ->
|
||||
ImageGetter.getImprovementIcon(name, size)
|
||||
ImageGetter.getImprovementPortrait(name, size)
|
||||
}
|
||||
val nation = { name: String, size: Float ->
|
||||
val nation = ImageGetter.ruleset.nations[name]
|
||||
if (nation == null) null
|
||||
else ImageGetter.getNationIndicator(nation, size)
|
||||
else ImageGetter.getNationPortrait(nation, size)
|
||||
}
|
||||
val policy = { name: String, size: Float ->
|
||||
// policy branch start and complete have no icons but are linked -> nonexistence must be passed down
|
||||
@ -75,13 +75,13 @@ object CivilopediaImageGetters {
|
||||
else null
|
||||
}
|
||||
val resource = { name: String, size: Float ->
|
||||
ImageGetter.getResourceImage(name, size)
|
||||
ImageGetter.getResourcePortrait(name, size)
|
||||
}
|
||||
val technology = { name: String, size: Float ->
|
||||
ImageGetter.getTechIconGroup(name, size)
|
||||
ImageGetter.getTechIconPortrait(name, size)
|
||||
}
|
||||
val promotion = { name: String, size: Float ->
|
||||
ImageGetter.getPromotionIcon(name, size)
|
||||
ImageGetter.getPromotionPortrait(name, size)
|
||||
}
|
||||
val terrain = { name: String, size: Float ->
|
||||
val terrain = ImageGetter.ruleset.terrains[name]
|
||||
@ -89,20 +89,7 @@ object CivilopediaImageGetters {
|
||||
else terrainImage(terrain, ImageGetter.ruleset, size)
|
||||
}
|
||||
val belief = { name: String, size: Float ->
|
||||
// Kludge until we decide how exactly to show Religions
|
||||
fun getInvertedCircledReligionIcon(iconName: String, size: Float) =
|
||||
ImageGetter.getCircledReligionIcon(iconName, size).apply {
|
||||
circle.color = Color.WHITE
|
||||
actor.color = Color.BLACK
|
||||
}
|
||||
if (ImageGetter.religionIconExists(name)) {
|
||||
getInvertedCircledReligionIcon(name, size)
|
||||
} else {
|
||||
val typeName = ImageGetter.ruleset.beliefs[name]?.type?.name
|
||||
if (typeName != null && ImageGetter.religionIconExists(typeName))
|
||||
getInvertedCircledReligionIcon(typeName, size)
|
||||
else null
|
||||
}
|
||||
ImageGetter.getReligionPortrait(name, size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,126 +201,71 @@ object ImageGetter {
|
||||
.apply { setSize(20f, 20f) }
|
||||
}
|
||||
|
||||
fun wonderImageExists(wonderName: String) = imageExists("WonderImages/$wonderName")
|
||||
fun getWonderImage(wonderName: String) = getImage("WonderImages/$wonderName")
|
||||
|
||||
fun getNationIcon(nation: String) = getImage("NationIcons/$nation")
|
||||
fun getNationPortrait(nation: Nation, size: Float): Portrait {
|
||||
return PortraitNation(nation.name, size)
|
||||
}
|
||||
|
||||
fun getRandomNationPortrait(size: Float): Portrait {
|
||||
return PortraitNation("Random", size)
|
||||
}
|
||||
|
||||
fun getUnitIcon(unitName: String, color: Color = Color.BLACK): Image {
|
||||
return getImage("UnitIcons/$unitName").apply { this.color = color }
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun getNationIndicator(nation: Nation, size: Float): IconCircleGroup {
|
||||
val civIconName = if (nation.isCityState()) "CityState" else nation.name
|
||||
return if (nationIconExists(civIconName)) {
|
||||
val cityStateIcon = getNationIcon(civIconName)
|
||||
cityStateIcon.color = nation.getInnerColor()
|
||||
cityStateIcon.surroundWithCircle(size * 0.9f).apply { circle.color = nation.getOuterColor() }
|
||||
.surroundWithCircle(size, false).apply { circle.color = nation.getInnerColor() }
|
||||
} else getCircle().apply { color = nation.getOuterColor() }
|
||||
.surroundWithCircle(size).apply { circle.color = nation.getInnerColor() }
|
||||
}
|
||||
|
||||
fun getRandomNationIndicator(size: Float): IconCircleGroup {
|
||||
return "?"
|
||||
.toLabel(Color.WHITE, (size * 5f/8f).toInt())
|
||||
.apply { this.setAlignment(Align.center) }
|
||||
.surroundWithCircle(size * 0.9f).apply { circle.color = Color.BLACK }
|
||||
.surroundWithCircle(size, false).apply { circle.color = Color.WHITE }
|
||||
}
|
||||
|
||||
private fun nationIconExists(nation: String) = imageExists("NationIcons/$nation")
|
||||
fun getNationIcon(nation: String) = getImage("NationIcons/$nation")
|
||||
|
||||
fun wonderImageExists(wonderName: String) = imageExists("WonderImages/$wonderName")
|
||||
fun getWonderImage(wonderName: String) = getImage("WonderImages/$wonderName")
|
||||
|
||||
private fun getColorFromStats(stats: Stats): Color? {
|
||||
if (stats.asSequence().none { it.value > 0 }) return Color.WHITE
|
||||
val highestStat = stats.asSequence().maxByOrNull { it.value }!!
|
||||
return highestStat.key.color
|
||||
}
|
||||
|
||||
|
||||
fun getImprovementIcon(improvementName: String, size: Float = 20f, withCircle: Boolean = true): Group {
|
||||
if (improvementName == Constants.cancelImprovementOrder)
|
||||
return getImage("OtherIcons/Stop").surroundWithCircle(size)
|
||||
|
||||
val icon = getImage("ImprovementIcons/$improvementName")
|
||||
|
||||
if (!withCircle) return icon.toGroup(size)
|
||||
|
||||
val group = icon.surroundWithCircle(size)
|
||||
val improvement = ruleset.tileImprovements[improvementName]
|
||||
if (improvement != null)
|
||||
group.circle.color = getColorFromStats(improvement)
|
||||
return group.surroundWithThinCircle()
|
||||
}
|
||||
|
||||
fun getPortraitImage(construction: String, size: Float): Group {
|
||||
fun getConstructionPortrait(construction: String, size: Float): Group {
|
||||
if (ruleset.buildings.containsKey(construction)) {
|
||||
val buildingPortraitLocation = "BuildingPortraits/$construction"
|
||||
return if (imageExists(buildingPortraitLocation)) {
|
||||
getImage(buildingPortraitLocation).toGroup(size)
|
||||
} else {
|
||||
val image = if (imageExists("BuildingIcons/$construction")) getImage("BuildingIcons/$construction")
|
||||
else getImage("BuildingIcons/Fallback")
|
||||
image.surroundWithCircle(size).surroundWithThinCircle()
|
||||
}
|
||||
return PortraitBuilding(construction, size)
|
||||
}
|
||||
if (ruleset.units.containsKey(construction)) {
|
||||
val unitPortraitLocation = "UnitPortraits/$construction"
|
||||
return if (imageExists(unitPortraitLocation)) {
|
||||
getImage(unitPortraitLocation).toGroup(size)
|
||||
} else
|
||||
getUnitIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
||||
return PortraitUnit(construction, size)
|
||||
}
|
||||
if (PerpetualConstruction.perpetualConstructionsMap.containsKey(construction))
|
||||
return getImage("OtherIcons/Convert$construction").toGroup(size)
|
||||
return getStatIcon(construction).surroundWithCircle(size).surroundWithThinCircle()
|
||||
}
|
||||
|
||||
fun getPromotionIcon(promotionName: String, size: Float = 30f): Actor {
|
||||
val nameWithoutBrackets = promotionName.replace("[", "").replace("]", "")
|
||||
fun getUniquePortrait(uniqueName: String, size: Float): Group {
|
||||
return PortraitUnique(uniqueName, size)
|
||||
}
|
||||
|
||||
var level = when {
|
||||
nameWithoutBrackets.endsWith(" I") -> 1
|
||||
nameWithoutBrackets.endsWith(" II") -> 2
|
||||
nameWithoutBrackets.endsWith(" III") -> 3
|
||||
else -> 0
|
||||
fun getPromotionPortrait(promotionName: String, size: Float = 30f): Group {
|
||||
return PortraitPromotion(promotionName, size)
|
||||
}
|
||||
|
||||
fun getResourcePortrait(resourceName: String, size: Float, amount: Int = 0): Group {
|
||||
return PortraitResource(resourceName, size, amount)
|
||||
}
|
||||
|
||||
fun getTechIconPortrait(techName: String, circleSize: Float): Group {
|
||||
return PortraitTech(techName, circleSize)
|
||||
}
|
||||
|
||||
fun getImprovementPortrait(improvementName: String, size: Float = 20f, dim: Boolean = false): Portrait {
|
||||
return PortraitImprovement(improvementName, size, dim)
|
||||
}
|
||||
|
||||
fun getUnitActionPortrait(actionName: String, size: Float = 20f): Portrait {
|
||||
return PortraitUnitAction(actionName, size)
|
||||
}
|
||||
|
||||
fun getReligionIcon(iconName: String): Image { return getImage("ReligionIcons/$iconName") }
|
||||
fun getReligionPortrait(iconName: String, size: Float): Portrait {
|
||||
if (religionIconExists(iconName)) {
|
||||
return PortraitReligion(iconName, size)
|
||||
} else {
|
||||
val typeName = ruleset.beliefs[iconName]?.type?.name
|
||||
if (typeName != null && religionIconExists(typeName))
|
||||
return PortraitReligion(typeName, size)
|
||||
}
|
||||
|
||||
val basePromotionName = nameWithoutBrackets.dropLast(if (level == 0) 0 else level + 1)
|
||||
|
||||
val imageAttempter = ImageAttempter(Unit)
|
||||
.tryImage { "UnitPromotionIcons/$nameWithoutBrackets" }
|
||||
.tryImage { "UnitPromotionIcons/$basePromotionName" }
|
||||
.tryImage { "UnitIcons/${basePromotionName.removeSuffix(" ability")}" }
|
||||
|
||||
if (imageAttempter.getPathOrNull() != null && imageAttempter.getPath()!!.endsWith(nameWithoutBrackets))
|
||||
level = 0
|
||||
|
||||
val promotionColor = colorFromRGB(255, 226, 0)
|
||||
val circle = imageAttempter.getImage()
|
||||
.apply { color = promotionColor }
|
||||
.surroundWithCircle(size)
|
||||
.apply { circle.color = colorFromRGB(0, 12, 49) }
|
||||
|
||||
if (level != 0) {
|
||||
val padding = if (level == 3) 0.5f else 2f
|
||||
val starTable = Table().apply { defaults().pad(padding) }
|
||||
for (i in 1..level) starTable.add(getImage("OtherIcons/Star")).size(size / 4f)
|
||||
starTable.centerX(circle)
|
||||
starTable.y = size / 6f
|
||||
circle.addActor(starTable)
|
||||
}
|
||||
return circle.surroundWithThinCircle(promotionColor)
|
||||
return PortraitReligion(iconName, size)
|
||||
}
|
||||
|
||||
fun religionIconExists(iconName: String) = imageExists("ReligionIcons/$iconName")
|
||||
fun getReligionImage(iconName: String): Image {
|
||||
return getImage("ReligionIcons/$iconName")
|
||||
}
|
||||
fun getCircledReligionIcon(iconName: String, size: Float): IconCircleGroup {
|
||||
return getReligionImage(iconName).surroundWithCircle(size, color = Color.BLACK )
|
||||
}
|
||||
|
||||
@Deprecated("Use skin defined base color instead", ReplaceWith("BaseScreen.skinStrings.skinConfig.baseColor", "com.unciv.ui.utils.BaseScreen"))
|
||||
fun getBlue() = Color(0x004085bf)
|
||||
@ -354,84 +299,6 @@ object ImageGetter {
|
||||
return image
|
||||
}
|
||||
|
||||
fun getResourceImage(resourceName: String, size: Float, amount: Int = 0): IconCircleGroup {
|
||||
val iconGroup = getImage("ResourceIcons/$resourceName").surroundWithCircle(size)
|
||||
val resource = ruleset.tileResources[resourceName]
|
||||
?: return iconGroup // This is the result of a bad modding setup, just give em an empty circle. Their problem.
|
||||
|
||||
val color = resource.resourceType.getColor()
|
||||
iconGroup.circle.color = color
|
||||
|
||||
// Show amount indicator for strategic resources (bottom-right)
|
||||
if (amount > 0) {
|
||||
val label = amount.toString().toLabel(
|
||||
fontSize = 8,
|
||||
fontColor = Color.WHITE,
|
||||
alignment = Align.center)
|
||||
val group = label.surroundWithCircle(size/2, true, Color.BLACK)
|
||||
|
||||
label.y -= 0.5f
|
||||
group.x = iconGroup.width - group.width * 2 / 3
|
||||
group.y = -group.height / 3
|
||||
|
||||
iconGroup.addActor(group)
|
||||
}
|
||||
|
||||
return iconGroup.surroundWithThinCircle()
|
||||
}
|
||||
|
||||
fun getTechIconGroup(techName: String, circleSize: Float, isResearched: Boolean = false): Group {
|
||||
|
||||
val portrait: Image
|
||||
val eraColor = ruleset.eras[ruleset.technologies[techName]?.era()]?.getColor()?.darken(0.6f) ?: Color.BLACK
|
||||
|
||||
// Inner part
|
||||
if (imageExists("TechPortraits/$techName"))
|
||||
portrait = getImage("TechPortraits/$techName")
|
||||
else {
|
||||
portrait = if (imageExists("TechIcons/$techName"))
|
||||
getImage("TechIcons/$techName")
|
||||
else
|
||||
getImage("TechIcons/Fallback")
|
||||
portrait.color = eraColor
|
||||
}
|
||||
|
||||
// Border / background
|
||||
if (imageExists("TechPortraits/Background")) {
|
||||
val background = getImage("TechPortraits/Background")
|
||||
val ratioW = portrait.width / background.width
|
||||
val ratioH = portrait.height / background.height
|
||||
|
||||
if (isResearched)
|
||||
background.color = Color.GOLD.cpy().brighten(0.5f)
|
||||
|
||||
background.setSize(circleSize, circleSize)
|
||||
portrait.setSize(circleSize*ratioW, circleSize*ratioH)
|
||||
|
||||
val group = Group()
|
||||
group.setSize(circleSize, circleSize)
|
||||
group.addActor(background)
|
||||
group.addActor(portrait)
|
||||
|
||||
background.center(group)
|
||||
portrait.center(group)
|
||||
|
||||
return group
|
||||
} else {
|
||||
return portrait.surroundWithCircle(circleSize).surroundWithThinCircle(eraColor)
|
||||
}
|
||||
}
|
||||
|
||||
fun getProgressBarHorizontal(
|
||||
width: Float, height: Float,
|
||||
percentComplete: Float,
|
||||
progressColor: Color,
|
||||
backgroundColor: Color): Group {
|
||||
return ProgressBar(width, height, false)
|
||||
.setBackground(backgroundColor)
|
||||
.setProgress(progressColor, percentComplete)
|
||||
}
|
||||
|
||||
fun getProgressBarVertical(
|
||||
width: Float,
|
||||
height: Float,
|
||||
|
303
core/src/com/unciv/ui/images/Portrait.kt
Normal file
@ -0,0 +1,303 @@
|
||||
package com.unciv.ui.images
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.models.ruleset.Nation
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.ui.utils.extensions.center
|
||||
import com.unciv.ui.utils.extensions.centerX
|
||||
import com.unciv.ui.utils.extensions.colorFromRGB
|
||||
import com.unciv.ui.utils.extensions.darken
|
||||
import com.unciv.ui.utils.extensions.surroundWithCircle
|
||||
import com.unciv.ui.utils.extensions.toGroup
|
||||
import com.unciv.ui.utils.extensions.toLabel
|
||||
import com.unciv.utils.Log
|
||||
|
||||
open class Portrait(val type: Type, val imageName: String, val size: Float, val borderSize: Float = 2f) : Group() {
|
||||
|
||||
enum class Type(val directory: String) {
|
||||
Unit("Unit"),
|
||||
Building("Building"),
|
||||
Tech("Tech"),
|
||||
Resource("Resource"),
|
||||
Improvement("Improvement"),
|
||||
Promotion("UnitPromotion"),
|
||||
Unique("Unique"),
|
||||
Nation("Nation"),
|
||||
Religion("Religion"),
|
||||
UnitAction("UnitAction")
|
||||
}
|
||||
|
||||
val image: Image
|
||||
val background: Group
|
||||
val ruleset: Ruleset = ImageGetter.ruleset
|
||||
|
||||
var isPortrait = false
|
||||
|
||||
val pathPortrait = "${type.directory}Portraits/$imageName"
|
||||
val pathPortraitFallback = "${type.directory}Portraits/Fallback"
|
||||
val pathIcon = "${type.directory}Icons/$imageName"
|
||||
val pathIconFallback = "${type.directory}Icons/Fallback"
|
||||
|
||||
open fun getDefaultInnerBackgroundTint(): Color { return Color.WHITE.cpy() }
|
||||
open fun getDefaultOuterBackgroundTint(): Color { return Color.BLACK.cpy() }
|
||||
open fun getDefaultImageTint(): Color { return Color.WHITE.cpy() }
|
||||
open fun getDefaultImage(): Image {
|
||||
return when {
|
||||
ImageGetter.imageExists(pathIcon) -> ImageGetter.getImage(pathIcon)
|
||||
ImageGetter.imageExists(pathIconFallback) -> ImageGetter.getImage(pathIconFallback)
|
||||
else -> ImageGetter.getCircle()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
isTransform = false
|
||||
|
||||
image = getMainImage()
|
||||
background = getMainBackground()
|
||||
|
||||
this.setSize(size + borderSize, size + borderSize)
|
||||
|
||||
background.center(this)
|
||||
image.center(this)
|
||||
|
||||
this.addActor(background)
|
||||
this.addActor(image)
|
||||
|
||||
}
|
||||
|
||||
/** Inner image */
|
||||
private fun getMainImage() : Image {
|
||||
return when {
|
||||
ImageGetter.imageExists(pathPortrait) -> {
|
||||
isPortrait = true
|
||||
ImageGetter.getImage(pathPortrait)
|
||||
}
|
||||
ImageGetter.imageExists(pathPortraitFallback) -> {
|
||||
isPortrait = true
|
||||
ImageGetter.getImage(pathPortraitFallback)
|
||||
}
|
||||
else -> getDefaultImage().apply { color = getDefaultImageTint() }
|
||||
}
|
||||
}
|
||||
|
||||
/** Border / background */
|
||||
private fun getMainBackground() : Group {
|
||||
|
||||
if (isPortrait && ImageGetter.imageExists("${type.directory}Portraits/Background")) {
|
||||
val backgroundImage = ImageGetter.getImage("${type.directory}Portraits/Background")
|
||||
val ratioW = image.width / backgroundImage.width
|
||||
val ratioH = image.height / backgroundImage.height
|
||||
image.setSize((size + borderSize)*ratioW, (size + borderSize)*ratioH)
|
||||
return backgroundImage.toGroup(size + borderSize)
|
||||
|
||||
} else {
|
||||
image.setSize(size*0.75f, size*0.75f)
|
||||
|
||||
val bg = Group().apply { isTransform = false }
|
||||
|
||||
val circleInner = ImageGetter.getCircle()
|
||||
val circleOuter = ImageGetter.getCircle()
|
||||
|
||||
circleInner.setSize(size, size)
|
||||
circleOuter.setSize(size + borderSize, size + borderSize)
|
||||
bg.setSize(size + borderSize, size + borderSize)
|
||||
|
||||
circleInner.align = Align.center
|
||||
circleOuter.align = Align.center
|
||||
|
||||
circleInner.color = getDefaultInnerBackgroundTint()
|
||||
circleOuter.color = getDefaultOuterBackgroundTint()
|
||||
|
||||
circleOuter.center(bg)
|
||||
circleInner.center(bg)
|
||||
|
||||
circleOuter.setOrigin(Align.center)
|
||||
circleInner.setOrigin(Align.center)
|
||||
|
||||
bg.addActor(circleOuter)
|
||||
bg.addActor(circleInner)
|
||||
|
||||
return bg
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PortraitResource(name: String, size: Float, amount: Int = 0) : Portrait(Type.Resource, name, size) {
|
||||
|
||||
init {
|
||||
if (amount > 0) {
|
||||
val label = amount.toString().toLabel(
|
||||
fontSize = 8,
|
||||
fontColor = Color.WHITE,
|
||||
alignment = Align.center)
|
||||
val amountGroup = label.surroundWithCircle(size/2, true, Color.BLACK)
|
||||
|
||||
label.y -= 0.5f
|
||||
amountGroup.x = width - amountGroup.width * 2 / 3
|
||||
amountGroup.y = -amountGroup.height / 3
|
||||
|
||||
addActor(amountGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultInnerBackgroundTint(): Color {
|
||||
return ruleset.tileResources[imageName]?.resourceType?.getColor() ?: Color.WHITE
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitTech(name: String, size: Float) : Portrait(Type.Tech, name, size) {
|
||||
override fun getDefaultOuterBackgroundTint(): Color {
|
||||
return getDefaultImageTint()
|
||||
}
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return ruleset.eras[ruleset.technologies[imageName]?.era()]?.getColor()?.darken(0.6f) ?: Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitUnit(name: String, size: Float) : Portrait(Type.Unit, name, size) {
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitBuilding(name: String, size: Float) : Portrait(Type.Building, name, size) {
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitUnique(name: String, size: Float) : Portrait(Type.Unique, name, size) {
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitReligion(name: String, size: Float) : Portrait(Type.Religion, name, size) {
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitUnitAction(name: String, size: Float) : Portrait(Type.UnitAction, name, size) {
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return Color.BLACK
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitImprovement(name: String, size: Float, dim: Boolean = false) : Portrait(Type.Improvement, name, size) {
|
||||
|
||||
init {
|
||||
if (dim) {
|
||||
image.color.a = 0.7f
|
||||
background.color.a = 0.7f
|
||||
}
|
||||
}
|
||||
|
||||
private fun getColorFromStats(stats: Stats): Color {
|
||||
if (stats.asSequence().none { it.value > 0 })
|
||||
return Color.WHITE
|
||||
return stats.asSequence().maxByOrNull { it.value }!!.key.color
|
||||
}
|
||||
|
||||
override fun getDefaultInnerBackgroundTint(): Color {
|
||||
val improvement = ImageGetter.ruleset.tileImprovements[imageName]
|
||||
if (improvement != null)
|
||||
return getColorFromStats(improvement)
|
||||
return Color.WHITE
|
||||
}
|
||||
}
|
||||
|
||||
class PortraitNation(name: String, size: Float) : Portrait(Type.Nation, name, size, size*0.1f) {
|
||||
|
||||
override fun getDefaultImage(): Image {
|
||||
|
||||
val nation = ruleset.nations[imageName]
|
||||
val isCityState = nation != null && nation.isCityState()
|
||||
val pathCityState = "NationIcons/CityState"
|
||||
|
||||
return when {
|
||||
ImageGetter.imageExists(pathIcon) -> ImageGetter.getImage(pathIcon)
|
||||
isCityState && ImageGetter.imageExists(pathCityState)-> ImageGetter.getImage(pathCityState)
|
||||
ImageGetter.imageExists(pathIconFallback) -> ImageGetter.getImage(pathIconFallback)
|
||||
else -> ImageGetter.getCircle()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultInnerBackgroundTint(): Color {
|
||||
return ruleset.nations[imageName]?.getOuterColor() ?: Color.BLACK
|
||||
}
|
||||
|
||||
override fun getDefaultOuterBackgroundTint(): Color {
|
||||
return getDefaultImageTint()
|
||||
}
|
||||
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return ruleset.nations[imageName]?.getInnerColor() ?: Color.WHITE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PortraitPromotion(name: String, size: Float) : Portrait(Type.Promotion, name, size) {
|
||||
|
||||
var level = 0
|
||||
|
||||
init {
|
||||
if (level > 0) {
|
||||
val padding = if (level == 3) 0.5f else 2f
|
||||
val starTable = Table().apply { defaults().pad(padding) }
|
||||
for (i in 1..level)
|
||||
starTable.add(ImageGetter.getImage("OtherIcons/Star")).size(size / 4f)
|
||||
starTable.centerX(this)
|
||||
starTable.y = size / 6f
|
||||
addActor(starTable)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultImage(): Image {
|
||||
|
||||
val nameWithoutBrackets = imageName.replace("[", "").replace("]", "")
|
||||
|
||||
level = when {
|
||||
nameWithoutBrackets.endsWith(" I") -> 1
|
||||
nameWithoutBrackets.endsWith(" II") -> 2
|
||||
nameWithoutBrackets.endsWith(" III") -> 3
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val basePromotionName = nameWithoutBrackets.dropLast(if (level == 0) 0 else level + 1)
|
||||
|
||||
val pathWithoutBrackets = "UnitPromotionIcons/$nameWithoutBrackets"
|
||||
val pathBase = "UnitPromotionIcons/$basePromotionName"
|
||||
val pathUnit = "UnitIcons/${basePromotionName.removeSuffix(" ability")}"
|
||||
|
||||
return when {
|
||||
ImageGetter.imageExists(pathWithoutBrackets) -> {
|
||||
level = 0
|
||||
ImageGetter.getImage(pathWithoutBrackets)
|
||||
}
|
||||
ImageGetter.imageExists(pathBase) -> ImageGetter.getImage(pathBase)
|
||||
ImageGetter.imageExists(pathUnit) -> ImageGetter.getImage(pathUnit)
|
||||
else -> ImageGetter.getImage(pathIconFallback)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDefaultImageTint(): Color {
|
||||
return colorFromRGB(255, 226, 0)
|
||||
}
|
||||
|
||||
override fun getDefaultOuterBackgroundTint(): Color {
|
||||
return getDefaultImageTint()
|
||||
}
|
||||
|
||||
override fun getDefaultInnerBackgroundTint(): Color {
|
||||
return colorFromRGB(0, 12, 49)
|
||||
}
|
||||
|
||||
}
|
@ -33,8 +33,8 @@ class NationTable(val nation: Nation, width: Float, minHeight: Float, ruleset: R
|
||||
"NewGameScreen/NationTable/Title", tintColor = outerColor
|
||||
)
|
||||
val nationIndicator: Actor =
|
||||
if (nation.name == Constants.random) ImageGetter.getRandomNationIndicator(50f)
|
||||
else ImageGetter.getNationIndicator(nation, 50f)
|
||||
if (nation.name == Constants.random) ImageGetter.getRandomNationPortrait(50f)
|
||||
else ImageGetter.getNationPortrait(nation, 50f)
|
||||
titleTable.add(nationIndicator).pad(10f).padLeft(0f) // left 0 for centering _with_ label
|
||||
|
||||
val titleText = if (ruleset == null || nation.name == Constants.random || nation.name == Constants.spectator)
|
||||
|
@ -219,8 +219,8 @@ class PlayerPickerTable(
|
||||
val nationTable = Table()
|
||||
val nationImage =
|
||||
if (player.chosenCiv == Constants.random)
|
||||
ImageGetter.getRandomNationIndicator(40f)
|
||||
else ImageGetter.getNationIndicator(previousScreen.ruleset.nations[player.chosenCiv]!!, 40f)
|
||||
ImageGetter.getRandomNationPortrait(40f)
|
||||
else ImageGetter.getNationPortrait(previousScreen.ruleset.nations[player.chosenCiv]!!, 40f)
|
||||
nationTable.add(nationImage).pad(5f)
|
||||
nationTable.add(player.chosenCiv.toLabel()).pad(5f)
|
||||
nationTable.touchable = Touchable.enabled
|
||||
|
@ -194,7 +194,7 @@ class CityOverviewTab(
|
||||
|
||||
val construction = city.cityConstructions.currentConstructionFromQueue
|
||||
if (construction.isNotEmpty()) {
|
||||
cityInfoTableDetails.add(ImageGetter.getPortraitImage(construction, iconSize*0.8f)).padRight(paddingHorz)
|
||||
cityInfoTableDetails.add(ImageGetter.getConstructionPortrait(construction, iconSize*0.8f)).padRight(paddingHorz)
|
||||
} else {
|
||||
cityInfoTableDetails.add()
|
||||
}
|
||||
@ -216,7 +216,7 @@ class CityOverviewTab(
|
||||
cityInfoTableDetails.add(image)
|
||||
}
|
||||
city.demandedResource.isNotEmpty() -> {
|
||||
val image = ImageGetter.getResourceImage(city.demandedResource, iconSize*0.7f)
|
||||
val image = ImageGetter.getResourcePortrait(city.demandedResource, iconSize*0.7f)
|
||||
image.addTooltip("Demanding [${city.demandedResource}]", 18f, tipAlign = Align.topLeft)
|
||||
cityInfoTableDetails.add(image).padLeft(iconSize*0.3f)
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class EspionageOverviewScreen(val civInfo: CivilizationInfo) : PickerScreen(true
|
||||
}
|
||||
|
||||
private fun addCityToSelectionTable(city: CityInfo) {
|
||||
citySelectionTable.add(ImageGetter.getNationIndicator(city.civInfo.nation, 30f)).pad(5f)
|
||||
citySelectionTable.add(ImageGetter.getNationPortrait(city.civInfo.nation, 30f)).pad(5f)
|
||||
citySelectionTable.add(city.name.toLabel()).pad(5f)
|
||||
if (city.espionage.hasSpyOf(civInfo)) {
|
||||
citySelectionTable.add(
|
||||
|
@ -16,7 +16,6 @@ import com.unciv.logic.civilization.diplomacy.DiplomacyFlags
|
||||
import com.unciv.logic.civilization.diplomacy.DiplomaticStatus
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.models.ruleset.Policy.PolicyBranchType
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.trade.DiplomacyScreen
|
||||
import com.unciv.ui.utils.AutoScrollPane
|
||||
@ -99,7 +98,7 @@ class GlobalPoliticsOverviewTable (
|
||||
civilizations.removeAll(civilizations.filter { it.isBarbarian() || it.isCityState() || it.isSpectator() })
|
||||
for (civ in civilizations) {
|
||||
// civ image
|
||||
add(ImageGetter.getNationIndicator(civ.nation, 100f)).pad(20f)
|
||||
add(ImageGetter.getNationPortrait(civ.nation, 100f)).pad(20f)
|
||||
|
||||
addSeparatorVertical(Color.GRAY)
|
||||
|
||||
@ -314,7 +313,7 @@ class GlobalPoliticsOverviewTable (
|
||||
|
||||
private fun getCivMiniTable(civInfo: CivilizationInfo): Table {
|
||||
val table = Table()
|
||||
table.add(ImageGetter.getNationIndicator(civInfo.nation, 25f)).pad(5f)
|
||||
table.add(ImageGetter.getNationPortrait(civInfo.nation, 25f)).pad(5f)
|
||||
table.add(civInfo.civName.toLabel()).left().padRight(10f)
|
||||
table.touchable = Touchable.enabled
|
||||
table.onClick {
|
||||
@ -409,7 +408,7 @@ class GlobalPoliticsOverviewTable (
|
||||
val civCount = undefeatedCivs.count()
|
||||
|
||||
for ((i, civ) in undefeatedCivs.withIndex()) {
|
||||
val civGroup = ImageGetter.getNationIndicator(civ.nation, 30f)
|
||||
val civGroup = ImageGetter.getNationPortrait(civ.nation, 30f)
|
||||
|
||||
val vector = HexMath.getVectorForAngle(2 * Math.PI.toFloat() * i / civCount)
|
||||
civGroup.center(this)
|
||||
|
@ -90,11 +90,11 @@ class ReligionOverviewTab(
|
||||
for (religion in existingReligions) {
|
||||
val image = if (religion.isPantheon()) {
|
||||
if (viewingPlayer.knows(religion.foundingCivName) || viewingPlayer.civName == religion.foundingCivName)
|
||||
ImageGetter.getNationIndicator(religion.getFounder().nation, 60f)
|
||||
ImageGetter.getNationPortrait(religion.getFounder().nation, 60f)
|
||||
else
|
||||
ImageGetter.getRandomNationIndicator(60f)
|
||||
ImageGetter.getRandomNationPortrait(60f)
|
||||
} else {
|
||||
ImageGetter.getCircledReligionIcon(religion.getIconName(), 60f)
|
||||
ImageGetter.getReligionPortrait(religion.getIconName(), 60f)
|
||||
}
|
||||
val button = Button(image, BaseScreen.skin)
|
||||
|
||||
|
@ -77,7 +77,7 @@ class ResourcesOverviewTab(
|
||||
private fun ResourceSupplyList.getTotalLabel(resource: TileResource): Label =
|
||||
filter { it.resource == resource }.sumOf { it.amount }.toLabel()
|
||||
private fun getResourceImage(name: String) =
|
||||
ImageGetter.getResourceImage(name, iconSize).apply {
|
||||
ImageGetter.getResourcePortrait(name, iconSize).apply {
|
||||
onClick {
|
||||
if (viewingPlayer.gameInfo.notifyExploredResources(viewingPlayer, name, 0, true))
|
||||
overviewScreen.game.popScreen()
|
||||
|
@ -203,7 +203,7 @@ class UnitOverviewTab(
|
||||
val promotionsTable = Table()
|
||||
// getPromotions goes by json order on demand, so this is same sorting as on picker
|
||||
for (promotion in unit.promotions.getPromotions(true))
|
||||
promotionsTable.add(ImageGetter.getPromotionIcon(promotion.name))
|
||||
promotionsTable.add(ImageGetter.getPromotionPortrait(promotion.name))
|
||||
if (unit.promotions.canBePromoted())
|
||||
promotionsTable.add(
|
||||
ImageGetter.getImage("OtherIcons/Star").apply {
|
||||
|
@ -19,7 +19,7 @@ class DiplomaticVotePickerScreen(private val votingCiv: CivilizationInfo) : Pick
|
||||
val choosableCivs = votingCiv.gameInfo.civilizations.filter { it.isMajorCiv() && it != votingCiv && !it.isDefeated() }
|
||||
for (civ in choosableCivs)
|
||||
{
|
||||
val button = PickerPane.getPickerOptionButton(ImageGetter.getNationIndicator(civ.nation, PickerPane.pickerOptionIconSize), civ.civName)
|
||||
val button = PickerPane.getPickerOptionButton(ImageGetter.getNationPortrait(civ.nation, PickerPane.pickerOptionIconSize), civ.civName)
|
||||
button.pack()
|
||||
button.onClick {
|
||||
chosenCiv = civ.civName
|
||||
|
@ -35,7 +35,7 @@ class DiplomaticVoteResultScreen(val votesCast: HashMap<String, String>, val vie
|
||||
val civ = gameInfo.civilizations.firstOrNull { it.civName == civName }
|
||||
if (civ == null || civ.isDefeated()) return
|
||||
|
||||
topTable.add(ImageGetter.getNationIndicator(civ.nation, 30f)).pad(10f)
|
||||
topTable.add(ImageGetter.getNationPortrait(civ.nation, 30f)).pad(10f)
|
||||
topTable.add(civName.toLabel()).pad(20f)
|
||||
if (civName !in votesCast.keys) {
|
||||
topTable.add("Abstained".toLabel()).row()
|
||||
@ -49,7 +49,7 @@ class DiplomaticVoteResultScreen(val votesCast: HashMap<String, String>, val vie
|
||||
}
|
||||
|
||||
topTable.add("Voted for".toLabel()).pad(20f)
|
||||
topTable.add(ImageGetter.getNationIndicator(votedCiv.nation, 30f)).pad(10f)
|
||||
topTable.add(ImageGetter.getNationPortrait(votedCiv.nation, 30f)).pad(10f)
|
||||
topTable.add(votedCiv.civName.toLabel()).row()
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ class ImprovementPickerScreen(
|
||||
else suggestRemoval = true
|
||||
}
|
||||
|
||||
val image = ImageGetter.getImprovementIcon(improvement.name, 30f)
|
||||
val image = ImageGetter.getImprovementPortrait(improvement.name, 30f)
|
||||
|
||||
// allow multiple key mappings to technologically supersede each other
|
||||
var shortcutKey = improvement.shortcutKey
|
||||
@ -205,11 +205,11 @@ class ImprovementPickerScreen(
|
||||
|
||||
// icon for adding the resource by improvement
|
||||
if (provideResource)
|
||||
statIcons.add(ImageGetter.getResourceImage(tileInfo.resource.toString(), 30f)).pad(3f)
|
||||
statIcons.add(ImageGetter.getResourcePortrait(tileInfo.resource.toString(), 30f)).pad(3f)
|
||||
|
||||
// icon for removing the resource by replacing improvement
|
||||
if (removeImprovement && tileInfo.hasViewableResource(currentPlayerCiv) && tileInfo.improvement != null && tileInfo.tileResource.isImprovedBy(tileInfo.improvement!!)) {
|
||||
val resourceIcon = ImageGetter.getResourceImage(tileInfo.resource!!, 30f)
|
||||
val resourceIcon = ImageGetter.getResourcePortrait(tileInfo.resource!!, 30f)
|
||||
statIcons.add(ImageGetter.getCrossedImage(resourceIcon, 30f))
|
||||
}
|
||||
return statIcons
|
||||
|
@ -101,7 +101,7 @@ class PromotionButton(
|
||||
|
||||
pad(5f)
|
||||
align(Align.left)
|
||||
add(ImageGetter.getPromotionIcon(node.promotion.name)).padRight(10f)
|
||||
add(ImageGetter.getPromotionPortrait(node.promotion.name)).padRight(10f)
|
||||
add(label).left().maxWidth(130f)
|
||||
|
||||
updateColor()
|
||||
|
@ -117,7 +117,7 @@ class ReligiousBeliefsPickerScreen (
|
||||
AskTextPopup(
|
||||
this,
|
||||
label = "Choose a name for your religion",
|
||||
icon = ImageGetter.getCircledReligionIcon(religionName!!, 80f),
|
||||
icon = ImageGetter.getReligionPortrait(religionName!!, 80f),
|
||||
defaultText = religionName!!,
|
||||
validate = { religionName ->
|
||||
religionName != Constants.noReligionName
|
||||
@ -150,7 +150,7 @@ class ReligiousBeliefsPickerScreen (
|
||||
for (religionName in ruleset.religions) {
|
||||
if (religionName == this.religionName)
|
||||
scrollTo = iconsTable.packIfNeeded().prefWidth
|
||||
val button = Button(ImageGetter.getCircledReligionIcon(religionName, 60f), skin)
|
||||
val button = Button(ImageGetter.getReligionPortrait(religionName, 60f), skin)
|
||||
buttonSetup(button, religionName)
|
||||
if (religionName == this.religionName) button.disable(Color(greenDisableColor))
|
||||
else if (gameInfo.religions.keys.any { it == religionName }) button.disable(redDisableColor)
|
||||
|
@ -6,7 +6,6 @@ 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.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.civilization.TechManager
|
||||
import com.unciv.models.ruleset.Building
|
||||
import com.unciv.models.ruleset.tile.TileImprovement
|
||||
@ -19,13 +18,9 @@ import com.unciv.ui.utils.extensions.addBorder
|
||||
import com.unciv.ui.utils.extensions.brighten
|
||||
import com.unciv.ui.utils.extensions.center
|
||||
import com.unciv.ui.utils.extensions.centerY
|
||||
import com.unciv.ui.utils.extensions.colorFromRGB
|
||||
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.surroundWithThinCircle
|
||||
import com.unciv.ui.utils.extensions.toGroup
|
||||
import com.unciv.ui.utils.extensions.toLabel
|
||||
|
||||
class TechButton(techName:String, private val techManager: TechManager, isWorldScreen: Boolean = true) : Table(BaseScreen.skin) {
|
||||
@ -52,8 +47,7 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
||||
|
||||
pad(0f).padBottom(5f).padTop(5f).padLeft(5f).padRight(0f)
|
||||
|
||||
val isResearched = (techManager.isResearched(techName) && techName != Constants.futureTech)
|
||||
add(ImageGetter.getTechIconGroup(techName, 46f, isResearched))
|
||||
add(ImageGetter.getTechIconPortrait(techName, 46f))
|
||||
.padRight(5f).padLeft(2f).left()
|
||||
|
||||
if (isWorldScreen) {
|
||||
@ -112,18 +106,18 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
||||
val icons = ArrayList<Group>()
|
||||
|
||||
for (unit in tech.getEnabledUnits(ruleset, techManager.civInfo)) {
|
||||
icons.add(ImageGetter.getPortraitImage(unit.name, techIconSize))
|
||||
icons.add(ImageGetter.getConstructionPortrait(unit.name, techIconSize))
|
||||
}
|
||||
|
||||
for (building in tech.getEnabledBuildings(ruleset, techManager.civInfo)) {
|
||||
icons.add(ImageGetter.getPortraitImage(building.name, techIconSize))
|
||||
icons.add(ImageGetter.getConstructionPortrait(building.name, techIconSize))
|
||||
}
|
||||
|
||||
for (obj in tech.getObsoletedObjects(ruleset, techManager.civInfo)) {
|
||||
val obsoletedIcon = when (obj) {
|
||||
is Building -> ImageGetter.getPortraitImage(obj.name, techIconSize)
|
||||
is TileResource -> ImageGetter.getResourceImage(obj.name, techIconSize)
|
||||
is TileImprovement -> ImageGetter.getImprovementIcon(obj.name, techIconSize)
|
||||
is Building -> ImageGetter.getConstructionPortrait(obj.name, techIconSize)
|
||||
is TileResource -> ImageGetter.getResourcePortrait(obj.name, techIconSize)
|
||||
is TileImprovement -> ImageGetter.getImprovementPortrait(obj.name, techIconSize)
|
||||
else -> continue
|
||||
}.also {
|
||||
val closeImage = ImageGetter.getRedCross(techIconSize / 2, 1f)
|
||||
@ -134,36 +128,31 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
|
||||
}
|
||||
|
||||
for (resource in ruleset.tileResources.values.filter { it.revealedBy == techName }) {
|
||||
icons.add(ImageGetter.getResourceImage(resource.name, techIconSize))
|
||||
icons.add(ImageGetter.getResourcePortrait(resource.name, techIconSize))
|
||||
}
|
||||
|
||||
for (improvement in ruleset.tileImprovements.values.asSequence()
|
||||
.filter { it.techRequired == techName }
|
||||
.filter { it.uniqueTo == null || it.uniqueTo == civName }
|
||||
) {
|
||||
icons.add(ImageGetter.getImprovementIcon(improvement.name, techIconSize, true))
|
||||
icons.add(ImageGetter.getImprovementPortrait(improvement.name, techIconSize))
|
||||
}
|
||||
|
||||
for (improvement in ruleset.tileImprovements.values.asSequence()
|
||||
.filter { it.uniqueObjects.any { u -> u.allParams.contains(techName) } }
|
||||
.filter { it.uniqueTo == null || it.uniqueTo == civName }
|
||||
) {
|
||||
icons.add(
|
||||
ImageGetter.getImage("OtherIcons/Unique")
|
||||
.surroundWithCircle(techIconSize)
|
||||
.surroundWithThinCircle())
|
||||
icons.add(ImageGetter.getUniquePortrait(improvement.name, techIconSize))
|
||||
}
|
||||
|
||||
for (unique in tech.uniques) {
|
||||
icons.add(
|
||||
when (unique) {
|
||||
UniqueType.EnablesCivWideStatProduction.text.replace("civWideStat", "Gold" )
|
||||
-> ImageGetter.getImage("OtherIcons/ConvertGold").toGroup(techIconSize)
|
||||
-> ImageGetter.getConstructionPortrait("Gold", techIconSize)
|
||||
UniqueType.EnablesCivWideStatProduction.text.replace("civWideStat", "Science" )
|
||||
-> ImageGetter.getImage("OtherIcons/ConvertScience").toGroup(techIconSize)
|
||||
else -> ImageGetter.getImage("OtherIcons/Unique")
|
||||
.surroundWithCircle(techIconSize)
|
||||
.surroundWithThinCircle()
|
||||
-> ImageGetter.getConstructionPortrait("Science", techIconSize)
|
||||
else -> ImageGetter.getUniquePortrait(unique, techIconSize)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.ui.popup
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextField
|
||||
import com.unciv.ui.images.IconCircleGroup
|
||||
@ -24,7 +25,7 @@ import com.unciv.ui.utils.extensions.toLabel
|
||||
class AskTextPopup(
|
||||
screen: BaseScreen,
|
||||
label: String = "Please enter some text",
|
||||
icon: IconCircleGroup = ImageGetter.getImage("OtherIcons/Pencil").apply { this.color = Color.BLACK }.surroundWithCircle(80f),
|
||||
icon: Group = ImageGetter.getImage("OtherIcons/Pencil").apply { this.color = Color.BLACK }.surroundWithCircle(80f),
|
||||
defaultText: String = "",
|
||||
errorText: String = "Invalid input! Please enter a different string.",
|
||||
maxLength: Int = 32,
|
||||
|
@ -7,10 +7,8 @@ import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.Actions
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.battle.CityCombatant
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.CityInfo
|
||||
@ -26,14 +24,10 @@ import com.unciv.ui.trade.DiplomacyScreen
|
||||
import com.unciv.ui.utils.BaseScreen
|
||||
import com.unciv.ui.utils.BorderedTable
|
||||
import com.unciv.ui.utils.Fonts
|
||||
import com.unciv.ui.utils.extensions.brighten
|
||||
import com.unciv.ui.utils.extensions.center
|
||||
import com.unciv.ui.utils.extensions.centerX
|
||||
import com.unciv.ui.utils.extensions.colorFromRGB
|
||||
import com.unciv.ui.utils.extensions.onClick
|
||||
import com.unciv.ui.utils.extensions.setSize
|
||||
import com.unciv.ui.utils.extensions.surroundWithCircle
|
||||
import com.unciv.ui.utils.extensions.surroundWithThinCircle
|
||||
import com.unciv.ui.utils.extensions.toGroup
|
||||
import com.unciv.ui.utils.extensions.toLabel
|
||||
import kotlin.math.max
|
||||
@ -321,7 +315,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
if (!forPopup) {
|
||||
val cityReligion = city.religion.getMajorityReligion()
|
||||
if (cityReligion != null) {
|
||||
val religionImage = ImageGetter.getReligionImage(cityReligion.getIconName()).apply {
|
||||
val religionImage = ImageGetter.getReligionIcon(cityReligion.getIconName()).apply {
|
||||
color = secondaryColor }.toGroup(20f)
|
||||
labelTable.add(religionImage).size(20f).padLeft(5f)
|
||||
}
|
||||
@ -451,7 +445,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
table.add(productionBar).padTop(1f).padBottom(1f)
|
||||
}
|
||||
|
||||
val constructionImage = ImageGetter.getPortraitImage(cityCurrentConstruction.name, 24f)
|
||||
val constructionImage = ImageGetter.getConstructionPortrait(cityCurrentConstruction.name, 24f)
|
||||
table.add(constructionImage).minHeight(32f).minWidth(26f)
|
||||
.expand().center().right().pad(0f).padRight(4f).padLeft(3f)
|
||||
table.pack()
|
||||
|
@ -127,14 +127,12 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
val shownImprovement = tileGroup.tileInfo.getShownImprovement(viewingCiv)
|
||||
if (shownImprovement == null || !showResourcesAndImprovements) return
|
||||
|
||||
val newImprovementImage = ImageGetter.getImprovementIcon(shownImprovement)
|
||||
val newImprovementImage = ImageGetter.getImprovementPortrait(shownImprovement, dim = false)
|
||||
tileGroup.miscLayerGroup.addActor(newImprovementImage)
|
||||
newImprovementImage.run {
|
||||
setSize(20f, 20f)
|
||||
center(tileGroup)
|
||||
this.x -= 22 // left
|
||||
this.y -= 10 // bottom
|
||||
color = Color.WHITE.cpy().apply { a = 0.7f }
|
||||
this.y -= 12 // bottom
|
||||
}
|
||||
improvementIcon = newImprovementImage
|
||||
}
|
||||
@ -170,7 +168,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
tileGroup.resourceImage?.remove()
|
||||
if (tileGroup.resource == null) tileGroup.resourceImage = null
|
||||
else {
|
||||
val newResourceIcon = ImageGetter.getResourceImage(tileGroup.tileInfo.resource!!, 20f, tileGroup.tileInfo.resourceAmount)
|
||||
val newResourceIcon = ImageGetter.getResourcePortrait(tileGroup.tileInfo.resource!!, 20f, tileGroup.tileInfo.resourceAmount)
|
||||
newResourceIcon.center(tileGroup)
|
||||
newResourceIcon.x = newResourceIcon.x - 22 // left
|
||||
newResourceIcon.y = newResourceIcon.y + 10 // top
|
||||
@ -215,7 +213,7 @@ class TileGroupIcons(val tileGroup: TileGroup) {
|
||||
var offsetY = (displayCount - 1) * 2f
|
||||
for (nation in nations.take(3).asReversed()) {
|
||||
val newNationIcon =
|
||||
ImageGetter.getNationIndicator(nation.second, 20f)
|
||||
ImageGetter.getNationPortrait(nation.second, 20f)
|
||||
tileGroup.miscLayerGroup.addActor(newNationIcon)
|
||||
newNationIcon.run {
|
||||
setSize(20f, 20f)
|
||||
|
@ -118,7 +118,7 @@ class DiplomacyScreen(
|
||||
selectCivY = leftSideTable.prefHeight
|
||||
}
|
||||
|
||||
val civIndicator = ImageGetter.getNationIndicator(civ.nation, nationIconSize)
|
||||
val civIndicator = ImageGetter.getNationPortrait(civ.nation, nationIconSize)
|
||||
|
||||
val relationLevel = civ.getDiplomacyManager(viewingCiv).relationshipLevel()
|
||||
val relationshipIcon = if (civ.isCityState() && relationLevel == RelationshipLevel.Ally)
|
||||
@ -202,7 +202,7 @@ class DiplomacyScreen(
|
||||
continue
|
||||
val name = supplyList.resource.name
|
||||
val wrapper = Table()
|
||||
val image = ImageGetter.getResourceImage(name, 30f)
|
||||
val image = ImageGetter.getResourcePortrait(name, 30f)
|
||||
wrapper.add(image).padRight(5f)
|
||||
wrapper.add(supplyList.amount.toLabel())
|
||||
resourcesTable.add(wrapper).padRight(20f)
|
||||
|
@ -30,7 +30,7 @@ class LeaderIntroTable (
|
||||
val nation = civInfo.nation
|
||||
val leaderPortraitFile = "LeaderIcons/" + nation.leaderName
|
||||
val leaderLabel = civInfo.getLeaderDisplayName().toLabel(fontSize = Constants.headingFontSize)
|
||||
val nationIndicator = ImageGetter.getNationIndicator(nation, 24f)
|
||||
val nationIndicator = ImageGetter.getNationPortrait(nation, 24f)
|
||||
if (nation.leaderName.isNotEmpty() && ImageGetter.imageExists(leaderPortraitFile)) {
|
||||
val nameTable = Table()
|
||||
nameTable.add(leaderLabel)
|
||||
|
@ -90,9 +90,9 @@ class OffersListScroll(
|
||||
val tradeLabel = offer.getOfferText(untradableOffers.sumBy(offer.name))
|
||||
val tradeIcon = when (offer.type) {
|
||||
Luxury_Resource, Strategic_Resource ->
|
||||
ImageGetter.getResourceImage(offer.name, 30f)
|
||||
ImageGetter.getResourcePortrait(offer.name, 30f)
|
||||
WarDeclaration ->
|
||||
ImageGetter.getNationIndicator(UncivGame.Current.gameInfo!!.ruleSet.nations[offer.name]!!, 30f)
|
||||
ImageGetter.getNationPortrait(UncivGame.Current.gameInfo!!.ruleSet.nations[offer.name]!!, 30f)
|
||||
else -> null
|
||||
}
|
||||
val tradeButton = IconTextButton(tradeLabel, tradeIcon).apply {
|
||||
|
@ -274,11 +274,11 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() {
|
||||
|| currentPlayer.isDefeated()
|
||||
|| currentPlayer.victoryManager.hasWon()
|
||||
) {
|
||||
civGroup.add(ImageGetter.getNationIndicator(civ.nation, 30f))
|
||||
civGroup.add(ImageGetter.getNationPortrait(civ.nation, 30f))
|
||||
backgroundColor = civ.nation.getOuterColor()
|
||||
labelColor = civ.nation.getInnerColor()
|
||||
} else {
|
||||
civGroup.add(ImageGetter.getRandomNationIndicator(30f))
|
||||
civGroup.add(ImageGetter.getRandomNationPortrait(30f))
|
||||
backgroundColor = Color.DARK_GRAY
|
||||
labelText = Constants.unknownNationName
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
.row()
|
||||
}
|
||||
} else { // Fallback
|
||||
add(ImageGetter.getPortraitImage(wonder.name, 100f)).pad(20f).row()
|
||||
add(ImageGetter.getConstructionPortrait(wonder.name, 100f)).pad(20f).row()
|
||||
}
|
||||
|
||||
val centerTable = Table()
|
||||
@ -227,7 +227,7 @@ class AlertPopup(val worldScreen: WorldScreen, val popupAlert: PopupAlert): Popu
|
||||
addSeparator()
|
||||
val centerTable = Table()
|
||||
centerTable.add(tech.quote.toLabel().apply { wrap = true }).width(worldScreen.stage.width / 3)
|
||||
centerTable.add(ImageGetter.getTechIconGroup(tech.name, 100f)).pad(20f)
|
||||
centerTable.add(ImageGetter.getTechIconPortrait(tech.name, 100f)).pad(20f)
|
||||
val descriptionScroll = ScrollPane(tech.getDescription(gameBasics).toLabel().apply { wrap = true })
|
||||
centerTable.add(descriptionScroll).width(worldScreen.stage.width / 3).maxHeight(worldScreen.stage.height / 2)
|
||||
add(centerTable).row()
|
||||
|
@ -151,7 +151,7 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
||||
val strategicResources = worldScreen.gameInfo.ruleSet.tileResources.values
|
||||
.filter { it.resourceType == ResourceType.Strategic }
|
||||
for (resource in strategicResources) {
|
||||
val resourceImage = ImageGetter.getResourceImage(resource.name, 20f)
|
||||
val resourceImage = ImageGetter.getResourcePortrait(resource.name, 20f)
|
||||
val resourceLabel = "0".toLabel()
|
||||
resourceActors += ResourceActors(resource, resourceLabel, resourceImage)
|
||||
}
|
||||
@ -241,7 +241,7 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() {
|
||||
|
||||
selectedCivLabel.setText(newCiv.tr())
|
||||
val nation = worldScreen.gameInfo.ruleSet.nations[worldScreen.selectedCiv.civName]!!
|
||||
val selectedCivIcon = ImageGetter.getNationIndicator(nation, 35f)
|
||||
val selectedCivIcon = ImageGetter.getNationPortrait(nation, 35f)
|
||||
selectedCivIconHolder.actor = selectedCivIcon
|
||||
invalidate()
|
||||
pack()
|
||||
|
@ -118,7 +118,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
|
||||
private fun getIcon(combatant:ICombatant) =
|
||||
if (combatant is MapUnitCombatant) UnitGroup(combatant.unit,25f)
|
||||
else ImageGetter.getNationIndicator(combatant.getCivInfo().nation, 25f)
|
||||
else ImageGetter.getNationPortrait(combatant.getCivInfo().nation, 25f)
|
||||
|
||||
private val quarterScreen = worldScreen.stage.width / 4
|
||||
|
||||
|
@ -251,7 +251,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table() {
|
||||
unitIconHolder.add(UnitGroup(selectedUnit!!, 30f)).pad(5f)
|
||||
|
||||
for (promotion in selectedUnit!!.promotions.getPromotions(true))
|
||||
promotionsTable.add(ImageGetter.getPromotionIcon(promotion.name))
|
||||
promotionsTable.add(ImageGetter.getPromotionPortrait(promotion.name))
|
||||
|
||||
// Since Clear also clears the listeners, we need to re-add them every time
|
||||
promotionsTable.onClick {
|
||||
|
@ -601,6 +601,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
- [pennant](https://thenounproject.com/term/pennant/194797/) by Sara Jeffries
|
||||
- [Maya civilization](https://thenounproject.com/term/maya-civilization/1715786/) by Olena Panasovska for The Maya
|
||||
- Aztec icon by Kāne, on Unciv Discord server
|
||||
- [Questionmark](https://thenounproject.com/icon/questionmark-4248169/) by YURR.studio for Random nation indicator
|
||||
- [View](https://thenounproject.com/icon/view-4211245/) by Adrien Coquet for Spectator
|
||||
|
||||
### Promotions
|
||||
|
||||
|
@ -41,11 +41,11 @@ These work best if they are square, between 100x100 and 256x256 pixels, and incl
|
||||
|
||||
For example, [here](https://github.com/yairm210/Unciv-leader-portrait-mod-example) is mod showing how to add leader portraits, which can complement the base game.
|
||||
|
||||
### Adding Unit, Building and Tech Portraits
|
||||
### Adding Portraits
|
||||
|
||||
The base game uses flat icons, colored to fit the civilization's flag colors, to denote units both on the map and in other UI elements. A mod can supply "Portraits" - static images that will remain uncolored - by adding their images to `/Images/UnitPortraits/`, `/Images/BuildingPortraits/` and '/Images/TechPortraits/', which will be used in all UI elements except for the world map. The file name must correspond exactly with the unit/building/tech name as defined in Units.json, Buildings.json or Techs.json or they will be ignored.
|
||||
The base game uses flat icons, surrounded with colored circles as backgrounds (e.g. for units to fit the civilization's flag colors), to denote entities such as: units, buildings, techs, resources, improvements, religions, promotions, uniques, unit actions and nations in the UI. A mod can supply "Portraits" - static images that will remain uncolored - by adding images to `/Images/<entityType>Portraits/` (e.g. `/Images/BuildingPortraits/`, /Images/ResourcesPortraits/, etc), which will be used in all UI elements (except for unit icons in the world map). The file name must correspond exactly with the unit/building/tech/resource/etc name defined in corresponding JSONs (e.g. Units.json, Buildings.json, TileResources.json, etc) or have the same name as the file they suppose to replace, or they will be ignored.
|
||||
|
||||
If mod supplies '/Images/TechPortraits/Background.png' image, it will be used as a background for tech portraits instead of default circle.
|
||||
If mod supplies '/Images/<entityType>Portraits/Background.png' images, they will be used as a background for corresponding portraits instead of default circle.
|
||||
|
||||
Portraits and backgrounds work best if they are full RGB square, between 100x100 and 256x256 pixels, and include some transparent border within that area.
|
||||
|
||||
|