Rework of City Screen: new Great People list + misc changes (#8180)

* Rework of City Screen: new Great People list + misc changes

* Added a bit of padding

* Buildings are united under one tabs, GP font icons replaced by tinted UnitIcons

* Fix color of separators

* Big update to "Detailed stats" UI

* Rebuild pngs

Co-authored-by: tunerzinc@gmail.com <vfylfhby>
Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
vegeta1k95
2022-12-21 10:46:35 +01:00
committed by GitHub
parent 47c21216b2
commit 2bc91f1216
19 changed files with 888 additions and 543 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 KiB

After

Width:  |  Height:  |  Size: 761 KiB

View File

@ -41,56 +41,91 @@ CityStateIcons/Religious
index: -1 index: -1
EmojiIcons/Culture EmojiIcons/Culture
rotate: false rotate: false
xy: 1270, 1122 xy: 1918, 1770
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Faith EmojiIcons/Faith
rotate: false rotate: false
xy: 1378, 1230 xy: 1270, 1020
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Food EmojiIcons/Food
rotate: false rotate: false
xy: 1486, 1344 xy: 1378, 1122
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Gold EmojiIcons/Gold
rotate: false rotate: false
xy: 1594, 1452 xy: 1486, 1230
size: 50, 50
orig: 50, 50
offset: 0, 0
index: -1
EmojiIcons/Great Artist
rotate: false
xy: 1594, 1338
size: 50, 50
orig: 50, 50
offset: 0, 0
index: -1
EmojiIcons/Great Engineer
rotate: false
xy: 1702, 1446
size: 50, 50
orig: 50, 50
offset: 0, 0
index: -1
EmojiIcons/Great General
rotate: false
xy: 356, 720
size: 50, 50
orig: 50, 50
offset: 0, 0
index: -1
EmojiIcons/Great Merchant
rotate: false
xy: 1004, 906
size: 50, 50
orig: 50, 50
offset: 0, 0
index: -1
EmojiIcons/Great Scientist
rotate: false
xy: 1810, 1604
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Happiness EmojiIcons/Happiness
rotate: false rotate: false
xy: 1702, 1554 xy: 1976, 1770
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Production EmojiIcons/Production
rotate: false rotate: false
xy: 414, 720 xy: 588, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Science EmojiIcons/Science
rotate: false rotate: false
xy: 530, 720 xy: 762, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
EmojiIcons/Turn EmojiIcons/Turn
rotate: false rotate: false
xy: 762, 720 xy: 1868, 1546
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -265,70 +300,70 @@ ImprovementIcons/Railroad
index: -1 index: -1
ImprovementIcons/Remove Fallout ImprovementIcons/Remove Fallout
rotate: false rotate: false
xy: 250, 0 xy: 1054, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Remove Forest ImprovementIcons/Remove Forest
rotate: false rotate: false
xy: 350, 0 xy: 1162, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Remove Jungle ImprovementIcons/Remove Jungle
rotate: false rotate: false
xy: 350, 0 xy: 1162, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Remove Marsh ImprovementIcons/Remove Marsh
rotate: false rotate: false
xy: 450, 0 xy: 838, 1187
size: 100, 100 size: 100, 99
orig: 100, 100 orig: 100, 99
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Remove Railroad ImprovementIcons/Remove Railroad
rotate: false rotate: false
xy: 550, 0 xy: 946, 1288
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Remove Road ImprovementIcons/Remove Road
rotate: false rotate: false
xy: 650, 0 xy: 1054, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Repair ImprovementIcons/Repair
rotate: false rotate: false
xy: 1270, 1720 xy: 1270, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Road ImprovementIcons/Road
rotate: false rotate: false
xy: 1162, 1504 xy: 1054, 1288
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Terrace farm ImprovementIcons/Terrace farm
rotate: false rotate: false
xy: 1378, 1396 xy: 1162, 1078
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ImprovementIcons/Trading post ImprovementIcons/Trading post
rotate: false rotate: false
xy: 1594, 1618 xy: 1378, 1288
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
@ -403,13 +438,6 @@ 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
@ -433,28 +461,28 @@ OtherIcons/Aircraft
index: -1 index: -1
OtherIcons/ArrowRight OtherIcons/ArrowRight
rotate: false rotate: false
xy: 838, 804 xy: 838, 805
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
NotificationIcons/MoveAutomatedUnits NotificationIcons/MoveAutomatedUnits
rotate: false rotate: false
xy: 838, 804 xy: 838, 805
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
NotificationIcons/NextUnit NotificationIcons/NextUnit
rotate: false rotate: false
xy: 838, 804 xy: 838, 805
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
StatIcons/Movement StatIcons/Movement
rotate: false rotate: false
xy: 838, 804 xy: 838, 805
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -475,7 +503,7 @@ OtherIcons/Banner
index: -1 index: -1
OtherIcons/Camera OtherIcons/Camera
rotate: false rotate: false
xy: 896, 829 xy: 1270, 987
size: 25, 25 size: 25, 25
orig: 25, 25 orig: 25, 25
offset: 0, 0 offset: 0, 0
@ -517,7 +545,7 @@ OtherIcons/Cities
index: -1 index: -1
OtherIcons/CityState OtherIcons/CityState
rotate: false rotate: false
xy: 1162, 1014 xy: 1810, 1662
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -587,21 +615,14 @@ OtherIcons/Hexagon
index: -1 index: -1
OtherIcons/Improvements OtherIcons/Improvements
rotate: false rotate: false
xy: 1918, 1770 xy: 1062, 906
size: 50, 50 size: 50, 50
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: 472, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -671,7 +692,7 @@ OtherIcons/Multiplayer
index: -1 index: -1
OtherIcons/Nations OtherIcons/Nations
rotate: false rotate: false
xy: 1976, 1770 xy: 530, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -783,140 +804,140 @@ OtherIcons/Quickstart
index: -1 index: -1
OtherIcons/Remove Heresy OtherIcons/Remove Heresy
rotate: false rotate: false
xy: 1054, 1504 xy: 1270, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Resources OtherIcons/Resources
rotate: false rotate: false
xy: 946, 1288 xy: 838, 1079
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Resume OtherIcons/Resume
rotate: false rotate: false
xy: 1054, 1396 xy: 946, 1180
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Search OtherIcons/Search
rotate: false rotate: false
xy: 1378, 1720 xy: 1270, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/SecretOptions OtherIcons/SecretOptions
rotate: false rotate: false
xy: 838, 1078 xy: 1378, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Settings OtherIcons/Settings
rotate: false rotate: false
xy: 1054, 1288 xy: 838, 971
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Shield OtherIcons/Shield
rotate: false rotate: false
xy: 1270, 1504 xy: 1054, 1180
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Sleep OtherIcons/Sleep
rotate: false rotate: false
xy: 838, 970 xy: 1378, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/Sleep UnitActionIcons/Sleep
rotate: false rotate: false
xy: 838, 970 xy: 1378, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Speaker OtherIcons/Speaker
rotate: false rotate: false
xy: 946, 1072 xy: 1486, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Spy OtherIcons/Spy
rotate: false rotate: false
xy: 1270, 1396 xy: 946, 964
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Spy_White OtherIcons/Spy_White
rotate: false rotate: false
xy: 1378, 1504 xy: 1054, 1072
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Star OtherIcons/Star
rotate: false rotate: false
xy: 1486, 1618 xy: 1162, 1186
size: 100, 94 size: 100, 94
orig: 100, 94 orig: 100, 94
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Stop OtherIcons/Stop
rotate: false rotate: false
xy: 1054, 1072 xy: 1594, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/Stop UnitActionIcons/Stop
rotate: false rotate: false
xy: 1054, 1072 xy: 1594, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/StopMove UnitActionIcons/StopMove
rotate: false rotate: false
xy: 1054, 1072 xy: 1594, 1612
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Swap OtherIcons/Swap
rotate: false rotate: false
xy: 1270, 1288 xy: 1054, 964
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/Swap UnitActionIcons/Swap
rotate: false rotate: false
xy: 1270, 1288 xy: 1054, 964
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Terrains OtherIcons/Terrains
rotate: false rotate: false
xy: 704, 720 xy: 1868, 1604
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Timer OtherIcons/Timer
rotate: false rotate: false
xy: 1486, 1510 xy: 1270, 1186
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
@ -930,35 +951,42 @@ OtherIcons/Triangle
index: -1 index: -1
OtherIcons/Turn right OtherIcons/Turn right
rotate: false rotate: false
xy: 1054, 964 xy: 1594, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Tyrannosaurus OtherIcons/Tyrannosaurus
rotate: false rotate: false
xy: 1162, 1072 xy: 1702, 1612
size: 100, 100
orig: 100, 100
offset: 0, 0
index: -1
OtherIcons/Unique
rotate: false
xy: 1810, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Wait OtherIcons/Wait
rotate: false rotate: false
xy: 1378, 1288 xy: 1270, 1078
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/Wait UnitActionIcons/Wait
rotate: false rotate: false
xy: 1378, 1288 xy: 1270, 1078
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
OtherIcons/Wonders OtherIcons/Wonders
rotate: false rotate: false
xy: 1810, 1720 xy: 1702, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
@ -1133,84 +1161,84 @@ ResourceIcons/Porcelain
index: -1 index: -1
ResourceIcons/Salt ResourceIcons/Salt
rotate: false rotate: false
xy: 1270, 1612 xy: 1162, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Sheep ResourceIcons/Sheep
rotate: false rotate: false
xy: 1162, 1396 xy: 946, 1072
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Silk ResourceIcons/Silk
rotate: false rotate: false
xy: 1378, 1612 xy: 1162, 1288
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Silver ResourceIcons/Silver
rotate: false rotate: false
xy: 1486, 1720 xy: 1270, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Spices ResourceIcons/Spices
rotate: false rotate: false
xy: 1162, 1288 xy: 838, 863
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Stone ResourceIcons/Stone
rotate: false rotate: false
xy: 946, 964 xy: 1486, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Sugar ResourceIcons/Sugar
rotate: false rotate: false
xy: 1162, 1180 xy: 1702, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Truffles ResourceIcons/Truffles
rotate: false rotate: false
xy: 1702, 1720 xy: 1486, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Uranium ResourceIcons/Uranium
rotate: false rotate: false
xy: 1270, 1180 xy: 1162, 970
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Whales ResourceIcons/Whales
rotate: false rotate: false
xy: 1486, 1402 xy: 1378, 1180
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Wheat ResourceIcons/Wheat
rotate: false rotate: false
xy: 1594, 1510 xy: 1486, 1288
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
ResourceIcons/Wine ResourceIcons/Wine
rotate: false rotate: false
xy: 1702, 1612 xy: 1594, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
@ -1250,20 +1278,6 @@ 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
@ -1273,7 +1287,7 @@ StatIcons/Happiness
index: -1 index: -1
StatIcons/InterceptRange StatIcons/InterceptRange
rotate: false rotate: false
xy: 356, 720 xy: 1810, 1546
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -1294,14 +1308,14 @@ StatIcons/Population
index: -1 index: -1
StatIcons/Range StatIcons/Range
rotate: false rotate: false
xy: 1062, 906 xy: 646, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
StatIcons/RangedStrength StatIcons/RangedStrength
rotate: false rotate: false
xy: 472, 720 xy: 704, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -1315,21 +1329,21 @@ StatIcons/ReligiousStrength
index: -1 index: -1
StatIcons/Resistance StatIcons/Resistance
rotate: false rotate: false
xy: 838, 1186 xy: 1378, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
StatIcons/Specialist StatIcons/Specialist
rotate: false rotate: false
xy: 1054, 1180 xy: 1594, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
StatIcons/Strength StatIcons/Strength
rotate: false rotate: false
xy: 646, 720 xy: 1868, 1662
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -1420,7 +1434,7 @@ UnitActionIcons/FoundCity
index: -1 index: -1
UnitActionIcons/HideMore UnitActionIcons/HideMore
rotate: false rotate: false
xy: 1810, 1662 xy: 414, 720
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
@ -1455,35 +1469,35 @@ UnitActionIcons/Upgrade
index: -1 index: -1
UnitActionIcons/RemoveHeresy UnitActionIcons/RemoveHeresy
rotate: false rotate: false
xy: 1162, 1612 xy: 1162, 1504
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/SetUp UnitActionIcons/SetUp
rotate: false rotate: false
xy: 946, 1180 xy: 1486, 1720
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/ShowMore UnitActionIcons/ShowMore
rotate: false rotate: false
xy: 588, 720 xy: 896, 805
size: 50, 50 size: 50, 50
orig: 50, 50 orig: 50, 50
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/Star UnitActionIcons/Star
rotate: false rotate: false
xy: 1594, 1726 xy: 1270, 1294
size: 100, 94 size: 100, 94
orig: 100, 94 orig: 100, 94
offset: 0, 0 offset: 0, 0
index: -1 index: -1
UnitActionIcons/StartGoldenAge UnitActionIcons/StartGoldenAge
rotate: false rotate: false
xy: 838, 862 xy: 1378, 1396
size: 100, 100 size: 100, 100
orig: 100, 100 orig: 100, 100
offset: 0, 0 offset: 0, 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 KiB

After

Width:  |  Height:  |  Size: 579 KiB

View File

@ -24,6 +24,11 @@ class StatTreeNode {
val children = LinkedHashMap<String, StatTreeNode>() val children = LinkedHashMap<String, StatTreeNode>()
private var innerStats: Stats? = null private var innerStats: Stats? = null
fun setInnerStat(stat: Stat, value: Float) {
if (innerStats == null) innerStats = Stats()
innerStats!![stat] = value
}
private fun addInnerStats(stats: Stats) { private fun addInnerStats(stats: Stats) {
if (innerStats == null) innerStats = stats.clone() // Copy the stats instead of referencing them if (innerStats == null) innerStats = stats.clone() // Copy the stats instead of referencing them
else innerStats!!.add(stats) // What happens if we add 2 stats to the same leaf? else innerStats!!.add(stats) // What happens if we add 2 stats to the same leaf?
@ -48,6 +53,13 @@ class StatTreeNode {
} }
} }
fun clone() : StatTreeNode {
val new = StatTreeNode()
new.innerStats = this.innerStats?.clone()
new.children.putAll(this.children)
return new
}
val totalStats: Stats val totalStats: Stats
get() { get() {
val toReturn = Stats() val toReturn = Stats()

View File

@ -82,6 +82,13 @@ class CityScreen(
} }
} }
private val detailedStatsButton = "Stats".toTextButton().apply {
labelCell.pad(10f)
onActivation {
DetailedStatsPopup(this@CityScreen).open()
}
}
/** Holds City tiles group*/ /** Holds City tiles group*/
private var tileGroups = ArrayList<CityTileGroup>() private var tileGroups = ArrayList<CityTileGroup>()
@ -127,6 +134,7 @@ class CityScreen(
stage.addActor(tileTable) stage.addActor(tileTable)
stage.addActor(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait stage.addActor(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait
stage.addActor(exitCityButton) stage.addActor(exitCityButton)
stage.addActor(detailedStatsButton)
update() update()
globalShortcuts.add(Input.Keys.LEFT) { page(-1) } globalShortcuts.add(Input.Keys.LEFT) { page(-1) }
@ -173,6 +181,8 @@ class CityScreen(
cityStatsTable.update(statsHeight) cityStatsTable.update(statsHeight)
cityStatsTable.setPosition(stage.width - posFromEdge, stage.height - posFromEdge, Align.topRight) cityStatsTable.setPosition(stage.width - posFromEdge, stage.height - posFromEdge, Align.topRight)
detailedStatsButton.setPosition(cityStatsTable.x - detailedStatsButton.width, stage.height - 20f, Align.top)
// Top center: Annex/Raze button // Top center: Annex/Raze button
updateAnnexAndRazeCityButton() updateAnnexAndRazeCityButton()

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Label 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.badlogic.gdx.utils.Align
@ -25,12 +26,17 @@ import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.ExpanderTab import com.unciv.ui.utils.ExpanderTab
import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.extensions.addSeparator import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.colorFromRGB import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.extensions.onClick 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.surroundWithCircle
import com.unciv.ui.utils.extensions.toGroup
import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toLabel
import java.text.DecimalFormat import java.text.DecimalFormat
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
import kotlin.math.round import kotlin.math.round
import com.unciv.ui.utils.AutoScrollPane as ScrollPane import com.unciv.ui.utils.AutoScrollPane as ScrollPane
@ -103,15 +109,13 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
// begin lowerTable // begin lowerTable
addCitizenManagement() addCitizenManagement()
addGreatPersonPointInfo(cityInfo)
if (!cityInfo.population.getMaxSpecialists().isEmpty()) { if (!cityInfo.population.getMaxSpecialists().isEmpty()) {
addSpecialistInfo() addSpecialistInfo()
} }
if (cityInfo.religion.getNumberOfFollowers().isNotEmpty() && cityInfo.civInfo.gameInfo.isReligionEnabled()) if (cityInfo.religion.getNumberOfFollowers().isNotEmpty() && cityInfo.civInfo.gameInfo.isReligionEnabled())
addReligionInfo() addReligionInfo()
addStatInfo()
addGreatPersonPointInfo(cityInfo)
addBuildingsInfo() addBuildingsInfo()
upperTable.pack() upperTable.pack()
@ -221,22 +225,40 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
} }
} }
// Buildings sorted alphabetically
wonders.sortBy { it.name }
specialistBuildings.sortBy { it.name }
otherBuildings.sortBy { it.name }
val totalTable = Table()
lowerTable.addCategory("Buildings", totalTable, false)
if (specialistBuildings.isNotEmpty()) { if (specialistBuildings.isNotEmpty()) {
val specialistBuildingsTable = Table() val specialistBuildingsTable = Table()
addCategory("Specialist Buildings", specialistBuildingsTable) totalTable.add().row()
totalTable.addSeparator(color = Color.LIGHT_GRAY)
totalTable.add("Specialist Buildings".toLabel().apply { setAlignment(Align.center) }).growX()
totalTable.addSeparator(color = Color.LIGHT_GRAY)
for (building in specialistBuildings) addBuildingButton(building, specialistBuildingsTable) for (building in specialistBuildings) addBuildingButton(building, specialistBuildingsTable)
totalTable.add(specialistBuildingsTable).growX().right().row()
} }
if (wonders.isNotEmpty()) { if (wonders.isNotEmpty()) {
val wondersTable = Table() val wondersTable = Table()
addCategory("Wonders", wondersTable) totalTable.addSeparator(color = Color.LIGHT_GRAY)
totalTable.add("Wonders".toLabel().apply { setAlignment(Align.center) }).growX()
totalTable.addSeparator(color = Color.LIGHT_GRAY)
for (building in wonders) addBuildingButton(building, wondersTable) for (building in wonders) addBuildingButton(building, wondersTable)
totalTable.add(wondersTable).growX().right().row()
} }
if (otherBuildings.isNotEmpty()) { if (otherBuildings.isNotEmpty()) {
val regularBuildingsTable = Table() val regularBuildingsTable = Table()
addCategory("Buildings", regularBuildingsTable) totalTable.addSeparator(color = Color.LIGHT_GRAY)
totalTable.add("Other".toLabel().apply { setAlignment(Align.center) }).growX()
totalTable.addSeparator(color = Color.LIGHT_GRAY)
for (building in otherBuildings) addBuildingButton(building, regularBuildingsTable) for (building in otherBuildings) addBuildingButton(building, regularBuildingsTable)
totalTable.add(regularBuildingsTable).growX().right().row()
} }
} }
@ -286,166 +308,75 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
cityScreen.update() cityScreen.update()
} }
destinationTable.add(button).pad(1f).expandX().right().row() destinationTable.add(button).pad(1f).padBottom(2f).padTop(2f).expandX().right().row()
} }
private fun addCategory(category: String, showHideTable: Table) { private fun Table.addCategory(category: String, showHideTable: Table, startsOpened: Boolean = true, innerPadding: Float = 10f) : ExpanderTab {
val expanderTab = ExpanderTab( val expanderTab = ExpanderTab(
title = category, title = category,
fontSize = Constants.defaultFontSize, fontSize = Constants.defaultFontSize,
persistenceID = "CityInfo.$category", persistenceID = "CityInfo.$category",
startsOutOpened = startsOpened,
defaultPad = innerPadding,
onChange = { onContentResize() } onChange = { onContentResize() }
) { ) {
it.add(showHideTable).fillX().right() it.add(showHideTable).fillX().right()
} }
lowerTable.add(expanderTab).growX().row() add(expanderTab).growX().row()
return expanderTab
} }
private fun addGreatPersonPointInfo(cityInfo: CityInfo) {
private fun addStatsToHashmap( val greatPeopleTable = Table()
statTreeNode: StatTreeNode,
hashMap: HashMap<String, Float>,
stat: Stat,
showDetails: Boolean,
indentation: Int = 0
) {
for ((name, child) in statTreeNode.children) {
val statAmount = child.totalStats[stat]
if (statAmount == 0f) continue
hashMap["- ".repeat(indentation) + name.tr()] = statAmount
if (showDetails) addStatsToHashmap(child, hashMap, stat, showDetails, indentation + 1)
}
}
private fun Table.addStatInfo() {
val cityStats = cityScreen.city.cityStats
val showFaith = cityScreen.city.civInfo.gameInfo.isReligionEnabled()
for (stat in Stat.values()) {
if (stat == Stat.Faith && !showFaith) continue
val statValuesTable = Table()
statValuesTable.touchable = Touchable.enabled
addCategory(stat.name, statValuesTable)
updateStatValuesTable(stat, cityStats, statValuesTable)
}
}
private fun updateStatValuesTable(
stat: Stat,
cityStats: CityStats,
statValuesTable: Table,
showDetails:Boolean = false
) {
statValuesTable.clear()
statValuesTable.defaults().pad(2f)
statValuesTable.onClick {
updateStatValuesTable(
stat,
cityStats,
statValuesTable,
!showDetails
)
onContentResize()
}
val relevantBaseStats = LinkedHashMap<String, Float>()
if (stat != Stat.Happiness)
addStatsToHashmap(cityStats.baseStatTree, relevantBaseStats, stat, showDetails)
else relevantBaseStats.putAll(cityStats.happinessList)
for (key in relevantBaseStats.keys.toList())
if (relevantBaseStats[key] == 0f) relevantBaseStats.remove(key)
if (relevantBaseStats.isEmpty()) return
statValuesTable.add("Base values".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).pad(4f)
.colspan(2).row()
var sumOfAllBaseValues = 0f
for (entry in relevantBaseStats) {
val specificStatValue = entry.value
if (!entry.key.startsWith('-'))
sumOfAllBaseValues += specificStatValue
statValuesTable.add(entry.key.toLabel()).left()
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
}
statValuesTable.addSeparator()
statValuesTable.add("Total".toLabel())
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
val relevantBonuses = LinkedHashMap<String, Float>()
addStatsToHashmap(cityStats.statPercentBonusTree, relevantBonuses, stat, showDetails)
val totalBonusStats = cityStats.statPercentBonusTree.totalStats
if (totalBonusStats[stat] != 0f) {
statValuesTable.add("Bonuses".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
.padTop(20f).row()
for ((source, bonusAmount) in relevantBonuses) {
statValuesTable.add(source.toLabel()).left()
statValuesTable.add(bonusAmount.toPercentLabel()).row() // negative bonus
}
statValuesTable.addSeparator()
statValuesTable.add("Total".toLabel())
statValuesTable.add(totalBonusStats[stat].toPercentLabel()).row() // negative bonus
statValuesTable.add("Final".toLabel(fontSize = FONT_SIZE_STAT_INFO_HEADER)).colspan(2)
.padTop(20f).row()
var finalTotal = 0f
for (entry in cityStats.finalStatList) {
val specificStatValue = entry.value[stat]
finalTotal += specificStatValue
if (specificStatValue == 0f) continue
statValuesTable.add(entry.key.toLabel())
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
}
statValuesTable.addSeparator()
statValuesTable.add("Total".toLabel())
statValuesTable.add(finalTotal.toOneDecimalLabel()).row()
}
statValuesTable.pack()
if (stat != Stat.Happiness) {
val toggleButton = getToggleButton(showDetails)
statValuesTable.addActor(toggleButton)
toggleButton.setPosition(0f, statValuesTable.height, Align.topLeft)
}
statValuesTable.padBottom(4f)
}
private fun getToggleButton(showDetails: Boolean): IconCircleGroup {
val label = (if (showDetails) "-" else "+").toLabel()
label.setAlignment(Align.center)
return label
.surroundWithCircle(25f, color = BaseScreen.skinStrings.skinConfig.baseColor)
.surroundWithCircle(27f, false)
}
private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) {
val greatPersonPoints = cityInfo.getGreatPersonPointsForNextTurn() val greatPersonPoints = cityInfo.getGreatPersonPointsForNextTurn()
val allGreatPersonNames = greatPersonPoints.asSequence().flatMap { it.value.keys }.distinct() val allGreatPersonNames = greatPersonPoints.asSequence().flatMap { it.value.keys }.distinct()
if (allGreatPersonNames.none())
return
for (greatPersonName in allGreatPersonNames) { for (greatPersonName in allGreatPersonNames) {
val expanderName = "[$greatPersonName] points"
val greatPersonTable = Table() var gppPerTurn = 0
addCategory(expanderName, greatPersonTable)
for ((source, gppCounter) in greatPersonPoints) { for ((_, gppCounter) in greatPersonPoints) {
val gppPointsFromSource = gppCounter[greatPersonName]!! val gppPointsFromSource = gppCounter[greatPersonName]!!
if (gppPointsFromSource == 0) continue if (gppPointsFromSource == 0) continue
greatPersonTable.add(source.toLabel()).padRight(10f) gppPerTurn += gppPointsFromSource
greatPersonTable.add(gppPointsFromSource.toLabel()).row()
} }
val info = Table()
info.add(ImageGetter.getUnitIcon(greatPersonName, Color.GOLD).toGroup(20f))
.left().padBottom(4f).padRight(5f)
info.add("$greatPersonName (+$gppPerTurn)".toLabel()).left().padBottom(4f).expandX().row()
val gppCurrent = cityInfo.civInfo.greatPeople.greatPersonPointsCounter[greatPersonName]
val gppNeeded = cityInfo.civInfo.greatPeople.pointsForNextGreatPerson
val percent = gppCurrent!! / gppNeeded.toFloat()
val progressBar = ImageGetter.ProgressBar(300f, 25f, false)
progressBar.setBackground(Color.BLACK.cpy().apply { a = 0.8f })
progressBar.setProgress(Color.ORANGE, percent)
progressBar.apply {
val bar = ImageGetter.getWhiteDot()
bar.color = Color.GRAY
bar.setSize(width+5f, height+5f)
bar.center(this)
addActor(bar)
bar.toBack()
}
progressBar.setLabel(Color.WHITE, "$gppCurrent/$gppNeeded", fontSize = 14)
info.add(progressBar).colspan(2).left().expandX().row()
greatPeopleTable.add(info).growX().top().padBottom(10f)
greatPeopleTable.add(ImageGetter.getPortraitImage(greatPersonName, 50f)).row()
} }
}
companion object { lowerTable.addCategory("Great People", greatPeopleTable)
private const val FONT_SIZE_STAT_INFO_HEADER = 22
private fun Float.toPercentLabel() =
"${if (this>0f) "+" else ""}${DecimalFormat("0.#").format(this)}%".toLabel()
private fun Float.toOneDecimalLabel() =
DecimalFormat("0.#").format(this).toLabel()
} }
} }

View File

@ -3,6 +3,7 @@ package com.unciv.ui.cityscreen
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
import com.unciv.logic.city.CityInfo import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo import com.unciv.logic.map.TileInfo
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
@ -46,11 +47,11 @@ class CityTileGroup(private val city: CityInfo, tileInfo: TileInfo, tileSetStrin
when { when {
tileInfo.getOwner() != city.civInfo -> { // outside of civ boundary tileInfo.getOwner() != city.civInfo -> { // outside of civ boundary
dim(0.3f) dim(0.3f)
yieldGroup.isVisible = true yieldGroup.isVisible = UncivGame.Current.settings.showTileYields
} }
tileInfo !in city.tilesInRange -> { // within city but not close enough to be workable tileInfo !in city.tilesInRange -> { // within city but not close enough to be workable
yieldGroup.isVisible = true yieldGroup.isVisible = UncivGame.Current.settings.showTileYields
dim(0.5f) dim(0.5f)
} }

View File

@ -0,0 +1,273 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.utils.Align
import com.unciv.logic.city.StatTreeNode
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.popup.Popup
import com.unciv.ui.utils.AutoScrollPane
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.extensions.addSeparator
import com.unciv.ui.utils.extensions.brighten
import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toLabel
import java.text.DecimalFormat
class DetailedStatsPopup(val cityScreen: CityScreen, stageToShowOn: Stage) : Popup(
stageToShowOn = stageToShowOn,
scrollable = false) {
constructor(screen: CityScreen) : this(screen, screen.stage)
private val totalTable = Table()
private var sourceHighlighted: String? = null
private var onlyWithStat: Stat? = null
private var isDetailed: Boolean = false
private val colorTotal: Color = Color.BLUE.brighten(0.5f)
private val colorSelector: Color = Color.GREEN.darken(0.5f)
init {
val scrollPane = AutoScrollPane(totalTable)
scrollPane.setOverscroll(false, false)
val scrollPaneCell = add(scrollPane)
scrollPaneCell.maxHeight(cityScreen.stage.height *3 / 4)
row()
addCloseButton("Cancel", KeyCharAndCode('n'))
update()
}
private fun update() {
totalTable.clear()
val cityStats = cityScreen.city.cityStats
val showFaith = cityScreen.city.civInfo.gameInfo.isReligionEnabled()
val stats = when {
onlyWithStat != null -> listOfNotNull(onlyWithStat)
!showFaith -> Stat.values().filter { it != Stat.Faith }
else -> Stat.values().toList()
}
totalTable.defaults().pad(3f).padLeft(0f).padRight(0f)
totalTable.add(getToggleButton(isDetailed).onClick {
isDetailed = !isDetailed
update() }).minWidth(150f).grow()
for (stat in stats) {
val label = (stat.character + " " + stat.name).toLabel()
label.onClick {
onlyWithStat = if (onlyWithStat == null) stat else null
update()
}
totalTable.add(wrapInTable(label, if (onlyWithStat == stat) colorSelector else null))
.minWidth(if (onlyWithStat == stat) 150f else 110f).grow()
}
totalTable.row()
totalTable.addSeparator().padBottom(2f)
totalTable.add("Base stats".toLabel().apply { setAlignment(Align.center) })
.colspan(totalTable.columns).padLeft(0f).padRight(0f).growX().row()
totalTable.addSeparator().padTop(2f)
traverseTree(totalTable, stats, cityStats.baseStatTree, mergeHappiness = true, percentage = false)
totalTable.addSeparator().padBottom(2f)
totalTable.add("Bonuses".toLabel().apply { setAlignment(Align.center) })
.colspan(totalTable.columns).padLeft(0f).padRight(0f).growX().row()
totalTable.addSeparator().padTop(2f)
traverseTree(totalTable, stats, cityStats.statPercentBonusTree, percentage = true)
totalTable.addSeparator().padBottom(2f)
totalTable.add("Final".toLabel().apply { setAlignment(Align.center) })
.colspan(totalTable.columns).padLeft(0f).padRight(0f).growX().row()
totalTable.addSeparator().padTop(2f)
val final = LinkedHashMap<Stat, Float>()
val map = cityStats.finalStatList.toSortedMap()
for ((key, value) in cityScreen.city.cityStats.happinessList) {
if (!map.containsKey(key)) {
map[key] = Stats()
map[key]!![Stat.Happiness] = value
} else if (map[key]!![Stat.Happiness] == 0f) {
map[key]!![Stat.Happiness] = value
}
}
for ((source, finalStats) in map) {
if (finalStats.all { it.value == 0f })
continue
if (onlyWithStat != null && finalStats[onlyWithStat!!] == 0f)
continue
val label = source.toLabel().apply {
setAlignment(Align.left)
onClick {
sourceHighlighted = if (sourceHighlighted == source) null else source
update()
}
}
var color: Color? = null
if (sourceHighlighted == source)
color = colorSelector
totalTable.add(wrapInTable(label, color, Align.left)).grow()
for (stat in stats) {
val value = finalStats[stat]
val cell = when (value) {
0f -> "-".toLabel()
else -> value.toOneDecimalLabel()
}
totalTable.add(wrapInTable(cell, color)).grow()
var f = final[stat]
if (f == null)
f = 0f
f += value
final[stat] = f
}
totalTable.row()
}
totalTable.add(wrapInTable("Total".toLabel(), colorTotal)).grow()
for (stat in stats) {
totalTable.add(wrapInTable(final[stat]?.toOneDecimalLabel(), colorTotal)).grow()
}
totalTable.row()
}
private fun getToggleButton(showDetails: Boolean): IconCircleGroup {
val label = (if (showDetails) "-" else "+").toLabel()
label.setAlignment(Align.center)
return label
.surroundWithCircle(25f, color = BaseScreen.skinStrings.skinConfig.baseColor)
.surroundWithCircle(27f, false)
}
private fun traverseTree(
table: Table,
stats: List<Stat>,
statTreeNode: StatTreeNode,
mergeHappiness: Boolean = false,
percentage: Boolean = false,
indentation: Int = 0
) {
val total = LinkedHashMap<Stat, Float>()
val map = statTreeNode.children.toSortedMap()
if (mergeHappiness) {
for ((key, value) in cityScreen.city.cityStats.happinessList) {
if (!map.containsKey(key)) {
map[key] = StatTreeNode()
map[key]?.setInnerStat(Stat.Happiness, value)
} else if (map[key]!!.totalStats.happiness == 0f) {
map[key]?.setInnerStat(Stat.Happiness, value)
}
}
}
for ((name, child) in map) {
val text = "- ".repeat(indentation) + name.tr()
if (child.totalStats.all { it.value == 0f }) {
table.row()
continue
}
if (onlyWithStat != null && child.totalStats[onlyWithStat!!] == 0f) {
table.row()
continue
}
val label = text.toLabel().apply {
setAlignment(Align.left)
onClick {
sourceHighlighted = if (sourceHighlighted == text) null else text
update()
}
}
var color: Color? = null
if (sourceHighlighted == text)
color = colorSelector
table.add(wrapInTable(label, color, Align.left)).fill().left()
for (stat in stats) {
val value = child.totalStats[stat]
val cell = when {
value == 0f -> "-".toLabel()
percentage -> value.toPercentLabel()
else -> value.toOneDecimalLabel()
}
table.add(wrapInTable(cell, color)).grow()
if (indentation == 0) {
var current = total[stat]
if (current == null)
current = 0f
total[stat] = current + value
}
}
table.row()
if (isDetailed)
traverseTree(table, stats, child, percentage = percentage, indentation = indentation + 1)
}
if (indentation == 0) {
table.add(wrapInTable("Total".toLabel(), colorTotal)).grow()
for (stat in stats) {
if (percentage)
table.add(wrapInTable(total[stat]?.toPercentLabel(), colorTotal)).grow()
else
table.add(wrapInTable(total[stat]?.toOneDecimalLabel(), colorTotal)).grow()
}
table.row()
}
}
private fun wrapInTable(label: Label?, color: Color? = null, align: Int = Align.center) : Table {
val tbl = Table()
label?.setAlignment(align)
if (color != null)
tbl.background = BaseScreen.skinStrings.getUiBackground("General/Border", tintColor = color)
tbl.add(label).growX()
return tbl
}
companion object {
private fun Float.toPercentLabel() =
"${if (this>0f) "+" else ""}${DecimalFormat("0.#").format(this)}%".toLabel()
private fun Float.toOneDecimalLabel() =
DecimalFormat("0.#").format(this).toLabel()
}
}

View File

@ -1,5 +1,6 @@
package com.unciv.ui.cityscreen package com.unciv.ui.cityscreen
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
@ -14,6 +15,7 @@ import com.unciv.ui.utils.extensions.addSeparatorVertical
import com.unciv.ui.utils.extensions.darken import com.unciv.ui.utils.extensions.darken
import com.unciv.ui.utils.extensions.onClick import com.unciv.ui.utils.extensions.onClick
import com.unciv.ui.utils.extensions.surroundWithCircle import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.toGroup
import com.unciv.ui.utils.extensions.toLabel import com.unciv.ui.utils.extensions.toLabel
class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) { class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
@ -104,13 +106,21 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
private fun getSpecialistStatsTable(specialistName: String): Table { private fun getSpecialistStatsTable(specialistName: String): Table {
val specialistStatTable = Table().apply { defaults().pad(5f) } val specialistStatTable = Table().apply { defaults().padBottom(5f).padTop(5f) }
val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(specialistName) val specialistStats = cityInfo.cityStats.getStatsOfSpecialist(specialistName)
for ((key, value) in specialistStats) { for ((key, value) in specialistStats) {
if (value == 0f) continue if (value == 0f) continue
specialistStatTable.add(ImageGetter.getStatIcon(key.name)).size(20f) specialistStatTable.add(value.toInt().toLabel())
specialistStatTable.add(value.toInt().toLabel()).padRight(10f) specialistStatTable.add(ImageGetter.getStatIcon(key.name)).size(20f).padRight(10f)
} }
val specialist = cityInfo.getRuleset().specialists[specialistName]!!
for (s in specialist.greatPersonPoints) {
specialistStatTable.add(s.value.toLabel())
specialistStatTable.add(ImageGetter.getUnitIcon(s.key, Color.GOLD).toGroup(20f)).padRight(10f)
}
return specialistStatTable return specialistStatTable
} }

View File

@ -11,6 +11,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Group
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.scenes.scene2d.utils.NinePatchDrawable import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable
@ -385,23 +386,79 @@ object ImageGetter {
.surroundWithThinCircle(techIconColor) .surroundWithThinCircle(techIconColor)
} }
fun getProgressBarVertical(width: Float, height: Float, percentComplete: Float, progressColor: Color, backgroundColor: Color): Group { fun getProgressBarHorizontal(width: Float, height: Float, percentComplete: Float, progressColor: Color, backgroundColor: Color): Group {
return VerticalProgressBar(width, height) return ProgressBar(width, height, false)
.addColor(backgroundColor, 1f) .setBackground(backgroundColor)
.addColor(progressColor, percentComplete) .setProgress(progressColor, percentComplete)
} }
class VerticalProgressBar(width: Float, height: Float):Group() { fun getProgressBarVertical(width: Float, height: Float, percentComplete: Float, progressColor: Color, backgroundColor: Color): Group {
return ProgressBar(width, height, true)
.setBackground(backgroundColor)
.setProgress(progressColor, percentComplete)
}
class ProgressBar(width: Float, height: Float, val vertical: Boolean = true):Group() {
var primaryPercentage: Float = 0f
var secondaryPercentage: Float = 0f
var label: Label? = null
var background: Image? = null
var secondaryProgress: Image? = null
var primaryProgress: Image? = null
init { init {
setSize(width, height) setSize(width, height)
isTransform = false isTransform = false
} }
fun addColor(color: Color, percentage: Float): VerticalProgressBar { fun setLabel(color: Color, text: String, fontSize: Int = Constants.defaultFontSize) : ProgressBar {
val bar = getWhiteDot() label = text.toLabel()
bar.color = color label?.setAlignment(Align.center)
bar.setSize(width, height * max(min(percentage, 1f),0f)) //clamp between 0 and 1 label?.setFontColor(color)
addActor(bar) label?.setFontSize(fontSize)
label?.toFront()
label?.center(this)
if (label != null)
addActor(label)
return this
}
fun setBackground(color: Color): ProgressBar {
background = getWhiteDot()
background?.color = color
background?.setSize(width, height) //clamp between 0 and 1
background?.toBack()
background?.center(this)
if (background != null)
addActor(background)
return this
}
fun setSemiProgress(color: Color, percentage: Float): ProgressBar {
secondaryPercentage = percentage
secondaryProgress = getWhiteDot()
secondaryProgress?.color = color
if (vertical)
secondaryProgress?.setSize(width, height * max(min(percentage, 1f),0f))
else
secondaryProgress?.setSize(width * max(min(percentage, 1f),0f), height)
if (secondaryProgress != null)
addActor(secondaryProgress)
return this
}
fun setProgress(color: Color, percentage: Float): ProgressBar {
primaryPercentage = percentage
primaryProgress = getWhiteDot()
primaryProgress?.color = color
if (vertical)
primaryProgress?.setSize(width, height * max(min(percentage, 1f),0f))
else
primaryProgress?.setSize(width * max(min(percentage, 1f),0f), height)
if (primaryProgress != null)
addActor(primaryProgress)
return this return this
} }
} }

View File

@ -62,10 +62,10 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS
val percentComplete = (techCost - remainingTech) / techCost.toFloat() val percentComplete = (techCost - remainingTech) / techCost.toFloat()
val percentWillBeComplete = (techCost - (remainingTech-techThisTurn)) / techCost.toFloat() val percentWillBeComplete = (techCost - (remainingTech-techThisTurn)) / techCost.toFloat()
val progressBar = ImageGetter.VerticalProgressBar(2f, 50f) val progressBar = ImageGetter.ProgressBar(2f, 50f, true)
.addColor(Color.WHITE, 1f) .setBackground(Color.WHITE)
.addColor(Color.BLUE.brighten(0.3f), percentWillBeComplete) .setSemiProgress(Color.BLUE.brighten(0.3f), percentWillBeComplete)
.addColor(Color.BLUE.darken(0.5f), percentComplete) .setProgress(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).width(145f).top().left().padRight(15f) rightSide.add(text).width(145f).top().left().padRight(15f)

View File

@ -124,6 +124,11 @@ class NativeBitmapFontData(
Fonts.culture -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Culture").region) Fonts.culture -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Culture").region)
Fonts.faith -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Faith").region) Fonts.faith -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Faith").region)
Fonts.happiness -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Happiness").region) Fonts.happiness -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Happiness").region)
Fonts.greatArtist -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Great Artist").region)
Fonts.greatEngineer -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Great Engineer").region)
Fonts.greatGeneral -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Great General").region)
Fonts.greatMerchant -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Great Merchant").region)
Fonts.greatScientist -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable("EmojiIcons/Great Scientist").region)
MayaCalendar.tun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.tunIcon).region) MayaCalendar.tun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.tunIcon).region)
MayaCalendar.katun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.katunIcon).region) MayaCalendar.katun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.katunIcon).region)
MayaCalendar.baktun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.baktunIcon).region) MayaCalendar.baktun -> Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(MayaCalendar.baktunIcon).region)
@ -231,4 +236,9 @@ object Fonts {
const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note') const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note')
const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face') const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face')
const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace') const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace')
const val greatArtist = '♬' // U+266C 'sixteenth note'
const val greatEngineer = '⚒' // U+2692 'hammer'
const val greatGeneral = '⛤' // U+26E4 'pentagram'
const val greatMerchant = '⚖' // U+2696 'scale'
const val greatScientist = '⚛' // U+269B 'atom'
} }

View File

@ -53,6 +53,9 @@ These shapes are used all over Unciv and can be replaced to make a lot of UI ele
| CityScreen/ConstructionInfoTable/ | SelectedConstructionTable | null | | | CityScreen/ConstructionInfoTable/ | SelectedConstructionTable | null | |
| CivilopediaScreen/ | EntryButton | null | | | CivilopediaScreen/ | EntryButton | null | |
| General/ | Border | null | | | General/ | Border | null | |
| General/ | Border | null | |
| General/ | Border | null | |
| General/ | Border | null | |
| General/ | ExpanderTab | null | | | General/ | ExpanderTab | null | |
| General/ | HealthBar | null | | | General/ | HealthBar | null | |
| General/ | TabbedPager | null | | | General/ | TabbedPager | null | |
@ -87,8 +90,11 @@ These shapes are used all over Unciv and can be replaced to make a lot of UI ele
| OverviewScreen/UnitOverviewTab/ | UnitSupplyTable | null | | | OverviewScreen/UnitOverviewTab/ | UnitSupplyTable | null | |
| PlayerReadyScreen/ | Background | null | | | PlayerReadyScreen/ | Background | null | |
| TechPickerScreen/ | Background | null | | | TechPickerScreen/ | Background | null | |
| TechPickerScreen/ | Background | null | |
| TechPickerScreen/ | BottomTable | null | | | TechPickerScreen/ | BottomTable | null | |
| TechPickerScreen/ | TechButton | roundedEdgeRectangle | | | TechPickerScreen/ | TechButton | roundedEdgeRectangle | |
| TechPickerScreen/ | TechButton | roundedEdgeRectangle | |
| TechPickerScreen/ | TechButtonIconsOutline | rectangleWithOutline | |
| VictoryScreen/ | CivGroup | roundedEdgeRectangle | | | VictoryScreen/ | CivGroup | roundedEdgeRectangle | |
| WorldScreen/ | AirUnitTable | null | | | WorldScreen/ | AirUnitTable | null | |
| WorldScreen/ | BattleTable | null | | | WorldScreen/ | BattleTable | null | |