diff --git a/android/Images/OtherIcons/Charts.png b/android/Images/OtherIcons/Charts.png new file mode 100644 index 0000000000..5f51037b86 Binary files /dev/null and b/android/Images/OtherIcons/Charts.png differ diff --git a/android/assets/game.atlas b/android/assets/game.atlas index 8b55814dc6..f4a8faab5b 100644 --- a/android/assets/game.atlas +++ b/android/assets/game.atlas @@ -6,133 +6,133 @@ filter: MipMapLinearLinear, MipMapLinearLinear repeat: none CityStateIcons/Cultured rotate: false - xy: 427, 1745 + xy: 127, 1219 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 CityStateIcons/Maritime rotate: false - xy: 1831, 1715 + xy: 1939, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 CityStateIcons/Mercantile rotate: false - xy: 1939, 1715 + xy: 535, 1577 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 CityStateIcons/Militaristic rotate: false - xy: 535, 1577 + xy: 643, 1592 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 CityStateIcons/Religious rotate: false - xy: 1615, 1499 + xy: 1723, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 EmojiIcons/Culture rotate: false - xy: 436, 418 + xy: 436, 316 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Death rotate: false - xy: 436, 360 + xy: 436, 258 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Faith rotate: false - xy: 436, 302 + xy: 436, 200 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Food rotate: false - xy: 436, 244 + xy: 436, 142 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Gold rotate: false - xy: 436, 128 + xy: 436, 26 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Great Artist rotate: false - xy: 436, 70 + xy: 494, 432 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Great Engineer rotate: false - xy: 436, 12 + xy: 494, 374 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Great General rotate: false - xy: 494, 534 + xy: 494, 316 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Great Merchant rotate: false - xy: 494, 476 + xy: 494, 258 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Great Scientist rotate: false - xy: 494, 418 + xy: 494, 200 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Happiness rotate: false - xy: 494, 360 + xy: 494, 142 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Production rotate: false - xy: 527, 607 + xy: 552, 273 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Science rotate: false - xy: 552, 433 + xy: 552, 99 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/Turn rotate: false - xy: 552, 317 + xy: 544, 1087 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -181,259 +181,259 @@ OtherIcons/Stop index: -1 ImprovementIcons/Citadel rotate: false - xy: 1492, 1931 + xy: 4, 261 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/City center rotate: false - xy: 4, 153 + xy: 1708, 1931 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/City ruins rotate: false - xy: 1708, 1931 + xy: 4, 45 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Customs house rotate: false - xy: 127, 1219 + xy: 119, 1111 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Farm rotate: false - xy: 427, 1637 + xy: 535, 1793 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Fishing Boats rotate: false - xy: 535, 1685 + xy: 643, 1808 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Fort rotate: false - xy: 643, 1700 + xy: 751, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Holy site rotate: false - xy: 967, 1715 + xy: 1075, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Landmark rotate: false - xy: 1399, 1823 + xy: 1399, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Lumber mill rotate: false - xy: 1615, 1823 + xy: 1615, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Manufactory rotate: false - xy: 1723, 1823 + xy: 1723, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Mine rotate: false - xy: 643, 1592 + xy: 751, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Moai rotate: false - xy: 751, 1607 + xy: 859, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Offshore Platform rotate: false - xy: 1507, 1607 + xy: 1615, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Oil well rotate: false - xy: 1723, 1607 + xy: 1831, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Pasture rotate: false - xy: 1939, 1607 + xy: 412, 1529 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Plantation rotate: false - xy: 514, 1253 + xy: 514, 1145 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Polder rotate: false - xy: 514, 1145 + xy: 643, 1484 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Quarry rotate: false - xy: 1075, 1499 + xy: 1183, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Railroad rotate: false - xy: 1507, 1499 + xy: 1615, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Remove Fallout rotate: false - xy: 1831, 1499 + xy: 1939, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Remove Forest rotate: false - xy: 1939, 1499 + xy: 751, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Remove Jungle rotate: false - xy: 1939, 1499 + xy: 751, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Remove Marsh rotate: false - xy: 859, 1392 + xy: 967, 1392 size: 100, 99 orig: 100, 99 offset: 0, 0 index: -1 ImprovementIcons/Remove Railroad rotate: false - xy: 967, 1391 + xy: 1075, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Remove Road rotate: false - xy: 1075, 1391 + xy: 1183, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Repair rotate: false - xy: 1183, 1391 + xy: 1291, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Road rotate: false - xy: 1507, 1391 + xy: 1615, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Terrace farm rotate: false - xy: 328, 773 + xy: 328, 671 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Trading post rotate: false - xy: 328, 557 + xy: 328, 455 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/EnhanceReligion rotate: false - xy: 112, 247 + xy: 112, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/FoundPantheon rotate: false - xy: 112, 247 + xy: 112, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/FoundReligion rotate: false - xy: 112, 247 + xy: 112, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/ReformReligion rotate: false - xy: 112, 247 + xy: 112, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Faith rotate: false - xy: 112, 247 + xy: 112, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/PickConstruction rotate: false - xy: 406, 1205 + xy: 520, 1469 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Production rotate: false - xy: 406, 1205 + xy: 520, 1469 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -447,14 +447,14 @@ NotificationIcons/PickPolicy index: -1 NotificationIcons/PickTech rotate: false - xy: 520, 1469 + xy: 514, 1361 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Science rotate: false - xy: 520, 1469 + xy: 514, 1361 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -503,7 +503,7 @@ StatIcons/Movement index: -1 OtherIcons/BackArrow rotate: false - xy: 436, 534 + xy: 436, 432 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -543,16 +543,23 @@ OtherIcons/Capital orig: 107, 101 offset: 0, 0 index: -1 -OtherIcons/Checkmark +OtherIcons/Charts rotate: false xy: 4, 369 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 +OtherIcons/Checkmark + rotate: false + xy: 1492, 1931 + size: 100, 100 + orig: 100, 100 + offset: 0, 0 + index: -1 NotificationIcons/NextTurn rotate: false - xy: 4, 369 + xy: 1492, 1931 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -566,56 +573,56 @@ OtherIcons/Circle index: -1 OtherIcons/Cities rotate: false - xy: 4, 261 + xy: 1600, 1931 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/CityState rotate: false - xy: 436, 476 + xy: 436, 374 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Close rotate: false - xy: 1816, 1931 + xy: 1924, 1931 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/CrosshairB rotate: false - xy: 298, 1376 + xy: 298, 1268 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Diplomacy rotate: false - xy: 112, 1003 + xy: 112, 895 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/DiplomacyW rotate: false - xy: 112, 895 + xy: 112, 787 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/DisbandUnit rotate: false - xy: 112, 787 + xy: 112, 679 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/ExclamationMark rotate: false - xy: 112, 139 + xy: 112, 31 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -629,7 +636,7 @@ OtherIcons/Fire index: -1 OtherIcons/ForwardArrow rotate: false - xy: 436, 186 + xy: 436, 84 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -650,168 +657,168 @@ OtherIcons/HexagonOutline index: -1 OtherIcons/Improvements rotate: false - xy: 494, 302 + xy: 494, 84 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Keyboard rotate: false - xy: 1291, 1715 + xy: 1399, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Link rotate: false - xy: 494, 186 + xy: 527, 505 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Load rotate: false - xy: 1399, 1715 + xy: 1507, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Loading rotate: false - xy: 1507, 1823 + xy: 1507, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/Loading rotate: false - xy: 1507, 1823 + xy: 1507, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/Working rotate: false - xy: 1507, 1823 + xy: 1507, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/LockSmall rotate: false - xy: 494, 128 + xy: 552, 447 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/MapEditor rotate: false - xy: 1723, 1715 + xy: 1831, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/MenuIcon rotate: false - xy: 1939, 1823 + xy: 1939, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Mods rotate: false - xy: 859, 1607 + xy: 967, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Multiplayer rotate: false - xy: 967, 1607 + xy: 1075, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/NationSwap rotate: false - xy: 1075, 1607 + xy: 1183, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Nations rotate: false - xy: 494, 70 + xy: 552, 389 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/New rotate: false - xy: 1183, 1607 + xy: 1291, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Notifications rotate: false - xy: 1399, 1607 + xy: 1507, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Options rotate: false - xy: 1831, 1607 + xy: 1939, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Pause rotate: false - xy: 494, 12 + xy: 552, 331 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Pencil rotate: false - xy: 406, 1421 + xy: 406, 1313 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Pentagon rotate: false - xy: 406, 1313 + xy: 406, 1205 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Pillage rotate: false - xy: 514, 1361 + xy: 514, 1253 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Politics rotate: false - xy: 643, 1484 + xy: 751, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NotificationIcons/WorldCongressVote rotate: false - xy: 643, 1484 + xy: 751, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Present rotate: false - xy: 967, 1499 + xy: 1075, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -825,119 +832,119 @@ OtherIcons/Puppet index: -1 OtherIcons/Quest rotate: false - xy: 1183, 1499 + xy: 1291, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Question rotate: false - xy: 1291, 1499 + xy: 1399, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Quickstart rotate: false - xy: 1399, 1499 + xy: 1507, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Remove Heresy rotate: false - xy: 751, 1391 + xy: 859, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Resources rotate: false - xy: 1291, 1391 + xy: 1399, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Resume rotate: false - xy: 1399, 1391 + xy: 1507, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Search rotate: false - xy: 1723, 1391 + xy: 1831, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/SecretOptions rotate: false - xy: 1831, 1391 + xy: 1939, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Settings rotate: false - xy: 1939, 1391 + xy: 227, 1111 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Shield rotate: false - xy: 220, 1003 + xy: 220, 895 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Sleep rotate: false - xy: 220, 679 + xy: 220, 571 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Speaker rotate: false - xy: 220, 571 + xy: 220, 463 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Spy rotate: false - xy: 220, 247 + xy: 220, 139 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Spy_White rotate: false - xy: 220, 139 + xy: 220, 31 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Star rotate: false - xy: 220, 37 + xy: 335, 1103 size: 100, 94 orig: 100, 94 offset: 0, 0 index: -1 OtherIcons/Swap rotate: false - xy: 328, 881 + xy: 328, 779 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Timer rotate: false - xy: 328, 665 + xy: 328, 563 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -951,35 +958,35 @@ OtherIcons/Triangle index: -1 OtherIcons/Turn right rotate: false - xy: 328, 341 + xy: 328, 239 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Tyrannosaurus rotate: false - xy: 328, 233 + xy: 328, 131 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/WLTKD rotate: false - xy: 436, 592 + xy: 436, 490 size: 83, 65 orig: 83, 65 offset: 0, 0 index: -1 OtherIcons/Wait rotate: false - xy: 328, 17 + xy: 436, 995 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Wonders rotate: false - xy: 436, 665 + xy: 436, 563 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -1014,224 +1021,224 @@ ResourceIcons/Cattle index: -1 ResourceIcons/Citrus rotate: false - xy: 1600, 1931 + xy: 4, 153 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Coal rotate: false - xy: 1924, 1931 + xy: 190, 1435 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Copper rotate: false - xy: 190, 1435 + xy: 190, 1327 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Cotton rotate: false - xy: 190, 1327 + xy: 298, 1484 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Crab rotate: false - xy: 298, 1484 + xy: 298, 1376 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Deer rotate: false - xy: 119, 1111 + xy: 112, 1003 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Dyes rotate: false - xy: 112, 355 + xy: 112, 247 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Fish rotate: false - xy: 535, 1793 + xy: 535, 1685 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Furs rotate: false - xy: 751, 1823 + xy: 751, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Gems rotate: false - xy: 751, 1715 + xy: 859, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Gold Ore rotate: false - xy: 859, 1715 + xy: 967, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Horses rotate: false - xy: 1075, 1823 + xy: 1075, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Incense rotate: false - xy: 1075, 1715 + xy: 1183, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Iron rotate: false - xy: 1183, 1823 + xy: 1183, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Ivory rotate: false - xy: 1183, 1715 + xy: 1291, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Jewelry rotate: false - xy: 1291, 1823 + xy: 1291, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Marble rotate: false - xy: 1831, 1823 + xy: 1831, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Oil rotate: false - xy: 1615, 1607 + xy: 1723, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Pearls rotate: false - xy: 412, 1529 + xy: 406, 1421 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Porcelain rotate: false - xy: 859, 1499 + xy: 967, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Salt rotate: false - xy: 1615, 1391 + xy: 1723, 1391 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Sheep rotate: false - xy: 227, 1111 + xy: 220, 1003 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Silk rotate: false - xy: 220, 895 + xy: 220, 787 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Silver rotate: false - xy: 220, 787 + xy: 220, 679 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Spices rotate: false - xy: 220, 355 + xy: 220, 247 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Stone rotate: false - xy: 335, 1097 + xy: 328, 995 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Sugar rotate: false - xy: 328, 989 + xy: 328, 887 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Truffles rotate: false - xy: 328, 449 + xy: 328, 347 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Uranium rotate: false - xy: 328, 125 + xy: 328, 23 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Whales rotate: false - xy: 436, 989 + xy: 436, 887 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Wheat rotate: false - xy: 436, 881 + xy: 436, 779 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Wine rotate: false - xy: 436, 773 + xy: 436, 671 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -1252,77 +1259,77 @@ StatIcons/CityConnection index: -1 StatIcons/Culture rotate: false - xy: 298, 1268 + xy: 427, 1745 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Food rotate: false - xy: 643, 1808 + xy: 643, 1700 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Gold rotate: false - xy: 859, 1823 + xy: 859, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Happiness rotate: false - xy: 967, 1823 + xy: 967, 1715 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/InterceptRange rotate: false - xy: 494, 244 + xy: 494, 26 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/Malcontent rotate: false - xy: 1615, 1715 + xy: 1723, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Population rotate: false - xy: 751, 1499 + xy: 859, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TileIcons/Worked rotate: false - xy: 751, 1499 + xy: 859, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Range rotate: false - xy: 552, 549 + xy: 552, 215 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/RangedStrength rotate: false - xy: 552, 491 + xy: 552, 157 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/ReligiousStrength rotate: false - xy: 1723, 1499 + xy: 1831, 1499 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -1336,14 +1343,14 @@ StatIcons/Resistance index: -1 StatIcons/Specialist rotate: false - xy: 220, 463 + xy: 220, 355 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Strength rotate: false - xy: 552, 375 + xy: 552, 41 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -1364,56 +1371,56 @@ TileIcons/Buy index: -1 TileIcons/CityCenter rotate: false - xy: 4, 45 + xy: 1816, 1931 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TileIcons/Locked rotate: false - xy: 1507, 1715 + xy: 1615, 1823 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TileIcons/NotWorked rotate: false - xy: 1291, 1607 + xy: 1399, 1607 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UniqueIcons/Fallback rotate: false - xy: 112, 31 + xy: 427, 1637 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitTypeIcons/DomainAir rotate: false - xy: 112, 679 + xy: 112, 571 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitTypeIcons/DomainLand rotate: false - xy: 112, 571 + xy: 112, 463 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Terrains rotate: false - xy: 112, 571 + xy: 112, 463 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitTypeIcons/DomainWater rotate: false - xy: 112, 463 + xy: 112, 355 size: 100, 100 orig: 100, 100 offset: 0, 0 diff --git a/android/assets/game.png b/android/assets/game.png index 50798b569b..3c62b1a4cc 100644 Binary files a/android/assets/game.png and b/android/assets/game.png differ diff --git a/core/src/com/unciv/ui/components/LineChart.kt b/core/src/com/unciv/ui/components/LineChart.kt new file mode 100644 index 0000000000..0639740cb4 --- /dev/null +++ b/core/src/com/unciv/ui/components/LineChart.kt @@ -0,0 +1,285 @@ +package com.unciv.ui.components + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.g2d.Batch +import com.badlogic.gdx.graphics.glutils.ShapeRenderer +import com.badlogic.gdx.math.Matrix4 +import com.badlogic.gdx.math.Rectangle +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.ui.Image +import com.badlogic.gdx.scenes.scene2d.ui.Label +import com.badlogic.gdx.scenes.scene2d.ui.Widget +import com.badlogic.gdx.utils.Align +import com.unciv.logic.civilization.Civilization +import com.unciv.ui.components.extensions.surroundWithCircle +import com.unciv.ui.screens.victoryscreen.VictoryScreenCivGroup +import kotlin.math.ceil +import kotlin.math.log10 +import kotlin.math.pow + +private data class DataPoint(val x: Int, val y: Int, val civ: Civilization) + +// TODO: This currently does not support negative values (e.g. for happiness or gold). Adding this +// seems like a major hassle. The question would be if you'd still want the x axis to be on the +// bottom, or whether it should move up somewhere to the middle. What if all values are negative? +// Should it then go to the top? And where do the labels of the x-axis go anyways? Or would we just +// want a non-zero based y-axis (yikes). Also computing the labels for the y axis, so that they are +// "nice" (whatever that means) would be quite challenging. +class LineChart( + data: Map>, + private val viewingCiv: Civilization, + private val selectedCiv: Civilization, + private val chartWidth: Float, + private val chartHeight: Float +) : Widget() { + + private val shapeRenderer = ShapeRenderer() + + private val axisLineWidth = 2f + private val axisColor = Color.WHITE + private val axisLabelColor = axisColor + private val axisToLabelPadding = 5f + private val chartLineWidth = 3f + private val orientationLineWidth = 0.5f + private val orientationLineColor = Color.LIGHT_GRAY + + /** This should not be changed lightly. There's code (e.g. for generating the labels) that + * assumes multiples of 10. Also please note, that the real number of labels is `maxLabels + 1` + * as `0` is not counted. */ + private val maxLabels = 10 + + private val paddingBetweenCivs = 10f + private val civGroupToChartPadding = 10f + + private val xLabels: List + private val yLabels: List + + private val dataPoints: List = data.flatMap { turn -> + turn.value.map { (civ, value) -> + DataPoint(turn.key, value, civ) + } + } + + init { + xLabels = generateLabels(dataPoints.maxOf { it.x }) + yLabels = generateLabels(dataPoints.maxOf { it.y }) + } + + private fun generateLabels(maxValue: Int): List { + val numberOfDigits = ceil(log10(maxValue.toDouble())).toInt() + val maxLabelValue = when { + numberOfDigits <= 0 -> 1 + else -> { + // Some examples: + // If `maxValue = 97` => `oneWithZeros = 10^(2-1) = 10 => ceil(97/10) * 10 = 100 + // If `maxValue = 567` => `oneWithZeros = 10^(3-1) = 100 => ceil(567/100) * 100 = 600 + val oneWithZeros = 10.0.pow(numberOfDigits - 1) + ceil(maxValue.toDouble() / oneWithZeros).toInt() * oneWithZeros.toInt() + } + } + val stepSize = ceil(maxLabelValue.toFloat() / maxLabels).toInt() + // `maxLabels + 1` because we want to end at `maxLabels * stepSize`. + return (0 until maxLabels + 1).map { (it * stepSize) } + } + + override fun draw(batch: Batch, parentAlpha: Float) { + super.draw(batch, parentAlpha) + + // Save the current batch transformation matrix + val oldTransformMatrix = batch.transformMatrix.cpy() + // Set the batch transformation matrix to the local coordinates of the LineChart widget + val stageCoords = localToStageCoordinates(Vector2(0f, 0f)) + batch.transformMatrix = Matrix4().translate(stageCoords.x, stageCoords.y, 0f) + +/* +++ WhoIsJohannes's code drew all the CivGroups on the right - I replaced that with just a + +++ Nation symbol at the selected civ's line end + + // We draw civilization labels first, because they limit the extension of the chart to the + // right. We want to draw orientation lines together with the labels of the y axis and + // therefore we need to know first how much space the civilization boxes took on the right. + var yPosOfNextCiv = chartHeight + val civGroups = lastTurnDataPoints.toList().sortedByDescending { (_, v) -> v.y }.map { + VictoryScreenCivGroup(it.first, " - ", it.second.y.toString(), currentPlayerCiv) + } + val largestCivGroupWidth = civGroups.maxOf { it.width } + civGroups.forEach { + it.setPosition( + chartWidth - largestCivGroupWidth + (largestCivGroupWidth - it.width) / 2, + yPosOfNextCiv - it.height + ) + it.draw(batch, 1f) + // Currently we don't really check whether y is overflowing to the bottom here. + yPosOfNextCiv -= it.height + paddingBetweenCivs + } + */ + val lastTurnDataPoints = getLastTurnDataPoints() + val selectedCivIcon: Actor? = + if (selectedCiv !in lastTurnDataPoints) null + else VictoryScreenCivGroup(selectedCiv, "", viewingCiv).children[0].run { + (this as? Image)?.surroundWithCircle(30f, color = Color.LIGHT_GRAY) + ?: this + } + val largestCivGroupWidth = if (selectedCivIcon == null) -civGroupToChartPadding else 33f + + val labelHeight = Label("123", Label.LabelStyle(Fonts.font, axisLabelColor)).height + val yLabelsAsLabels = + yLabels.map { Label(it.toString(), Label.LabelStyle(Fonts.font, axisLabelColor)) } + val widestYLabelWidth = yLabelsAsLabels.maxOf { it.width } + // We assume here that all labels have the same height. We need to deduct the height of + // a label from the available height, because otherwise the label on the top would + // overrun the height since the (x,y) coordinates define the bottom left corner of the + // Label. + val yAxisLabelMaxY = chartHeight - labelHeight + // This is to account for the x axis and its labels which are below the lowest point + val xAxisLabelsHeight = labelHeight + val zeroYAxisLabelHeight = labelHeight + val yAxisLabelMinY = + xAxisLabelsHeight + axisToLabelPadding + axisLineWidth / 2 - zeroYAxisLabelHeight / 2 + val yAxisLabelYRange = yAxisLabelMaxY - yAxisLabelMinY + + // We draw the y-axis labels second. They will take away some space on the left of the + // widget which we need to consider when drawing the rest of the graph. + yLabelsAsLabels.forEachIndexed { index, label -> + val yPos = yAxisLabelMinY + index * (yAxisLabelYRange / (yLabels.size - 1)) + label.setPosition((widestYLabelWidth - label.width) / 2, yPos) + label.draw(batch, 1f) + + // Draw y-axis orientation lines + if (index > 0) drawLine( + batch, + widestYLabelWidth + axisToLabelPadding + axisLineWidth, + yPos + labelHeight / 2, + chartWidth - largestCivGroupWidth - civGroupToChartPadding, + yPos + labelHeight / 2, + orientationLineColor, + orientationLineWidth + ) + } + + // Draw x-axis labels + val xLabelsAsLabels = + xLabels.map { Label(it.toString(), Label.LabelStyle(Fonts.font, axisLabelColor)) } + val firstXAxisLabelWidth = xLabelsAsLabels[0].width + val lastXAxisLabelWidth = xLabelsAsLabels[xLabelsAsLabels.size - 1].width + val xAxisLabelMinX = + widestYLabelWidth + axisToLabelPadding + axisLineWidth / 2 - firstXAxisLabelWidth / 2 + val xAxisLabelMaxX = + chartWidth - largestCivGroupWidth - paddingBetweenCivs - lastXAxisLabelWidth / 2 + val xAxisLabelXRange = xAxisLabelMaxX - xAxisLabelMinX + xLabels.forEachIndexed { index, labelAsInt -> + val label = Label(labelAsInt.toString(), Label.LabelStyle(Fonts.font, axisLabelColor)) + val xPos = xAxisLabelMinX + index * (xAxisLabelXRange / (xLabels.size - 1)) + label.setPosition(xPos - label.width / 2, 0f) + label.draw(batch, 1f) + + // Draw x-axis orientation lines + if (index > 0) drawLine( + batch, + xPos, + labelHeight + axisToLabelPadding + axisLineWidth, + xPos, + chartHeight, + orientationLineColor, + orientationLineWidth + ) + } + + // Draw y-axis + val yAxisX = widestYLabelWidth + axisToLabelPadding + axisLineWidth / 2 + val xAxisY = labelHeight + axisToLabelPadding + axisLineWidth / 2 + drawLine(batch, yAxisX, xAxisY, yAxisX, chartHeight, axisColor, axisLineWidth) + + // Draw x-axis + val xAxisRight = chartWidth - largestCivGroupWidth - civGroupToChartPadding + drawLine(batch, yAxisX, xAxisY, xAxisRight, xAxisY, axisColor, axisLineWidth) + + + // Draw line charts for each color + val linesMinX = widestYLabelWidth + axisToLabelPadding + axisLineWidth + val linesMaxX = + chartWidth - largestCivGroupWidth - civGroupToChartPadding - lastXAxisLabelWidth / 2 + val linesMinY = labelHeight + axisToLabelPadding + axisLineWidth + val linesMaxY = chartHeight - labelHeight / 2 + val scaleX = (linesMaxX - linesMinX) / xLabels.max() + val scaleY = (linesMaxY - linesMinY) / yLabels.max() + val sortedPoints = dataPoints.sortedBy { it.x } + val pointsByCiv = sortedPoints.groupBy { it.civ } + // We want the current player civ to be drawn last, so it is never overlapped by another player. + val civIterationOrder = + // By default the players with the highest points will be drawn last (i.e. they will + // overlap others). + pointsByCiv.keys.toList().sortedBy { lastTurnDataPoints[it]!!.y } + .toMutableList() + // The current player might be a spectator. + if (selectedCiv in civIterationOrder) { + civIterationOrder.remove(selectedCiv) + civIterationOrder.add(selectedCiv) + } + for (civ in civIterationOrder) { + val points = pointsByCiv[civ]!! + for (i in 1 until points.size) { + val prevPoint = points[i - 1] + val currPoint = points[i] + // See TODO at the top of the file. We currently don't support negative values. + if (prevPoint.y < 0) continue + if (currPoint.y < 0) continue + drawLine( + batch, + linesMinX + prevPoint.x * scaleX, linesMinY + prevPoint.y * scaleY, + linesMinX + currPoint.x * scaleX, linesMinY + currPoint.y * scaleY, + civ.nation.getOuterColor(), chartLineWidth + ) + } + } + + // Draw the selected Civ icon to the right of its last datapoint + selectedCivIcon?.run { + val yPos = linesMinY + lastTurnDataPoints[selectedCiv]!!.y * scaleY + setPosition(chartWidth, yPos, Align.right) + setSize(33f, 33f) // Dead Civs need this + draw(batch, parentAlpha) + } + + // Restore the previous batch transformation matrix + batch.transformMatrix = oldTransformMatrix + } + + private fun getLastTurnDataPoints(): MutableMap { + val lastDataPoints = mutableMapOf() + for (dataPoint in dataPoints) { + if (!lastDataPoints.containsKey(dataPoint.civ) || lastDataPoints[dataPoint.civ]!!.x < dataPoint.x) { + lastDataPoints[dataPoint.civ] = dataPoint + } + } + return lastDataPoints + } + + private fun drawLine( + batch: Batch, + x1: Float, + y1: Float, + x2: Float, + y2: Float, + color: Color, + width: Float + ) { + shapeRenderer.projectionMatrix = batch.projectionMatrix + shapeRenderer.transformMatrix = batch.transformMatrix + batch.end() + + shapeRenderer.begin(ShapeRenderer.ShapeType.Filled) + shapeRenderer.color = color + shapeRenderer.rectLine(x1, y1, x2, y2, width) + shapeRenderer.end() + + batch.begin() + } + + override fun getMinWidth() = chartWidth + override fun getMinHeight() = chartHeight + override fun getPrefWidth() = chartWidth + override fun getPrefHeight() = chartHeight + override fun getMaxWidth() = chartWidth + override fun getMaxHeight() = chartHeight +} diff --git a/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreen.kt b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreen.kt index b46aec4f22..5cf7b9d969 100644 --- a/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreen.kt +++ b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreen.kt @@ -60,6 +60,11 @@ class VictoryScreen( override fun getContent(worldScreen: WorldScreen) = VictoryScreenCivRankings(worldScreen) override fun isHidden(playerCiv: Civilization) = UncivGame.Current.settings.useDemographics }, + Charts('C', "OtherIcons/Charts") { + override fun getContent(worldScreen: WorldScreen) = VictoryScreenCharts(worldScreen) + override fun isHidden(playerCiv: Civilization) = + !playerCiv.isSpectator() && playerCiv.statsHistory.size < 2 + }, Replay('P', "OtherIcons/Load", allowAsSecret = true) { override fun getContent(worldScreen: WorldScreen) = VictoryScreenReplay(worldScreen) override fun isHidden(playerCiv: Civilization) = diff --git a/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenCharts.kt b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenCharts.kt new file mode 100644 index 0000000000..5dd9ac65de --- /dev/null +++ b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenCharts.kt @@ -0,0 +1,123 @@ +package com.unciv.ui.screens.victoryscreen + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.Touchable +import com.badlogic.gdx.scenes.scene2d.ui.Container +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.utils.Align +import com.unciv.logic.civilization.Civilization +import com.unciv.ui.components.AutoScrollPane +import com.unciv.ui.components.LineChart +import com.unciv.ui.components.TabbedPager +import com.unciv.ui.components.extensions.onChange +import com.unciv.ui.components.extensions.onClick +import com.unciv.ui.components.extensions.packIfNeeded +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.screens.basescreen.BaseScreen +import com.unciv.ui.screens.worldscreen.WorldScreen +import com.unciv.ui.screens.newgamescreen.TranslatedSelectBox + +class VictoryScreenCharts( + worldScreen: WorldScreen +) : Table(BaseScreen.skin), TabbedPager.IPageExtensions { + private val gameInfo = worldScreen.gameInfo + + private var rankingType = RankingType.Score + private var selectedCiv = worldScreen.selectedCiv + private val viewingCiv = worldScreen.viewingCiv + + private val rankingTypeSelect = TranslatedSelectBox(RankingType.values().map { it.name }, rankingType.name, skin) + private val civButtonsTable = Table() + private val civButtonsScroll = AutoScrollPane(civButtonsTable) + private val controlsColumn = Table() + private val markerIcon = ImageGetter.getImage("OtherIcons/Star").apply { + color = Color.GOLD + align = Align.center + } + + private val chartHolder = Container(null) + + init { + civButtonsScroll.setScrollingDisabled(true, false) + civButtonsTable.defaults().space(20f).fillX() + controlsColumn.defaults().space(20f).fillX() + controlsColumn.add(rankingTypeSelect).right().row() + controlsColumn.add(civButtonsScroll).fillY() + defaults().fill().pad(20f) + add(controlsColumn) + add(chartHolder).growX().top().padLeft(0f) + + rankingTypeSelect.onChange { + rankingType = RankingType.values() + .firstOrNull { it.name == rankingTypeSelect.selected.value } + ?: RankingType.Score + update() + } + } + + private fun update() { + updateControls() + updateChart() + } + + private fun updateControls() { + civButtonsTable.clear() + val sortedCivs = gameInfo.civilizations.asSequence() + .filter { it.isMajorCiv() } + .map { VictoryScreen.CivWithStat(it, rankingType) } + .sortedByDescending { it.value } + for (civEntry in sortedCivs) { + if (civEntry.civ != selectedCiv) civButtonsTable.add() + else civButtonsTable.add(markerIcon).size(24f).right() + val button = VictoryScreenCivGroup(civEntry, viewingCiv) + button.touchable = Touchable.enabled + civButtonsTable.add(button).row() + button.onClick { + selectedCiv = civEntry.civ + update() + } + } + civButtonsTable.add().padBottom(20f).row() + civButtonsTable.pack() + civButtonsScroll.layout() + } + + private fun updateChart() { + // LineChart does not "cooperate" in Layout - the size we set here is final. + // These values seem to fit the cell it'll be in - we subtract padding and some extra manually + packIfNeeded() + chartHolder.actor = LineChart( + getLineChartData(rankingType), + viewingCiv, + selectedCiv, + parent.width - getColumnWidth(0) - 60f, + parent.height - 60f + ) + chartHolder.invalidateHierarchy() + } + + private fun getLineChartData( + rankingType: RankingType + ): Map> { + return gameInfo.civilizations.asSequence() + .filter { it.isMajorCiv() } + .flatMap { civ -> + civ.statsHistory + .filterValues { it.containsKey(rankingType) } + .map { (turn, data) -> Pair(turn, Pair(civ, data.getValue(rankingType))) } + }.groupBy({ it.first }, { it.second }) + .mapValues { group -> group.value.toMap() } + } + + override fun activated(index: Int, caption: String, pager: TabbedPager) { + pager.setScrollDisabled(true) + getCell(controlsColumn).height(parent.height) + getCell(chartHolder).height(parent.height) + if (chartHolder.actor == null) update() + civButtonsTable.invalidateHierarchy() + } + + override fun deactivated(index: Int, caption: String, pager: TabbedPager) { + pager.setScrollDisabled(false) + } +} diff --git a/docs/Credits.md b/docs/Credits.md index afac4afd2f..8c065e6a2e 100644 --- a/docs/Credits.md +++ b/docs/Credits.md @@ -728,6 +728,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https: - [Transform] created by letstalkaboutdune - [Swords](https://thenounproject.com/icon/swords-1580316/) created by Muhajir ila Robbi for Blockaded tile marker - [Keyboard](https://thenounproject.com/icon/keyboard-2685534/) by Twenty Foo Studio for Options Keys +- [charts](https://thenounproject.com/icon/charts-2312023/) by Srinivas Agra (gimped to appear bolder) for the Charts page + ### Main menu