diff --git a/android/Images/OtherIcons/Quest.png b/android/Images/OtherIcons/Quest.png new file mode 100644 index 0000000000..a03c75ba2c Binary files /dev/null and b/android/Images/OtherIcons/Quest.png differ diff --git a/android/assets/game.atlas b/android/assets/game.atlas index e0350b438f..7cb08197a6 100644 --- a/android/assets/game.atlas +++ b/android/assets/game.atlas @@ -489,7 +489,7 @@ BuildingIcons/Paper Maker index: -1 BuildingIcons/Pentagon rotate: false - xy: 920, 82 + xy: 818, 82 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -1014,7 +1014,7 @@ OtherIcons/Fire index: -1 OtherIcons/Hexagon rotate: false - xy: 281, 1802 + xy: 2, 1802 size: 277, 240 orig: 277, 240 offset: 0, 0 @@ -1077,7 +1077,7 @@ OtherIcons/Options index: -1 OtherIcons/Pentagon rotate: false - xy: 818, 82 + xy: 920, 82 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -1096,7 +1096,7 @@ OtherIcons/Puppet orig: 100, 100 offset: 0, 0 index: -1 -OtherIcons/Quickstart +OtherIcons/Quest rotate: false xy: 1328, 2 size: 100, 100 @@ -1819,14 +1819,14 @@ TileSets/Default/CrosshatchHexagon index: -1 TileSets/FantasyHex/Hexagon rotate: false - xy: 2, 1802 + xy: 281, 1802 size: 277, 240 orig: 277, 240 offset: 0, 0 index: -1 TileSets/Default/Hexagon rotate: false - xy: 2, 1802 + xy: 281, 1802 size: 277, 240 orig: 277, 240 offset: 0, 0 @@ -2329,399 +2329,406 @@ filter: MipMapLinearLinear,MipMapLinearLinear repeat: none BuildingIcons/Research Lab rotate: false - xy: 2, 616 + xy: 104, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/SS Booster rotate: false - xy: 206, 616 + xy: 308, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/SS Cockpit rotate: false - xy: 308, 718 + xy: 410, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/SS Engine rotate: false - xy: 410, 820 + xy: 512, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/SS Stasis Chamber rotate: false - xy: 512, 922 + xy: 2, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Satrap's Court rotate: false - xy: 308, 616 + xy: 410, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Seaport rotate: false - xy: 2, 208 + xy: 104, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Sistine Chapel rotate: false - xy: 104, 208 + xy: 206, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Solar Plant rotate: false - xy: 410, 514 + xy: 512, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Spaceship Factory rotate: false - xy: 614, 718 + xy: 716, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Stable rotate: false - xy: 206, 208 + xy: 308, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Stadium rotate: false - xy: 308, 310 + xy: 410, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Statue of Liberty rotate: false - xy: 410, 412 + xy: 512, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Statue of Zeus rotate: false - xy: 512, 514 + xy: 614, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Stock Exchange rotate: false - xy: 920, 922 + xy: 104, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Stone Works rotate: false - xy: 206, 106 + xy: 308, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Stonehenge rotate: false - xy: 308, 208 + xy: 410, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Sydney Opera House rotate: false - xy: 818, 718 + xy: 920, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Taj Mahal rotate: false - xy: 920, 820 + xy: 1022, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Temple rotate: false - xy: 206, 4 + xy: 308, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Temple of Artemis rotate: false - xy: 308, 106 + xy: 410, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Terracotta Army rotate: false - xy: 614, 412 + xy: 716, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/The Great Library rotate: false - xy: 716, 514 + xy: 818, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/The Great Lighthouse rotate: false - xy: 818, 616 + xy: 920, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/The Louvre rotate: false - xy: 920, 718 + xy: 1022, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/The Oracle rotate: false - xy: 1022, 820 + xy: 1124, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/The Pyramids rotate: false - xy: 308, 4 + xy: 410, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Theatre rotate: false - xy: 512, 208 + xy: 614, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/University rotate: false - xy: 410, 4 + xy: 512, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Walls rotate: false - xy: 614, 208 + xy: 716, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Walls of Babylon rotate: false - xy: 716, 310 + xy: 818, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Wat rotate: false - xy: 1124, 717 + xy: 1226, 819 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Water Mill rotate: false - xy: 1226, 820 + xy: 1328, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Windmill rotate: false - xy: 614, 106 + xy: 716, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 BuildingIcons/Workshop rotate: false - xy: 1022, 514 + xy: 1124, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 EmojiIcons/Turn rotate: false - xy: 1536, 764 + xy: 1900, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 EmojiIcons/TurnOld rotate: false - xy: 1588, 764 + xy: 1952, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 ImprovementIcons/Road rotate: false - xy: 104, 616 + xy: 206, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Terrace farm rotate: false - xy: 512, 310 + xy: 614, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Trading post rotate: false - xy: 716, 412 + xy: 818, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/Rome rotate: false - xy: 2, 412 + xy: 104, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/Russia rotate: false - xy: 104, 514 + xy: 206, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/Siam rotate: false - xy: 512, 718 + xy: 614, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/Songhai rotate: false - xy: 512, 616 + xy: 614, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/Spain rotate: false - xy: 716, 820 + xy: 818, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 NationIcons/The Ottomans rotate: false - xy: 1124, 922 + xy: 308, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Aircraft rotate: false - xy: 668, 54 + xy: 1022, 462 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/BackArrow rotate: false - xy: 1022, 462 + xy: 1430, 959 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Down rotate: false - xy: 1074, 462 + xy: 1380, 716 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 +OtherIcons/Quickstart + rotate: false + xy: 2, 922 + size: 100, 100 + orig: 100, 100 + offset: 0, 0 + index: -1 OtherIcons/Resume rotate: false - xy: 206, 820 + xy: 308, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Scenario rotate: false - xy: 410, 718 + xy: 512, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Shield rotate: false - xy: 308, 514 + xy: 410, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Sleep rotate: false - xy: 206, 310 + xy: 308, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/Stop rotate: false - xy: 410, 310 + xy: 512, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 OtherIcons/TableBackground rotate: false - xy: 1848, 816 + xy: 1796, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/Up rotate: false - xy: 1692, 764 + xy: 1952, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 OtherIcons/buttonBackground rotate: false - xy: 614, 54 + xy: 716, 156 size: 52, 50 orig: 52, 50 offset: 0, 0 @@ -2735,406 +2742,406 @@ OtherIcons/whiteDot index: -1 PolicyIcons/Aristocracy rotate: false - xy: 818, 258 + xy: 1226, 665 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Citizenship rotate: false - xy: 1328, 805 + xy: 818, 206 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Civil Society rotate: false - xy: 1328, 753 + xy: 870, 258 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Collective Rule rotate: false - xy: 818, 206 + xy: 972, 360 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Constitution rotate: false - xy: 870, 258 + xy: 1074, 462 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Democracy rotate: false - xy: 972, 360 + xy: 1380, 768 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Entrepreneurship rotate: false - xy: 1278, 614 + xy: 1432, 751 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Fascism rotate: false - xy: 1330, 649 + xy: 1545, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Free Religion rotate: false - xy: 1545, 972 + xy: 1701, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Free Speech rotate: false - xy: 1597, 972 + xy: 1753, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Free Thought rotate: false - xy: 1649, 972 + xy: 1805, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Humanism rotate: false - xy: 1857, 972 + xy: 1482, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Landed Elite rotate: false - xy: 1534, 920 + xy: 1586, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Legalism rotate: false - xy: 1586, 920 + xy: 1586, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Mandate Of Heaven rotate: false - xy: 1690, 920 + xy: 1638, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Mercantilism rotate: false - xy: 1846, 920 + xy: 1742, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Meritocracy rotate: false - xy: 1898, 920 + xy: 1742, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Militarism rotate: false - xy: 1950, 920 + xy: 1794, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Military Caste rotate: false - xy: 1482, 868 + xy: 1794, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Military Tradition rotate: false - xy: 1534, 868 + xy: 1846, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Monarchy rotate: false - xy: 1638, 868 + xy: 1898, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Oligarchy rotate: false - xy: 1794, 868 + xy: 1950, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Organized Religion rotate: false - xy: 1846, 868 + xy: 1484, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Patronage rotate: false - xy: 1898, 868 + xy: 1484, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Police State rotate: false - xy: 1950, 868 + xy: 1536, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Populism rotate: false - xy: 922, 308 + xy: 1484, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Professional Army rotate: false - xy: 922, 256 + xy: 1536, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Protectionism rotate: false - xy: 974, 308 + xy: 1588, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Reformation rotate: false - xy: 974, 204 + xy: 1640, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Representation rotate: false - xy: 1380, 803 + xy: 1640, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Republic rotate: false - xy: 1024, 410 + xy: 1692, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Scientific Revolution rotate: false - xy: 1076, 410 + xy: 1640, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Secularism rotate: false - xy: 1484, 816 + xy: 1744, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Sovereignty rotate: false - xy: 1744, 816 + xy: 1796, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Theocracy rotate: false - xy: 1952, 816 + xy: 1900, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Total War rotate: false - xy: 1432, 764 + xy: 1848, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Trade Unions rotate: false - xy: 1484, 764 + xy: 1900, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Universal Suffrage rotate: false - xy: 1640, 764 + xy: 1952, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Warrior Code rotate: false - xy: 1796, 764 + xy: 1536, 660 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 ResourceIcons/Sheep rotate: false - xy: 206, 412 + xy: 308, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Silk rotate: false - xy: 614, 820 + xy: 716, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Silver rotate: false - xy: 716, 922 + xy: 2, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Spices rotate: false - xy: 104, 106 + xy: 206, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Stone rotate: false - xy: 104, 4 + xy: 206, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Sugar rotate: false - xy: 614, 514 + xy: 716, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Uranium rotate: false - xy: 512, 106 + xy: 614, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Whales rotate: false - xy: 1328, 922 + xy: 512, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Wheat rotate: false - xy: 512, 4 + xy: 614, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ResourceIcons/Wine rotate: false - xy: 716, 208 + xy: 818, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/InterceptRange rotate: false - xy: 1961, 972 + xy: 1534, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/Movement rotate: false - xy: 1742, 868 + xy: 1950, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/Range rotate: false - xy: 974, 256 + xy: 1536, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/RangedStrength rotate: false - xy: 922, 204 + xy: 1588, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 StatIcons/Resistance rotate: false - xy: 104, 718 + xy: 206, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Specialist rotate: false - xy: 2, 4 + xy: 104, 106 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 StatIcons/Strength rotate: false - xy: 1796, 816 + xy: 1848, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 TechIcons/Radar rotate: false - xy: 2, 922 + xy: 2, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Radio rotate: false - xy: 2, 820 + xy: 104, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 @@ -3148,2142 +3155,2142 @@ TechIcons/Railroad index: -1 TechIcons/Refrigeration rotate: false - xy: 104, 820 + xy: 206, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Replaceable Parts rotate: false - xy: 206, 922 + xy: 2, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Rifling rotate: false - xy: 2, 514 + xy: 104, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Robotics rotate: false - xy: 206, 718 + xy: 308, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Rocketry rotate: false - xy: 410, 922 + xy: 2, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Sailing rotate: false - xy: 2, 310 + xy: 104, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Satellites rotate: false - xy: 206, 514 + xy: 308, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Scientific Theory rotate: false - xy: 512, 820 + xy: 614, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Steam Power rotate: false - xy: 716, 718 + xy: 818, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Steel rotate: false - xy: 818, 820 + xy: 920, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/The Wheel rotate: false - xy: 410, 106 + xy: 512, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Theology rotate: false - xy: 614, 310 + xy: 716, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Trapping rotate: false - xy: 818, 514 + xy: 920, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TechIcons/Writing rotate: false - xy: 1124, 615 + xy: 1226, 717 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TileSets/Default/Railroad rotate: false - xy: 104, 922 + xy: 104, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 ImprovementIcons/Railroad rotate: false - xy: 104, 922 + xy: 104, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 TileSets/FantasyHex/Railroad rotate: false - xy: 1328, 909 + xy: 1430, 1011 size: 61, 11 orig: 61, 11 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Academy rotate: false - xy: 716, 118 + xy: 1278, 679 size: 32, 36 orig: 32, 36 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Aluminum rotate: false - xy: 1176, 585 + xy: 614, 11 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Ancient ruins rotate: false - xy: 768, 178 + xy: 770, 178 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Atoll rotate: false - xy: 1380, 773 + xy: 1226, 635 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Bananas rotate: false - xy: 1058, 380 + xy: 954, 330 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Barbarian encampment rotate: false - xy: 1092, 380 + xy: 1056, 432 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Barringer Crater rotate: false - xy: 1176, 555 + xy: 1158, 534 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Camp+Deer rotate: false - xy: 2002, 874 + xy: 1794, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Camp+Furs rotate: false - xy: 2004, 844 + xy: 1828, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Camp+Ivory rotate: false - xy: 2004, 814 + xy: 1862, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Cattle rotate: false - xy: 1244, 584 + xy: 768, 118 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Cerro de Potosi rotate: false - xy: 1244, 554 + xy: 1692, 652 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Citadel rotate: false - xy: 836, 169 + xy: 1794, 645 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/City rotate: false - xy: 870, 169 + xy: 1828, 645 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+City rotate: false - xy: 870, 169 + xy: 1828, 645 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+City rotate: false - xy: 870, 169 + xy: 1828, 645 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/City ruins rotate: false - xy: 802, 146 + xy: 1862, 652 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/City-Ancient era rotate: false - xy: 1986, 772 + xy: 2002, 922 size: 32, 40 orig: 32, 40 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/City-Classical era rotate: false - xy: 1312, 555 + xy: 2002, 880 size: 32, 40 orig: 32, 40 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/City-Medieval era rotate: false - xy: 1346, 555 + xy: 1896, 640 size: 32, 40 orig: 32, 40 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Coal rotate: false - xy: 870, 139 + xy: 1964, 654 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Coast rotate: false - xy: 1986, 742 + xy: 1862, 622 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Coast+Atoll rotate: false - xy: 904, 174 + xy: 1896, 610 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Coast+Ice rotate: false - xy: 904, 144 + xy: 1930, 624 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Coast+Oil well rotate: false - xy: 938, 174 + xy: 1964, 624 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Cotton rotate: false - xy: 1006, 174 + xy: 802, 118 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Customs house rotate: false - xy: 754, 85 + xy: 872, 169 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Deer rotate: false - xy: 754, 55 + xy: 836, 118 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert rotate: false - xy: 770, 25 + xy: 872, 139 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+City rotate: false - xy: 1026, 345 + xy: 2004, 845 size: 32, 33 orig: 32, 33 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+Fallout rotate: false - xy: 1026, 315 + xy: 2004, 815 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+Farm rotate: false - xy: 1060, 350 + xy: 2004, 785 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+Flood plains rotate: false - xy: 1026, 285 + xy: 2004, 755 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+Flood plains+Farm rotate: false - xy: 1060, 320 + xy: 2004, 725 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Desert+Oasis rotate: false - xy: 1026, 255 + xy: 870, 109 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Dyes rotate: false - xy: 1026, 225 + xy: 1964, 594 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/El Dorado rotate: false - xy: 1060, 261 + xy: 1312, 685 size: 32, 29 orig: 32, 29 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Fish rotate: false - xy: 1060, 231 + xy: 1346, 686 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Fishing Boats rotate: false - xy: 1094, 350 + xy: 1312, 655 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Fishing Boats+Whales rotate: false - xy: 1094, 320 + xy: 1380, 686 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Fort rotate: false - xy: 1094, 255 + xy: 1380, 651 size: 32, 33 orig: 32, 33 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Fountain of Youth rotate: false - xy: 1094, 221 + xy: 906, 172 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Furs rotate: false - xy: 1094, 191 + xy: 648, 11 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Gems rotate: false - xy: 1108, 161 + xy: 870, 79 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Gold rotate: false - xy: 1074, 131 + xy: 2004, 695 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grand Mesa rotate: false - xy: 1108, 127 + xy: 1998, 661 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland rotate: false - xy: 1040, 117 + xy: 1998, 631 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Fallout rotate: false - xy: 1074, 101 + xy: 1998, 601 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Farm rotate: false - xy: 1108, 97 + xy: 677, 76 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest rotate: false - xy: 1126, 500 + xy: 711, 71 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Aluminum rotate: false - xy: 1126, 467 + xy: 666, 43 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Camp rotate: false - xy: 1128, 434 + xy: 700, 38 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Camp+Deer rotate: false - xy: 1128, 401 + xy: 1414, 666 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Camp+Furs rotate: false - xy: 1128, 368 + xy: 1448, 666 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Coal rotate: false - xy: 1128, 335 + xy: 1414, 633 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Gold rotate: false - xy: 1128, 302 + xy: 1448, 633 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Iron rotate: false - xy: 1128, 269 + xy: 1482, 627 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Lumber mill rotate: false - xy: 1128, 236 + xy: 1516, 627 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Forest+Silver rotate: false - xy: 1128, 203 + xy: 1550, 627 size: 32, 31 orig: 32, 31 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Jungle rotate: false - xy: 1382, 739 + xy: 1584, 626 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Jungle+Trading post rotate: false - xy: 1382, 705 + xy: 1618, 626 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Grassland+Marsh rotate: false - xy: 1382, 674 + xy: 1652, 629 size: 32, 29 orig: 32, 29 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Great Barrier Reef rotate: false - xy: 1382, 614 + xy: 1024, 402 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill rotate: false - xy: 1484, 734 + xy: 1024, 342 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Fallout rotate: false - xy: 1416, 670 + xy: 1058, 338 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Farm rotate: false - xy: 1450, 704 + xy: 1092, 342 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Forest rotate: false - xy: 1518, 734 + xy: 1126, 504 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Forest+Camp rotate: false - xy: 1416, 640 + xy: 1126, 474 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Forest+Lumber mill rotate: false - xy: 1450, 674 + xy: 1160, 504 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Forest+Trading post rotate: false - xy: 1484, 704 + xy: 1160, 474 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Marble+Quarry rotate: false - xy: 1552, 734 + xy: 1194, 504 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Mine rotate: false - xy: 1416, 610 + xy: 1194, 474 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Stone+Quarry rotate: false - xy: 1450, 644 + xy: 1126, 444 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Hill+Terrace farm rotate: false - xy: 1484, 674 + xy: 1160, 444 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Horses rotate: false - xy: 1450, 614 + xy: 1126, 384 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Incense rotate: false - xy: 1518, 674 + xy: 1126, 354 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Iron rotate: false - xy: 1552, 704 + xy: 1160, 384 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Ivory rotate: false - xy: 1484, 614 + xy: 1160, 354 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Krakatoa rotate: false - xy: 1586, 674 + xy: 1092, 310 size: 32, 30 orig: 32, 30 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Lakes rotate: false - xy: 1518, 614 + xy: 1126, 296 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Landmark rotate: false - xy: 1688, 726 + xy: 922, 292 size: 32, 36 orig: 32, 36 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Manufactory rotate: false - xy: 1688, 685 + xy: 990, 261 size: 32, 39 orig: 32, 39 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Marble rotate: false - xy: 1756, 734 + xy: 1058, 308 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Mine rotate: false - xy: 1654, 648 + xy: 1092, 280 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Moai rotate: false - xy: 1722, 673 + xy: 990, 230 size: 32, 29 orig: 32, 29 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Mount Fuji rotate: false - xy: 1756, 702 + xy: 1092, 248 size: 32, 30 orig: 32, 30 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Mountain rotate: false - xy: 1790, 696 + xy: 1126, 258 size: 32, 36 orig: 32, 36 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Ocean rotate: false - xy: 1824, 734 + xy: 1092, 218 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Ocean+Atoll rotate: false - xy: 1858, 734 + xy: 1126, 228 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Ocean+Ice rotate: false - xy: 1824, 704 + xy: 1160, 236 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Oil rotate: false - xy: 1892, 734 + xy: 1194, 236 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Oil well rotate: false - xy: 1858, 704 + xy: 956, 210 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Old Faithful rotate: false - xy: 1892, 700 + xy: 990, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pasture rotate: false - xy: 1824, 674 + xy: 1092, 188 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pasture+Cattle rotate: false - xy: 1416, 576 + xy: 1160, 202 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pasture+Horses rotate: false - xy: 1450, 580 + xy: 1194, 202 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pasture+Sheep rotate: false - xy: 1484, 580 + xy: 940, 176 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pasture2 rotate: false - xy: 1858, 674 + xy: 1126, 198 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Pearls rotate: false - xy: 1518, 584 + xy: 940, 146 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains rotate: false - xy: 1620, 588 + xy: 974, 136 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+City rotate: false - xy: 1654, 581 + xy: 1008, 129 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Fallout rotate: false - xy: 1688, 597 + xy: 1042, 160 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Farm rotate: false - xy: 1722, 613 + xy: 1042, 130 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Forest rotate: false - xy: 1756, 610 + xy: 1076, 154 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Forest+Camp rotate: false - xy: 1790, 632 + xy: 1076, 120 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Forest+Lumber mill rotate: false - xy: 1824, 640 + xy: 1110, 154 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Jungle rotate: false - xy: 1858, 640 + xy: 1110, 120 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plains+Jungle+Trading post rotate: false - xy: 1892, 666 + xy: 1228, 601 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation rotate: false - xy: 1892, 636 + xy: 1228, 571 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Bananas rotate: false - xy: 1790, 602 + xy: 940, 116 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Cotton rotate: false - xy: 1824, 610 + xy: 906, 114 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Dyes rotate: false - xy: 1858, 610 + xy: 904, 84 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Incense rotate: false - xy: 1892, 606 + xy: 974, 106 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Silk rotate: false - xy: 1414, 546 + xy: 1008, 99 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Spices rotate: false - xy: 1722, 583 + xy: 1042, 100 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Sugar rotate: false - xy: 1756, 580 + xy: 1076, 90 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Plantation+Wine rotate: false - xy: 1688, 567 + xy: 1110, 90 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Polder rotate: false - xy: 1790, 572 + xy: 940, 86 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Quarry rotate: false - xy: 1824, 580 + xy: 974, 76 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Quarry+Marble rotate: false - xy: 1858, 580 + xy: 1008, 69 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Quarry+Stone rotate: false - xy: 1892, 576 + xy: 1042, 70 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/River-Bottom rotate: false - xy: 1756, 550 + xy: 1110, 60 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/Default/Tiles/River-Bottom rotate: false - xy: 1756, 550 + xy: 1110, 60 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/River-BottomLeft rotate: false - xy: 1790, 542 + xy: 1042, 40 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/Default/Tiles/River-BottomLeft rotate: false - xy: 1790, 542 + xy: 1042, 40 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/River-BottomRight rotate: false - xy: 1824, 550 + xy: 1076, 30 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/Default/Tiles/River-BottomRight rotate: false - xy: 1824, 550 + xy: 1076, 30 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Rock of Gibraltar rotate: false - xy: 1858, 546 + xy: 1110, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Sheep rotate: false - xy: 1858, 516 + xy: 682, 8 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Silk rotate: false - xy: 1620, 558 + xy: 1998, 571 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Silver rotate: false - xy: 1654, 551 + xy: 1228, 541 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Snow rotate: false - xy: 1756, 520 + xy: 1228, 481 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Snow+Farm rotate: false - xy: 1790, 512 + xy: 1228, 451 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Spices rotate: false - xy: 1858, 486 + xy: 1228, 391 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Stone rotate: false - xy: 1892, 488 + xy: 1228, 361 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Sugar rotate: false - xy: 938, 116 + xy: 1228, 331 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Trading post rotate: false - xy: 1108, 67 + xy: 1228, 181 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra rotate: false - xy: 1142, 115 + xy: 768, 60 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+City rotate: false - xy: 1142, 78 + xy: 802, 53 size: 32, 35 orig: 32, 35 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Fallout rotate: false - xy: 1142, 48 + xy: 768, 30 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Farm rotate: false - xy: 1926, 726 + xy: 836, 58 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Forest rotate: false - xy: 1926, 692 + xy: 870, 45 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Forest+Camp rotate: false - xy: 1926, 658 + xy: 904, 50 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Forest+Camp+Deer rotate: false - xy: 1926, 624 + xy: 938, 52 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Forest+Camp+Furs rotate: false - xy: 1926, 590 + xy: 972, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Tundra+Forest+Lumber mill rotate: false - xy: 1926, 556 + xy: 1006, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Uranium rotate: false - xy: 1926, 498 + xy: 870, 15 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Whales rotate: false - xy: 1518, 554 + xy: 1006, 5 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Wheat rotate: false - xy: 1552, 554 + xy: 1040, 10 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Tiles/Wine rotate: false - xy: 1586, 554 + xy: 1346, 626 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/TopBorder rotate: false - xy: 1074, 71 + xy: 1228, 211 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Anti-Aircraft Gun rotate: false - xy: 1124, 533 + xy: 920, 330 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Anti-Tank Gun rotate: false - xy: 2013, 994 + xy: 1022, 432 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Archer rotate: false - xy: 1024, 380 + xy: 1124, 534 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Artillery rotate: false - xy: 1432, 877 + xy: 2013, 994 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Ballista rotate: false - xy: 1952, 786 + xy: 1692, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Battleship rotate: false - xy: 768, 150 + xy: 1726, 684 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Berserker rotate: false - xy: 2013, 964 + xy: 988, 330 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Bowman rotate: false - xy: 1952, 756 + xy: 1090, 432 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Brute rotate: false - xy: 2002, 934 + xy: 1192, 534 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Camel Archer rotate: false - xy: 2002, 904 + xy: 1760, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Cannon rotate: false - xy: 720, 88 + xy: 1896, 682 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Caravel rotate: false - xy: 720, 60 + xy: 1930, 684 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Carrier rotate: false - xy: 1210, 586 + xy: 1964, 684 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Catapult rotate: false - xy: 1210, 556 + xy: 770, 148 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Cavalry rotate: false - xy: 1278, 584 + xy: 2013, 964 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Chariot Archer rotate: false - xy: 1278, 554 + xy: 1726, 654 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Chu-Ko-Nu rotate: false - xy: 802, 176 + xy: 1760, 652 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/CivilianLandUnit rotate: false - xy: 836, 139 + xy: 1930, 654 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Companion Cavalry rotate: false - xy: 938, 146 + xy: 1278, 651 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Conquistador rotate: false - xy: 972, 176 + xy: 804, 178 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Cossack rotate: false - xy: 972, 146 + xy: 804, 148 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Crossbowman rotate: false - xy: 1006, 144 + xy: 838, 176 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Cruiser rotate: false - xy: 750, 122 + xy: 838, 148 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Destroyer rotate: false - xy: 1060, 292 + xy: 1930, 596 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Foreign Legion rotate: false - xy: 1094, 290 + xy: 1346, 656 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Frigate rotate: false - xy: 1060, 203 + xy: 906, 144 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Galleass rotate: false - xy: 1040, 175 + xy: 768, 90 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Galley rotate: false - xy: 1040, 147 + xy: 802, 90 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Gatling Gun rotate: false - xy: 1074, 161 + xy: 836, 88 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Machine Gun rotate: false - xy: 1074, 161 + xy: 836, 88 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great Artist rotate: false - xy: 1382, 644 + xy: 1686, 622 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great Engineer rotate: false - xy: 1382, 584 + xy: 1024, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Worker rotate: false - xy: 1382, 584 + xy: 1024, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great General rotate: false - xy: 1380, 554 + xy: 1058, 402 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great Merchant rotate: false - xy: 1416, 734 + xy: 1058, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Settler rotate: false - xy: 1416, 734 + xy: 1058, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great Scientist rotate: false - xy: 1450, 734 + xy: 1092, 402 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Great War Infantry rotate: false - xy: 1416, 704 + xy: 1092, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Infantry rotate: false - xy: 1416, 704 + xy: 1092, 372 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Hoplite rotate: false - xy: 1518, 704 + xy: 1194, 444 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Horseman rotate: false - xy: 1586, 734 + xy: 1126, 414 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Hwach'a rotate: false - xy: 1484, 644 + xy: 1160, 414 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Ironclad rotate: false - xy: 1620, 736 + xy: 1194, 416 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Jaguar rotate: false - xy: 1518, 644 + xy: 1194, 386 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Janissary rotate: false - xy: 1552, 674 + xy: 1194, 356 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Keshik rotate: false - xy: 1586, 706 + xy: 1126, 326 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Khan rotate: false - xy: 1654, 736 + xy: 1160, 326 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Knight rotate: false - xy: 1620, 706 + xy: 1194, 326 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Lancer rotate: false - xy: 1552, 644 + xy: 1160, 296 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/LandUnit rotate: false - xy: 1654, 706 + xy: 1194, 296 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Warrior rotate: false - xy: 1654, 706 + xy: 1194, 296 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Landship rotate: false - xy: 1620, 676 + xy: 956, 300 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Landsknecht rotate: false - xy: 1552, 614 + xy: 922, 262 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Legion rotate: false - xy: 1586, 644 + xy: 956, 270 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Longbowman rotate: false - xy: 1722, 734 + xy: 922, 232 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Longswordsman rotate: false - xy: 1620, 646 + xy: 956, 240 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Mandekalu Cavalry rotate: false - xy: 1654, 678 + xy: 990, 302 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Maori Warrior rotate: false - xy: 1586, 614 + xy: 1024, 312 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Marine rotate: false - xy: 1722, 704 + xy: 1024, 282 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Mechanized Infantry rotate: false - xy: 1620, 618 + xy: 1058, 280 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Minuteman rotate: false - xy: 1688, 655 + xy: 1024, 252 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Mohawk Warrior rotate: false - xy: 1790, 734 + xy: 1058, 250 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Musketeer rotate: false - xy: 1756, 672 + xy: 1160, 266 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Musketman rotate: false - xy: 1654, 618 + xy: 1194, 266 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Naresuan's Elephant rotate: false - xy: 1688, 627 + xy: 1024, 224 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Norwegian Ski Infantry rotate: false - xy: 1722, 643 + xy: 1058, 220 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Panzer rotate: false - xy: 1756, 644 + xy: 1024, 196 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Paratrooper rotate: false - xy: 1790, 666 + xy: 1058, 190 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Persian Immortal rotate: false - xy: 1552, 584 + xy: 974, 166 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Pikeman rotate: false - xy: 1586, 584 + xy: 1008, 166 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Rifleman rotate: false - xy: 1722, 553 + xy: 1076, 60 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Rocket Artillery rotate: false - xy: 1892, 546 + xy: 1652, 599 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Scout rotate: false - xy: 1824, 520 + xy: 1686, 592 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Ship of the Line rotate: false - xy: 1892, 518 + xy: 716, 2 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Sipahi rotate: false - xy: 1688, 539 + xy: 750, 2 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Slinger rotate: false - xy: 1722, 523 + xy: 1228, 511 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Spearman rotate: false - xy: 1824, 490 + xy: 1228, 421 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Submarine rotate: false - xy: 904, 116 + xy: 784, 2 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Swordsman rotate: false - xy: 972, 116 + xy: 1228, 301 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Tank rotate: false - xy: 1006, 114 + xy: 1228, 271 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Tercio rotate: false - xy: 1040, 87 + xy: 1228, 241 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Trebuchet rotate: false - xy: 1142, 173 + xy: 734, 41 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Trireme rotate: false - xy: 1142, 145 + xy: 818, 2 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Turtle Ship rotate: false - xy: 1926, 528 + xy: 836, 30 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/War Chariot rotate: false - xy: 1926, 468 + xy: 904, 20 size: 32, 28 orig: 32, 28 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/War Elephant rotate: false - xy: 1892, 460 + xy: 938, 24 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/WaterUnit rotate: false - xy: 1926, 440 + xy: 972, 14 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/Units/Work Boats rotate: false - xy: 1620, 530 + xy: 1074, 2 size: 32, 26 orig: 32, 26 offset: 0, 0 index: -1 TileSets/FantasyHex/road rotate: false - xy: 1430, 1011 + xy: 614, 93 size: 61, 11 orig: 61, 11 offset: 0, 0 index: -1 TileSets/Default/road rotate: false - xy: 1430, 1011 + xy: 614, 93 size: 61, 11 orig: 61, 11 offset: 0, 0 index: -1 UnitIcons/Rifleman rotate: false - xy: 308, 922 + xy: 2, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Rocket Artillery rotate: false - xy: 308, 820 + xy: 410, 922 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Samurai rotate: false - xy: 104, 412 + xy: 206, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Scout rotate: false - xy: 614, 922 + xy: 2, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Settler rotate: false - xy: 104, 310 + xy: 206, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Ship of the Line rotate: false - xy: 410, 616 + xy: 512, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Sipahi rotate: false - xy: 2, 106 + xy: 104, 208 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Slinger rotate: false - xy: 308, 412 + xy: 410, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Spearman rotate: false - xy: 818, 922 + xy: 2, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Stealth Bomber rotate: false - xy: 614, 616 + xy: 716, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Submarine rotate: false - xy: 512, 412 + xy: 614, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Swordsman rotate: false - xy: 716, 616 + xy: 818, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Tank rotate: false - xy: 1022, 922 + xy: 206, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Tercio rotate: false - xy: 410, 208 + xy: 512, 310 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Trebuchet rotate: false - xy: 920, 616 + xy: 1022, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Triplane rotate: false - xy: 1022, 718 + xy: 1124, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Trireme rotate: false - xy: 1124, 819 + xy: 1226, 921 size: 100, 101 orig: 100, 101 offset: 0, 0 index: -1 UnitIcons/Turtle Ship rotate: false - xy: 1226, 922 + xy: 410, 4 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/War Chariot rotate: false - xy: 818, 412 + xy: 920, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/War Elephant rotate: false - xy: 920, 514 + xy: 1022, 616 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Warrior rotate: false - xy: 1022, 616 + xy: 1124, 718 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Work Boats rotate: false - xy: 818, 310 + xy: 920, 412 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Worker rotate: false - xy: 920, 412 + xy: 1022, 514 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitIcons/Zero rotate: false - xy: 1226, 718 + xy: 1328, 820 size: 100, 100 orig: 100, 100 offset: 0, 0 index: -1 UnitPromotionIcons/Accuracy rotate: false - xy: 614, 2 + xy: 818, 258 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Air Repair rotate: false - xy: 666, 2 + xy: 920, 360 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Ambush rotate: false - xy: 718, 2 + xy: 1124, 564 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Armor Plating rotate: false - xy: 920, 360 + xy: 1328, 768 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Barrage rotate: false - xy: 1124, 563 + xy: 614, 41 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Blitz rotate: false - xy: 1226, 666 + xy: 1430, 907 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Boarding Party rotate: false - xy: 1328, 857 + xy: 1430, 855 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Bombardment rotate: false - xy: 1430, 959 + xy: 1328, 716 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Charge rotate: false - xy: 716, 156 + xy: 716, 104 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Coastal Raider rotate: false - xy: 1226, 614 + xy: 870, 206 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Cover rotate: false - xy: 870, 206 + xy: 1176, 564 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 PolicyIcons/Discipline rotate: false - xy: 870, 206 + xy: 1176, 564 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Drill rotate: false - xy: 1278, 666 + xy: 1432, 803 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Evasion rotate: false - xy: 1430, 907 + xy: 1432, 699 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Extended Range rotate: false - xy: 1330, 701 + xy: 1493, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Operational Range rotate: false - xy: 1330, 701 + xy: 1493, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Flight Deck rotate: false - xy: 1330, 597 + xy: 1597, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Formation rotate: false - xy: 1493, 972 + xy: 1649, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Great Generals rotate: false - xy: 1701, 972 + xy: 1857, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Quick Study rotate: false - xy: 1701, 972 + xy: 1857, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Haka War Dance rotate: false - xy: 1753, 972 + xy: 1909, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Heal Instantly rotate: false - xy: 1805, 972 + xy: 1961, 972 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Indirect Fire rotate: false - xy: 1909, 972 + xy: 1482, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Interception rotate: false - xy: 1482, 920 + xy: 1534, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 @@ -5297,112 +5304,112 @@ UnitPromotionIcons/Logistics index: -1 UnitPromotionIcons/March rotate: false - xy: 1742, 920 + xy: 1690, 920 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Medic rotate: false - xy: 1794, 920 + xy: 1690, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Mobility rotate: false - xy: 1586, 868 + xy: 1846, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Morale rotate: false - xy: 1690, 868 + xy: 1898, 868 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Rejuvenation rotate: false - xy: 1380, 855 + xy: 1588, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Scouting rotate: false - xy: 1432, 816 + xy: 1692, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Sentry rotate: false - xy: 1432, 816 + xy: 1692, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Shock rotate: false - xy: 1536, 816 + xy: 1692, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Siege rotate: false - xy: 1588, 816 + xy: 1744, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Slinger Withdraw rotate: false - xy: 1640, 816 + xy: 1796, 816 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Sortie rotate: false - xy: 1692, 816 + xy: 1744, 712 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Targeting rotate: false - xy: 1900, 816 + xy: 1848, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Targeting I (air) rotate: false - xy: 1900, 816 + xy: 1848, 764 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Volley rotate: false - xy: 1744, 764 + xy: 1484, 660 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Wolfpack rotate: false - xy: 1848, 764 + xy: 1588, 660 size: 50, 50 orig: 50, 50 offset: 0, 0 index: -1 UnitPromotionIcons/Woodsman rotate: false - xy: 1900, 764 + xy: 1640, 660 size: 50, 50 orig: 50, 50 offset: 0, 0 diff --git a/android/assets/game.png b/android/assets/game.png index a78404127c..21b33c0d74 100644 Binary files a/android/assets/game.png and b/android/assets/game.png differ diff --git a/android/assets/game2.png b/android/assets/game2.png index d534f07ac1..77c45d425a 100644 Binary files a/android/assets/game2.png and b/android/assets/game2.png differ diff --git a/android/assets/jsons/Civ V - Vanilla/Quests.json b/android/assets/jsons/Civ V - Vanilla/Quests.json new file mode 100644 index 0000000000..4558775a4e --- /dev/null +++ b/android/assets/jsons/Civ V - Vanilla/Quests.json @@ -0,0 +1,113 @@ +[ + { + "name": "Route", + "description": "Build a road to connect your capital to our city.", + "influence": 50 + }, + /* + { + "name": "Kill Camp", + "description": "We feel threatened by a Barbarian Camp near our city. Please take care of it.", + "type": "Global", + "influence": 50, + "minimumCivs": 1 + }, + { + "name": "Connect Resource", + "description": "In order to make our civilizations stronger, connect [Resource] to your trade network." + },*/ + { + "name": "Construct Wonder", + "description": "We recommend you to start building [Wonder] to show the whole world your civilization strength." + },/* + { + "name": "Great Person", + "description": "Great People can change the course of a Civilization! You will be rewarded for acquiring a new [Great Person]." + }, + { + "name": "Kill City State", + "description": "You will be rewarded for destroying the city state of [Target]!", + "influence": 80 + }, + { + "name": "Find Player", + "description": "You have yet to discover where [Civilization] set up their cities. You will be rewarded for finding their territories.", + "influence": 35 + }, + { + "name": "Find Natural Wonder", + "description": "Send your best explorers on a quest to discover Natural Wonders. Nobody knows the location of [Natural Wonder] yet." + },*/ + /* G&K */ + /* + { + "name": "Give Gold", + "description": "", + "influence": 20, + "duration": 30 + }, + { + "name": "Pledge to Protect", + "description": "", + "influence": 20, + "duration": 30 + }, + */ + /* + { + "name": "Contest Culture", + "description": "The civilization with the largest Culture growth will gain a reward.", + "type": "Global", + "duration": 30, + "minimumCivs": 3 + },*/ + /* + { + "name": "Contest Faith", + "description": "", + "type": "Global", + "duration": 30, + "minimumCivs": 3 + },*/ + { + "name": "Contest Techs", + "description": "The civilization with the largest number of new Technologies researched will gain a reward.", + "type": "Global", + "duration": 30, + "minimumCivs": 3 + }, + /* + { + "name": "Invest", + "description": "", + "type": "Global", + "influence": 0, + "duration": 30, + "minimumCivs": 2 + }, + { + "name": "Bully City State", + "description": "" + "duration": 30 + }, + { + "name": "Denounce Civilization", + "description": "", + "duration": 30 + } + */ + /* + { + "name": "Spread Religion", + "description": "" + }, + */ + + /* BNW */ + /* + { + "name": "Trade Route", + "description": "" + } + */ +] \ No newline at end of file diff --git a/android/assets/jsons/translations/template.properties b/android/assets/jsons/translations/template.properties index 4af3f5b6be..a3f6ad302d 100644 --- a/android/assets/jsons/translations/template.properties +++ b/android/assets/jsons/translations/template.properties @@ -90,6 +90,9 @@ Favorable = Friend = Ally = +[questName] (+[influenceAmount] influence) = +Remaining [remainingTurns] turns = + ## Diplomatic modifiers You declared war on us! = @@ -436,7 +439,8 @@ Our proposed trade request is no longer relevant! = [building] has provided [amount] Gold! = [civName] has stolen your territory! = Clearing a [forest] has created [amount] Production for [cityName] = - +[civName] assigned you a new quest: [questName]. = +[civName] rewarded you with [influence] influence for completing the [questName] quest. = # World Screen UI @@ -916,3 +920,24 @@ in this city = in every city = in capital = +# Quests +Route = +Build a road to connect your capital to our city. = +Kill Camp = +We feel threatened by a Barbarian Camp near our city. Please take care of it. = +Connect Resource = +In order to make our civilizations stronger, connect [Resource] to your trade network. = +Construct Wonder = +We recommend you to start building [Wonder] to show the whole world your civilization strength. = +Great Person = +Great People can change the course of a Civilization! You will be rewarded for acquiring a new [Great Person]. = +Kill City State = +You will be rewarded for destroying the city state of [Target]! = +Find Player = +You have yet to discover where [Civilization] set up their cities. You will be rewarded for finding their territories. = +Find Natural Wonder = +Send your best explorers on a quest to discover Natural Wonders. Nobody knows the location of [Natural Wonder] yet. = +Contest Culture = +The civilization with the largest Culture growth will gain a reward. = +Contest Techs = +The civilization with the largest number of new Technologies researched will gain a reward. = diff --git a/core/src/com/unciv/logic/GameInfo.kt b/core/src/com/unciv/logic/GameInfo.kt index 47b9006bc4..2110890275 100644 --- a/core/src/com/unciv/logic/GameInfo.kt +++ b/core/src/com/unciv/logic/GameInfo.kt @@ -73,6 +73,8 @@ class GameInfo { fun getBarbarianCivilization() = getCivilization(Constants.barbarians) fun getDifficulty() = difficultyObject fun getCities() = civilizations.flatMap { it.cities } + fun getAliveCityStates() = civilizations.filter { it.isAlive() && it.isCityState() } + fun getAliveMajorCivs() = civilizations.filter { it.isAlive() && it.isMajorCiv() } //endregion fun nextTurn() { diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 6ecc4c129d..2b8568676d 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -3,7 +3,6 @@ package com.unciv.logic.civilization import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 import com.unciv.Constants -import com.unciv.JsonParser import com.unciv.UncivGame import com.unciv.logic.GameInfo import com.unciv.logic.UncivShowableException @@ -12,12 +11,14 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomaticStatus +import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo import com.unciv.logic.trade.TradeEvaluation import com.unciv.logic.trade.TradeRequest import com.unciv.models.ruleset.* import com.unciv.models.ruleset.tile.ResourceSupplyList +import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.stats.Stats import com.unciv.models.translations.equalsPlaceholderText @@ -56,6 +57,7 @@ class CivilizationInfo { var civName = "" var tech = TechManager() var policies = PolicyManager() + var questManager = QuestManager() var goldenAges = GoldenAgeManager() var greatPeople = GreatPersonManager() var victoryManager=VictoryManager() @@ -89,6 +91,7 @@ class CivilizationInfo { toReturn.civName = civName toReturn.tech = tech.clone() toReturn.policies = policies.clone() + toReturn.questManager = questManager.clone() toReturn.goldenAges = goldenAges.clone() toReturn.greatPeople = greatPeople.clone() toReturn.victoryManager = victoryManager.clone() @@ -133,6 +136,8 @@ class CivilizationInfo { fun isCityState(): Boolean = nation.isCityState() fun getCityStateType(): CityStateType = nation.cityStateType!! fun isMajorCiv() = nation.isMajorCiv() + fun isAlive(): Boolean = !isDefeated() + fun hasEverBeenFriendWith(otherCiv: CivilizationInfo): Boolean = getDiplomacyManager(otherCiv).everBeenFriends() fun victoryType(): VictoryType { if(gameInfo.gameParameters.victoryTypes.size==1) @@ -160,6 +165,8 @@ class CivilizationInfo { return newResourceSupplyList } + fun isCapitalConnectedToCity(city: CityInfo): Boolean = citiesConnectedToCapitalToMediums.keys.contains(city) + /** * Returns a dictionary of ALL resource names, and the amount that the civ has of each @@ -367,11 +374,15 @@ class CivilizationInfo { fun setTransients() { goldenAges.civInfo = this + policies.civInfo = this if(policies.adoptedPolicies.size>0 && policies.numberOfAdoptedPolicies == 0) policies.numberOfAdoptedPolicies = policies.adoptedPolicies.count { !it.endsWith("Complete") } policies.setTransients() + questManager.civInfo = this + questManager.setTransients() + if(citiesCreated==0 && cities.any()) citiesCreated = cities.filter { it.name in nation.cities }.count() @@ -438,6 +449,9 @@ class CivilizationInfo { policies.endTurn(nextTurnStats.culture.toInt()) + if (isCityState()) + questManager.endTurn() + // disband units until there are none left OR the gold values are normal if (!isBarbarian() && gold < -100 && nextTurnStats.gold.toInt() < 0) { for (i in 1 until (gold / -100)) { diff --git a/core/src/com/unciv/logic/civilization/Notification.kt b/core/src/com/unciv/logic/civilization/Notification.kt index ee4caef9a9..48d5def01f 100644 --- a/core/src/com/unciv/logic/civilization/Notification.kt +++ b/core/src/com/unciv/logic/civilization/Notification.kt @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 import com.unciv.ui.cityscreen.CityScreen import com.unciv.ui.pickerscreens.TechPickerScreen +import com.unciv.ui.trade.DiplomacyScreen import com.unciv.ui.worldscreen.WorldScreen /** @@ -54,4 +55,12 @@ data class CityAction(val city: Vector2 = Vector2.Zero): NotificationAction { } } +} + +data class DiplomacyAction(val otherCivName: String = ""): NotificationAction { + override fun execute(worldScreen: WorldScreen) { + val screen = DiplomacyScreen(worldScreen.viewingCiv) + screen.updateRightSide(worldScreen.gameInfo.getCivilization(otherCivName)) + worldScreen.game.setScreen(screen) + } } \ No newline at end of file diff --git a/core/src/com/unciv/logic/civilization/QuestManager.kt b/core/src/com/unciv/logic/civilization/QuestManager.kt new file mode 100644 index 0000000000..4e545572d6 --- /dev/null +++ b/core/src/com/unciv/logic/civilization/QuestManager.kt @@ -0,0 +1,378 @@ +package com.unciv.logic.civilization + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.math.Vector2 +import com.unciv.UncivGame +import com.unciv.logic.GameInfo +import com.unciv.logic.map.TileInfo +import com.unciv.models.ruleset.Building +import com.unciv.models.ruleset.Quest +import com.unciv.models.ruleset.tile.ResourceType +import com.unciv.models.ruleset.tile.TileResource +import com.unciv.models.ruleset.unit.BaseUnit +import com.unciv.models.translations.equalsPlaceholderText +import com.unciv.models.translations.fillPlaceholders +import kotlin.math.max +import kotlin.random.Random + +class QuestManager { + + companion object { + const val UNSET = -1 + + const val GLOBAL_QUEST_FIRST_POSSIBLE_TURN = 30 + const val INDIVIDUAL_QUEST_FIRST_POSSIBLE_TURN = 30 + + const val GLOBAL_QUEST_FIRST_POSSIBLE_TURN_RAND = 20 + const val INDIVIDUAL_QUEST_FIRST_POSSIBLE_TURN_RAND = 20 + + const val GLOBAL_QUEST_MIN_TURNS_BETWEEN = 40 + const val INDIVIDUAL_QUEST_MIN_TURNS_BETWEEN = 20 + + const val GLOBAL_QUEST_RAND_TURNS_BETWEEN = 25 + const val INDIVIDUAL_QUEST_RAND_TURNS_BETWEEN = 25 + + const val GLOBAL_QUEST_MAX_ACTIVE = 1 + const val INDIVIDUAL_QUEST_MAX_ACTIVE = 2 + } + + /** Civilization object holding and dispatching quests */ + @Transient + lateinit var civInfo: CivilizationInfo + + /** List of active quests, both global and individual ones*/ + var assignedQuests: ArrayList = ArrayList() + + /** Number of turns left before starting new global quest */ + private var globalQuestCountdown: Int = UNSET + + /** Number of turns left before this city state can start a new individual quest */ + private var individualQuestCountdown: HashMap = HashMap() + + /** Returns [true] if [civInfo] have active quests for [challenger] */ + fun haveQuestsFor(challenger: CivilizationInfo): Boolean = assignedQuests.any { it.assignee == challenger.civName } + + fun clone(): QuestManager { + val toReturn = QuestManager() + toReturn.globalQuestCountdown = globalQuestCountdown + toReturn.individualQuestCountdown.putAll(individualQuestCountdown) + toReturn.assignedQuests.addAll(assignedQuests) + return toReturn + } + + fun setTransients() { + for (quest in assignedQuests) + quest.gameInfo = civInfo.gameInfo + } + + fun endTurn() { + + if (civInfo.isDefeated()) { + assignedQuests.clear() + individualQuestCountdown.clear() + globalQuestCountdown = UNSET + return + } + + seedGlobalQuestCountdown() + seedIndividualQuestsCountdown() + + decrementQuestCountdowns() + + handleGlobalQuests() + handleIndividualQuests() + + tryStartNewGlobalQuest() + tryStartNewIndividualQuests() + } + + private fun decrementQuestCountdowns() { + if (globalQuestCountdown > 0) + globalQuestCountdown -= 1 + + for (entry in individualQuestCountdown) + if (entry.value > 0) + entry.setValue(entry.value - 1) + } + + private fun seedGlobalQuestCountdown() { + if (civInfo.gameInfo.turns < GLOBAL_QUEST_FIRST_POSSIBLE_TURN) + return + + if (globalQuestCountdown != UNSET) + return + + val countdown = + if (civInfo.gameInfo.turns == GLOBAL_QUEST_FIRST_POSSIBLE_TURN) + Random.nextInt(GLOBAL_QUEST_FIRST_POSSIBLE_TURN_RAND) + else + GLOBAL_QUEST_MIN_TURNS_BETWEEN + Random.nextInt(GLOBAL_QUEST_RAND_TURNS_BETWEEN) + + globalQuestCountdown = (countdown * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + } + + private fun seedIndividualQuestsCountdown() { + if (civInfo.gameInfo.turns < INDIVIDUAL_QUEST_FIRST_POSSIBLE_TURN) + return + + val majorCivs = civInfo.gameInfo.getAliveMajorCivs() + for (majorCiv in majorCivs) + if (!individualQuestCountdown.containsKey(majorCiv.civName) || individualQuestCountdown[majorCiv.civName] == UNSET) + seedIndividualQuestsCountdown(majorCiv) + } + + private fun seedIndividualQuestsCountdown(challenger: CivilizationInfo) { + val countdown: Int = + if (civInfo.gameInfo.turns == INDIVIDUAL_QUEST_FIRST_POSSIBLE_TURN) + Random.nextInt(INDIVIDUAL_QUEST_FIRST_POSSIBLE_TURN_RAND) + else + INDIVIDUAL_QUEST_MIN_TURNS_BETWEEN + Random.nextInt(INDIVIDUAL_QUEST_RAND_TURNS_BETWEEN) + + individualQuestCountdown[challenger.civName] = (countdown * civInfo.gameInfo.gameParameters.gameSpeed.modifier).toInt() + } + + private fun tryStartNewGlobalQuest() { + if (globalQuestCountdown != 0) + return + if (assignedQuests.count { it.isGlobal() } >= GLOBAL_QUEST_MAX_ACTIVE) + return + + val globalQuests = civInfo.gameInfo.ruleSet.quests.values.filter { it.isGlobal() } + val majorCivs = civInfo.getKnownCivs().filter { it.isMajorCiv() && !it.isAtWarWith(civInfo) } + + val assignableQuests = ArrayList() + for (quest in globalQuests) { + val numberValidMajorCivs = majorCivs.count { civ -> isQuestValid(quest, civ) } + if (numberValidMajorCivs >= quest.minimumCivs) + assignableQuests.add(quest) + } + + //TODO: quest probabilities should change based on City State personality and traits + if (assignableQuests.isNotEmpty()) { + val quest = assignableQuests.random() + val assignees = civInfo.gameInfo.getAliveMajorCivs().filter { !it.isAtWarWith(civInfo) && isQuestValid(quest, it) } + + assignNewQuest(quest, assignees) + globalQuestCountdown = UNSET + } + } + + private fun tryStartNewIndividualQuests() { + for ((challengerName, countdown) in individualQuestCountdown) { + val challenger = civInfo.gameInfo.getCivilization(challengerName) + + if (countdown != 0) + return + + if (assignedQuests.count { it.assignee == challenger.civName && it.isIndividual() } >= INDIVIDUAL_QUEST_MAX_ACTIVE) + return + + val assignableQuests = civInfo.gameInfo.ruleSet.quests.values.filter { it.isIndividual() && isQuestValid(it, challenger) } + //TODO: quest probabilities should change based on City State personality and traits + if (assignableQuests.isNotEmpty()) { + + val quest = assignableQuests.random() + val assignees = arrayListOf(challenger) + + assignNewQuest(quest, assignees) + } + } + } + + private fun handleGlobalQuests() { + val globalQuestsExpired = assignedQuests.filter { it.isGlobal() && it.isExpired() }.map { it.questName }.distinct() + for (globalQuestName in globalQuestsExpired) + handleGlobalQuest(globalQuestName) + } + + private fun handleGlobalQuest(questName: String) { + val quests = assignedQuests.filter { it.questName == questName } + if (quests.isEmpty()) + return + + val topScore = quests.map { getScoreForQuest(it) }.max()!! + + for (quest in quests) { + if (getScoreForQuest(quest) >= topScore) + giveReward(quest) + } + + assignedQuests.removeAll(quests) + } + + private fun handleIndividualQuests() { + val toRemove = ArrayList() + + for (assignedQuest in assignedQuests.filter { it.isIndividual() }) { + val shouldRemove = handleIndividualQuest(assignedQuest) + if (shouldRemove) + toRemove.add(assignedQuest) + } + + assignedQuests.removeAll(toRemove) + } + + /** If quest is complete, it gives the influence reward to the player. + * Returns [true] if the quest can be removed (is either complete, obsolete or expired) */ + private fun handleIndividualQuest(assignedQuest: AssignedQuest): Boolean { + val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) + + // One of the civs is defeated, or they started a war: remove quest + if (!canAssignAQuestTo(assignee)) + return true + + if (isComplete(assignedQuest)) { + giveReward(assignedQuest) + return true + } + + if (isObsolete(assignedQuest)) + return true + + if (assignedQuest.isExpired()) + return true + + return false + } + + private fun assignNewQuest(quest: Quest, assignees: Iterable) { + + val turn = civInfo.gameInfo.turns + + for (assignee in assignees) { + + var data1 = "" + var data2 = "" + + when (quest.name) { + "Construct Wonder" -> data1 = getWonderToBuildForQuest(assignee)!!.name + "Contest Techs" -> data1 = assignee.tech.getNumberOfTechsResearched().toString() + } + + val newQuest = AssignedQuest( + questName = quest.name, + assigner = civInfo.civName, + assignee = assignee.civName, + assignedOnTurn = turn, + data1 = data1, + data2 = data2 + ) + newQuest.gameInfo = civInfo.gameInfo + + assignedQuests.add(newQuest) + assignee.addNotification("[${civInfo.civName}] assigned you a new quest: [${quest.name}].", Color.GOLD, DiplomacyAction(civInfo.civName)) + + if (quest.isIndividual()) + individualQuestCountdown[assignee.civName] = UNSET + } + } + + /** Returns [true] if [civInfo] can assign a quest to [challenger] */ + private fun canAssignAQuestTo(challenger: CivilizationInfo): Boolean { + return !challenger.isDefeated() && challenger.isMajorCiv() && + civInfo.knows(challenger) && !civInfo.isAtWarWith(challenger) + } + + /** Returns [true] if the [quest] can be assigned to [challenger] */ + private fun isQuestValid(quest: Quest, challenger: CivilizationInfo): Boolean { + if (!canAssignAQuestTo(challenger)) + return false + if (assignedQuests.any { it.assignee == challenger.civName && it.questName == quest.name }) + return false + + return when (quest.name) { + "Route" -> civInfo.hasEverBeenFriendWith(challenger) && !civInfo.isCapitalConnectedToCity(challenger.getCapital()) + "Construct Wonder" -> civInfo.hasEverBeenFriendWith(challenger) && getWonderToBuildForQuest(challenger) != null + else -> true + } + } + + /** Returns [true] if the [assignedQuest] is successfully completed */ + private fun isComplete(assignedQuest: AssignedQuest): Boolean { + val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) + return when (assignedQuest.questName) { + "Route" -> civInfo.isCapitalConnectedToCity(assignee.getCapital()) + "Construct Wonder" -> assignee.cities.any { it.cityConstructions.isBuilt(assignedQuest.data1) } + else -> false + } + } + + /** Returns [true] if the [assignedQuest] request cannot be fulfilled anymore */ + private fun isObsolete(assignedQuest: AssignedQuest): Boolean { + val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) + return when (assignedQuest.questName) { + "Construct Wonder" -> civInfo.gameInfo.getCities().any { it.civInfo != assignee && it.cityConstructions.isBuilt(assignedQuest.data1) } + else -> false + } + } + + /** Increments [assignedQuest.assignee] influence on [civInfo] and adds a [Notification] */ + private fun giveReward(assignedQuest: AssignedQuest) { + val rewardInfluence = civInfo.gameInfo.ruleSet.quests[assignedQuest.questName]!!.influece + val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) + + civInfo.getDiplomacyManager(assignedQuest.assignee).influence += rewardInfluence + if (rewardInfluence > 0) + assignee.addNotification("[${civInfo.civName}] rewarded you with [${rewardInfluence.toInt()}] influence for completing the [${assignedQuest.questName}] quest.", civInfo.getCapital().location, Color.GOLD) + } + + /** Returns the score for the [assignedQuest] */ + private fun getScoreForQuest(assignedQuest: AssignedQuest): Int { + val assignee = civInfo.gameInfo.getCivilization(assignedQuest.assignee) + return when (assignedQuest.questName) { + "Contest Techs" -> assignee.tech.getNumberOfTechsResearched() - assignedQuest.data1.toInt() + else -> 0 + } + } + + //region get-quest-target + private fun getWonderToBuildForQuest(challenger: CivilizationInfo): Building? { + val wonders = civInfo.gameInfo.ruleSet.buildings.values + .filter { building -> + building.isWonder && + (building.requiredTech == null || challenger.tech.isResearched(building.requiredTech!!)) && + civInfo.gameInfo.getCities().none { it.cityConstructions.isBuilt(building.name) } + } + + if (wonders.isNotEmpty()) + return wonders.random() + + return null + } + //endregion +} + + +class AssignedQuest(val questName: String = "", + val assigner: String = "", + val assignee: String = "", + val assignedOnTurn: Int = 0, + val data1: String = "", + val data2: String = "") { + + @Transient + lateinit var gameInfo: GameInfo + + fun isIndividual(): Boolean = !isGlobal() + fun isGlobal(): Boolean = gameInfo.ruleSet.quests[questName]!!.isGlobal() + fun doesExpire(): Boolean = gameInfo.ruleSet.quests[questName]!!.duration > 0 + fun isExpired(): Boolean = doesExpire() && getRemainingTurns() == 0 + fun getDuration(): Int = (gameInfo.gameParameters.gameSpeed.modifier * gameInfo.ruleSet.quests[questName]!!.duration).toInt() + fun getRemainingTurns(): Int = max(0, (assignedOnTurn + getDuration()) - gameInfo.turns) + + fun getDescription(): String { + val quest = gameInfo.ruleSet.quests[questName]!! + return quest.description.fillPlaceholders(data1) + } + + fun onClickAction() { + val game = UncivGame.Current + + when (questName) { + "Route" -> { + game.setWorldScreen() + game.worldScreen.mapHolder.setCenterPosition(gameInfo.getCivilization(assigner).getCapital().location, selectUnit = false) + } + } + } +} diff --git a/core/src/com/unciv/logic/civilization/TechManager.kt b/core/src/com/unciv/logic/civilization/TechManager.kt index 9503d030fc..bafb951d46 100644 --- a/core/src/com/unciv/logic/civilization/TechManager.kt +++ b/core/src/com/unciv/logic/civilization/TechManager.kt @@ -59,6 +59,8 @@ class TechManager { return toReturn } + fun getNumberOfTechsResearched(): Int = techsResearched.size + fun getRuleset() = civInfo.gameInfo.ruleSet fun costOfTech(techName: String): Int { diff --git a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt index 7ba0f6c5c6..29bf76a020 100644 --- a/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt +++ b/core/src/com/unciv/logic/civilization/diplomacy/DiplomacyManager.kt @@ -33,7 +33,8 @@ enum class DiplomacyFlags{ SettledCitiesNearUs, AgreedToNotSettleNearUs, IgnoreThemSettlingNearUs, - ProvideMilitaryUnit + ProvideMilitaryUnit, + EverBeenFriends } enum class DiplomaticModifiers{ @@ -285,6 +286,16 @@ class DiplomacyManager() { nextTurnFlags() if (civInfo.isCityState() && !otherCiv().isCityState()) nextTurnCityStateInfluence() + updateEverBeenFriends() + } + + /** True when the two civs have been friends in the past */ + fun everBeenFriends(): Boolean = hasFlag(DiplomacyFlags.EverBeenFriends) + + /** Set [DiplomacyFlags.EverBeenFriends] if the two civilization are currently at least friends */ + private fun updateEverBeenFriends() { + if (relationshipLevel() >= RelationshipLevel.Friend && !everBeenFriends()) + setFlag(DiplomacyFlags.EverBeenFriends, -1) } private fun nextTurnCityStateInfluence() { @@ -310,21 +321,35 @@ class DiplomacyManager() { } private fun nextTurnFlags() { - for (flag in flagsCountdown.keys.toList()) { - if (flag == DiplomacyFlags.ResearchAgreement.name){ + loop@ for (flag in flagsCountdown.keys.toList()) { + // No need to decrement negative countdown flags: they do not expire + if (flagsCountdown[flag]!! > 0) + flagsCountdown[flag] = flagsCountdown[flag]!! - 1 + + // At the end of every turn + if (flag == DiplomacyFlags.ResearchAgreement.name) totalOfScienceDuringRA += civInfo.statsForNextTurn.science.toInt() - } - flagsCountdown[flag] = flagsCountdown[flag]!! - 1 + + // Only when flag is expired if (flagsCountdown[flag] == 0) { - if (flag == DiplomacyFlags.ResearchAgreement.name && !otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)) - sciencefromResearchAgreement() - if (flag == DiplomacyFlags.ProvideMilitaryUnit.name && civInfo.cities.isEmpty() || otherCiv().cities.isEmpty()) - continue + when (flag) { + DiplomacyFlags.ResearchAgreement.name -> { + if (!otherCivDiplomacy().hasFlag(DiplomacyFlags.ResearchAgreement)) + sciencefromResearchAgreement() + } + DiplomacyFlags.ProvideMilitaryUnit.name -> { + // Do not unset the flag + if (civInfo.cities.isEmpty() || otherCiv().cities.isEmpty()) + continue@loop + else + civInfo.giftMilitaryUnitTo(otherCiv()) + } + DiplomacyFlags.AgreedToNotSettleNearUs.name -> { + addModifier(DiplomaticModifiers.FulfilledPromiseToNotSettleCitiesNearUs, 10f) + } + } + flagsCountdown.remove(flag) - if (flag == DiplomacyFlags.AgreedToNotSettleNearUs.name) - addModifier(DiplomaticModifiers.FulfilledPromiseToNotSettleCitiesNearUs, 10f) - else if (flag == DiplomacyFlags.ProvideMilitaryUnit.name) - civInfo.giftMilitaryUnitTo(otherCiv()) } } } diff --git a/core/src/com/unciv/models/ruleset/Quest.kt b/core/src/com/unciv/models/ruleset/Quest.kt new file mode 100644 index 0000000000..7312577aa9 --- /dev/null +++ b/core/src/com/unciv/models/ruleset/Quest.kt @@ -0,0 +1,35 @@ +package com.unciv.models.ruleset + +import com.unciv.models.stats.INamed + +enum class QuestType { + Individual, + Global +} + +/** [Quest] class holds all functionality relative to a quest */ +class Quest : INamed { + + /** Unique identifier name of the quest, it is also shown */ + override var name: String = "" + + /** Descrption of the quest shown to players */ + var description: String = "" + + /** [QuestType]: it is either Individual or Global */ + var type: QuestType = QuestType.Individual + + /** Influence reward gained on quest completion */ + var influece: Float = 40f + + /** Maximum number of turns to complete the quest, 0 if there's no turn limit */ + var duration: Int = 0 + + /**Minimum number of [CivInfo] needed to start the quest. It is meaningful only for [QuestType.Global] + * quests [type]. */ + var minimumCivs: Int = 1 + + /** Checks if [this] is a Global quest */ + fun isGlobal(): Boolean = type == QuestType.Global + fun isIndividual(): Boolean = !isGlobal() +} \ No newline at end of file diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index 30509e15a0..e01d46ae7a 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -1,11 +1,8 @@ package com.unciv.models.ruleset -import com.badlogic.gdx.Files import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle -import com.unciv.Constants import com.unciv.JsonParser -import com.unciv.UncivGame import com.unciv.logic.UncivShowableException import com.unciv.models.metadata.BaseRuleset import com.unciv.models.metadata.GameParameters @@ -17,7 +14,6 @@ import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.Promotion import com.unciv.models.stats.INamed -import java.lang.StringBuilder import kotlin.collections.set object ModOptionsConstants { @@ -46,6 +42,7 @@ class Ruleset { val units = LinkedHashMap() val unitPromotions = LinkedHashMap() val nations = LinkedHashMap() + val quests = LinkedHashMap() val policyBranches = LinkedHashMap() val difficulties = LinkedHashMap() val mods = LinkedHashSet() @@ -70,6 +67,7 @@ class Ruleset { difficulties.putAll(ruleset.difficulties) nations.putAll(ruleset.nations) policyBranches.putAll(ruleset.policyBranches) + quests.putAll(ruleset.quests) technologies.putAll(ruleset.technologies) for (techToRemove in ruleset.modOptions.techsToRemove) technologies.remove(techToRemove) terrains.putAll(ruleset.terrains) @@ -87,6 +85,7 @@ class Ruleset { difficulties.clear() nations.clear() policyBranches.clear() + quests.clear() technologies.clear() buildings.clear() terrains.clear() @@ -139,6 +138,9 @@ class Ruleset { val promotionsFile = folderHandle.child("UnitPromotions.json") if (promotionsFile.exists()) unitPromotions += createHashmap(jsonParser.getFromJson(Array::class.java, promotionsFile)) + val questsFile = folderHandle.child("Quests.json") + if (questsFile.exists()) quests += createHashmap(jsonParser.getFromJson(Array::class.java, questsFile)) + val policiesFile = folderHandle.child("Policies.json") if (policiesFile.exists()) { policyBranches += createHashmap(jsonParser.getFromJson(Array::class.java, policiesFile)) diff --git a/core/src/com/unciv/models/translations/Translations.kt b/core/src/com/unciv/models/translations/Translations.kt index c15bbad89d..4508e4d4ef 100644 --- a/core/src/com/unciv/models/translations/Translations.kt +++ b/core/src/com/unciv/models/translations/Translations.kt @@ -282,4 +282,16 @@ fun String.equalsPlaceholderText(str:String): Boolean { return this.getPlaceholderText() == str } -fun String.getPlaceholderParameters() = squareBraceRegex.findAll(this).map { it.groups[1]!!.value }.toList() \ No newline at end of file +fun String.getPlaceholderParameters() = squareBraceRegex.findAll(this).map { it.groups[1]!!.value }.toList() + +/** Substitutes placeholders with [strings], respecting order of appearance. */ +fun String.fillPlaceholders(vararg strings: String): String { + val keys = this.getPlaceholderParameters() + if (keys.size > strings.size) + throw Exception("String $this has a different number of placeholders ${keys.joinToString()} (${keys.size}) than the substitutive strings ${strings.joinToString()} (${strings.size})!") + + var filledString = this + for (i in keys.indices) + filledString = filledString.replaceFirst(keys[i], strings[i]) + return filledString +} diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index 970af9da7d..e7d16878bd 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -4,12 +4,10 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.ui.SplitPane import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton +import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.UncivGame -import com.unciv.logic.civilization.AlertType -import com.unciv.logic.civilization.CityStateType -import com.unciv.logic.civilization.CivilizationInfo -import com.unciv.logic.civilization.PopupAlert +import com.unciv.logic.civilization.* import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.civilization.diplomacy.DiplomacyManager import com.unciv.logic.civilization.diplomacy.DiplomaticModifiers.* @@ -18,8 +16,10 @@ import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType import com.unciv.models.ruleset.ModOptionsConstants +import com.unciv.models.ruleset.Quest import com.unciv.models.translations.tr import com.unciv.ui.utils.* +import kotlin.math.floor import kotlin.math.roundToInt import com.unciv.ui.utils.AutoScrollPane as ScrollPane @@ -65,6 +65,12 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { relationship.setSize(30f,30f) civIndicator.addActor(relationship) + if (civ.isCityState() && civ.questManager.haveQuestsFor(viewingCiv)) { + val questIcon = ImageGetter.getImage("OtherIcons/Quest").surroundWithCircle(size = 30f, color = Color.GOLDENROD) + civIndicator.addActor(questIcon) + questIcon.setX(floor(civIndicator.width - questIcon.width)) + } + leftSideTable.add(civIndicator).row() civIndicator.onClick { @@ -171,9 +177,34 @@ class DiplomacyScreen(val viewingCiv:CivilizationInfo):CameraStageBaseScreen() { } } + for (assignedQuest in otherCiv.questManager.assignedQuests.filter { it.assignee == viewingCiv.civName}) { + diplomacyTable.addSeparator() + diplomacyTable.add(getQuestTable(assignedQuest)).row() + } + return diplomacyTable } + private fun getQuestTable(assignedQuest: AssignedQuest): Table { + val questTable = Table() + questTable.defaults().pad(10f) + + val quest: Quest = viewingCiv.gameInfo.ruleSet.quests[assignedQuest.questName]!! + val remainingTurns: Int = assignedQuest.getRemainingTurns() + val title = "[${quest.name}] (+[${quest.influece.toInt()}] influence)" + val description = assignedQuest.getDescription() + + questTable.add(title.toLabel(fontSize = 24)).row() + questTable.add(description.toLabel()).row() + if (quest.duration > 0) + questTable.add("Remaining [${remainingTurns}] turns".toLabel()).row() + + questTable.onClick { + assignedQuest.onClickAction() + } + return questTable + } + private fun getMajorCivDiplomacyTable(otherCiv: CivilizationInfo): Table { val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv) diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index 235382664a..6858f81411 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -166,8 +166,8 @@ fun Actor.onChange(function: () -> Unit): Actor { return this } -fun Actor.surroundWithCircle(size:Float,resizeActor:Boolean=true): IconCircleGroup { - return IconCircleGroup(size,this,resizeActor) +fun Actor.surroundWithCircle(size: Float, resizeActor: Boolean = true, color: Color = Color.WHITE): IconCircleGroup { + return IconCircleGroup(size,this,resizeActor, color) } fun Actor.addBorder(size:Float,color:Color,expandCell:Boolean=false):Table{ diff --git a/core/src/com/unciv/ui/utils/IconCircleGroup.kt b/core/src/com/unciv/ui/utils/IconCircleGroup.kt index 3d38da3bc9..bfd5d348e1 100644 --- a/core/src/com/unciv/ui/utils/IconCircleGroup.kt +++ b/core/src/com/unciv/ui/utils/IconCircleGroup.kt @@ -1,10 +1,11 @@ package com.unciv.ui.utils +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Group -class IconCircleGroup(size:Float, val actor: Actor, resizeActor:Boolean=true): Group(){ - val circle = ImageGetter.getCircle().apply { setSize(size, size) } +class IconCircleGroup(size: Float, val actor: Actor, resizeActor: Boolean = true, color: Color = Color.WHITE): Group(){ + val circle = ImageGetter.getCircle().apply { setSize(size, size); setColor(color) } init { isTransform=false // performance helper - nothing here is rotated or scaled setSize(size, size)