diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..9d3627e --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,25 @@ +# Imperium Porcorum + +## Credits + +### Programmer +- Kazhnuz + +### Music +- Ozzed (found in Jamendo) + +### Tileset +- Made by surt (found in OpenGameArt) +- Some modified by Kazhnuz + +### Sprites +- Kazhnuz + +## Other thanks +- Everyone who helped me +- The Löve framework +- The sti module for love +- The Tiled developpers +- The Atom Developpers + +Thank's for playing ! diff --git a/README.md b/README.md index b8d1f3e..7cfe5b0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# imperium-porcorum +# Imperium Porcorum -Un jeu de plateforme avec une armée de cochon \ No newline at end of file +A platformer about warrior pigs. diff --git a/imperium-porcorum.love/CREDITS.md b/imperium-porcorum.love/CREDITS.md new file mode 100644 index 0000000..f0d5e78 --- /dev/null +++ b/imperium-porcorum.love/CREDITS.md @@ -0,0 +1,6 @@ +# Imperium Porcorum + +## Credits + +### Code + diff --git a/imperium-porcorum.love/assets/backgrounds/back.png b/imperium-porcorum.love/assets/backgrounds/back.png new file mode 100644 index 0000000..a14a8cf Binary files /dev/null and b/imperium-porcorum.love/assets/backgrounds/back.png differ diff --git a/imperium-porcorum.love/assets/backgrounds/backshadow.png b/imperium-porcorum.love/assets/backgrounds/backshadow.png new file mode 100644 index 0000000..04f51e6 Binary files /dev/null and b/imperium-porcorum.love/assets/backgrounds/backshadow.png differ diff --git a/imperium-porcorum.love/assets/backgrounds/credits.md b/imperium-porcorum.love/assets/backgrounds/credits.md new file mode 100644 index 0000000..4948185 --- /dev/null +++ b/imperium-porcorum.love/assets/backgrounds/credits.md @@ -0,0 +1,7 @@ +# Imperium Porcorum :: assets/sprites/ + +## Credits + +- **back.png** :: simple diagonals stripes. Under public domain. + +- **worldmap.png** :: based on [Blowhard 2: Blow Harder](https://opengameart.org/content/blowhard-2-blow-harder) set by surt (under CC0) and ["Micropolis SNES"](https://opengameart.org/content/micropolis-snes-tiles) set by usr_share (under GPL 3.0). Resulting work is under GPL 3.0 diff --git a/imperium-porcorum.love/assets/backgrounds/worldmap.png b/imperium-porcorum.love/assets/backgrounds/worldmap.png new file mode 100644 index 0000000..0767492 Binary files /dev/null and b/imperium-porcorum.love/assets/backgrounds/worldmap.png differ diff --git a/imperium-porcorum.love/assets/fonts/boxy_bold_font_4.png b/imperium-porcorum.love/assets/fonts/boxy_bold_font_4.png new file mode 100644 index 0000000..49d5734 Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/boxy_bold_font_4.png differ diff --git a/imperium-porcorum.love/assets/fonts/credits.md b/imperium-porcorum.love/assets/fonts/credits.md new file mode 100644 index 0000000..e144a37 --- /dev/null +++ b/imperium-porcorum.love/assets/fonts/credits.md @@ -0,0 +1,7 @@ +# Imperium Porcorum + +## Fonts credits + +- **Good Neighbors** by Clint Bellanger (Licence CC0), found on [OpenGameArt](http://opengameart.org/content/good-neighbors-pixel-font) + +- **Boxy Bold Font+** by usr_share and Clint Bellanger (Licence CC0), found on [OpenGameArt](http://opengameart.org/content/boxy-bold-font-0) diff --git a/imperium-porcorum.love/assets/fonts/good_neighbors.png b/imperium-porcorum.love/assets/fonts/good_neighbors.png new file mode 100644 index 0000000..9c391e4 Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/good_neighbors.png differ diff --git a/imperium-porcorum.love/assets/fonts/large.lua b/imperium-porcorum.love/assets/fonts/large.lua new file mode 100644 index 0000000..a9f5da7 --- /dev/null +++ b/imperium-porcorum.love/assets/fonts/large.lua @@ -0,0 +1,5 @@ +return { + filename = "large.png", + layout = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", + extraspacing = 1, +} diff --git a/imperium-porcorum.love/assets/fonts/large.png b/imperium-porcorum.love/assets/fonts/large.png new file mode 100644 index 0000000..9b3f47d Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/large.png differ diff --git a/imperium-porcorum.love/assets/fonts/medium.png b/imperium-porcorum.love/assets/fonts/medium.png new file mode 100644 index 0000000..271fe5f Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/medium.png differ diff --git a/imperium-porcorum.love/assets/fonts/small.lua b/imperium-porcorum.love/assets/fonts/small.lua new file mode 100644 index 0000000..0094239 --- /dev/null +++ b/imperium-porcorum.love/assets/fonts/small.lua @@ -0,0 +1,5 @@ +return { + filename = "small.png", + glyphs = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", + extraspacing = 1, +} diff --git a/imperium-porcorum.love/assets/fonts/small.png b/imperium-porcorum.love/assets/fonts/small.png new file mode 100644 index 0000000..52635bb Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/small.png differ diff --git a/imperium-porcorum.love/assets/fonts/testfont.png b/imperium-porcorum.love/assets/fonts/testfont.png new file mode 100644 index 0000000..c57cce5 Binary files /dev/null and b/imperium-porcorum.love/assets/fonts/testfont.png differ diff --git a/imperium-porcorum.love/assets/maps/level1.lua b/imperium-porcorum.love/assets/maps/level1.lua new file mode 100644 index 0000000..624bb16 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/level1.lua @@ -0,0 +1,3026 @@ +return { + version = "1.1", + luaversion = "5.1", + tiledversion = "0.18.2", + orientation = "orthogonal", + renderorder = "right-down", + width = 210, + height = 17, + tilewidth = 16, + tileheight = 16, + nextobjectid = 29, + properties = {}, + tilesets = { + { + name = "base_tiles", + firstgid = 1, + tilewidth = 16, + tileheight = 16, + spacing = 0, + margin = 0, + image = "tilesets/base_tiles.png", + imagewidth = 2048, + imageheight = 2048, + tileoffset = { + x = 0, + y = 0 + }, + properties = {}, + terrains = { + { + name = "solid", + tile = -1, + properties = { + ["collidable"] = true + } + }, + { + name = "hurt", + tile = -1, + properties = {} + } + }, + tilecount = 16384, + tiles = { + { + id = 0, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3, + terrain = { 0, 0, 0, 0 } + }, + { + id = 4, + terrain = { 0, 0, 0, 0 } + }, + { + id = 5, + terrain = { 0, 0, 0, 0 } + }, + { + id = 6, + terrain = { 0, 0, 0, 0 } + }, + { + id = 7, + terrain = { 0, 0, 0, 0 } + }, + { + id = 8, + terrain = { 0, 0, 0, 0 } + }, + { + id = 9, + terrain = { 0, 0, 0, 0 } + }, + { + id = 10, + terrain = { 0, 0, 0, 0 } + }, + { + id = 11, + terrain = { 0, 0, 0, 0 } + }, + { + id = 12, + terrain = { 0, 0, 0, 0 } + }, + { + id = 13, + terrain = { 0, 0, 0, 0 } + }, + { + id = 14, + terrain = { 0, 0, 0, 0 } + }, + { + id = 15, + terrain = { 0, 0, 0, 0 } + }, + { + id = 16, + terrain = { 0, 0, 0, 0 } + }, + { + id = 17, + terrain = { 0, 0, 0, 0 } + }, + { + id = 18, + terrain = { 0, 0, 0, 0 } + }, + { + id = 19, + terrain = { 0, 0, 0, 0 } + }, + { + id = 20, + terrain = { 0, 0, 0, 0 } + }, + { + id = 21, + terrain = { 0, 0, 0, 0 } + }, + { + id = 22, + terrain = { 0, 0, 0, 0 } + }, + { + id = 23, + terrain = { 0, 0, 0, 0 } + }, + { + id = 24, + terrain = { 0, 0, 0, 0 } + }, + { + id = 25, + terrain = { 0, 0, 0, 0 } + }, + { + id = 26, + terrain = { 0, 0, 0, 0 } + }, + { + id = 27, + terrain = { 0, 0, 0, 0 } + }, + { + id = 28, + terrain = { 0, 0, 0, 0 } + }, + { + id = 29, + terrain = { 0, 0, 0, 0 } + }, + { + id = 30, + terrain = { 0, 0, 0, 0 } + }, + { + id = 31, + terrain = { 0, 0, 0, 0 } + }, + { + id = 128, + terrain = { 0, 0, 0, 0 } + }, + { + id = 129, + terrain = { 0, 0, 0, 0 } + }, + { + id = 130, + terrain = { 0, 0, 0, 0 } + }, + { + id = 131, + terrain = { 0, 0, 0, 0 } + }, + { + id = 132, + terrain = { 0, 0, 0, 0 } + }, + { + id = 133, + terrain = { 0, 0, 0, 0 } + }, + { + id = 134, + terrain = { 0, 0, 0, 0 } + }, + { + id = 135, + terrain = { 0, 0, 0, 0 } + }, + { + id = 136, + terrain = { 0, 0, 0, 0 } + }, + { + id = 137, + terrain = { 0, 0, 0, 0 } + }, + { + id = 138, + terrain = { 0, 0, 0, 0 } + }, + { + id = 139, + terrain = { 0, 0, 0, 0 } + }, + { + id = 140, + terrain = { 0, 0, 0, 0 } + }, + { + id = 141, + terrain = { 0, 0, 0, 0 } + }, + { + id = 142, + terrain = { 0, 0, 0, 0 } + }, + { + id = 143, + terrain = { 0, 0, 0, 0 } + }, + { + id = 144, + terrain = { 0, 0, 0, 0 } + }, + { + id = 145, + terrain = { 0, 0, 0, 0 } + }, + { + id = 146, + terrain = { 0, 0, 0, 0 } + }, + { + id = 147, + terrain = { 0, 0, 0, 0 } + }, + { + id = 148, + terrain = { 0, 0, 0, 0 } + }, + { + id = 149, + terrain = { 0, 0, 0, 0 } + }, + { + id = 150, + terrain = { 0, 0, 0, 0 } + }, + { + id = 151, + terrain = { 0, 0, 0, 0 } + }, + { + id = 152, + terrain = { 0, 0, 0, 0 } + }, + { + id = 153, + terrain = { 0, 0, 0, 0 } + }, + { + id = 154, + terrain = { 0, 0, 0, 0 } + }, + { + id = 155, + terrain = { 0, 0, 0, 0 } + }, + { + id = 156, + terrain = { 0, 0, 0, 0 } + }, + { + id = 157, + terrain = { 0, 0, 0, 0 } + }, + { + id = 158, + terrain = { 0, 0, 0, 0 } + }, + { + id = 159, + terrain = { 0, 0, 0, 0 } + }, + { + id = 172, + terrain = { -1, 1, -1, 1 } + }, + { + id = 173, + terrain = { 1, -1, 1, -1 } + }, + { + id = 256, + terrain = { 0, 0, 0, 0 } + }, + { + id = 257, + terrain = { 0, 0, 0, 0 } + }, + { + id = 258, + terrain = { 0, 0, 0, 0 } + }, + { + id = 259, + terrain = { 0, 0, 0, 0 } + }, + { + id = 260, + terrain = { 0, 0, 0, 0 } + }, + { + id = 261, + terrain = { 0, 0, 0, 0 } + }, + { + id = 262, + terrain = { 0, 0, 0, 0 } + }, + { + id = 263, + terrain = { 0, 0, 0, 0 } + }, + { + id = 264, + terrain = { 0, 0, 0, 0 } + }, + { + id = 265, + terrain = { 0, 0, 0, 0 } + }, + { + id = 266, + terrain = { 0, 0, 0, 0 } + }, + { + id = 267, + terrain = { 0, 0, 0, 0 } + }, + { + id = 268, + terrain = { 0, 0, 0, 0 } + }, + { + id = 269, + terrain = { 0, 0, 0, 0 } + }, + { + id = 270, + terrain = { 0, 0, 0, 0 } + }, + { + id = 271, + terrain = { 0, 0, 0, 0 } + }, + { + id = 272, + terrain = { 0, 0, 0, 0 } + }, + { + id = 273, + terrain = { 0, 0, 0, 0 } + }, + { + id = 274, + terrain = { 0, 0, 0, 0 } + }, + { + id = 275, + terrain = { 0, 0, 0, 0 } + }, + { + id = 276, + terrain = { 0, 0, 0, 0 } + }, + { + id = 277, + terrain = { 0, 0, 0, 0 } + }, + { + id = 278, + terrain = { 0, 0, 0, 0 } + }, + { + id = 279, + terrain = { 0, 0, 0, 0 } + }, + { + id = 280, + terrain = { 0, 0, 0, 0 } + }, + { + id = 281, + terrain = { 0, 0, 0, 0 } + }, + { + id = 282, + terrain = { 0, 0, 0, 0 } + }, + { + id = 283, + terrain = { 0, 0, 0, 0 } + }, + { + id = 284, + terrain = { 0, 0, 0, 0 } + }, + { + id = 285, + terrain = { 0, 0, 0, 0 } + }, + { + id = 286, + terrain = { 0, 0, 0, 0 } + }, + { + id = 287, + terrain = { 0, 0, 0, 0 } + }, + { + id = 297, + terrain = { -1, -1, 1, 1 } + }, + { + id = 298, + terrain = { 1, 1, 1, 1 } + }, + { + id = 299, + terrain = { -1, -1, 1, 1 } + }, + { + id = 300, + terrain = { 1, 1, 1, 1 } + }, + { + id = 301, + terrain = { 1, 1, 1, 1 } + }, + { + id = 340, + terrain = { 0, 0, 0, 0 } + }, + { + id = 384, + terrain = { 0, 0, 0, 0 } + }, + { + id = 385, + terrain = { 0, 0, 0, 0 } + }, + { + id = 386, + terrain = { 0, 0, 0, 0 } + }, + { + id = 387, + terrain = { 0, 0, 0, 0 } + }, + { + id = 388, + terrain = { 0, 0, 0, 0 } + }, + { + id = 389, + terrain = { 0, 0, 0, 0 } + }, + { + id = 390, + terrain = { 0, 0, 0, 0 } + }, + { + id = 391, + terrain = { 0, 0, 0, 0 } + }, + { + id = 392, + terrain = { 0, 0, 0, 0 } + }, + { + id = 393, + terrain = { 0, 0, 0, 0 } + }, + { + id = 394, + terrain = { 0, 0, 0, 0 } + }, + { + id = 395, + terrain = { 0, 0, 0, 0 } + }, + { + id = 396, + terrain = { 0, 0, 0, 0 } + }, + { + id = 397, + terrain = { 0, 0, 0, 0 } + }, + { + id = 398, + terrain = { 0, 0, 0, 0 } + }, + { + id = 399, + terrain = { 0, 0, 0, 0 } + }, + { + id = 400, + terrain = { 0, 0, 0, 0 } + }, + { + id = 401, + terrain = { 0, 0, 0, 0 } + }, + { + id = 402, + terrain = { 0, 0, 0, 0 } + }, + { + id = 403, + terrain = { 0, 0, 0, 0 } + }, + { + id = 404, + terrain = { 0, 0, 0, 0 } + }, + { + id = 405, + terrain = { 0, 0, 0, 0 } + }, + { + id = 406, + terrain = { 0, 0, 0, 0 } + }, + { + id = 407, + terrain = { 0, 0, 0, 0 } + }, + { + id = 408, + terrain = { 0, 0, 0, 0 } + }, + { + id = 409, + terrain = { 0, 0, 0, 0 } + }, + { + id = 410, + terrain = { 0, 0, 0, 0 } + }, + { + id = 411, + terrain = { 0, 0, 0, 0 } + }, + { + id = 412, + terrain = { 0, 0, 0, 0 } + }, + { + id = 413, + terrain = { 0, 0, 0, 0 } + }, + { + id = 414, + terrain = { 0, 0, 0, 0 } + }, + { + id = 415, + terrain = { 0, 0, 0, 0 } + }, + { + id = 425, + terrain = { 1, 1, -1, -1 } + }, + { + id = 426, + terrain = { 1, 1, 1, 1 } + }, + { + id = 427, + terrain = { 1, 1, -1, -1 } + }, + { + id = 428, + terrain = { -1, 1, -1, 1 } + }, + { + id = 429, + terrain = { 1, -1, 1, -1 } + }, + { + id = 468, + terrain = { 0, 0, 0, 0 } + }, + { + id = 471, + terrain = { 0, 0, 0, 0 } + }, + { + id = 512, + terrain = { 0, 0, 0, 0 } + }, + { + id = 513, + terrain = { 0, 0, 0, 0 } + }, + { + id = 514, + terrain = { 0, 0, 0, 0 } + }, + { + id = 515, + terrain = { 0, 0, 0, 0 } + }, + { + id = 516, + terrain = { 0, 0, 0, 0 } + }, + { + id = 517, + terrain = { 0, 0, 0, 0 } + }, + { + id = 518, + terrain = { 0, 0, 0, 0 } + }, + { + id = 519, + terrain = { 0, 0, 0, 0 } + }, + { + id = 520, + terrain = { 0, 0, 0, 0 } + }, + { + id = 521, + terrain = { 0, 0, 0, 0 } + }, + { + id = 522, + terrain = { 0, 0, 0, 0 } + }, + { + id = 523, + terrain = { 0, 0, 0, 0 } + }, + { + id = 524, + terrain = { 0, 0, 0, 0 } + }, + { + id = 525, + terrain = { 0, 0, 0, 0 } + }, + { + id = 526, + terrain = { 0, 0, 0, 0 } + }, + { + id = 527, + terrain = { 0, 0, 0, 0 } + }, + { + id = 528, + terrain = { 0, 0, 0, 0 } + }, + { + id = 529, + terrain = { 0, 0, 0, 0 } + }, + { + id = 530, + terrain = { 0, 0, 0, 0 } + }, + { + id = 531, + terrain = { 0, 0, 0, 0 } + }, + { + id = 532, + terrain = { 0, 0, 0, 0 } + }, + { + id = 533, + terrain = { 0, 0, 0, 0 } + }, + { + id = 534, + terrain = { 0, 0, 0, 0 } + }, + { + id = 535, + terrain = { 0, 0, 0, 0 } + }, + { + id = 536, + terrain = { 0, 0, 0, 0 } + }, + { + id = 537, + terrain = { 0, 0, 0, 0 } + }, + { + id = 538, + terrain = { 0, 0, 0, 0 } + }, + { + id = 539, + terrain = { 0, 0, 0, 0 } + }, + { + id = 540, + terrain = { 0, 0, 0, 0 } + }, + { + id = 541, + terrain = { 0, 0, 0, 0 } + }, + { + id = 542, + terrain = { 0, 0, 0, 0 } + }, + { + id = 543, + terrain = { 0, 0, 0, 0 } + }, + { + id = 560, + terrain = { 0, 0, 0, 0 } + }, + { + id = 561, + terrain = { 0, 0, 0, 0 } + }, + { + id = 562, + terrain = { 0, 0, 0, 0 } + }, + { + id = 563, + terrain = { 0, 0, 0, 0 } + }, + { + id = 564, + terrain = { 0, 0, 0, 0 } + }, + { + id = 596, + terrain = { 0, 0, 0, 0 } + }, + { + id = 599, + terrain = { 0, 0, 0, 0 } + }, + { + id = 640, + terrain = { 0, 0, 0, 0 } + }, + { + id = 641, + terrain = { 0, 0, 0, 0 } + }, + { + id = 642, + terrain = { 0, 0, 0, 0 } + }, + { + id = 643, + terrain = { 0, 0, 0, 0 } + }, + { + id = 644, + terrain = { 0, 0, 0, 0 } + }, + { + id = 645, + terrain = { 0, 0, 0, 0 } + }, + { + id = 646, + terrain = { 0, 0, 0, 0 } + }, + { + id = 647, + terrain = { 0, 0, 0, 0 } + }, + { + id = 648, + terrain = { 0, 0, 0, 0 } + }, + { + id = 649, + terrain = { 0, 0, 0, 0 } + }, + { + id = 650, + terrain = { 0, 0, 0, 0 } + }, + { + id = 651, + terrain = { 0, 0, 0, 0 } + }, + { + id = 652, + terrain = { 0, 0, 0, 0 } + }, + { + id = 653, + terrain = { 0, 0, 0, 0 } + }, + { + id = 654, + terrain = { 0, 0, 0, 0 } + }, + { + id = 655, + terrain = { 0, 0, 0, 0 } + }, + { + id = 656, + terrain = { 0, 0, 0, 0 } + }, + { + id = 657, + terrain = { 0, 0, 0, 0 } + }, + { + id = 658, + terrain = { 0, 0, 0, 0 } + }, + { + id = 659, + terrain = { 0, 0, 0, 0 } + }, + { + id = 660, + terrain = { 0, 0, 0, 0 } + }, + { + id = 661, + terrain = { 0, 0, 0, 0 } + }, + { + id = 662, + terrain = { 0, 0, 0, 0 } + }, + { + id = 663, + terrain = { 0, 0, 0, 0 } + }, + { + id = 664, + terrain = { 0, 0, 0, 0 } + }, + { + id = 665, + terrain = { 0, 0, 0, 0 } + }, + { + id = 666, + terrain = { 0, 0, 0, 0 } + }, + { + id = 667, + terrain = { 0, 0, 0, 0 } + }, + { + id = 668, + terrain = { 0, 0, 0, 0 } + }, + { + id = 669, + terrain = { 0, 0, 0, 0 } + }, + { + id = 670, + terrain = { 0, 0, 0, 0 } + }, + { + id = 671, + terrain = { 0, 0, 0, 0 } + }, + { + id = 688, + terrain = { 0, 0, 0, 0 } + }, + { + id = 689, + terrain = { 0, 0, 0, 0 } + }, + { + id = 690, + terrain = { 0, 0, 0, 0 } + }, + { + id = 691, + terrain = { 0, 0, 0, 0 } + }, + { + id = 692, + terrain = { 0, 0, 0, 0 } + }, + { + id = 707, + terrain = { 0, 0, 0, 0 } + }, + { + id = 708, + terrain = { 0, 0, 0, 0 } + }, + { + id = 709, + terrain = { 0, 0, 0, 0 } + }, + { + id = 710, + terrain = { 0, 0, 0, 0 } + }, + { + id = 711, + terrain = { 0, 0, 0, 0 } + }, + { + id = 712, + terrain = { 0, 0, 0, 0 } + }, + { + id = 724, + terrain = { 0, 0, 0, 0 } + }, + { + id = 727, + terrain = { 0, 0, 0, 0 } + }, + { + id = 768, + terrain = { 0, 0, 0, 0 } + }, + { + id = 769, + terrain = { 0, 0, 0, 0 } + }, + { + id = 770, + terrain = { 0, 0, 0, 0 } + }, + { + id = 771, + terrain = { 0, 0, 0, 0 } + }, + { + id = 772, + terrain = { 0, 0, 0, 0 } + }, + { + id = 773, + terrain = { 0, 0, 0, 0 } + }, + { + id = 774, + terrain = { 0, 0, 0, 0 } + }, + { + id = 775, + terrain = { 0, 0, 0, 0 } + }, + { + id = 776, + terrain = { 0, 0, 0, 0 } + }, + { + id = 777, + terrain = { 0, 0, 0, 0 } + }, + { + id = 778, + terrain = { 0, 0, 0, 0 } + }, + { + id = 779, + terrain = { 0, 0, 0, 0 } + }, + { + id = 780, + terrain = { 0, 0, 0, 0 } + }, + { + id = 781, + terrain = { 0, 0, 0, 0 } + }, + { + id = 782, + terrain = { 0, 0, 0, 0 } + }, + { + id = 783, + terrain = { 0, 0, 0, 0 } + }, + { + id = 784, + terrain = { 0, 0, 0, 0 } + }, + { + id = 785, + terrain = { 0, 0, 0, 0 } + }, + { + id = 786, + terrain = { 0, 0, 0, 0 } + }, + { + id = 787, + terrain = { 0, 0, 0, 0 } + }, + { + id = 788, + terrain = { 0, 0, 0, 0 } + }, + { + id = 789, + terrain = { 0, 0, 0, 0 } + }, + { + id = 790, + terrain = { 0, 0, 0, 0 } + }, + { + id = 791, + terrain = { 0, 0, 0, 0 } + }, + { + id = 792, + terrain = { 0, 0, 0, 0 } + }, + { + id = 793, + terrain = { 0, 0, 0, 0 } + }, + { + id = 794, + terrain = { 0, 0, 0, 0 } + }, + { + id = 795, + terrain = { 0, 0, 0, 0 } + }, + { + id = 796, + terrain = { 0, 0, 0, 0 } + }, + { + id = 797, + terrain = { 0, 0, 0, 0 } + }, + { + id = 798, + terrain = { 0, 0, 0, 0 } + }, + { + id = 799, + terrain = { 0, 0, 0, 0 } + }, + { + id = 816, + terrain = { 0, 0, 0, 0 } + }, + { + id = 817, + terrain = { 0, 0, 0, 0 } + }, + { + id = 818, + terrain = { 0, 0, 0, 0 } + }, + { + id = 819, + terrain = { 0, 0, 0, 0 } + }, + { + id = 820, + terrain = { 0, 0, 0, 0 } + }, + { + id = 835, + terrain = { 0, 0, 0, 0 } + }, + { + id = 836, + terrain = { 0, 0, 0, 0 } + }, + { + id = 837, + terrain = { 0, 0, 0, 0 } + }, + { + id = 838, + terrain = { 0, 0, 0, 0 } + }, + { + id = 839, + terrain = { 0, 0, 0, 0 } + }, + { + id = 840, + terrain = { 0, 0, 0, 0 } + }, + { + id = 841, + terrain = { 0, 0, 0, 0 } + }, + { + id = 842, + terrain = { 0, 0, 0, 0 } + }, + { + id = 843, + terrain = { 0, 0, 0, 0 } + }, + { + id = 844, + terrain = { 0, 0, 0, 0 } + }, + { + id = 845, + terrain = { 0, 0, 0, 0 } + }, + { + id = 846, + terrain = { 0, 0, 0, 0 } + }, + { + id = 896, + terrain = { 0, 0, 0, 0 } + }, + { + id = 897, + terrain = { 0, 0, 0, 0 } + }, + { + id = 898, + terrain = { 0, 0, 0, 0 } + }, + { + id = 899, + terrain = { 0, 0, 0, 0 } + }, + { + id = 900, + terrain = { 0, 0, 0, 0 } + }, + { + id = 901, + terrain = { 0, 0, 0, 0 } + }, + { + id = 902, + terrain = { 0, 0, 0, 0 } + }, + { + id = 903, + terrain = { 0, 0, 0, 0 } + }, + { + id = 904, + terrain = { 0, 0, 0, 0 } + }, + { + id = 905, + terrain = { 0, 0, 0, 0 } + }, + { + id = 906, + terrain = { 0, 0, 0, 0 } + }, + { + id = 907, + terrain = { 0, 0, 0, 0 } + }, + { + id = 908, + terrain = { 0, 0, 0, 0 } + }, + { + id = 909, + terrain = { 0, 0, 0, 0 } + }, + { + id = 910, + terrain = { 0, 0, 0, 0 } + }, + { + id = 911, + terrain = { 0, 0, 0, 0 } + }, + { + id = 912, + terrain = { 0, 0, 0, 0 } + }, + { + id = 913, + terrain = { 0, 0, 0, 0 } + }, + { + id = 914, + terrain = { 0, 0, 0, 0 } + }, + { + id = 915, + terrain = { 0, 0, 0, 0 } + }, + { + id = 916, + terrain = { 0, 0, 0, 0 } + }, + { + id = 917, + terrain = { 0, 0, 0, 0 } + }, + { + id = 918, + terrain = { 0, 0, 0, 0 } + }, + { + id = 919, + terrain = { 0, 0, 0, 0 } + }, + { + id = 920, + terrain = { 0, 0, 0, 0 } + }, + { + id = 921, + terrain = { 0, 0, 0, 0 } + }, + { + id = 922, + terrain = { 0, 0, 0, 0 } + }, + { + id = 923, + terrain = { 0, 0, 0, 0 } + }, + { + id = 924, + terrain = { 0, 0, 0, 0 } + }, + { + id = 925, + terrain = { 0, 0, 0, 0 } + }, + { + id = 926, + terrain = { 0, 0, 0, 0 } + }, + { + id = 927, + terrain = { 0, 0, 0, 0 } + }, + { + id = 944, + terrain = { 0, 0, 0, 0 } + }, + { + id = 945, + terrain = { 0, 0, 0, 0 } + }, + { + id = 946, + terrain = { 0, 0, 0, 0 } + }, + { + id = 947, + terrain = { 0, 0, 0, 0 } + }, + { + id = 963, + terrain = { 0, 0, 0, 0 } + }, + { + id = 964, + terrain = { 0, 0, 0, 0 } + }, + { + id = 965, + terrain = { 0, 0, 0, 0 } + }, + { + id = 966, + terrain = { 0, 0, 0, 0 } + }, + { + id = 967, + terrain = { 0, 0, 0, 0 } + }, + { + id = 968, + terrain = { 0, 0, 0, 0 } + }, + { + id = 969, + terrain = { 0, 0, 0, 0 } + }, + { + id = 970, + terrain = { 0, 0, 0, 0 } + }, + { + id = 971, + terrain = { 0, 0, 0, 0 } + }, + { + id = 972, + terrain = { 0, 0, 0, 0 } + }, + { + id = 973, + terrain = { 0, 0, 0, 0 } + }, + { + id = 974, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1024, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1025, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1026, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1027, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1028, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1029, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1030, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1031, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1032, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1033, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1034, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1035, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1036, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1037, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1038, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1039, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1040, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1041, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1042, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1043, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1044, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1045, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1046, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1047, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1048, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1049, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1050, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1051, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1073, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1074, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1092, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1093, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1094, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1095, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1096, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1097, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1098, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1099, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1100, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1101, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1102, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1152, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1153, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1154, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1155, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1156, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1157, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1158, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1159, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1160, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1161, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1162, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1163, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1164, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1165, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1166, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1167, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1168, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1169, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1170, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1171, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1172, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1173, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1174, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1175, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1176, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1177, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1178, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1179, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1190, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1191, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1192, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1206, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1207, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1208, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1209, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1210, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1211, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1222, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1223, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1224, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1225, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1280, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1281, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1282, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1283, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1284, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1285, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1286, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1287, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1288, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1289, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1290, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1291, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1292, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1293, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1294, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1295, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1296, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1297, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1298, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1299, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1300, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1301, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1302, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1303, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1304, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1305, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1306, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1307, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1318, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1319, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1320, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1334, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1335, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1336, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1337, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1338, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1339, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1350, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1351, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1352, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1353, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1408, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1409, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1410, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1411, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1412, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1413, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1414, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1415, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1416, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1417, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1418, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1419, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1420, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1421, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1422, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1423, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1424, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1425, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1426, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1427, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1428, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1429, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1430, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1431, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1432, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1433, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1434, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1435, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1446, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1447, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1448, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1463, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1464, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1465, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1574, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1575, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1576, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1851, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1852, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1853, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1854, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1979, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1980, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1981, + terrain = { 0, 0, 0, 0 } + }, + { + id = 1982, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2001, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2002, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2003, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2004, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2005, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2006, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2007, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2123, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2129, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2130, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2131, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2132, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2133, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2134, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2135, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2229, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2230, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2231, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2251, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2254, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2257, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2258, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2259, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2260, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2261, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2262, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2263, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2357, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2358, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2359, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2377, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2378, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2379, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2380, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2381, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2382, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2385, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2386, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2387, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2388, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2389, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2390, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2391, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2490, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2491, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2492, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2493, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2505, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2506, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2507, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2508, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2509, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2510, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2513, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2514, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2515, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2516, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2517, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2518, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2519, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2618, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2619, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2620, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2621, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2623, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2627, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2628, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2631, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2632, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2633, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2634, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2635, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2636, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2637, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2638, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2641, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2642, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2643, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2644, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2645, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2646, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2647, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2736, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2737, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2738, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2739, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2740, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2741, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2742, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2743, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2744, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2745, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2746, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2747, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2748, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2749, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2750, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2751, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2752, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2753, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2754, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2755, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2756, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2757, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2758, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2759, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2760, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2761, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2762, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2763, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2764, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2765, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2766, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2767, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2768, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2769, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2770, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2771, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2772, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2773, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2774, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2775, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2864, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2865, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2866, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2867, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2868, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2869, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2870, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2871, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2872, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2873, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2874, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2875, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2876, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2877, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2878, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2879, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2880, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2881, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2882, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2883, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2884, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2885, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2886, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2887, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2888, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2889, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2890, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2891, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2892, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2893, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2894, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2895, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2896, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2897, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2898, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2899, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2900, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2901, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2902, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2903, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2992, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2993, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2994, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2995, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2996, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2997, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2998, + terrain = { 0, 0, 0, 0 } + }, + { + id = 2999, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3000, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3001, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3002, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3003, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3004, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3005, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3006, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3007, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3008, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3009, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3010, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3011, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3012, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3013, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3014, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3015, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3016, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3017, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3018, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3019, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3020, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3021, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3022, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3023, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3024, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3025, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3026, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3027, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3028, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3029, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3030, + terrain = { 0, 0, 0, 0 } + }, + { + id = 3031, + terrain = { 0, 0, 0, 0 } + }, + { + id = 7698, + terrain = { 0, 0, 0, 0 } + }, + { + id = 7826, + terrain = { -1, 0, -1, -1 } + }, + { + id = 7827, + terrain = { 0, 0, -1, 0 } + } + } + } + }, + layers = { + { + type = "tilelayer", + name = "Calque de Tile 1", + x = 0, + y = 0, + width = 210, + height = 17, + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + properties = {}, + encoding = "lua", + data = { + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 836, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 836, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 968, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 836, 968, 968, 968, 968, 968, 968, 968, 968, 968, 1099, 1099, 1099, 1099, 1099, 1099, 1352, 1352, 1352, 1352, 1103, 571, 571, 830, 831, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 830, 831, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 836, 968, 968, 968, 968, 968, 968, 968, 968, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 1464, 1465, 1352, 1352, 1352, 1352, 1352, 1352, 1465, 1466, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 1866, 1867, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 1994, 1995, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 2122, 2123, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 2365, 2366, 571, 2250, 2251, 571, 2103, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 1866, 1867, 571, 571, 571, 708, 710, 709, 710, 710, 709, 847, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 1866, 1867, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 830, 831, 571, 571, 571, 571, 571, 571, 1994, 1995, 571, 571, 571, 836, 972, 972, 972, 972, 972, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 1994, 1995, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 2122, 2123, 571, 571, 571, 836, 972, 972, 972, 972, 972, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 571, 571, 571, 2122, 2123, 571, 571, 2632, 2633, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 2365, 2366, 571, 2250, 2251, 571, 2103, 571, 836, 972, 972, 972, 972, 972, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 571, 2365, 2366, 571, 2250, 2251, 571, 571, 2760, 2761, 571, 571, 571, 571, 571, 571, 571, 571, 571, 1207, 710, 710, 710, 710, 710, 710, 710, 710, 710, 836, 972, 972, 972, 972, 972, 975, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 562, 562, 562, 562, 562, 562, 562, 562, 562, 562, 562, 565, 571, 571, 571, 571, 571, 571, 571, 836, 965, 965, 965, 965, 965, 965, 965, 965, 965, 968, 972, 972, 972, 972, 972, 975, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7078, 7080, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 692, 692, 692, 692, 692, 692, 692, 692, 692, 692, 692, 693, 571, 571, 571, 571, 571, 571, 571, 836, 965, 965, 965, 965, 965, 965, 965, 965, 965, 968, 972, 972, 972, 972, 972, 975, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7208, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, + 692, 692, 692, 692, 692, 692, 692, 692, 692, 692, 692, 693, 571, 571, 571, 571, 571, 571, 571, 836, 965, 965, 965, 965, 965, 965, 965, 965, 965, 968, 972, 972, 972, 972, 972, 975, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7207, 7208, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571 + } + }, + { + type = "tilelayer", + name = "death", + x = 0, + y = 0, + width = 210, + height = 17, + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + properties = {}, + encoding = "lua", + data = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } + }, + { + type = "objectgroup", + name = "collision", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = { + ["collidable"] = true + }, + objects = { + { + id = 21, + name = "", + type = "", + shape = "rectangle", + x = 304, + y = 0, + width = 160, + height = 80, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 22, + name = "", + type = "", + shape = "rectangle", + x = 304, + y = 208, + width = 272, + height = 64, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 23, + name = "", + type = "", + shape = "rectangle", + x = 0, + y = 224, + width = 192, + height = 48, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 24, + name = "", + type = "", + shape = "rectangle", + x = 464, + y = 0, + width = 176, + height = 48, + rotation = 0, + visible = true, + properties = { + ["collidable"] = true + } + }, + { + id = 25, + name = "", + type = "", + shape = "rectangle", + x = 576, + y = 208, + width = 0, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 26, + name = "", + type = "", + shape = "rectangle", + x = 464, + y = 144, + width = 112, + height = 64, + rotation = 0, + visible = true, + properties = { + ["collidable"] = true + } + }, + { + id = 27, + name = "", + type = "", + shape = "rectangle", + x = 128, + y = 192, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 28, + name = "", + type = "", + shape = "rectangle", + x = 576, + y = 224, + width = 432, + height = 48, + rotation = 0, + visible = true, + properties = {} + } + } + } + } +} diff --git a/imperium-porcorum.love/assets/maps/level1.tmx b/imperium-porcorum.love/assets/maps/level1.tmx new file mode 100644 index 0000000..f4b169f --- /dev/null +++ b/imperium-porcorum.love/assets/maps/level1.tmx @@ -0,0 +1,774 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,836,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,836,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,968,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,836,968,968,968,968,968,968,968,968,968,1099,1099,1099,1099,1099,1099,1352,1352,1352,1352,1103,571,571,830,831,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,830,831,571,571,571,571,571,571,571,571,571,571,571,571,836,968,968,968,968,968,968,968,968,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,1464,1465,1352,1352,1352,1352,1352,1352,1465,1466,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,1866,1867,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,1994,1995,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,2122,2123,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,2365,2366,571,2250,2251,571,2103,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,1866,1867,571,571,571,708,710,709,710,710,709,847,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,1866,1867,571,571,571,571,571,571,571,571,571,571,830,831,571,571,571,571,571,571,1994,1995,571,571,571,836,972,972,972,972,972,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,1994,1995,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,2122,2123,571,571,571,836,972,972,972,972,972,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,571,571,571,2122,2123,571,571,2632,2633,571,571,571,571,571,571,571,571,571,571,571,2365,2366,571,2250,2251,571,2103,571,836,972,972,972,972,972,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +571,2365,2366,571,2250,2251,571,571,2760,2761,571,571,571,571,571,571,571,571,571,1207,710,710,710,710,710,710,710,710,710,836,972,972,972,972,972,975,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +562,562,562,562,562,562,562,562,562,562,562,565,571,571,571,571,571,571,571,836,965,965,965,965,965,965,965,965,965,968,972,972,972,972,972,975,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7078,7080,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +692,692,692,692,692,692,692,692,692,692,692,693,571,571,571,571,571,571,571,836,965,965,965,965,965,965,965,965,965,968,972,972,972,972,972,975,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7208,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571, +692,692,692,692,692,692,692,692,692,692,692,693,571,571,571,571,571,571,571,836,965,965,965,965,965,965,965,965,965,968,972,972,972,972,972,975,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7207,7208,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,301,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/imperium-porcorum.love/assets/maps/test-map2.lua b/imperium-porcorum.love/assets/maps/test-map2.lua new file mode 100644 index 0000000..319c0c7 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/test-map2.lua @@ -0,0 +1,481 @@ +return { + version = "1.1", + luaversion = "5.1", + tiledversion = "0.18.1", + orientation = "orthogonal", + renderorder = "right-down", + width = 100, + height = 100, + tilewidth = 16, + tileheight = 16, + nextobjectid = 27, + backgroundcolor = { 85, 170, 255 }, + properties = {}, + tilesets = { + { + name = "beastlands", + firstgid = 1, + tilewidth = 16, + tileheight = 16, + spacing = 0, + margin = 0, + image = "tilesets/beastlands.png", + imagewidth = 944, + imageheight = 544, + transparentcolor = "#55aaff", + tileoffset = { + x = 0, + y = 0 + }, + grid = { + orientation = "orthogonal", + width = 16, + height = 16 + }, + properties = {}, + terrains = {}, + tilecount = 2006, + tiles = {} + } + }, + layers = { + { + type = "tilelayer", + name = "Calque de Tile 1", + x = 0, + y = 0, + width = 100, + height = 100, + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + properties = {}, + encoding = "lua", + data = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 798, 799, 799, 799, 799, 799, 799, 799, 801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 863, 865, 865, 865, 865, 865, 865, 865, 866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 951, 952, 953, 954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 863, 865, 865, 865, 865, 865, 865, 865, 866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 863, 865, 865, 865, 865, 865, 865, 865, 866, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 123, 124, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 500, 500, 500, 500, 500, 500, 497, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 499, 798, 799, 799, 799, 799, 799, 799, 799, 801, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 182, 183, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 241, 242, 243, 0, 0, 0, 0, 123, 124, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 300, 301, 1243, 1245, 1245, 1246, 0, 182, 183, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 241, 242, 243, 0, 500, 500, 500, 500, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1243, 301, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1417, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 544, 544, 545, 546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1476, 1477, 1478, 1479, 1480, 1481, 1482, 1483, 603, 603, 604, 605, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 857, 858, 858, 858, 858, 858, 858, 858, 859, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 443, 443, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 603, 603, 604, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, + 502, 502, 502, 602, 603, 604, 502, 502, 602, 603, 603, 603, 604, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502, 502 + } + }, + { + type = "objectgroup", + name = "block", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = { + ["item"] = "coin" + }, + objects = { + { + id = 26, + name = "", + type = "", + shape = "rectangle", + x = 736, + y = 1392, + width = 144, + height = 48, + rotation = 0, + visible = true, + properties = {} + } + } + }, + { + type = "objectgroup", + name = "coin", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 12, + name = "", + type = "", + shape = "rectangle", + x = 240, + y = 1472, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 13, + name = "", + type = "", + shape = "rectangle", + x = 272, + y = 1472, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 14, + name = "", + type = "", + shape = "rectangle", + x = 304, + y = 1472, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 15, + name = "", + type = "", + shape = "rectangle", + x = 352, + y = 1408, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 16, + name = "", + type = "", + shape = "rectangle", + x = 384, + y = 1408, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 17, + name = "", + type = "", + shape = "rectangle", + x = 416, + y = 1408, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 18, + name = "", + type = "", + shape = "rectangle", + x = 448, + y = 1408, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 19, + name = "", + type = "", + shape = "rectangle", + x = 144, + y = 1456, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 20, + name = "", + type = "", + shape = "rectangle", + x = 144, + y = 1424, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 21, + name = "", + type = "", + shape = "rectangle", + x = 144, + y = 1392, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 22, + name = "", + type = "", + shape = "rectangle", + x = 144, + y = 1360, + width = 16, + height = 16, + rotation = 0, + visible = true, + properties = {} + } + } + }, + { + type = "objectgroup", + name = "playerstart", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 23, + name = "", + type = "", + shape = "rectangle", + x = 64, + y = 1472, + width = 32, + height = 32, + rotation = 0, + visible = true, + properties = {} + } + } + }, + { + type = "objectgroup", + name = "wall", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 6, + name = "", + type = "", + shape = "rectangle", + x = 128, + y = 1536, + width = 80, + height = 64, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 7, + name = "", + type = "", + shape = "rectangle", + x = 48, + y = 1536, + width = 48, + height = 64, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 8, + name = "", + type = "", + shape = "rectangle", + x = 240, + y = 1504, + width = 80, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 10, + name = "", + type = "", + shape = "rectangle", + x = 352, + y = 1440, + width = 528, + height = 16, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 11, + name = "", + type = "", + shape = "rectangle", + x = 736, + y = 1456, + width = 144, + height = 112, + rotation = 0, + visible = true, + properties = {} + }, + { + id = 25, + name = "", + type = "", + shape = "rectangle", + x = 736, + y = 1264, + width = 144, + height = 128, + rotation = 0, + visible = true, + properties = {} + } + } + }, + { + type = "objectgroup", + name = "platform", + visible = true, + opacity = 1, + offsetx = 0, + offsety = 0, + draworder = "topdown", + properties = {}, + objects = { + { + id = 5, + name = "", + type = "", + shape = "rectangle", + x = 64, + y = 1504, + width = 96, + height = 32, + rotation = 0, + visible = true, + properties = {} + } + } + } + } +} diff --git a/imperium-porcorum.love/assets/maps/test-map2.tmx b/imperium-porcorum.love/assets/maps/test-map2.tmx new file mode 100644 index 0000000..d1f0d29 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/test-map2.tmx @@ -0,0 +1,143 @@ + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,798,799,799,799,799,799,799,799,801,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,865,865,865,865,865,865,865,866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,951,952,953,954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,865,865,865,865,865,865,865,866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,865,865,865,865,865,865,865,866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,123,124,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,500,500,500,500,500,500,500,497,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,499,798,799,799,799,799,799,799,799,801,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,182,183,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,241,242,243,0,0,0,0,123,124,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,300,301,1243,1245,1245,1246,0,182,183,184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1299,1300,1301,1302,1303,1304,1305,1306,1307,241,242,243,0,500,500,500,500,500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1358,1359,1360,1361,1362,1363,1364,1365,1366,1243,301,302,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1417,1418,1419,1420,1421,1422,1423,1424,544,544,545,546,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1476,1477,1478,1479,1480,1481,1482,1483,603,603,604,605,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,858,858,858,858,858,858,858,859,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +443,443,1535,1536,1537,1538,1539,1540,1541,1542,603,603,604,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443,443, +502,502,502,602,603,604,502,502,602,603,603,603,604,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/imperium-porcorum.love/assets/maps/tilesets/base_tiles.png b/imperium-porcorum.love/assets/maps/tilesets/base_tiles.png new file mode 100644 index 0000000..c032a6c Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/base_tiles.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/base_tiles.tsx b/imperium-porcorum.love/assets/maps/tilesets/base_tiles.tsx new file mode 100644 index 0000000..33dc617 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/tilesets/base_tiles.tsx @@ -0,0 +1,705 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/imperium-porcorum.love/assets/maps/tilesets/beastland.tsx b/imperium-porcorum.love/assets/maps/tilesets/beastland.tsx new file mode 100644 index 0000000..0e82a15 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/tilesets/beastland.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/imperium-porcorum.love/assets/maps/tilesets/beastlands.png b/imperium-porcorum.love/assets/maps/tilesets/beastlands.png new file mode 100644 index 0000000..67808a9 Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/beastlands.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/credits.md b/imperium-porcorum.love/assets/maps/tilesets/credits.md new file mode 100644 index 0000000..c61dd23 --- /dev/null +++ b/imperium-porcorum.love/assets/maps/tilesets/credits.md @@ -0,0 +1,13 @@ +# Imperium Porcorum :: assets.tileset + +## Credits + +- **beastlands.png** :: from [Beastlands](https://opengameart.org/content/beastlands) set by Surt, under CC-BY 3.0 + +- **plastic_shamtastic.png** and **plastic_shastastic_alt_palette.png** :: from [Plastic Shamtastic](https://opengameart.org/content/plastic-shamtastic) set by Surt, under CC-BY 3.0 + +- **monkeylad_further.png** :: from [Monkey Lad in Magical Planet](https://opengameart.org/content/monkey-lad-in-magical-planet) set by Surt, under CC-BY 3.0 + +- **psygen.png** :: from [Psygen](https://opengameart.org/content/psygen) set by Surt, under CC-BY 3.0 + +- **space_merc.png** :: from [Space Merc](https://opengameart.org/content/space-merc) set by Surt, under CC-BY 3.0 diff --git a/imperium-porcorum.love/assets/maps/tilesets/monkeylad_further.png b/imperium-porcorum.love/assets/maps/tilesets/monkeylad_further.png new file mode 100644 index 0000000..2f12a58 Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/monkeylad_further.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic.png b/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic.png new file mode 100644 index 0000000..b416bb2 Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic_alt_palette.png b/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic_alt_palette.png new file mode 100644 index 0000000..aa14bb3 Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/plastic_shamtastic_alt_palette.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/psygen.png b/imperium-porcorum.love/assets/maps/tilesets/psygen.png new file mode 100644 index 0000000..fa872bd Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/psygen.png differ diff --git a/imperium-porcorum.love/assets/maps/tilesets/space_merc.png b/imperium-porcorum.love/assets/maps/tilesets/space_merc.png new file mode 100644 index 0000000..3c11377 Binary files /dev/null and b/imperium-porcorum.love/assets/maps/tilesets/space_merc.png differ diff --git a/imperium-porcorum.love/assets/mastersystem-palette.png b/imperium-porcorum.love/assets/mastersystem-palette.png new file mode 100644 index 0000000..5f352bc Binary files /dev/null and b/imperium-porcorum.love/assets/mastersystem-palette.png differ diff --git a/imperium-porcorum.love/assets/music/1up.ogg b/imperium-porcorum.love/assets/music/1up.ogg new file mode 100644 index 0000000..d134b50 Binary files /dev/null and b/imperium-porcorum.love/assets/music/1up.ogg differ diff --git a/imperium-porcorum.love/assets/music/Bumblebee loop.ogg b/imperium-porcorum.love/assets/music/Bumblebee loop.ogg new file mode 100644 index 0000000..45571f5 Binary files /dev/null and b/imperium-porcorum.love/assets/music/Bumblebee loop.ogg differ diff --git a/imperium-porcorum.love/assets/music/Bumbledee under pressure.mp3 b/imperium-porcorum.love/assets/music/Bumbledee under pressure.mp3 new file mode 100644 index 0000000..d7d7dc8 Binary files /dev/null and b/imperium-porcorum.love/assets/music/Bumbledee under pressure.mp3 differ diff --git a/imperium-porcorum.love/assets/music/Metropolis rush.ogg b/imperium-porcorum.love/assets/music/Metropolis rush.ogg new file mode 100644 index 0000000..cb9c7c2 Binary files /dev/null and b/imperium-porcorum.love/assets/music/Metropolis rush.ogg differ diff --git a/imperium-porcorum.love/assets/music/boss.ogg b/imperium-porcorum.love/assets/music/boss.ogg new file mode 100644 index 0000000..e024601 Binary files /dev/null and b/imperium-porcorum.love/assets/music/boss.ogg differ diff --git a/imperium-porcorum.love/assets/music/credits.txt b/imperium-porcorum.love/assets/music/credits.txt new file mode 100644 index 0000000..2b0d932 --- /dev/null +++ b/imperium-porcorum.love/assets/music/credits.txt @@ -0,0 +1,32 @@ +# Gosth Island - Credits + +## Musics + +### Di Rodrigues (taken from opensonic) + +- title.ogg (CC-BY-SA 3.0) +- options.ogg (CC-BY-SA 3.0) +- speed.ogg (CC-BY-SA 3.0) +- invincible.ogg (CC-BY-SA 3.0) +- 1up.ogg (CC-BY-SA 3.0) +- goal.ogg (CC-BY-SA 3.0) + +SilverstepP and Joepotato28 (taken from opensonic) + +- boss.ogg (CC-BY-SA 3.0) + +### [jobromedia](http://opengameart.org/users/jobromedia) + +- options2.ogg (CC-BY-SA 3.0) + +- sharp.ogg (CC-BY-SA 3.0) + +- Bumblebee under pressure.ogg (CC-BY-SA 3.0) + +- Bumblebee loop.ogg (CC-BY-SA 3.0) + +- Sunny Paradise act 1.mp3 (CC-BY-SA 3.0) + +- Sunny Paradise act 2.mp3 (CC-BY-SA 3.0) + +- Metropolis Rush.ogg (CC-BY-SA 3.0) diff --git a/imperium-porcorum.love/assets/music/goal.ogg b/imperium-porcorum.love/assets/music/goal.ogg new file mode 100644 index 0000000..0088bc5 Binary files /dev/null and b/imperium-porcorum.love/assets/music/goal.ogg differ diff --git a/imperium-porcorum.love/assets/music/invincible.ogg b/imperium-porcorum.love/assets/music/invincible.ogg new file mode 100644 index 0000000..f094e6b Binary files /dev/null and b/imperium-porcorum.love/assets/music/invincible.ogg differ diff --git a/imperium-porcorum.love/assets/music/options.ogg b/imperium-porcorum.love/assets/music/options.ogg new file mode 100644 index 0000000..be17f4a Binary files /dev/null and b/imperium-porcorum.love/assets/music/options.ogg differ diff --git a/imperium-porcorum.love/assets/music/options2.ogg b/imperium-porcorum.love/assets/music/options2.ogg new file mode 100644 index 0000000..372e64e Binary files /dev/null and b/imperium-porcorum.love/assets/music/options2.ogg differ diff --git a/imperium-porcorum.love/assets/music/sharp.ogg b/imperium-porcorum.love/assets/music/sharp.ogg new file mode 100644 index 0000000..094b392 Binary files /dev/null and b/imperium-porcorum.love/assets/music/sharp.ogg differ diff --git a/imperium-porcorum.love/assets/music/speed.ogg b/imperium-porcorum.love/assets/music/speed.ogg new file mode 100644 index 0000000..dcb986f Binary files /dev/null and b/imperium-porcorum.love/assets/music/speed.ogg differ diff --git a/imperium-porcorum.love/assets/music/sunnyparadise1.mp3 b/imperium-porcorum.love/assets/music/sunnyparadise1.mp3 new file mode 100644 index 0000000..e2c867e Binary files /dev/null and b/imperium-porcorum.love/assets/music/sunnyparadise1.mp3 differ diff --git a/imperium-porcorum.love/assets/music/sunnyparadise2.mp3 b/imperium-porcorum.love/assets/music/sunnyparadise2.mp3 new file mode 100644 index 0000000..cf00be6 Binary files /dev/null and b/imperium-porcorum.love/assets/music/sunnyparadise2.mp3 differ diff --git a/imperium-porcorum.love/assets/music/title.ogg b/imperium-porcorum.love/assets/music/title.ogg new file mode 100644 index 0000000..3d5784e Binary files /dev/null and b/imperium-porcorum.love/assets/music/title.ogg differ diff --git a/imperium-porcorum.love/assets/sfx/acidshield.wav b/imperium-porcorum.love/assets/sfx/acidshield.wav new file mode 100644 index 0000000..c695ae5 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/acidshield.wav differ diff --git a/imperium-porcorum.love/assets/sfx/break.wav b/imperium-porcorum.love/assets/sfx/break.wav new file mode 100644 index 0000000..27dd229 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/break.wav differ diff --git a/imperium-porcorum.love/assets/sfx/checkpoint.wav b/imperium-porcorum.love/assets/sfx/checkpoint.wav new file mode 100644 index 0000000..1518e57 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/checkpoint.wav differ diff --git a/imperium-porcorum.love/assets/sfx/collectcoin.wav b/imperium-porcorum.love/assets/sfx/collectcoin.wav new file mode 100644 index 0000000..5b6a7c3 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/collectcoin.wav differ diff --git a/imperium-porcorum.love/assets/sfx/credits.md b/imperium-porcorum.love/assets/sfx/credits.md new file mode 100644 index 0000000..c94208c --- /dev/null +++ b/imperium-porcorum.love/assets/sfx/credits.md @@ -0,0 +1,35 @@ +# Credits + +## Mateus Reis + +- break.wav (CC-BY-SA 3.0) + +- checkpoint.wav (CC-BY-SA 3.0) + +- jump.wav (CC-BY-SA 3.0) + +- spring.wav (CC-BY-SA 3.0) + +## SilverstepP + +- shield.wav (GPL) + +- acidshield.wav (GPL) + +- fireshield.wav (GPL) + +- thundershield.wav (GPL) + +- watershield.wav (GPL) + +- windshield.wav (GPL) + +## Alexandre + +- spikes_appearing.wav (CC-BY-SA 3.0) + +- spikes_disappearing.wav (CC-BY-SA 3.0) + +## Supertux + +- collectcoin.wav (GPL v2) diff --git a/imperium-porcorum.love/assets/sfx/fireshield.wav b/imperium-porcorum.love/assets/sfx/fireshield.wav new file mode 100644 index 0000000..bc633b2 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/fireshield.wav differ diff --git a/imperium-porcorum.love/assets/sfx/jump.wav b/imperium-porcorum.love/assets/sfx/jump.wav new file mode 100644 index 0000000..0826405 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/jump.wav differ diff --git a/imperium-porcorum.love/assets/sfx/shield.wav b/imperium-porcorum.love/assets/sfx/shield.wav new file mode 100644 index 0000000..6c78c30 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/shield.wav differ diff --git a/imperium-porcorum.love/assets/sfx/spikes_appearing.wav b/imperium-porcorum.love/assets/sfx/spikes_appearing.wav new file mode 100644 index 0000000..730fab4 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/spikes_appearing.wav differ diff --git a/imperium-porcorum.love/assets/sfx/spikes_disappearing.wav b/imperium-porcorum.love/assets/sfx/spikes_disappearing.wav new file mode 100644 index 0000000..471e311 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/spikes_disappearing.wav differ diff --git a/imperium-porcorum.love/assets/sfx/spring.wav b/imperium-porcorum.love/assets/sfx/spring.wav new file mode 100644 index 0000000..e8d1434 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/spring.wav differ diff --git a/imperium-porcorum.love/assets/sfx/thundershield.wav b/imperium-porcorum.love/assets/sfx/thundershield.wav new file mode 100644 index 0000000..2da35c0 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/thundershield.wav differ diff --git a/imperium-porcorum.love/assets/sfx/watershield.wav b/imperium-porcorum.love/assets/sfx/watershield.wav new file mode 100644 index 0000000..85576d5 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/watershield.wav differ diff --git a/imperium-porcorum.love/assets/sfx/windshield.wav b/imperium-porcorum.love/assets/sfx/windshield.wav new file mode 100644 index 0000000..9e91ce1 Binary files /dev/null and b/imperium-porcorum.love/assets/sfx/windshield.wav differ diff --git a/imperium-porcorum.love/assets/sprites/block.png b/imperium-porcorum.love/assets/sprites/block.png new file mode 100644 index 0000000..b004057 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/block.png differ diff --git a/imperium-porcorum.love/assets/sprites/coin.png b/imperium-porcorum.love/assets/sprites/coin.png new file mode 100644 index 0000000..cfd977c Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/coin.png differ diff --git a/imperium-porcorum.love/assets/sprites/credits.md b/imperium-porcorum.love/assets/sprites/credits.md new file mode 100644 index 0000000..b604f77 --- /dev/null +++ b/imperium-porcorum.love/assets/sprites/credits.md @@ -0,0 +1,17 @@ +# Imperium Porcorum :: assets/sprites/ + +## Credits + +- **emblem.png** :: based on assets from the [Heraldry project](https://fr.wikipedia.org/wiki/Projet:Blasons) from Wikipedia, under CC BY-SA + +- **coin.png** :: based on the [Tux Bros](https://opengameart.org/content/tux-bros) art from surt, under GPL + +- **weapon.png** :: based on the [16×16 Fantasy Tileset](https://opengameart.org/content/16x16-fantasy-tileset) from Jerom (under CC BY-SA), the [Recolor All The Items](https://opengameart.org/content/recolor-all-the-items) set from Priorblue (based on work from Jerom, 7souls, Dungeon Crawl Soup and using the Dawnbringer palette) (under CC BY-SA) and the [DawnLike](https://opengameart.org/content/dawnlike-16x16-universal-rogue-like-tileset-v181) set from DragonDePlatino using the Dawnbringer palette) + +- **cochon.png** :: original work, by Kazhnuz (under CC BY-SA 3.0) + +- **debris.png** :: origina work, by Kazhnuz (under CC0) + +- **block.png** :: from [Monkey Lad in Magical Planet](https://opengameart.org/content/monkey-lad-in-magical-planet) set by Surt, under CC-BY 3.0 + +- **poof.png** :: from [Items and Content](https://opengameart.org/content/items-and-elements) set by GrafxKid, under CC0 diff --git a/imperium-porcorum.love/assets/sprites/debris.png b/imperium-porcorum.love/assets/sprites/debris.png new file mode 100644 index 0000000..6dde06e Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/debris.png differ diff --git a/imperium-porcorum.love/assets/sprites/gem.png b/imperium-porcorum.love/assets/sprites/gem.png new file mode 100644 index 0000000..e89d976 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gem.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/banner.png b/imperium-porcorum.love/assets/sprites/gui/banner.png new file mode 100644 index 0000000..0f9981e Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/banner.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/emblem.png b/imperium-porcorum.love/assets/sprites/gui/emblem.png new file mode 100644 index 0000000..d2a6858 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/emblem.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/hborder.png b/imperium-porcorum.love/assets/sprites/gui/hborder.png new file mode 100644 index 0000000..4bf20ac Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/hborder.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/progressbar/backbar.png b/imperium-porcorum.love/assets/sprites/gui/progressbar/backbar.png new file mode 100644 index 0000000..3eb74cc Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/progressbar/backbar.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/progressbar/bluebar.png b/imperium-porcorum.love/assets/sprites/gui/progressbar/bluebar.png new file mode 100644 index 0000000..2d21d29 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/progressbar/bluebar.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/progressbar/greenbar.png b/imperium-porcorum.love/assets/sprites/gui/progressbar/greenbar.png new file mode 100644 index 0000000..1038d53 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/progressbar/greenbar.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/textbox/bluebox.png b/imperium-porcorum.love/assets/sprites/gui/textbox/bluebox.png new file mode 100644 index 0000000..a06e1b5 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/textbox/bluebox.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/textbox/bluetextbox.png b/imperium-porcorum.love/assets/sprites/gui/textbox/bluetextbox.png new file mode 100644 index 0000000..7a62864 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/textbox/bluetextbox.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/textbox/greenbox.png b/imperium-porcorum.love/assets/sprites/gui/textbox/greenbox.png new file mode 100644 index 0000000..e7f7371 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/textbox/greenbox.png differ diff --git a/imperium-porcorum.love/assets/sprites/gui/textbox/yellowbox.png b/imperium-porcorum.love/assets/sprites/gui/textbox/yellowbox.png new file mode 100644 index 0000000..ac3717a Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/gui/textbox/yellowbox.png differ diff --git a/imperium-porcorum.love/assets/sprites/pigs/bling-bling.png b/imperium-porcorum.love/assets/sprites/pigs/bling-bling.png new file mode 100644 index 0000000..e22c9df Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/pigs/bling-bling.png differ diff --git a/imperium-porcorum.love/assets/sprites/pigs/cochon.png b/imperium-porcorum.love/assets/sprites/pigs/cochon.png new file mode 100644 index 0000000..4c08171 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/pigs/cochon.png differ diff --git a/imperium-porcorum.love/assets/sprites/pigs/lifeicons.png b/imperium-porcorum.love/assets/sprites/pigs/lifeicons.png new file mode 100644 index 0000000..6028f77 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/pigs/lifeicons.png differ diff --git a/imperium-porcorum.love/assets/sprites/pigs/robo-chon.png b/imperium-porcorum.love/assets/sprites/pigs/robo-chon.png new file mode 100644 index 0000000..2c5d7f5 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/pigs/robo-chon.png differ diff --git a/imperium-porcorum.love/assets/sprites/poof.png b/imperium-porcorum.love/assets/sprites/poof.png new file mode 100644 index 0000000..3d08f8d Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/poof.png differ diff --git a/imperium-porcorum.love/assets/sprites/sparkle.png b/imperium-porcorum.love/assets/sprites/sparkle.png new file mode 100644 index 0000000..619973e Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/sparkle.png differ diff --git a/imperium-porcorum.love/assets/sprites/weapon.png b/imperium-porcorum.love/assets/sprites/weapon.png new file mode 100644 index 0000000..2b88fb2 Binary files /dev/null and b/imperium-porcorum.love/assets/sprites/weapon.png differ diff --git a/imperium-porcorum.love/conf.lua b/imperium-porcorum.love/conf.lua new file mode 100644 index 0000000..c977f3d --- /dev/null +++ b/imperium-porcorum.love/conf.lua @@ -0,0 +1,41 @@ +function love.conf(t) + t.identity = nil -- The name of the save directory (string) + t.version = "0.10.1" -- The LÖVE version this game was made for (string) + t.console = false -- Attach a console (boolean, Windows only) + t.accelerometerjoystick = false -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) + t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean) + + t.window.title = "Imperium Porcorum" -- The window title (string) + t.window.icon = nil -- Filepath to an image to use as the window's icon (string) + t.window.width = 480*2 -- The window width (number) + t.window.height = 272*2 -- The window height (number) + t.window.borderless = false -- Remove all border visuals from the window (boolean) + t.window.resizable = false -- Let the window be user-resizable (boolean) + t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) + t.window.minheight = 1 -- Minimum window height if the window is resizable (number) + t.window.fullscreen = false -- Enable fullscreen (boolean) + t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string) + t.window.vsync = true -- Enable vertical sync (boolean) + t.window.msaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) + t.window.display = 1 -- Index of the monitor to show the window in (number) + t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) + t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) + t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) + + t.modules.audio = true -- Enable the audio module (boolean) + t.modules.event = true -- Enable the event module (boolean) + t.modules.graphics = true -- Enable the graphics module (boolean) + t.modules.image = true -- Enable the image module (boolean) + t.modules.joystick = true -- Enable the joystick module (boolean) + t.modules.keyboard = true -- Enable the keyboard module (boolean) + t.modules.math = true -- Enable the math module (boolean) + t.modules.mouse = true -- Enable the mouse module (boolean) + t.modules.physics = true -- Enable the physics module (boolean) + t.modules.sound = true -- Enable the sound module (boolean) + t.modules.system = true -- Enable the system module (boolean) + t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update + t.modules.touch = true -- Enable the touch module (boolean) + t.modules.video = true -- Enable the video module (boolean) + t.modules.window = true -- Enable the window module (boolean) + t.modules.thread = true -- Enable the thread module (boolean) +end diff --git a/imperium-porcorum.love/datas/cochons/races.lua b/imperium-porcorum.love/datas/cochons/races.lua new file mode 100644 index 0000000..67a0dc2 --- /dev/null +++ b/imperium-porcorum.love/datas/cochons/races.lua @@ -0,0 +1,4 @@ +return { + ["cochon"] = {}, + ["bling-bling"] = {}, +} diff --git a/imperium-porcorum.love/datas/entities.lua b/imperium-porcorum.love/datas/entities.lua new file mode 100644 index 0000000..6a44e43 --- /dev/null +++ b/imperium-porcorum.love/datas/entities.lua @@ -0,0 +1,4 @@ +return { + ["coin"] = {w = 16, h = 16}, + ["block"] = {w = 16, h = 16}, +} diff --git a/imperium-porcorum.love/datas/init.lua b/imperium-porcorum.love/datas/init.lua new file mode 100644 index 0000000..ea93605 --- /dev/null +++ b/imperium-porcorum.love/datas/init.lua @@ -0,0 +1,8 @@ +Datas = {} + +Datas.levels = require "datas.levels" +Datas.layers = require "datas.layers" +Datas.entities = require "datas.entities" +Datas.vpad = require "datas.vpad" + +return Datas diff --git a/imperium-porcorum.love/datas/layers.lua b/imperium-porcorum.love/datas/layers.lua new file mode 100644 index 0000000..ad9516b --- /dev/null +++ b/imperium-porcorum.love/datas/layers.lua @@ -0,0 +1,3 @@ +return { + "wall", "platform", "water" +} diff --git a/imperium-porcorum.love/datas/levels/init.lua b/imperium-porcorum.love/datas/levels/init.lua new file mode 100644 index 0000000..21a6ae1 --- /dev/null +++ b/imperium-porcorum.love/datas/levels/init.lua @@ -0,0 +1,20 @@ +return { + [1] = { + realm = "Mystery Zone", + name = "Test Level", + missions = { + [1] = { + missionName = "GameTest", + description = "Test and debug the game !", + mapfile = "test-map2", + music = "", + gravity = 0, + autorun = 0, + objectiveID = 0, + startx = 48, + starty = 272/2, + music = "sunnyparadise1.mp3" + } + } + } +} diff --git a/imperium-porcorum.love/datas/vpad.lua b/imperium-porcorum.love/datas/vpad.lua new file mode 100644 index 0000000..3b63222 --- /dev/null +++ b/imperium-porcorum.love/datas/vpad.lua @@ -0,0 +1,12 @@ +return { + { + ["left"] = "left", + ["right"] = "right", + ["up"] = "up", + ["down"] = "down", + ["A"] = "a", + ["B"] = "z", + ["C"] = "e", + ["start"] = "return", + } +} diff --git a/imperium-porcorum.love/libs/anim8.lua b/imperium-porcorum.love/libs/anim8.lua new file mode 100644 index 0000000..8fefe99 --- /dev/null +++ b/imperium-porcorum.love/libs/anim8.lua @@ -0,0 +1,302 @@ +local anim8 = { + _VERSION = 'anim8 v2.3.0', + _DESCRIPTION = 'An animation library for LÖVE', + _URL = 'https://github.com/kikito/anim8', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2011 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +local Grid = {} + +local _frames = {} + +local function assertPositiveInteger(value, name) + if type(value) ~= 'number' then error(("%s should be a number, was %q"):format(name, tostring(value))) end + if value < 1 then error(("%s should be a positive number, was %d"):format(name, value)) end + if value ~= math.floor(value) then error(("%s should be an integer, was %d"):format(name, value)) end +end + +local function createFrame(self, x, y) + local fw, fh = self.frameWidth, self.frameHeight + return love.graphics.newQuad( + self.left + (x-1) * fw + x * self.border, + self.top + (y-1) * fh + y * self.border, + fw, + fh, + self.imageWidth, + self.imageHeight + ) +end + +local function getGridKey(...) + return table.concat( {...} ,'-' ) +end + +local function getOrCreateFrame(self, x, y) + if x < 1 or x > self.width or y < 1 or y > self.height then + error(("There is no frame for x=%d, y=%d"):format(x, y)) + end + local key = self._key + _frames[key] = _frames[key] or {} + _frames[key][x] = _frames[key][x] or {} + _frames[key][x][y] = _frames[key][x][y] or createFrame(self, x, y) + return _frames[key][x][y] +end + +local function parseInterval(str) + if type(str) == "number" then return str,str,1 end + str = str:gsub('%s', '') -- remove spaces + local min, max = str:match("^(%d+)-(%d+)$") + assert(min and max, ("Could not parse interval from %q"):format(str)) + min, max = tonumber(min), tonumber(max) + local step = min <= max and 1 or -1 + return min, max, step +end + +function Grid:getFrames(...) + local result, args = {}, {...} + local minx, maxx, stepx, miny, maxy, stepy + + for i=1, #args, 2 do + minx, maxx, stepx = parseInterval(args[i]) + miny, maxy, stepy = parseInterval(args[i+1]) + for y = miny, maxy, stepy do + for x = minx, maxx, stepx do + result[#result+1] = getOrCreateFrame(self,x,y) + end + end + end + + return result +end + +local Gridmt = { + __index = Grid, + __call = Grid.getFrames +} + +local function newGrid(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border) + assertPositiveInteger(frameWidth, "frameWidth") + assertPositiveInteger(frameHeight, "frameHeight") + assertPositiveInteger(imageWidth, "imageWidth") + assertPositiveInteger(imageHeight, "imageHeight") + + left = left or 0 + top = top or 0 + border = border or 0 + + local key = getGridKey(frameWidth, frameHeight, imageWidth, imageHeight, left, top, border) + + local grid = setmetatable( + { frameWidth = frameWidth, + frameHeight = frameHeight, + imageWidth = imageWidth, + imageHeight = imageHeight, + left = left, + top = top, + border = border, + width = math.floor(imageWidth/frameWidth), + height = math.floor(imageHeight/frameHeight), + _key = key + }, + Gridmt + ) + return grid +end + +----------------------------------------------------------- + +local Animation = {} + +local function cloneArray(arr) + local result = {} + for i=1,#arr do result[i] = arr[i] end + return result +end + +local function parseDurations(durations, frameCount) + local result = {} + if type(durations) == 'number' then + for i=1,frameCount do result[i] = durations end + else + local min, max, step + for key,duration in pairs(durations) do + assert(type(duration) == 'number', "The value [" .. tostring(duration) .. "] should be a number") + min, max, step = parseInterval(key) + for i = min,max,step do result[i] = duration end + end + end + + if #result < frameCount then + error("The durations table has length of " .. tostring(#result) .. ", but it should be >= " .. tostring(frameCount)) + end + + return result +end + +local function parseIntervals(durations) + local result, time = {0},0 + for i=1,#durations do + time = time + durations[i] + result[i+1] = time + end + return result, time +end + +local Animationmt = { __index = Animation } +local nop = function() end + +local function newAnimation(frames, durations, onLoop) + local td = type(durations); + if (td ~= 'number' or durations <= 0) and td ~= 'table' then + error("durations must be a positive number. Was " .. tostring(durations) ) + end + onLoop = onLoop or nop + durations = parseDurations(durations, #frames) + local intervals, totalDuration = parseIntervals(durations) + return setmetatable({ + frames = cloneArray(frames), + durations = durations, + intervals = intervals, + totalDuration = totalDuration, + onLoop = onLoop, + timer = 0, + position = 1, + status = "playing", + flippedH = false, + flippedV = false + }, + Animationmt + ) +end + +function Animation:clone() + local newAnim = newAnimation(self.frames, self.durations, self.onLoop) + newAnim.flippedH, newAnim.flippedV = self.flippedH, self.flippedV + return newAnim +end + +function Animation:flipH() + self.flippedH = not self.flippedH + return self +end + +function Animation:flipV() + self.flippedV = not self.flippedV + return self +end + +local function seekFrameIndex(intervals, timer) + local high, low, i = #intervals-1, 1, 1 + + while(low <= high) do + i = math.floor((low + high) / 2) + if timer > intervals[i+1] then low = i + 1 + elseif timer <= intervals[i] then high = i - 1 + else + return i + end + end + + return i +end + +function Animation:update(dt) + if self.status ~= "playing" then return end + + self.timer = self.timer + dt + local loops = math.floor(self.timer / self.totalDuration) + if loops ~= 0 then + self.timer = self.timer - self.totalDuration * loops + local f = type(self.onLoop) == 'function' and self.onLoop or self[self.onLoop] + f(self, loops) + end + + self.position = seekFrameIndex(self.intervals, self.timer) +end + +function Animation:pause() + self.status = "paused" +end + +function Animation:gotoFrame(position) + self.position = position + self.timer = self.intervals[self.position] +end + +function Animation:pauseAtEnd() + self.position = #self.frames + self.timer = self.totalDuration + self:pause() +end + +function Animation:pauseAtStart() + self.position = 1 + self.timer = 0 + self:pause() +end + +function Animation:resume() + self.status = "playing" +end + +function Animation:draw(image, x, y, r, sx, sy, ox, oy, kx, ky) + love.graphics.draw(image, self:getFrameInfo(x, y, r, sx, sy, ox, oy, kx, ky)) +end + +function Animation:getFrameInfo(x, y, r, sx, sy, ox, oy, kx, ky) + local frame = self.frames[self.position] + if self.flippedH or self.flippedV then + r,sx,sy,ox,oy,kx,ky = r or 0, sx or 1, sy or 1, ox or 0, oy or 0, kx or 0, ky or 0 + local _,_,w,h = frame:getViewport() + + if self.flippedH then + sx = sx * -1 + ox = w - ox + kx = kx * -1 + ky = ky * -1 + end + + if self.flippedV then + sy = sy * -1 + oy = h - oy + kx = kx * -1 + ky = ky * -1 + end + end + return frame, x, y, r, sx, sy, ox, oy, kx, ky +end + +function Animation:getDimensions() + local _,_,w,h = self.frames[self.position]:getViewport() + return w,h +end + +----------------------------------------------------------- + +anim8.newGrid = newGrid +anim8.newAnimation = newAnimation + +return anim8 diff --git a/imperium-porcorum.love/libs/assets/init.lua b/imperium-porcorum.love/libs/assets/init.lua new file mode 100644 index 0000000..0f3cf4d --- /dev/null +++ b/imperium-porcorum.love/libs/assets/init.lua @@ -0,0 +1,9 @@ +local AssetManager = Object:extend() + +local SoundManager = "libs.assets.sfx" + +function AssetManager:new() + +end + +return AssetManager diff --git a/imperium-porcorum.love/libs/assets/sfx.lua b/imperium-porcorum.love/libs/assets/sfx.lua new file mode 100644 index 0000000..6a1dcbb --- /dev/null +++ b/imperium-porcorum.love/libs/assets/sfx.lua @@ -0,0 +1,12 @@ +local SoundManager = Object:extend() +local SFX = Object:extend() + +function SoundManager:new() + self.datas = {} +end + +function SoundManager:addSFX() + self.datas = {} +end + +return SoundManager diff --git a/imperium-porcorum.love/libs/binser.lua b/imperium-porcorum.love/libs/binser.lua new file mode 100644 index 0000000..5aa1299 --- /dev/null +++ b/imperium-porcorum.love/libs/binser.lua @@ -0,0 +1,687 @@ +-- binser.lua + +--[[ +Copyright (c) 2016 Calvin Rose + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +]] + +local assert = assert +local error = error +local select = select +local pairs = pairs +local getmetatable = getmetatable +local setmetatable = setmetatable +local tonumber = tonumber +local type = type +local loadstring = loadstring or load +local concat = table.concat +local char = string.char +local byte = string.byte +local format = string.format +local sub = string.sub +local dump = string.dump +local floor = math.floor +local frexp = math.frexp +local unpack = unpack or table.unpack + +-- Lua 5.3 frexp polyfill +-- From https://github.com/excessive/cpml/blob/master/modules/utils.lua +if not frexp then + local log, abs, floor = math.log, math.abs, math.floor + local log2 = log(2) + frexp = function(x) + if x == 0 then return 0, 0 end + local e = floor(log(abs(x)) / log2 + 1) + return x / 2 ^ e, e + end +end + +-- NIL = 202 +-- FLOAT = 203 +-- TRUE = 204 +-- FALSE = 205 +-- STRING = 206 +-- TABLE = 207 +-- REFERENCE = 208 +-- CONSTRUCTOR = 209 +-- FUNCTION = 210 +-- RESOURCE = 211 +-- INT64 = 212 + +local mts = {} +local ids = {} +local serializers = {} +local deserializers = {} +local resources = {} +local resources_by_name = {} + +local function pack(...) + return {...}, select("#", ...) +end + +local function not_array_index(x, len) + return type(x) ~= "number" or x < 1 or x > len or x ~= floor(x) +end + +local function type_check(x, tp, name) + assert(type(x) == tp, + format("Expected parameter %q to be of type %q.", name, tp)) +end + +local bigIntSupport = false +local isInteger +if math.type then -- Detect Lua 5.3 + local mtype = math.type + bigIntSupport = loadstring[[ + local char = string.char + return function(n) + local nn = n < 0 and -(n + 1) or n + local b1 = nn // 0x100000000000000 + local b2 = nn // 0x1000000000000 % 0x100 + local b3 = nn // 0x10000000000 % 0x100 + local b4 = nn // 0x100000000 % 0x100 + local b5 = nn // 0x1000000 % 0x100 + local b6 = nn // 0x10000 % 0x100 + local b7 = nn // 0x100 % 0x100 + local b8 = nn % 0x100 + if n < 0 then + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + return char(212, b1, b2, b3, b4, b5, b6, b7, b8) + end]]() + isInteger = function(x) + return mtype(x) == 'integer' + end +else + isInteger = function(x) + return floor(x) == x + end +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number serialization code modified from https://github.com/fperrad/lua-MessagePack +-- Encode a number as a big-endian ieee-754 double, big-endian signed 64 bit integer, or a small integer +local function number_to_str(n) + if isInteger(n) then -- int + if n <= 100 and n >= -27 then -- 1 byte, 7 bits of data + return char(n + 27) + elseif n <= 8191 and n >= -8192 then -- 2 bytes, 14 bits of data + n = n + 8192 + return char(128 + (floor(n / 0x100) % 0x100), n % 0x100) + elseif bigIntSupport then + return bigIntSupport(n) + end + end + local sign = 0 + if n < 0.0 then + sign = 0x80 + n = -n + end + local m, e = frexp(n) -- mantissa, exponent + if m ~= m then + return char(203, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + elseif m == 1/0 then + if sign == 0 then + return char(203, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + else + return char(203, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + end + end + e = e + 0x3FE + if e < 1 then -- denormalized numbers + m = m * 2 ^ (52 + e) + e = 0 + else + m = (m * 2 - 1) * 2 ^ 52 + end + return char(203, + sign + floor(e / 0x10), + (e % 0x10) * 0x10 + floor(m / 0x1000000000000), + floor(m / 0x10000000000) % 0x100, + floor(m / 0x100000000) % 0x100, + floor(m / 0x1000000) % 0x100, + floor(m / 0x10000) % 0x100, + floor(m / 0x100) % 0x100, + m % 0x100) +end + +-- Copyright (C) 2012-2015 Francois Perrad. +-- number deserialization code also modified from https://github.com/fperrad/lua-MessagePack +local function number_from_str(str, index) + local b = byte(str, index) + if b < 128 then + return b - 27, index + 1 + elseif b < 192 then + return byte(str, index + 1) + 0x100 * (b - 128) - 8192, index + 2 + end + local b1, b2, b3, b4, b5, b6, b7, b8 = byte(str, index + 1, index + 8) + if b == 212 then + local flip = b1 >= 128 + if flip then -- negative + b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4 + b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8 + end + local n = ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + if flip then + return (-n) - 1, index + 9 + else + return n, index + 9 + end + end + local sign = b1 > 0x7F and -1 or 1 + local e = (b1 % 0x80) * 0x10 + floor(b2 / 0x10) + local m = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8 + local n + if e == 0 then + if m == 0 then + n = sign * 0.0 + else + n = sign * (m / 2 ^ 52) * 2 ^ -1022 + end + elseif e == 0x7FF then + if m == 0 then + n = sign * (1/0) + else + n = 0.0/0.0 + end + else + n = sign * (1.0 + m / 2 ^ 52) * 2 ^ (e - 0x3FF) + end + return n, index + 9 +end + +local types = {} + +types["nil"] = function(x, visited, accum) + accum[#accum + 1] = "\202" +end + +function types.number(x, visited, accum) + accum[#accum + 1] = number_to_str(x) +end + +function types.boolean(x, visited, accum) + accum[#accum + 1] = x and "\204" or "\205" +end + +function types.string(x, visited, accum) + local alen = #accum + if visited[x] then + accum[alen + 1] = "\208" + accum[alen + 2] = number_to_str(visited[x]) + else + visited[x] = visited.next + visited.next = visited.next + 1 + accum[alen + 1] = "\206" + accum[alen + 2] = number_to_str(#x) + accum[alen + 3] = x + end +end + +local function check_custom_type(x, visited, accum) + local res = resources[x] + if res then + accum[#accum + 1] = "\211" + types[type(res)](res, visited, accum) + return true + end + local mt = getmetatable(x) + local id = mt and ids[mt] + if id then + if x == visited.temp then + error("Infinite loop in constructor.") + end + visited.temp = x + accum[#accum + 1] = "\209" + types[type(id)](id, visited, accum) + local args, len = pack(serializers[id](x)) + accum[#accum + 1] = number_to_str(len) + for i = 1, len do + local arg = args[i] + types[type(arg)](arg, visited, accum) + end + visited[x] = visited.next + visited.next = visited.next + 1 + return true + end +end + +function types.userdata(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + error("Cannot serialize this userdata.") + end +end + +function types.table(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local xlen = #x + accum[#accum + 1] = "\207" + accum[#accum + 1] = number_to_str(xlen) + for i = 1, xlen do + local v = x[i] + types[type(v)](v, visited, accum) + end + local key_count = 0 + for k in pairs(x) do + if not_array_index(k, xlen) then + key_count = key_count + 1 + end + end + accum[#accum + 1] = number_to_str(key_count) + for k, v in pairs(x) do + if not_array_index(k, xlen) then + types[type(k)](k, visited, accum) + types[type(v)](v, visited, accum) + end + end + end +end + +types["function"] = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, accum) then return end + visited[x] = visited.next + visited.next = visited.next + 1 + local str = dump(x) + accum[#accum + 1] = "\210" + accum[#accum + 1] = number_to_str(#str) + accum[#accum + 1] = str + end +end + +types.cdata = function(x, visited, accum) + if visited[x] then + accum[#accum + 1] = "\208" + accum[#accum + 1] = number_to_str(visited[x]) + else + if check_custom_type(x, visited, #accum) then return end + error("Cannot serialize this cdata.") + end +end + +types.thread = function() error("Cannot serialize threads.") end + +local function deserialize_value(str, index, visited) + local t = byte(str, index) + if not t then return end + if t < 128 then + return t - 27, index + 1 + elseif t < 192 then + return byte(str, index + 1) + 0x100 * (t - 128) - 8192, index + 2 + elseif t == 202 then + return nil, index + 1 + elseif t == 203 then + return number_from_str(str, index) + elseif t == 204 then + return true, index + 1 + elseif t == 205 then + return false, index + 1 + elseif t == 206 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local substr = sub(str, dataindex, nextindex - 1) + visited[#visited + 1] = substr + return substr, nextindex + elseif t == 207 then + local count, nextindex = number_from_str(str, index + 1) + local ret = {} + visited[#visited + 1] = ret + for i = 1, count do + ret[i], nextindex = deserialize_value(str, nextindex, visited) + end + count, nextindex = number_from_str(str, nextindex) + for i = 1, count do + local k, v + k, nextindex = deserialize_value(str, nextindex, visited) + v, nextindex = deserialize_value(str, nextindex, visited) + ret[k] = v + end + return ret, nextindex + elseif t == 208 then + local ref, nextindex = number_from_str(str, index + 1) + return visited[ref], nextindex + elseif t == 209 then + local count + local name, nextindex = deserialize_value(str, index + 1, visited) + count, nextindex = number_from_str(str, nextindex) + local args = {} + for i = 1, count do + args[i], nextindex = deserialize_value(str, nextindex, visited) + end + local ret = deserializers[name](unpack(args)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 210 then + local length, dataindex = deserialize_value(str, index + 1, visited) + local nextindex = dataindex + length + local ret = loadstring(sub(str, dataindex, nextindex - 1)) + visited[#visited + 1] = ret + return ret, nextindex + elseif t == 211 then + local res, nextindex = deserialize_value(str, index + 1, visited) + return resources_by_name[res], nextindex + elseif t == 212 then + return number_from_str(str, index) + else + error("Could not deserialize type byte " .. t .. ".") + end +end + +local function serialize(...) + local visited = {next = 1} + local accum = {} + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + return concat(accum) +end + +local function make_file_writer(file) + return setmetatable({}, { + __newindex = function(_, _, v) + file:write(v) + end + }) +end + +local function serialize_to_file(path, mode, ...) + local file, err = io.open(path, mode) + assert(file, err) + local visited = {next = 1} + local accum = make_file_writer(file) + for i = 1, select("#", ...) do + local x = select(i, ...) + types[type(x)](x, visited, accum) + end + -- flush the writer + file:flush() + file:close() +end + +local function writeFile(path, ...) + return serialize_to_file(path, "wb", ...) +end + +local function appendFile(path, ...) + return serialize_to_file(path, "ab", ...) +end + +local function deserialize(str, index) + assert(type(str) == "string", "Expected string to deserialize.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + return vals, len +end + +local function deserializeN(str, n, index) + assert(type(str) == "string", "Expected string to deserialize.") + n = n or 1 + assert(type(n) == "number", "Expected a number for parameter n.") + assert(n > 0 and floor(n) == n, "N must be a poitive integer.") + local vals = {} + index = index or 1 + local visited = {} + local len = 0 + local val + while index and len < n do + val, index = deserialize_value(str, index, visited) + if index then + len = len + 1 + vals[len] = val + end + end + vals[len + 1] = index + return unpack(vals, 1, n + 1) +end + +local function readFile(path) + local file, err = io.open(path, "rb") + assert(file, err) + local str = file:read("*all") + file:close() + return deserialize(str) +end + +local function default_deserialize(metatable) + return function(...) + local ret = {} + for i = 1, select("#", ...), 2 do + ret[select(i, ...)] = select(i + 1, ...) + end + return setmetatable(ret, metatable) + end +end + +local function default_serialize(x) + assert(type(x) == "table", + "Default serialization for custom types only works for tables.") + local args = {} + local len = 0 + for k, v in pairs(x) do + args[len + 1], args[len + 2] = k, v + len = len + 2 + end + return unpack(args, 1, len) +end + +-- Templating + +local function normalize_template(template) + local ret = {} + for i = 1, #template do + ret[i] = template[i] + end + local non_array_part = {} + -- The non-array part of the template (nested templates) have to be deterministic, so they are sorted. + -- This means that inherently non deterministicly sortable keys (tables, functions) should NOT be used + -- in templates. Looking for way around this. + for k in pairs(template) do + if not_array_index(k, #template) then + non_array_part[#non_array_part + 1] = k + end + end + table.sort(non_array_part) + for i = 1, #non_array_part do + local name = non_array_part[i] + ret[#ret + 1] = {name, normalize_template(template[name])} + end + return ret +end + +local function templatepart_serialize(part, argaccum, x, len) + local extras = {} + local extracount = 0 + for k, v in pairs(x) do + extras[k] = v + extracount = extracount + 1 + end + for i = 1, #part do + extracount = extracount - 1 + if type(part[i]) == "table" then + extras[part[i][1]] = nil + len = templatepart_serialize(part[i][2], argaccum, x[part[i][1]], len) + else + extras[part[i]] = nil + len = len + 1 + argaccum[len] = x[part[i]] + end + end + if extracount > 0 then + argaccum[len + 1] = extras + else + argaccum[len + 1] = nil + end + return len + 1 +end + +local function templatepart_deserialize(ret, part, values, vindex) + for i = 1, #part do + local name = part[i] + if type(name) == "table" then + local newret = {} + ret[name[1]] = newret + vindex = templatepart_deserialize(newret, name[2], values, vindex) + else + ret[name] = values[vindex] + vindex = vindex + 1 + end + end + local extras = values[vindex] + if extras then + for k, v in pairs(extras) do + ret[k] = v + end + end + return vindex + 1 +end + +local function template_serializer_and_deserializer(metatable, template) + return function(x) + argaccum = {} + local len = templatepart_serialize(template, argaccum, x, 0) + return unpack(argaccum, 1, len) + end, function(...) + local ret = {} + local len = select("#", ...) + local args = {...} + templatepart_deserialize(ret, template, args, 1) + return setmetatable(ret, metatable) + end +end + +local function register(metatable, name, serialize, deserialize) + name = name or metatable.name + serialize = serialize or metatable._serialize + deserialize = deserialize or metatable._deserialize + if not serialize then + if metatable._template then + local t = normalize_template(metatable._template) + serialize, deserialize = template_serializer_and_deserializer(metatable, t) + elseif not deserialize then + serialize = default_serialize + deserialize = default_deserialize(metatable) + else + serialize = metatable + end + end + type_check(metatable, "table", "metatable") + type_check(name, "string", "name") + type_check(serialize, "function", "serialize") + type_check(deserialize, "function", "deserialize") + assert(not ids[metatable], "Metatable already registered.") + assert(not mts[name], ("Name %q already registered."):format(name)) + mts[name] = metatable + ids[metatable] = name + serializers[name] = serialize + deserializers[name] = deserialize + return metatable +end + +local function unregister(item) + local name, metatable + if type(item) == "string" then -- assume name + name, metatable = item, mts[item] + else -- assume metatable + name, metatable = ids[item], item + end + type_check(name, "string", "name") + type_check(metatable, "table", "metatable") + mts[name] = nil + ids[metatable] = nil + serializers[name] = nil + deserializers[name] = nil + return metatable +end + +local function registerClass(class, name) + name = name or class.name + if class.__instanceDict then -- middleclass + register(class.__instanceDict, name) + else -- assume 30log or similar library + register(class, name) + end + return class +end + +local function registerResource(resource, name) + type_check(name, "string", "name") + assert(not resources[resource], + "Resource already registered.") + assert(not resources_by_name[name], + format("Resource %q already exists.", name)) + resources_by_name[name] = resource + resources[resource] = name + return resource +end + +local function unregisterResource(name) + type_check(name, "string", "name") + assert(resources_by_name[name], format("Resource %q does not exist.", name)) + local resource = resources_by_name[name] + resources_by_name[name] = nil + resources[resource] = nil + return resource +end + +return { + -- aliases + s = serialize, + d = deserialize, + dn = deserializeN, + r = readFile, + w = writeFile, + a = appendFile, + + serialize = serialize, + deserialize = deserialize, + deserializeN = deserializeN, + readFile = readFile, + writeFile = writeFile, + appendFile = appendFile, + register = register, + unregister = unregister, + registerResource = registerResource, + unregisterResource = unregisterResource, + registerClass = registerClass +} diff --git a/imperium-porcorum.love/libs/bump.lua b/imperium-porcorum.love/libs/bump.lua new file mode 100644 index 0000000..5626d4f --- /dev/null +++ b/imperium-porcorum.love/libs/bump.lua @@ -0,0 +1,775 @@ +local bump = { + _VERSION = 'bump v3.1.7', + _URL = 'https://github.com/kikito/bump.lua', + _DESCRIPTION = 'A collision detection library for Lua', + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2014 Enrique García Cota + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ]] +} + +------------------------------------------ +-- Auxiliary functions +------------------------------------------ +local DELTA = 1e-10 -- floating-point margin of error + +local abs, floor, ceil, min, max = math.abs, math.floor, math.ceil, math.min, math.max + +local function sign(x) + if x > 0 then return 1 end + if x == 0 then return 0 end + return -1 +end + +local function nearest(x, a, b) + if abs(a - x) < abs(b - x) then return a else return b end +end + +local function assertType(desiredType, value, name) + if type(value) ~= desiredType then + error(name .. ' must be a ' .. desiredType .. ', but was ' .. tostring(value) .. '(a ' .. type(value) .. ')') + end +end + +local function assertIsPositiveNumber(value, name) + if type(value) ~= 'number' or value <= 0 then + error(name .. ' must be a positive integer, but was ' .. tostring(value) .. '(' .. type(value) .. ')') + end +end + +local function assertIsRect(x,y,w,h) + assertType('number', x, 'x') + assertType('number', y, 'y') + assertIsPositiveNumber(w, 'w') + assertIsPositiveNumber(h, 'h') +end + +local defaultFilter = function() + return 'slide' +end + +------------------------------------------ +-- Rectangle functions +------------------------------------------ + +local function rect_getNearestCorner(x,y,w,h, px, py) + return nearest(px, x, x+w), nearest(py, y, y+h) +end + +-- This is a generalized implementation of the liang-barsky algorithm, which also returns +-- the normals of the sides where the segment intersects. +-- Returns nil if the segment never touches the rect +-- Notice that normals are only guaranteed to be accurate when initially ti1, ti2 == -math.huge, math.huge +local function rect_getSegmentIntersectionIndices(x,y,w,h, x1,y1,x2,y2, ti1,ti2) + ti1, ti2 = ti1 or 0, ti2 or 1 + local dx, dy = x2-x1, y2-y1 + local nx, ny + local nx1, ny1, nx2, ny2 = 0,0,0,0 + local p, q, r + + for side = 1,4 do + if side == 1 then nx,ny,p,q = -1, 0, -dx, x1 - x -- left + elseif side == 2 then nx,ny,p,q = 1, 0, dx, x + w - x1 -- right + elseif side == 3 then nx,ny,p,q = 0, -1, -dy, y1 - y -- top + else nx,ny,p,q = 0, 1, dy, y + h - y1 -- bottom + end + + if p == 0 then + if q <= 0 then return nil end + else + r = q / p + if p < 0 then + if r > ti2 then return nil + elseif r > ti1 then ti1,nx1,ny1 = r,nx,ny + end + else -- p > 0 + if r < ti1 then return nil + elseif r < ti2 then ti2,nx2,ny2 = r,nx,ny + end + end + end + end + + return ti1,ti2, nx1,ny1, nx2,ny2 +end + +-- Calculates the minkowsky difference between 2 rects, which is another rect +local function rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) + return x2 - x1 - w1, + y2 - y1 - h1, + w1 + w2, + h1 + h2 +end + +local function rect_containsPoint(x,y,w,h, px,py) + return px - x > DELTA and py - y > DELTA and + x + w - px > DELTA and y + h - py > DELTA +end + +local function rect_isIntersecting(x1,y1,w1,h1, x2,y2,w2,h2) + return x1 < x2+w2 and x2 < x1+w1 and + y1 < y2+h2 and y2 < y1+h1 +end + +local function rect_getSquareDistance(x1,y1,w1,h1, x2,y2,w2,h2) + local dx = x1 - x2 + (w1 - w2)/2 + local dy = y1 - y2 + (h1 - h2)/2 + return dx*dx + dy*dy +end + +local function rect_detectCollision(x1,y1,w1,h1, x2,y2,w2,h2, goalX, goalY) + goalX = goalX or x1 + goalY = goalY or y1 + + local dx, dy = goalX - x1, goalY - y1 + local x,y,w,h = rect_getDiff(x1,y1,w1,h1, x2,y2,w2,h2) + + local overlaps, ti, nx, ny + + if rect_containsPoint(x,y,w,h, 0,0) then -- item was intersecting other + local px, py = rect_getNearestCorner(x,y,w,h, 0, 0) + local wi, hi = min(w1, abs(px)), min(h1, abs(py)) -- area of intersection + ti = -wi * hi -- ti is the negative area of intersection + overlaps = true + else + local ti1,ti2,nx1,ny1 = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, math.huge) + + -- item tunnels into other + if ti1 + and ti1 < 1 + and (abs(ti1 - ti2) >= DELTA) -- special case for rect going through another rect's corner + and (0 < ti1 + DELTA + or 0 == ti1 and ti2 > 0) + then + ti, nx, ny = ti1, nx1, ny1 + overlaps = false + end + end + + if not ti then return end + + local tx, ty + + if overlaps then + if dx == 0 and dy == 0 then + -- intersecting and not moving - use minimum displacement vector + local px, py = rect_getNearestCorner(x,y,w,h, 0,0) + if abs(px) < abs(py) then py = 0 else px = 0 end + nx, ny = sign(px), sign(py) + tx, ty = x1 + px, y1 + py + else + -- intersecting and moving - move in the opposite direction + local ti1, _ + ti1,_,nx,ny = rect_getSegmentIntersectionIndices(x,y,w,h, 0,0,dx,dy, -math.huge, 1) + if not ti1 then return end + tx, ty = x1 + dx * ti1, y1 + dy * ti1 + end + else -- tunnel + tx, ty = x1 + dx * ti, y1 + dy * ti + end + + return { + overlaps = overlaps, + ti = ti, + move = {x = dx, y = dy}, + normal = {x = nx, y = ny}, + touch = {x = tx, y = ty}, + itemRect = {x = x1, y = y1, w = w1, h = h1}, + otherRect = {x = x2, y = y2, w = w2, h = h2} + } +end + +------------------------------------------ +-- Grid functions +------------------------------------------ + +local function grid_toWorld(cellSize, cx, cy) + return (cx - 1)*cellSize, (cy-1)*cellSize +end + +local function grid_toCell(cellSize, x, y) + return floor(x / cellSize) + 1, floor(y / cellSize) + 1 +end + +-- grid_traverse* functions are based on "A Fast Voxel Traversal Algorithm for Ray Tracing", +-- by John Amanides and Andrew Woo - http://www.cse.yorku.ca/~amana/research/grid.pdf +-- It has been modified to include both cells when the ray "touches a grid corner", +-- and with a different exit condition + +local function grid_traverse_initStep(cellSize, ct, t1, t2) + local v = t2 - t1 + if v > 0 then + return 1, cellSize / v, ((ct + v) * cellSize - t1) / v + elseif v < 0 then + return -1, -cellSize / v, ((ct + v - 1) * cellSize - t1) / v + else + return 0, math.huge, math.huge + end +end + +local function grid_traverse(cellSize, x1,y1,x2,y2, f) + local cx1,cy1 = grid_toCell(cellSize, x1,y1) + local cx2,cy2 = grid_toCell(cellSize, x2,y2) + local stepX, dx, tx = grid_traverse_initStep(cellSize, cx1, x1, x2) + local stepY, dy, ty = grid_traverse_initStep(cellSize, cy1, y1, y2) + local cx,cy = cx1,cy1 + + f(cx, cy) + + -- The default implementation had an infinite loop problem when + -- approaching the last cell in some occassions. We finish iterating + -- when we are *next* to the last cell + while abs(cx - cx2) + abs(cy - cy2) > 1 do + if tx < ty then + tx, cx = tx + dx, cx + stepX + f(cx, cy) + else + -- Addition: include both cells when going through corners + if tx == ty then f(cx + stepX, cy) end + ty, cy = ty + dy, cy + stepY + f(cx, cy) + end + end + + -- If we have not arrived to the last cell, use it + if cx ~= cx2 or cy ~= cy2 then f(cx2, cy2) end + +end + +local function grid_toCellRect(cellSize, x,y,w,h) + local cx,cy = grid_toCell(cellSize, x, y) + local cr,cb = ceil((x+w) / cellSize), ceil((y+h) / cellSize) + return cx, cy, cr - cx + 1, cb - cy + 1 +end + +------------------------------------------ +-- Responses +------------------------------------------ + +local touch = function(world, col, x,y,w,h, goalX, goalY, filter) + return col.touch.x, col.touch.y, {}, 0 +end + +local cross = function(world, col, x,y,w,h, goalX, goalY, filter) + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +local slide = function(world, col, x,y,w,h, goalX, goalY, filter) + goalX = goalX or x + goalY = goalY or y + + local tch, move = col.touch, col.move + local sx, sy = tch.x, tch.y + if move.x ~= 0 or move.y ~= 0 then + if col.normal.x == 0 then + sx = goalX + else + sy = goalY + end + end + + col.slide = {x = sx, y = sy} + + x,y = tch.x, tch.y + goalX, goalY = sx, sy + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +local bounce = function(world, col, x,y,w,h, goalX, goalY, filter) + goalX = goalX or x + goalY = goalY or y + + local tch, move = col.touch, col.move + local tx, ty = tch.x, tch.y + + local bx, by = tx, ty + + if move.x ~= 0 or move.y ~= 0 then + local bnx, bny = goalX - tx, goalY - ty + if col.normal.x == 0 then bny = -bny else bnx = -bnx end + bx, by = tx + bnx, ty + bny + end + + col.bounce = {x = bx, y = by} + x,y = tch.x, tch.y + goalX, goalY = bx, by + + local cols, len = world:project(col.item, x,y,w,h, goalX, goalY, filter) + return goalX, goalY, cols, len +end + +------------------------------------------ +-- World +------------------------------------------ + +local World = {} +local World_mt = {__index = World} + +-- Private functions and methods + +local function sortByWeight(a,b) return a.weight < b.weight end + +local function sortByTiAndDistance(a,b) + if a.ti == b.ti then + local ir, ar, br = a.itemRect, a.otherRect, b.otherRect + local ad = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, ar.x,ar.y,ar.w,ar.h) + local bd = rect_getSquareDistance(ir.x,ir.y,ir.w,ir.h, br.x,br.y,br.w,br.h) + return ad < bd + end + return a.ti < b.ti +end + +local function addItemToCell(self, item, cx, cy) + self.rows[cy] = self.rows[cy] or setmetatable({}, {__mode = 'v'}) + local row = self.rows[cy] + row[cx] = row[cx] or {itemCount = 0, x = cx, y = cy, items = setmetatable({}, {__mode = 'k'})} + local cell = row[cx] + self.nonEmptyCells[cell] = true + if not cell.items[item] then + cell.items[item] = true + cell.itemCount = cell.itemCount + 1 + end +end + +local function removeItemFromCell(self, item, cx, cy) + local row = self.rows[cy] + if not row or not row[cx] or not row[cx].items[item] then return false end + + local cell = row[cx] + cell.items[item] = nil + cell.itemCount = cell.itemCount - 1 + if cell.itemCount == 0 then + self.nonEmptyCells[cell] = nil + end + return true +end + +local function getDictItemsInCellRect(self, cl,ct,cw,ch) + local items_dict = {} + for cy=ct,ct+ch-1 do + local row = self.rows[cy] + if row then + for cx=cl,cl+cw-1 do + local cell = row[cx] + if cell and cell.itemCount > 0 then -- no cell.itemCount > 1 because tunneling + for item,_ in pairs(cell.items) do + items_dict[item] = true + end + end + end + end + end + + return items_dict +end + +local function getCellsTouchedBySegment(self, x1,y1,x2,y2) + + local cells, cellsLen, visited = {}, 0, {} + + grid_traverse(self.cellSize, x1,y1,x2,y2, function(cx, cy) + local row = self.rows[cy] + if not row then return end + local cell = row[cx] + if not cell or visited[cell] then return end + + visited[cell] = true + cellsLen = cellsLen + 1 + cells[cellsLen] = cell + end) + + return cells, cellsLen +end + +local function getInfoAboutItemsTouchedBySegment(self, x1,y1, x2,y2, filter) + local cells, len = getCellsTouchedBySegment(self, x1,y1,x2,y2) + local cell, rect, l,t,w,h, ti1,ti2, tii0,tii1 + local visited, itemInfo, itemInfoLen = {},{},0 + for i=1,len do + cell = cells[i] + for item in pairs(cell.items) do + if not visited[item] then + visited[item] = true + if (not filter or filter(item)) then + rect = self.rects[item] + l,t,w,h = rect.x,rect.y,rect.w,rect.h + + ti1,ti2 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, 0, 1) + if ti1 and ((0 < ti1 and ti1 < 1) or (0 < ti2 and ti2 < 1)) then + -- the sorting is according to the t of an infinite line, not the segment + tii0,tii1 = rect_getSegmentIntersectionIndices(l,t,w,h, x1,y1, x2,y2, -math.huge, math.huge) + itemInfoLen = itemInfoLen + 1 + itemInfo[itemInfoLen] = {item = item, ti1 = ti1, ti2 = ti2, weight = min(tii0,tii1)} + end + end + end + end + end + table.sort(itemInfo, sortByWeight) + return itemInfo, itemInfoLen +end + +local function getResponseByName(self, name) + local response = self.responses[name] + if not response then + error(('Unknown collision type: %s (%s)'):format(name, type(name))) + end + return response +end + + +-- Misc Public Methods + +function World:addResponse(name, response) + self.responses[name] = response +end + +function World:project(item, x,y,w,h, goalX, goalY, filter) + assertIsRect(x,y,w,h) + + goalX = goalX or x + goalY = goalY or y + filter = filter or defaultFilter + + local collisions, len = {}, 0 + + local visited = {} + if item ~= nil then visited[item] = true end + + -- This could probably be done with less cells using a polygon raster over the cells instead of a + -- bounding rect of the whole movement. Conditional to building a queryPolygon method + local tl, tt = min(goalX, x), min(goalY, y) + local tr, tb = max(goalX + w, x+w), max(goalY + h, y+h) + local tw, th = tr-tl, tb-tt + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, tl,tt,tw,th) + + local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) + + for other,_ in pairs(dictItemsInCellRect) do + if not visited[other] then + visited[other] = true + + local responseName = filter(item, other) + if responseName then + local ox,oy,ow,oh = self:getRect(other) + local col = rect_detectCollision(x,y,w,h, ox,oy,ow,oh, goalX, goalY) + + if col then + col.other = other + col.item = item + col.type = responseName + + len = len + 1 + collisions[len] = col + end + end + end + end + + table.sort(collisions, sortByTiAndDistance) + + return collisions, len +end + +function World:countCells() + local count = 0 + for _,row in pairs(self.rows) do + for _,_ in pairs(row) do + count = count + 1 + end + end + return count +end + +function World:hasItem(item) + return not not self.rects[item] +end + +function World:getItems() + local items, len = {}, 0 + for item,_ in pairs(self.rects) do + len = len + 1 + items[len] = item + end + return items, len +end + +function World:countItems() + local len = 0 + for _ in pairs(self.rects) do len = len + 1 end + return len +end + +function World:getRect(item) + local rect = self.rects[item] + if not rect then + error('Item ' .. tostring(item) .. ' must be added to the world before getting its rect. Use world:add(item, x,y,w,h) to add it first.') + end + return rect.x, rect.y, rect.w, rect.h +end + +function World:toWorld(cx, cy) + return grid_toWorld(self.cellSize, cx, cy) +end + +function World:toCell(x,y) + return grid_toCell(self.cellSize, x, y) +end + + +--- Query methods + +function World:queryRect(x,y,w,h, filter) + + assertIsRect(x,y,w,h) + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + local dictItemsInCellRect = getDictItemsInCellRect(self, cl,ct,cw,ch) + + local items, len = {}, 0 + + local rect + for item,_ in pairs(dictItemsInCellRect) do + rect = self.rects[item] + if (not filter or filter(item)) + and rect_isIntersecting(x,y,w,h, rect.x, rect.y, rect.w, rect.h) + then + len = len + 1 + items[len] = item + end + end + + return items, len +end + +function World:queryPoint(x,y, filter) + local cx,cy = self:toCell(x,y) + local dictItemsInCellRect = getDictItemsInCellRect(self, cx,cy,1,1) + + local items, len = {}, 0 + + local rect + for item,_ in pairs(dictItemsInCellRect) do + rect = self.rects[item] + if (not filter or filter(item)) + and rect_containsPoint(rect.x, rect.y, rect.w, rect.h, x, y) + then + len = len + 1 + items[len] = item + end + end + + return items, len +end + +function World:querySegment(x1, y1, x2, y2, filter) + local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) + local items = {} + for i=1, len do + items[i] = itemInfo[i].item + end + return items, len +end + +function World:querySegmentWithCoords(x1, y1, x2, y2, filter) + local itemInfo, len = getInfoAboutItemsTouchedBySegment(self, x1, y1, x2, y2, filter) + local dx, dy = x2-x1, y2-y1 + local info, ti1, ti2 + for i=1, len do + info = itemInfo[i] + ti1 = info.ti1 + ti2 = info.ti2 + + info.weight = nil + info.x1 = x1 + dx * ti1 + info.y1 = y1 + dy * ti1 + info.x2 = x1 + dx * ti2 + info.y2 = y1 + dy * ti2 + end + return itemInfo, len +end + + +--- Main methods + +function World:add(item, x,y,w,h) + local rect = self.rects[item] + if rect then + error('Item ' .. tostring(item) .. ' added to the world twice.') + end + assertIsRect(x,y,w,h) + + self.rects[item] = {x=x,y=y,w=w,h=h} + + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + for cy = ct, ct+ch-1 do + for cx = cl, cl+cw-1 do + addItemToCell(self, item, cx, cy) + end + end + + return item +end + +function World:remove(item) + local x,y,w,h = self:getRect(item) + + self.rects[item] = nil + local cl,ct,cw,ch = grid_toCellRect(self.cellSize, x,y,w,h) + for cy = ct, ct+ch-1 do + for cx = cl, cl+cw-1 do + removeItemFromCell(self, item, cx, cy) + end + end +end + +function World:update(item, x2,y2,w2,h2) + local x1,y1,w1,h1 = self:getRect(item) + w2,h2 = w2 or w1, h2 or h1 + assertIsRect(x2,y2,w2,h2) + + if x1 ~= x2 or y1 ~= y2 or w1 ~= w2 or h1 ~= h2 then + + local cellSize = self.cellSize + local cl1,ct1,cw1,ch1 = grid_toCellRect(cellSize, x1,y1,w1,h1) + local cl2,ct2,cw2,ch2 = grid_toCellRect(cellSize, x2,y2,w2,h2) + + if cl1 ~= cl2 or ct1 ~= ct2 or cw1 ~= cw2 or ch1 ~= ch2 then + + local cr1, cb1 = cl1+cw1-1, ct1+ch1-1 + local cr2, cb2 = cl2+cw2-1, ct2+ch2-1 + local cyOut + + for cy = ct1, cb1 do + cyOut = cy < ct2 or cy > cb2 + for cx = cl1, cr1 do + if cyOut or cx < cl2 or cx > cr2 then + removeItemFromCell(self, item, cx, cy) + end + end + end + + for cy = ct2, cb2 do + cyOut = cy < ct1 or cy > cb1 + for cx = cl2, cr2 do + if cyOut or cx < cl1 or cx > cr1 then + addItemToCell(self, item, cx, cy) + end + end + end + + end + + local rect = self.rects[item] + rect.x, rect.y, rect.w, rect.h = x2,y2,w2,h2 + + end +end + +function World:move(item, goalX, goalY, filter) + local actualX, actualY, cols, len = self:check(item, goalX, goalY, filter) + + self:update(item, actualX, actualY) + + return actualX, actualY, cols, len +end + +function World:check(item, goalX, goalY, filter) + filter = filter or defaultFilter + + local visited = {[item] = true} + local visitedFilter = function(itm, other) + if visited[other] then return false end + return filter(itm, other) + end + + local cols, len = {}, 0 + + local x,y,w,h = self:getRect(item) + + local projected_cols, projected_len = self:project(item, x,y,w,h, goalX,goalY, visitedFilter) + + while projected_len > 0 do + local col = projected_cols[1] + len = len + 1 + cols[len] = col + + visited[col.other] = true + + local response = getResponseByName(self, col.type) + + goalX, goalY, projected_cols, projected_len = response( + self, + col, + x, y, w, h, + goalX, goalY, + visitedFilter + ) + end + + return goalX, goalY, cols, len +end + + +-- Public library functions + +bump.newWorld = function(cellSize) + cellSize = cellSize or 64 + assertIsPositiveNumber(cellSize, 'cellSize') + local world = setmetatable({ + cellSize = cellSize, + rects = {}, + rows = {}, + nonEmptyCells = {}, + responses = {} + }, World_mt) + + world:addResponse('touch', touch) + world:addResponse('cross', cross) + world:addResponse('slide', slide) + world:addResponse('bounce', bounce) + + return world +end + +bump.rect = { + getNearestCorner = rect_getNearestCorner, + getSegmentIntersectionIndices = rect_getSegmentIntersectionIndices, + getDiff = rect_getDiff, + containsPoint = rect_containsPoint, + isIntersecting = rect_isIntersecting, + getSquareDistance = rect_getSquareDistance, + detectCollision = rect_detectCollision +} + +bump.responses = { + touch = touch, + cross = cross, + slide = slide, + bounce = bounce +} + +return bump diff --git a/imperium-porcorum.love/libs/classic.lua b/imperium-porcorum.love/libs/classic.lua new file mode 100644 index 0000000..cbd6f81 --- /dev/null +++ b/imperium-porcorum.love/libs/classic.lua @@ -0,0 +1,68 @@ +-- +-- classic +-- +-- Copyright (c) 2014, rxi +-- +-- This module is free software; you can redistribute it and/or modify it under +-- the terms of the MIT license. See LICENSE for details. +-- + + +local Object = {} +Object.__index = Object + + +function Object:new() +end + + +function Object:extend() + local cls = {} + for k, v in pairs(self) do + if k:find("__") == 1 then + cls[k] = v + end + end + cls.__index = cls + cls.super = self + setmetatable(cls, self) + return cls +end + + +function Object:implement(...) + for _, cls in pairs({...}) do + for k, v in pairs(cls) do + if self[k] == nil and type(v) == "function" then + self[k] = v + end + end + end +end + + +function Object:is(T) + local mt = getmetatable(self) + while mt do + if mt == T then + return true + end + mt = getmetatable(mt) + end + return false +end + + +function Object:__tostring() + return "Object" +end + + +function Object:__call(...) + local obj = setmetatable({}, self) + obj:new(...) + return obj +end + + +return Object diff --git a/imperium-porcorum.love/libs/cscreen.lua b/imperium-porcorum.love/libs/cscreen.lua new file mode 100644 index 0000000..579ea0d --- /dev/null +++ b/imperium-porcorum.love/libs/cscreen.lua @@ -0,0 +1,99 @@ +--[[ +CScreen v1.3 by CodeNMore +A simple way to make resolution-independent Love2D games +Tested for LOVE 0.10.1 +See: https://github.com/CodeNMore/CScreen +Zlib License: +Copyright (c) 2016 CodeNMore +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from +the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be appreciated +but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +--]] + +local CScreen = {} +local rx, ry, ctr = 800, 600, true +local rxv, ryv, fsv, fsvr = 800, 600, 1.0, 1.0 +local tx, ty, rwf, rhf = 0, 0, 800, 600 +local cr, cg, cb, ca = 0, 0, 0, 255 + +-- Initializes CScreen with the initial size values +function CScreen.init(tw, th, cntr) + rx = tw or 800 + ry = th or 600 + ctr = cntr or false + CScreen.update(love.graphics.getWidth(), love.graphics.getHeight()) +end + +-- Draws letterbox borders +function CScreen.cease() + if ctr then + local pr, pg, pb, pa = love.graphics.getColor() + love.graphics.setColor(cr, cg, cb, ca) + love.graphics.scale(fsvr, fsvr) + + if tx ~= 0 then + love.graphics.rectangle("fill", -tx, 0, tx, rhf) + love.graphics.rectangle("fill", rxv, 0, tx, rhf) + elseif ty ~= 0 then + love.graphics.rectangle("fill", 0, -ty, rwf, ty) + love.graphics.rectangle("fill", 0, ryv, rwf, ty) + end + + love.graphics.setColor(pr, pg, pb, pa) + end +end + +-- Scales and centers all graphics properly +function CScreen.apply() + if ctr then + love.graphics.translate(tx, ty) + end + love.graphics.scale(fsv, fsv) +end + +-- Updates CScreen when the window size changes +function CScreen.update(w, h) + local sx = w / rx + local sy = h / ry + fsv = math.min(sx, sy) + fsvr = 1 / fsv + -- Centering + if ctr and fsv == sx then -- Vertically + tx = 0 + ty = (h / 2) - (ry * fsv / 2) + elseif ctr and fsv == sy then -- Horizontally + ty = 0 + tx = (w / 2) - (rx * fsv / 2) + end + -- Variable sets + rwf = w + rhf = h + rxv = rx * fsv + ryv = ry * fsv +end + +-- Convert from window coordinates to target coordinates +function CScreen.project(x, y) + return math.floor((x - tx) / fsv), math.floor((y - ty) / fsv) +end + +-- Change letterbox color +function CScreen.setColor(r, g, b, a) + cr = r + cg = g + cb = b + ca = a +end + +-- Return the table for use +return CScreen diff --git a/imperium-porcorum.love/libs/hump/camera.lua b/imperium-porcorum.love/libs/hump/camera.lua new file mode 100644 index 0000000..cb86a79 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/camera.lua @@ -0,0 +1,216 @@ +--[[ +Copyright (c) 2010-2015 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local _PATH = (...):match('^(.*[%./])[^%.%/]+$') or '' +local cos, sin = math.cos, math.sin + +local camera = {} +camera.__index = camera + +-- Movement interpolators (for camera locking/windowing) +camera.smooth = {} + +function camera.smooth.none() + return function(dx,dy) return dx,dy end +end + +function camera.smooth.linear(speed) + assert(type(speed) == "number", "Invalid parameter: speed = "..tostring(speed)) + return function(dx,dy, s) + -- normalize direction + local d = math.sqrt(dx*dx+dy*dy) + local dts = math.min((s or speed) * love.timer.getDelta(), d) -- prevent overshooting the goal + if d > 0 then + dx,dy = dx/d, dy/d + end + + return dx*dts, dy*dts + end +end + +function camera.smooth.damped(stiffness) + assert(type(stiffness) == "number", "Invalid parameter: stiffness = "..tostring(stiffness)) + return function(dx,dy, s) + local dts = love.timer.getDelta() * (s or stiffness) + return dx*dts, dy*dts + end +end + + +local function new(x,y, zoom, rot, smoother) + x,y = x or love.graphics.getWidth()/2, y or love.graphics.getHeight()/2 + zoom = zoom or 1 + rot = rot or 0 + smoother = smoother or camera.smooth.none() -- for locking, see below + return setmetatable({x = x, y = y, scale = zoom, rot = rot, smoother = smoother}, camera) +end + +function camera:lookAt(x,y) + self.x, self.y = x, y + return self +end + +function camera:move(dx,dy) + self.x, self.y = self.x + dx, self.y + dy + return self +end + +function camera:position() + return self.x, self.y +end + +function camera:rotate(phi) + self.rot = self.rot + phi + return self +end + +function camera:rotateTo(phi) + self.rot = phi + return self +end + +function camera:zoom(mul) + self.scale = self.scale * mul + return self +end + +function camera:zoomTo(zoom) + self.scale = zoom + return self +end + +function camera:attach(x,y,w,h, noclip) + x,y = x or 0, y or 0 + w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() + + self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor() + if not noclip then + love.graphics.setScissor(x,y,w,h) + end + + local cx,cy = x+w/2, y+h/2 + love.graphics.push() + love.graphics.translate(cx, cy) + love.graphics.scale(self.scale) + love.graphics.rotate(self.rot) + love.graphics.translate(-self.x, -self.y) +end + +function camera:detach() + love.graphics.pop() + love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh) +end + +function camera:draw(...) + local x,y,w,h,noclip,func + local nargs = select("#", ...) + if nargs == 1 then + func = ... + elseif nargs == 5 then + x,y,w,h,func = ... + elseif nargs == 6 then + x,y,w,h,noclip,func = ... + else + error("Invalid arguments to camera:draw()") + end + + self:attach(x,y,w,h,noclip) + func() + self:detach() +end + +-- world coordinates to camera coordinates +function camera:cameraCoords(x,y, ox,oy,w,h) + ox, oy = ox or 0, oy or 0 + w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() + + -- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center + local c,s = cos(self.rot), sin(self.rot) + x,y = x - self.x, y - self.y + x,y = c*x - s*y, s*x + c*y + return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy +end + +-- camera coordinates to world coordinates +function camera:worldCoords(x,y, ox,oy,w,h) + ox, oy = ox or 0, oy or 0 + w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() + + -- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y) + local c,s = cos(-self.rot), sin(-self.rot) + x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale + x,y = c*x - s*y, s*x + c*y + return x+self.x, y+self.y +end + +function camera:mousePosition(ox,oy,w,h) + local mx,my = love.mouse.getPosition() + return self:worldCoords(mx,my, ox,oy,w,h) +end + +-- camera scrolling utilities +function camera:lockX(x, smoother, ...) + local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...) + self.x = self.x + dx + return self +end + +function camera:lockY(y, smoother, ...) + local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...) + self.y = self.y + dy + return self +end + +function camera:lockPosition(x,y, smoother, ...) + return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...)) +end + +function camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...) + -- figure out displacement in camera coordinates + x,y = self:cameraCoords(x,y) + local dx, dy = 0,0 + if x < x_min then + dx = x - x_min + elseif x > x_max then + dx = x - x_max + end + if y < y_min then + dy = y - y_min + elseif y > y_max then + dy = y - y_max + end + + -- transform displacement to movement in world coordinates + local c,s = cos(-self.rot), sin(-self.rot) + dx,dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale + + -- move + self:move((smoother or self.smoother)(dx,dy,...)) +end + +-- the module +return setmetatable({new = new, smooth = camera.smooth}, + {__call = function(_, ...) return new(...) end}) diff --git a/imperium-porcorum.love/libs/hump/class.lua b/imperium-porcorum.love/libs/hump/class.lua new file mode 100644 index 0000000..7d62707 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/class.lua @@ -0,0 +1,98 @@ +--[[ +Copyright (c) 2010-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local function include_helper(to, from, seen) + if from == nil then + return to + elseif type(from) ~= 'table' then + return from + elseif seen[from] then + return seen[from] + end + + seen[from] = to + for k,v in pairs(from) do + k = include_helper({}, k, seen) -- keys might also be tables + if to[k] == nil then + to[k] = include_helper({}, v, seen) + end + end + return to +end + +-- deeply copies `other' into `class'. keys in `other' that are already +-- defined in `class' are omitted +local function include(class, other) + return include_helper(class, other, {}) +end + +-- returns a deep copy of `other' +local function clone(other) + return setmetatable(include({}, other), getmetatable(other)) +end + +local function new(class) + -- mixins + class = class or {} -- class can be nil + local inc = class.__includes or {} + if getmetatable(inc) then inc = {inc} end + + for _, other in ipairs(inc) do + if type(other) == "string" then + other = _G[other] + end + include(class, other) + end + + -- class implementation + class.__index = class + class.init = class.init or class[1] or function() end + class.include = class.include or include + class.clone = class.clone or clone + + -- constructor call + return setmetatable(class, {__call = function(c, ...) + local o = setmetatable({}, c) + o:init(...) + return o + end}) +end + +-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons). +if class_commons ~= false and not common then + common = {} + function common.class(name, prototype, parent) + return new{__includes = {prototype, parent}} + end + function common.instance(class, ...) + return class(...) + end +end + + +-- the module +return setmetatable({new = new, include = include, clone = clone}, + {__call = function(_,...) return new(...) end}) diff --git a/imperium-porcorum.love/libs/hump/gamestate.lua b/imperium-porcorum.love/libs/hump/gamestate.lua new file mode 100644 index 0000000..4a42205 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/gamestate.lua @@ -0,0 +1,108 @@ +--[[ +Copyright (c) 2010-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local function __NULL__() end + + -- default gamestate produces error on every callback +local state_init = setmetatable({leave = __NULL__}, + {__index = function() error("Gamestate not initialized. Use Gamestate.switch()") end}) +local stack = {state_init} +local initialized_states = setmetatable({}, {__mode = "k"}) +local state_is_dirty = true + +local GS = {} +function GS.new(t) return t or {} end -- constructor - deprecated! + +local function change_state(stack_offset, to, ...) + local pre = stack[#stack] + + -- initialize only on first call + ;(initialized_states[to] or to.init or __NULL__)(to) + initialized_states[to] = __NULL__ + + stack[#stack+stack_offset] = to + state_is_dirty = true + return (to.enter or __NULL__)(to, pre, ...) +end + +function GS.switch(to, ...) + assert(to, "Missing argument: Gamestate to switch to") + assert(to ~= GS, "Can't call switch with colon operator") + ;(stack[#stack].leave or __NULL__)(stack[#stack]) + return change_state(0, to, ...) +end + +function GS.push(to, ...) + assert(to, "Missing argument: Gamestate to switch to") + assert(to ~= GS, "Can't call push with colon operator") + return change_state(1, to, ...) +end + +function GS.pop(...) + assert(#stack > 1, "No more states to pop!") + local pre, to = stack[#stack], stack[#stack-1] + stack[#stack] = nil + ;(pre.leave or __NULL__)(pre) + state_is_dirty = true + return (to.resume or __NULL__)(to, pre, ...) +end + +function GS.current() + return stack[#stack] +end + +-- fetch event callbacks from love.handlers +local all_callbacks = { 'draw', 'errhand', 'update' } +for k in pairs(love.handlers) do + all_callbacks[#all_callbacks+1] = k +end + +function GS.registerEvents(callbacks) + local registry = {} + callbacks = callbacks or all_callbacks + for _, f in ipairs(callbacks) do + registry[f] = love[f] or __NULL__ + love[f] = function(...) + registry[f](...) + return GS[f](...) + end + end +end + +-- forward any undefined functions +setmetatable(GS, {__index = function(_, func) + -- call function only if at least one 'update' was called beforehand + -- (see issue #46) + if not state_is_dirty or func == 'update' then + state_is_dirty = false + return function(...) + return (stack[#stack][func] or __NULL__)(stack[#stack], ...) + end + end + return __NULL__ +end}) + +return GS diff --git a/imperium-porcorum.love/libs/hump/signal.lua b/imperium-porcorum.love/libs/hump/signal.lua new file mode 100644 index 0000000..e204ca0 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/signal.lua @@ -0,0 +1,102 @@ +--[[ +Copyright (c) 2012-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local Registry = {} +Registry.__index = function(self, key) + return Registry[key] or (function() + local t = {} + rawset(self, key, t) + return t + end)() +end + +function Registry:register(s, f) + self[s][f] = f + return f +end + +function Registry:emit(s, ...) + for f in pairs(self[s]) do + f(...) + end +end + +function Registry:remove(s, ...) + local f = {...} + for i = 1,select('#', ...) do + self[s][f[i]] = nil + end +end + +function Registry:clear(...) + local s = {...} + for i = 1,select('#', ...) do + self[s[i]] = {} + end +end + +function Registry:emitPattern(p, ...) + for s in pairs(self) do + if s:match(p) then self:emit(s, ...) end + end +end + +function Registry:registerPattern(p, f) + for s in pairs(self) do + if s:match(p) then self:register(s, f) end + end + return f +end + +function Registry:removePattern(p, ...) + for s in pairs(self) do + if s:match(p) then self:remove(s, ...) end + end +end + +function Registry:clearPattern(p) + for s in pairs(self) do + if s:match(p) then self[s] = {} end + end +end + +-- instancing +function Registry.new() + return setmetatable({}, Registry) +end + +-- default instance +local default = Registry.new() + +-- module forwards calls to default instance +local module = {} +for k in pairs(Registry) do + if k ~= "__index" then + module[k] = function(...) return default[k](default, ...) end + end +end + +return setmetatable(module, {__call = Registry.new}) diff --git a/imperium-porcorum.love/libs/hump/timer.lua b/imperium-porcorum.love/libs/hump/timer.lua new file mode 100644 index 0000000..5b4e515 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/timer.lua @@ -0,0 +1,210 @@ +--[[ +Copyright (c) 2010-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local Timer = {} +Timer.__index = Timer + +local function _nothing_() end + +function Timer:update(dt) + local to_remove = {} + + for handle in pairs(self.functions) do + -- handle: { + -- time = , + -- after = , + -- during = , + -- limit = , + -- count = , + -- } + + handle.time = handle.time + dt + handle.during(dt, math.max(handle.limit - handle.time, 0)) + + while handle.time >= handle.limit and handle.count > 0 do + if handle.after(handle.after) == false then + handle.count = 0 + break + end + handle.time = handle.time - handle.limit + handle.count = handle.count - 1 + end + + if handle.count == 0 then + table.insert(to_remove, handle) + end + end + + for i = 1, #to_remove do + self.functions[to_remove[i]] = nil + end +end + +function Timer:during(delay, during, after) + local handle = { time = 0, during = during, after = after or _nothing_, limit = delay, count = 1 } + self.functions[handle] = true + return handle +end + +function Timer:after(delay, func) + return self:during(delay, _nothing_, func) +end + +function Timer:every(delay, after, count) + local count = count or math.huge -- exploit below: math.huge - 1 = math.huge + local handle = { time = 0, during = _nothing_, after = after, limit = delay, count = count } + self.functions[handle] = true + return handle +end + +function Timer:cancel(handle) + self.functions[handle] = nil +end + +function Timer:clear() + self.functions = {} +end + +function Timer:script(f) + local co = coroutine.wrap(f) + co(function(t) + self:after(t, co) + coroutine.yield() + end) +end + +Timer.tween = setmetatable({ + -- helper functions + out = function(f) -- 'rotates' a function + return function(s, ...) return 1 - f(1-s, ...) end + end, + chain = function(f1, f2) -- concatenates two functions + return function(s, ...) return (s < .5 and f1(2*s, ...) or 1 + f2(2*s-1, ...)) * .5 end + end, + + -- useful tweening functions + linear = function(s) return s end, + quad = function(s) return s*s end, + cubic = function(s) return s*s*s end, + quart = function(s) return s*s*s*s end, + quint = function(s) return s*s*s*s*s end, + sine = function(s) return 1-math.cos(s*math.pi/2) end, + expo = function(s) return 2^(10*(s-1)) end, + circ = function(s) return 1 - math.sqrt(1-s*s) end, + + back = function(s,bounciness) + bounciness = bounciness or 1.70158 + return s*s*((bounciness+1)*s - bounciness) + end, + + bounce = function(s) -- magic numbers ahead + local a,b = 7.5625, 1/2.75 + return math.min(a*s^2, a*(s-1.5*b)^2 + .75, a*(s-2.25*b)^2 + .9375, a*(s-2.625*b)^2 + .984375) + end, + + elastic = function(s, amp, period) + amp, period = amp and math.max(1, amp) or 1, period or .3 + return (-amp * math.sin(2*math.pi/period * (s-1) - math.asin(1/amp))) * 2^(10*(s-1)) + end, +}, { + +-- register new tween +__call = function(tween, self, len, subject, target, method, after, ...) + -- recursively collects fields that are defined in both subject and target into a flat list + local function tween_collect_payload(subject, target, out) + for k,v in pairs(target) do + local ref = subject[k] + assert(type(v) == type(ref), 'Type mismatch in field "'..k..'".') + if type(v) == 'table' then + tween_collect_payload(ref, v, out) + else + local ok, delta = pcall(function() return (v-ref)*1 end) + assert(ok, 'Field "'..k..'" does not support arithmetic operations') + out[#out+1] = {subject, k, delta} + end + end + return out + end + + method = tween[method or 'linear'] -- see __index + local payload, t, args = tween_collect_payload(subject, target, {}), 0, {...} + + local last_s = 0 + return self:during(len, function(dt) + t = t + dt + local s = method(math.min(1, t/len), unpack(args)) + local ds = s - last_s + last_s = s + for _, info in ipairs(payload) do + local ref, key, delta = unpack(info) + ref[key] = ref[key] + delta * ds + end + end, after) +end, + +-- fetches function and generated compositions for method `key` +__index = function(tweens, key) + if type(key) == 'function' then return key end + + assert(type(key) == 'string', 'Method must be function or string.') + if rawget(tweens, key) then return rawget(tweens, key) end + + local function construct(pattern, f) + local method = rawget(tweens, key:match(pattern)) + if method then return f(method) end + return nil + end + + local out, chain = rawget(tweens,'out'), rawget(tweens,'chain') + return construct('^in%-([^-]+)$', function(...) return ... end) + or construct('^out%-([^-]+)$', out) + or construct('^in%-out%-([^-]+)$', function(f) return chain(f, out(f)) end) + or construct('^out%-in%-([^-]+)$', function(f) return chain(out(f), f) end) + or error('Unknown interpolation method: ' .. key) +end}) + +-- Timer instancing +function Timer.new() + return setmetatable({functions = {}, tween = Timer.tween}, Timer) +end + +-- default instance +local default = Timer.new() + +-- module forwards calls to default instance +local module = {} +for k in pairs(Timer) do + if k ~= "__index" then + module[k] = function(...) return default[k](default, ...) end + end +end +module.tween = setmetatable({}, { + __index = Timer.tween, + __newindex = function(k,v) Timer.tween[k] = v end, + __call = function(t, ...) return default:tween(...) end, +}) + +return setmetatable(module, {__call = Timer.new}) diff --git a/imperium-porcorum.love/libs/hump/vector-light.lua b/imperium-porcorum.love/libs/hump/vector-light.lua new file mode 100644 index 0000000..fc47a13 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/vector-light.lua @@ -0,0 +1,172 @@ +--[[ +Copyright (c) 2012-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2 + +local function str(x,y) + return "("..tonumber(x)..","..tonumber(y)..")" +end + +local function mul(s, x,y) + return s*x, s*y +end + +local function div(s, x,y) + return x/s, y/s +end + +local function add(x1,y1, x2,y2) + return x1+x2, y1+y2 +end + +local function sub(x1,y1, x2,y2) + return x1-x2, y1-y2 +end + +local function permul(x1,y1, x2,y2) + return x1*x2, y1*y2 +end + +local function dot(x1,y1, x2,y2) + return x1*x2 + y1*y2 +end + +local function det(x1,y1, x2,y2) + return x1*y2 - y1*x2 +end + +local function eq(x1,y1, x2,y2) + return x1 == x2 and y1 == y2 +end + +local function lt(x1,y1, x2,y2) + return x1 < x2 or (x1 == x2 and y1 < y2) +end + +local function le(x1,y1, x2,y2) + return x1 <= x2 and y1 <= y2 +end + +local function len2(x,y) + return x*x + y*y +end + +local function len(x,y) + return sqrt(x*x + y*y) +end + +local function fromPolar(angle, radius) + return cos(angle)*radius, sin(angle)*radius +end + +local function toPolar(x, y) + return atan2(y,x), len(x,y) +end + +local function dist2(x1,y1, x2,y2) + return len2(x1-x2, y1-y2) +end + +local function dist(x1,y1, x2,y2) + return len(x1-x2, y1-y2) +end + +local function normalize(x,y) + local l = len(x,y) + if l > 0 then + return x/l, y/l + end + return x,y +end + +local function rotate(phi, x,y) + local c, s = cos(phi), sin(phi) + return c*x - s*y, s*x + c*y +end + +local function perpendicular(x,y) + return -y, x +end + +local function project(x,y, u,v) + local s = (x*u + y*v) / (u*u + v*v) + return s*u, s*v +end + +local function mirror(x,y, u,v) + local s = 2 * (x*u + y*v) / (u*u + v*v) + return s*u - x, s*v - y +end + +-- ref.: http://blog.signalsondisplay.com/?p=336 +local function trim(maxLen, x, y) + local s = maxLen * maxLen / len2(x, y) + s = s > 1 and 1 or math.sqrt(s) + return x * s, y * s +end + +local function angleTo(x,y, u,v) + if u and v then + return atan2(y, x) - atan2(v, u) + end + return atan2(y, x) +end + +-- the module +return { + str = str, + + fromPolar = fromPolar, + toPolar = toPolar, + + -- arithmetic + mul = mul, + div = div, + add = add, + sub = sub, + permul = permul, + dot = dot, + det = det, + cross = det, + + -- relation + eq = eq, + lt = lt, + le = le, + + -- misc operations + len2 = len2, + len = len, + dist2 = dist2, + dist = dist, + normalize = normalize, + rotate = rotate, + perpendicular = perpendicular, + project = project, + mirror = mirror, + trim = trim, + angleTo = angleTo, +} diff --git a/imperium-porcorum.love/libs/hump/vector.lua b/imperium-porcorum.love/libs/hump/vector.lua new file mode 100644 index 0000000..14775f3 --- /dev/null +++ b/imperium-porcorum.love/libs/hump/vector.lua @@ -0,0 +1,199 @@ +--[[ +Copyright (c) 2010-2013 Matthias Richter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +Except as contained in this notice, the name(s) of the above copyright holders +shall not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +]]-- + +local assert = assert +local sqrt, cos, sin, atan2 = math.sqrt, math.cos, math.sin, math.atan2 + +local vector = {} +vector.__index = vector + +local function new(x,y) + return setmetatable({x = x or 0, y = y or 0}, vector) +end +local zero = new(0,0) + +local function fromPolar(angle, radius) + return new(cos(angle) * radius, sin(angle) * radius) +end + +local function isvector(v) + return type(v) == 'table' and type(v.x) == 'number' and type(v.y) == 'number' +end + +function vector:clone() + return new(self.x, self.y) +end + +function vector:unpack() + return self.x, self.y +end + +function vector:__tostring() + return "("..tonumber(self.x)..","..tonumber(self.y)..")" +end + +function vector.__unm(a) + return new(-a.x, -a.y) +end + +function vector.__add(a,b) + assert(isvector(a) and isvector(b), "Add: wrong argument types ( expected)") + return new(a.x+b.x, a.y+b.y) +end + +function vector.__sub(a,b) + assert(isvector(a) and isvector(b), "Sub: wrong argument types ( expected)") + return new(a.x-b.x, a.y-b.y) +end + +function vector.__mul(a,b) + if type(a) == "number" then + return new(a*b.x, a*b.y) + elseif type(b) == "number" then + return new(b*a.x, b*a.y) + else + assert(isvector(a) and isvector(b), "Mul: wrong argument types ( or expected)") + return a.x*b.x + a.y*b.y + end +end + +function vector.__div(a,b) + assert(isvector(a) and type(b) == "number", "wrong argument types (expected / )") + return new(a.x / b, a.y / b) +end + +function vector.__eq(a,b) + return a.x == b.x and a.y == b.y +end + +function vector.__lt(a,b) + return a.x < b.x or (a.x == b.x and a.y < b.y) +end + +function vector.__le(a,b) + return a.x <= b.x and a.y <= b.y +end + +function vector.permul(a,b) + assert(isvector(a) and isvector(b), "permul: wrong argument types ( expected)") + return new(a.x*b.x, a.y*b.y) +end + +function vector:toPolar() + return new(atan2(self.x, self.y), self:len()) +end + +function vector:len2() + return self.x * self.x + self.y * self.y +end + +function vector:len() + return sqrt(self.x * self.x + self.y * self.y) +end + +function vector.dist(a, b) + assert(isvector(a) and isvector(b), "dist: wrong argument types ( expected)") + local dx = a.x - b.x + local dy = a.y - b.y + return sqrt(dx * dx + dy * dy) +end + +function vector.dist2(a, b) + assert(isvector(a) and isvector(b), "dist: wrong argument types ( expected)") + local dx = a.x - b.x + local dy = a.y - b.y + return (dx * dx + dy * dy) +end + +function vector:normalizeInplace() + local l = self:len() + if l > 0 then + self.x, self.y = self.x / l, self.y / l + end + return self +end + +function vector:normalized() + return self:clone():normalizeInplace() +end + +function vector:rotateInplace(phi) + local c, s = cos(phi), sin(phi) + self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y + return self +end + +function vector:rotated(phi) + local c, s = cos(phi), sin(phi) + return new(c * self.x - s * self.y, s * self.x + c * self.y) +end + +function vector:perpendicular() + return new(-self.y, self.x) +end + +function vector:projectOn(v) + assert(isvector(v), "invalid argument: cannot project vector on " .. type(v)) + -- (self * v) * v / v:len2() + local s = (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y) + return new(s * v.x, s * v.y) +end + +function vector:mirrorOn(v) + assert(isvector(v), "invalid argument: cannot mirror vector on " .. type(v)) + -- 2 * self:projectOn(v) - self + local s = 2 * (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y) + return new(s * v.x - self.x, s * v.y - self.y) +end + +function vector:cross(v) + assert(isvector(v), "cross: wrong argument types ( expected)") + return self.x * v.y - self.y * v.x +end + +-- ref.: http://blog.signalsondisplay.com/?p=336 +function vector:trimInplace(maxLen) + local s = maxLen * maxLen / self:len2() + s = (s > 1 and 1) or math.sqrt(s) + self.x, self.y = self.x * s, self.y * s + return self +end + +function vector:angleTo(other) + if other then + return atan2(self.y, self.x) - atan2(other.y, other.x) + end + return atan2(self.y, self.x) +end + +function vector:trimmed(maxLen) + return self:clone():trimInplace(maxLen) +end + + +-- the module +return setmetatable({new = new, fromPolar = fromPolar, isvector = isvector, zero = zero}, + {__call = function(_, ...) return new(...) end}) diff --git a/imperium-porcorum.love/libs/lovebird.lua b/imperium-porcorum.love/libs/lovebird.lua new file mode 100644 index 0000000..8b296eb --- /dev/null +++ b/imperium-porcorum.love/libs/lovebird.lua @@ -0,0 +1,737 @@ +-- +-- lovebird +-- +-- Copyright (c) 2017 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- + +local socket = require "socket" + +local lovebird = { _version = "0.4.3" } + +lovebird.loadstring = loadstring or load +lovebird.inited = false +lovebird.host = "*" +lovebird.buffer = "" +lovebird.lines = {} +lovebird.connections = {} +lovebird.pages = {} + +lovebird.wrapprint = true +lovebird.timestamp = true +lovebird.allowhtml = false +lovebird.echoinput = true +lovebird.port = 8000 +lovebird.whitelist = { "127.0.0.1" } +lovebird.maxlines = 200 +lovebird.updateinterval = .5 + + +lovebird.pages["index"] = [[ + + + + + + + + lovebird + + + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + +]] + + +lovebird.pages["buffer"] = [[ ]] + + +lovebird.pages["env.json"] = [[ + +{ + "valid": true, + "path": "", + "vars": [ + + { + "key": "", + "value": , + "type": "", + }, + + ] +} +]] + + + +function lovebird.init() + -- Init server + lovebird.server = assert(socket.bind(lovebird.host, lovebird.port)) + lovebird.addr, lovebird.port = lovebird.server:getsockname() + lovebird.server:settimeout(0) + -- Wrap print + lovebird.origprint = print + if lovebird.wrapprint then + local oldprint = print + print = function(...) + oldprint(...) + lovebird.print(...) + end + end + -- Compile page templates + for k, page in pairs(lovebird.pages) do + lovebird.pages[k] = lovebird.template(page, "lovebird, req", + "pages." .. k) + end + lovebird.inited = true +end + + +function lovebird.template(str, params, chunkname) + params = params and ("," .. params) or "" + local f = function(x) return string.format(" echo(%q)", x) end + str = ("?>"..str.."(.-)<%?lua", f) + str = "local echo " .. params .. " = ..." .. str + local fn = assert(lovebird.loadstring(str, chunkname)) + return function(...) + local output = {} + local echo = function(str) table.insert(output, str) end + fn(echo, ...) + return table.concat(lovebird.map(output, tostring)) + end +end + + +function lovebird.map(t, fn) + local res = {} + for k, v in pairs(t) do res[k] = fn(v) end + return res +end + + +function lovebird.trace(...) + local str = "[lovebird] " .. table.concat(lovebird.map({...}, tostring), " ") + print(str) + if not lovebird.wrapprint then lovebird.print(str) end +end + + +function lovebird.unescape(str) + local f = function(x) return string.char(tonumber("0x"..x)) end + return (str:gsub("%+", " "):gsub("%%(..)", f)) +end + + +function lovebird.parseurl(url) + local res = {} + res.path, res.search = url:match("/([^%?]*)%??(.*)") + res.query = {} + for k, v in res.search:gmatch("([^&^?]-)=([^&^#]*)") do + res.query[k] = lovebird.unescape(v) + end + return res +end + + +local htmlescapemap = { + ["<"] = "<", + ["&"] = "&", + ['"'] = """, + ["'"] = "'", +} + +function lovebird.htmlescape(str) + return ( str:gsub("[<&\"']", htmlescapemap) ) +end + + +function lovebird.truncate(str, len) + if #str <= len then + return str + end + return str:sub(1, len - 3) .. "..." +end + + +function lovebird.compare(a, b) + local na, nb = tonumber(a), tonumber(b) + if na then + if nb then return na < nb end + return false + elseif nb then + return true + end + return tostring(a) < tostring(b) +end + + +function lovebird.checkwhitelist(addr) + if lovebird.whitelist == nil then return true end + for _, a in pairs(lovebird.whitelist) do + local ptn = "^" .. a:gsub("%.", "%%."):gsub("%*", "%%d*") .. "$" + if addr:match(ptn) then return true end + end + return false +end + + +function lovebird.clear() + lovebird.lines = {} + lovebird.buffer = "" +end + + +function lovebird.pushline(line) + line.time = os.time() + line.count = 1 + table.insert(lovebird.lines, line) + if #lovebird.lines > lovebird.maxlines then + table.remove(lovebird.lines, 1) + end + lovebird.recalcbuffer() +end + + +function lovebird.recalcbuffer() + local function doline(line) + local str = line.str + if not lovebird.allowhtml then + str = lovebird.htmlescape(line.str):gsub("\n", "
") + end + if line.type == "input" then + str = '' .. str .. '' + else + if line.type == "error" then + str = '! ' .. str + str = '' .. str .. '' + end + if line.count > 1 then + str = '' .. line.count .. ' ' .. str + end + if lovebird.timestamp then + str = os.date('%H:%M:%S ', line.time) .. + str + end + end + return str + end + lovebird.buffer = table.concat(lovebird.map(lovebird.lines, doline), "
") +end + + +function lovebird.print(...) + local t = {} + for i = 1, select("#", ...) do + table.insert(t, tostring(select(i, ...))) + end + local str = table.concat(t, " ") + local last = lovebird.lines[#lovebird.lines] + if last and str == last.str then + -- Update last line if this line is a duplicate of it + last.time = os.time() + last.count = last.count + 1 + lovebird.recalcbuffer() + else + -- Create new line + lovebird.pushline({ type = "output", str = str }) + end +end + + +function lovebird.onerror(err) + lovebird.pushline({ type = "error", str = err }) + if lovebird.wrapprint then + lovebird.origprint("[lovebird] ERROR: " .. err) + end +end + + +function lovebird.onrequest(req, client) + local page = req.parsedurl.path + page = page ~= "" and page or "index" + -- Handle "page not found" + if not lovebird.pages[page] then + return "HTTP/1.1 404\r\nContent-Length: 8\r\n\r\nBad page" + end + -- Handle page + local str + xpcall(function() + local data = lovebird.pages[page](lovebird, req) + local contenttype = "text/html" + if string.match(page, "%.json$") then + contenttype = "application/json" + end + str = "HTTP/1.1 200 OK\r\n" .. + "Content-Type: " .. contenttype .. "\r\n" .. + "Content-Length: " .. #data .. "\r\n" .. + "\r\n" .. data + end, lovebird.onerror) + return str +end + + +function lovebird.receive(client, pattern) + while 1 do + local data, msg = client:receive(pattern) + if not data then + if msg == "timeout" then + -- Wait for more data + coroutine.yield(true) + else + -- Disconnected -- yielding nil means we're done + coroutine.yield(nil) + end + else + return data + end + end +end + + +function lovebird.send(client, data) + local idx = 1 + while idx < #data do + local res, msg = client:send(data, idx) + if not res and msg == "closed" then + -- Handle disconnect + coroutine.yield(nil) + else + idx = idx + res + coroutine.yield(true) + end + end +end + + +function lovebird.onconnect(client) + -- Create request table + local requestptn = "(%S*)%s*(%S*)%s*(%S*)" + local req = {} + req.socket = client + req.addr, req.port = client:getsockname() + req.request = lovebird.receive(client, "*l") + req.method, req.url, req.proto = req.request:match(requestptn) + req.headers = {} + while 1 do + local line, msg = lovebird.receive(client, "*l") + if not line or #line == 0 then break end + local k, v = line:match("(.-):%s*(.*)$") + req.headers[k] = v + end + if req.headers["Content-Length"] then + req.body = lovebird.receive(client, req.headers["Content-Length"]) + end + -- Parse body + req.parsedbody = {} + if req.body then + for k, v in req.body:gmatch("([^&]-)=([^&^#]*)") do + req.parsedbody[k] = lovebird.unescape(v) + end + end + -- Parse request line's url + req.parsedurl = lovebird.parseurl(req.url) + -- Handle request; get data to send and send + local data = lovebird.onrequest(req) + lovebird.send(client, data) + -- Clear up + client:close() +end + + +function lovebird.update() + if not lovebird.inited then lovebird.init() end + -- Handle new connections + while 1 do + -- Accept new connections + local client = lovebird.server:accept() + if not client then break end + client:settimeout(0) + local addr = client:getsockname() + if lovebird.checkwhitelist(addr) then + -- Connection okay -- create and add coroutine to set + local conn = coroutine.wrap(function() + xpcall(function() lovebird.onconnect(client) end, function() end) + end) + lovebird.connections[conn] = true + else + -- Reject connection not on whitelist + lovebird.trace("got non-whitelisted connection attempt: ", addr) + client:close() + end + end + -- Handle existing connections + for conn in pairs(lovebird.connections) do + -- Resume coroutine, remove if it has finished + local status = conn() + if status == nil then + lovebird.connections[conn] = nil + end + end +end + + +return lovebird diff --git a/imperium-porcorum.love/libs/sti/graphics.lua b/imperium-porcorum.love/libs/sti/graphics.lua new file mode 100644 index 0000000..50f9036 --- /dev/null +++ b/imperium-porcorum.love/libs/sti/graphics.lua @@ -0,0 +1,103 @@ +local lg = love.graphics +local isCreated = lg.isCreated +local graphics = {isCreated = isCreated} + +function graphics.newSpriteBatch(...) + if isCreated() then + return lg.newSpriteBatch(...) + end +end + +function graphics.newCanvas(...) + if isCreated() then + return lg.newCanvas(...) + end +end + +function graphics.newQuad(...) + if isCreated() then + return lg.newQuad(...) + end +end + +function graphics.getCanvas(...) + if isCreated() then + return lg.getCanvas(...) + end +end + +function graphics.setCanvas(...) + if isCreated() then + return lg.setCanvas(...) + end +end + +function graphics.clear(...) + if isCreated() then + return lg.clear(...) + end +end + +function graphics.push(...) + if isCreated() then + return lg.push(...) + end +end + +function graphics.origin(...) + if isCreated() then + return lg.origin(...) + end +end + +function graphics.pop(...) + if isCreated() then + return lg.pop(...) + end +end + +function graphics.draw(...) + if isCreated() then + return lg.draw(...) + end +end + +function graphics.getColor(...) + if isCreated() then + return lg.getColor(...) + end +end + +function graphics.setColor(...) + if isCreated() then + return lg.setColor(...) + end +end + +function graphics.line(...) + if isCreated() then + return lg.line(...) + end +end + +function graphics.polygon(...) + if isCreated() then + return lg.polygon(...) + end +end + +function graphics.getWidth() + if isCreated() then + return lg.getWidth() + end + return 0 +end + +function graphics.getHeight() + if isCreated() then + return lg.getHeight() + end + return 0 +end + +return graphics \ No newline at end of file diff --git a/imperium-porcorum.love/libs/sti/init.lua b/imperium-porcorum.love/libs/sti/init.lua new file mode 100644 index 0000000..bc34333 --- /dev/null +++ b/imperium-porcorum.love/libs/sti/init.lua @@ -0,0 +1,1432 @@ +--- Simple and fast Tiled map loader and renderer. +-- @module sti +-- @author Landon Manning +-- @copyright 2016 +-- @license MIT/X11 + +local STI = { + _LICENSE = "MIT/X11", + _URL = "https://github.com/karai17/Simple-Tiled-Implementation", + _VERSION = "0.18.1.0", + _DESCRIPTION = "Simple Tiled Implementation is a Tiled Map Editor library designed for the *awesome* LÖVE framework.", + cache = {} +} +STI.__index = STI + +local cwd = (...):gsub('%.init$', '') .. "." +local utils = require(cwd .. "utils") +local ceil = math.ceil +local floor = math.floor +local lg = require(cwd .. "graphics") +local Map = {} +Map.__index = Map + +local function new(map, plugins, ox, oy) + local dir = "" + + if type(map) == "table" then + map = setmetatable(map, Map) + else + -- Check for valid map type + local ext = map:sub(-4, -1) + assert(ext == ".lua", string.format( + "Invalid file type: %s. File must be of type: lua.", + ext + )) + + -- Get directory of map + dir = map:reverse():find("[/\\]") or "" + if dir ~= "" then + dir = map:sub(1, 1 + (#map - dir)) + end + + -- Load map + map = setmetatable(love.filesystem.load(map)(), Map) + end + + map:init(dir, plugins, ox, oy) + + return map +end + +--- Instance a new map. +-- @param map Path to the map file or the map table itself +-- @param plugins A list of plugins to load +-- @param ox Offset of map on the X axis (in pixels) +-- @param oy Offset of map on the Y axis (in pixels) +-- @return table The loaded Map +function STI:__call(map, plugins, ox, oy) + return new(map, plugins, ox, oy) +end + +--- Flush image cache. +function STI:flush() + self.cache = {} +end + +--- Map object + +--- Instance a new map +-- @param path Path to the map file +-- @param plugins A list of plugins to load +-- @param ox Offset of map on the X axis (in pixels) +-- @param oy Offset of map on the Y axis (in pixels) +-- @return nil +function Map:init(path, plugins, ox, oy) + if type(plugins) == "table" then + self:loadPlugins(plugins) + end + + self:resize() + self.objects = {} + self.tiles = {} + self.tileInstances = {} + self.drawRange = { + sx = 1, + sy = 1, + ex = self.width, + ey = self.height, + } + self.offsetx = ox or 0 + self.offsety = oy or 0 + + -- Set tiles, images + local gid = 1 + for i, tileset in ipairs(self.tilesets) do + assert(tileset.image, "STI does not support Tile Collections.\nYou need to create a Texture Atlas.") + + -- Cache images + local formatted_path = utils.format_path(path .. tileset.image) + if not STI.cache[formatted_path] then + utils.cache_image(STI, formatted_path) + end + + -- Pull images from cache + tileset.image = STI.cache[formatted_path] + + utils.fixTransparentColor(tileset) + + gid = self:setTiles(i, tileset, gid) + end + + -- Set layers + for _, layer in ipairs(self.layers) do + self:setLayer(layer, path) + end +end + +--- Load plugins +-- @param plugins A list of plugins to load +-- @return nil +function Map:loadPlugins(plugins) + for _, plugin in ipairs(plugins) do + local pluginModulePath = cwd .. 'plugins.' .. plugin + local ok, pluginModule = pcall(require, pluginModulePath) + if ok then + for k, func in pairs(pluginModule) do + if not self[k] then + self[k] = func + end + end + end + end +end + +--- Create Tiles +-- @param index Index of the Tileset +-- @param tileset Tileset data +-- @param gid First Global ID in Tileset +-- @return number Next Tileset's first Global ID +function Map:setTiles(index, tileset, gid) + local quad = lg.newQuad + local imageW = tileset.imagewidth + local imageH = tileset.imageheight + local tileW = tileset.tilewidth + local tileH = tileset.tileheight + local margin = tileset.margin + local spacing = tileset.spacing + local w = utils.get_tiles(imageW, tileW, margin, spacing) + local h = utils.get_tiles(imageH, tileH, margin, spacing) + + for y = 1, h do + for x = 1, w do + local id = gid - tileset.firstgid + local quadX = (x - 1) * tileW + margin + (x - 1) * spacing + local quadY = (y - 1) * tileH + margin + (y - 1) * spacing + local properties, terrain, animation, objectGroup + + for _, tile in pairs(tileset.tiles) do + if tile.id == id then + properties = tile.properties + animation = tile.animation + objectGroup = tile.objectGroup + + if tile.terrain then + terrain = {} + + for i = 1, #tile.terrain do + terrain[i] = tileset.terrains[tile.terrain[i] + 1] + end + end + end + end + + local tile = { + id = id, + gid = gid, + tileset = index, + quad = quad( + quadX, quadY, + tileW, tileH, + imageW, imageH + ), + properties = properties or {}, + terrain = terrain, + animation = animation, + objectGroup = objectGroup, + frame = 1, + time = 0, + width = tileW, + height = tileH, + sx = 1, + sy = 1, + r = 0, + offset = tileset.tileoffset, + } + + self.tiles[gid] = tile + gid = gid + 1 + end + end + + return gid +end + +--- Create Layers +-- @param layer Layer data +-- @param path (Optional) Path to an Image Layer's image +-- @return nil +function Map:setLayer(layer, path) + if layer.encoding then + if layer.encoding == "base64" then + assert(require "ffi", "Compressed maps require LuaJIT FFI.\nPlease Switch your interperator to LuaJIT or your Tile Layer Format to \"CSV\".") + local fd = love.filesystem.newFileData(layer.data, "data", "base64"):getString() + + if not layer.compression then + layer.data = utils.get_decompressed_data(fd) + else + assert(love.math.decompress, "zlib and gzip compression require LOVE 0.10.0+.\nPlease set your Tile Layer Format to \"Base64 (uncompressed)\" or \"CSV\".") + + if layer.compression == "zlib" then + local data = love.math.decompress(fd, "zlib") + layer.data = utils.get_decompressed_data(data) + end + + if layer.compression == "gzip" then + local data = love.math.decompress(fd, "gzip") + layer.data = utils.get_decompressed_data(data) + end + end + end + end + + layer.x = (layer.x or 0) + layer.offsetx + self.offsetx + layer.y = (layer.y or 0) + layer.offsety + self.offsety + layer.update = function() end + + if layer.type == "tilelayer" then + self:setTileData(layer) + self:setSpriteBatches(layer) + layer.draw = function() self:drawTileLayer(layer) end + elseif layer.type == "objectgroup" then + self:setObjectData(layer) + self:setObjectCoordinates(layer) + self:setObjectSpriteBatches(layer) + layer.draw = function() self:drawObjectLayer(layer) end + elseif layer.type == "imagelayer" then + layer.draw = function() self:drawImageLayer(layer) end + + if layer.image ~= "" then + local formatted_path = utils.format_path(path .. layer.image) + if not STI.cache[formatted_path] then + utils.cache_image(STI, formatted_path) + end + + layer.image = STI.cache[formatted_path] + layer.width = layer.image:getWidth() + layer.height = layer.image:getHeight() + end + end + + self.layers[layer.name] = layer +end + +--- Add Tiles to Tile Layer +-- @param layer The Tile Layer +-- @return nil +function Map:setTileData(layer) + local i = 1 + local map = {} + + for y = 1, layer.height do + map[y] = {} + for x = 1, layer.width do + local gid = layer.data[i] + + if gid > 0 then + map[y][x] = self.tiles[gid] or self:setFlippedGID(gid) + end + + i = i + 1 + end + end + + layer.data = map +end + +--- Add Objects to Layer +-- @param layer The Object Layer +-- @return nil +function Map:setObjectData(layer) + for _, object in ipairs(layer.objects) do + object.layer = layer + self.objects[object.id] = object + end +end + +--- Correct position and orientation of Objects in an Object Layer +-- @param layer The Object Layer +-- @return nil +function Map:setObjectCoordinates(layer) + for _, object in ipairs(layer.objects) do + local x = layer.x + object.x + local y = layer.y + object.y + local w = object.width + local h = object.height + local r = object.rotation + local cos = math.cos(math.rad(r)) + local sin = math.sin(math.rad(r)) + + if object.shape == "rectangle" and not object.gid then + object.rectangle = {} + + local vertices = { + { x=x, y=y }, + { x=x + w, y=y }, + { x=x + w, y=y + h }, + { x=x, y=y + h }, + } + + for _, vertex in ipairs(vertices) do + vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) + table.insert(object.rectangle, { x = vertex.x, y = vertex.y }) + end + elseif object.shape == "ellipse" then + object.ellipse = {} + local vertices = utils.convert_ellipse_to_polygon(x, y, w, h) + + for _, vertex in ipairs(vertices) do + vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) + table.insert(object.ellipse, { x = vertex.x, y = vertex.y }) + end + elseif object.shape == "polygon" then + for _, vertex in ipairs(object.polygon) do + vertex.x = vertex.x + x + vertex.y = vertex.y + y + vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) + end + elseif object.shape == "polyline" then + for _, vertex in ipairs(object.polyline) do + vertex.x = vertex.x + x + vertex.y = vertex.y + y + vertex.x, vertex.y = utils.rotate_vertex(self, vertex, x, y, cos, sin) + end + end + end +end + +--- Batch Tiles in Tile Layer for improved draw speed +-- @param layer The Tile Layer +-- @return nil +function Map:setSpriteBatches(layer) + local newBatch = lg.newSpriteBatch + local tileW = self.tilewidth + local tileH = self.tileheight + local batches = {} + + if self.orientation == "orthogonal" or self.orientation == "isometric" then + local startX = 1 + local startY = 1 + local endX = layer.width + local endY = layer.height + local incrementX = 1 + local incrementY = 1 + + -- Determine order to add tiles to sprite batch + -- Defaults to right-down + if self.renderorder == "right-up" then + startX, endX, incrementX = startX, endX, 1 + startY, endY, incrementY = endY, startY, -1 + elseif self.renderorder == "left-down" then + startX, endX, incrementX = endX, startX, -1 + startY, endY, incrementY = startY, endY, 1 + elseif self.renderorder == "left-up" then + startX, endX, incrementX = endX, startX, -1 + startY, endY, incrementY = endY, startY, -1 + end + + for y = startY, endY, incrementY do + for x = startX, endX, incrementX do + local tile = layer.data[y][x] + + if tile then + local tileset = tile.tileset + local image = self.tilesets[tile.tileset].image + + batches[tileset] = batches[tileset] or newBatch(image, layer.width * layer.height) + + local batch = batches[tileset] + local tileX, tileY + + if self.orientation == "orthogonal" then + tileX = (x - 1) * tileW + tile.offset.x + tileY = (y - 1) * tileH + tile.offset.y + tileX, tileY = utils.compensate(tile, tileX, tileY, tileW, tileH) + else + tileX = (x - y) * (tileW / 2) + tile.offset.x + layer.width * tileW / 2 - self.tilewidth / 2 + tileY = (x + y - 2) * (tileH / 2) + tile.offset.y + end + + local tab = { + layer = layer, + gid = tile.gid, + x = tileX, + y = tileY, + r = tile.r, + oy = 0 + } + + if batch then + tab.batch = batch + tab.id = batch:add(tile.quad, tileX, tileY, tile.r, tile.sx, tile.sy) + end + + self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {} + table.insert(self.tileInstances[tile.gid], tab) + end + end + end + else + local sideLen = self.hexsidelength or 0 + + if self.staggeraxis == "y" then + for y = 1, layer.height do + for x = 1, layer.width do + local tile = layer.data[y][x] + + if tile then + local tileset = tile.tileset + local image = self.tilesets[tile.tileset].image + + batches[tileset] = batches[tileset] or newBatch(image, layer.width * layer.height) + + local batch = batches[tileset] + local tileX, tileY + + if self.staggerindex == "odd" then + if y % 2 == 0 then + tileX = (x - 1) * tileW + tileW / 2 + tile.offset.x + else + tileX = (x - 1) * tileW + tile.offset.x + end + else + if y % 2 == 0 then + tileX = (x - 1) * tileW + tile.offset.x + else + tileX = (x - 1) * tileW + tileW / 2 + tile.offset.x + end + end + + local rowH = tileH - (tileH - sideLen) / 2 + tileY = (y - 1) * rowH + tile.offset.y + + local tab = { + layer = layer, + gid = tile.gid, + x = tileX, + y = tileY, + r = tile.r, + oy = 0 + } + + if batch then + tab.batch = batch + tab.id = batch:add(tile.quad, tileX, tileY, tile.r, tile.sx, tile.sy) + end + + self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {} + table.insert(self.tileInstances[tile.gid], tab) + end + end + end + else + local i = 0 + local _x + + if self.staggerindex == "odd" then + _x = 1 + else + _x = 2 + end + + while i < layer.width * layer.height do + for _y = 1, layer.height + 0.5, 0.5 do + local y = floor(_y) + + for x = _x, layer.width, 2 do + i = i + 1 + local tile = layer.data[y][x] + + if tile then + local tileset = tile.tileset + local image = self.tilesets[tile.tileset].image + + batches[tileset] = batches[tileset] or newBatch(image, layer.width * layer.height) + + local batch = batches[tileset] + local tileX, tileY + + if self.staggerindex == "odd" then + if x % 2 == 0 then + tileY = (y - 1) * tileH + tileH / 2 + tile.offset.y + else + tileY = (y - 1) * tileH + tile.offset.y + end + else + if x % 2 == 0 then + tileY = (y - 1) * tileH + tile.offset.y + else + tileY = (y - 1) * tileH + tileH / 2 + tile.offset.y + end + end + + local colW = tileW - (tileW - sideLen) / 2 + tileX = (x - 1) * colW + tile.offset.x + + local tab = { + layer = layer, + gid = tile.gid, + x = tileX, + y = tileY, + r = tile.r, + oy = 0 + } + + if batch then + tab.batch = batch + bat.id = batch:add(tile.quad, tileX, tileY, tile.r, tile.sx, tile.sy) + end + + self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {} + table.insert(self.tileInstances[tile.gid], tab) + end + end + + if _x == 1 then + _x = 2 + else + _x = 1 + end + end + end + end + end + + layer.batches = batches +end + +--- Batch Tiles in Object Layer for improved draw speed +-- @param layer The Object Layer +-- @return nil +function Map:setObjectSpriteBatches(layer) + local newBatch = lg.newSpriteBatch + local tileW = self.tilewidth + local tileH = self.tileheight + local batches = {} + + if layer.draworder == "topdown" then + table.sort(layer.objects, function(a, b) + return a.y + a.height < b.y + b.height + end) + end + + for _, object in ipairs(layer.objects) do + if object.gid then + local tile = self.tiles[object.gid] or self:setFlippedGID(object.gid) + local tileset = tile.tileset + local image = self.tilesets[tile.tileset].image + + batches[tileset] = batches[tileset] or newBatch(image) + + local batch = batches[tileset] + local tileX = object.x + tile.offset.x + local tileY = object.y + tile.offset.y - tile.height + local tileR = math.rad(object.rotation) + local oy = 0 + + -- Compensation for scale/rotation shift + if tile.sx == 1 and tile.sy == 1 then + if tileR ~= 0 then + tileY = tileY + tileH + oy = tileH + end + else + if tile.sx < 0 then tileX = tileX + tileW end + if tile.sy < 0 then tileY = tileY + tileH end + if tileR > 0 then tileX = tileX + tileW end + if tileR < 0 then tileY = tileY + tileH end + end + + local tab = { + layer = layer, + gid = tile.gid, + x = tileX, + y = tileY, + r = tileR, + oy = oy + } + + if batch then + tab.batch = batch + tab.id = batch:add(tile.quad, tileX, tileY, tileR, tile.sx, tile.sy, 0, oy) + end + + self.tileInstances[tile.gid] = self.tileInstances[tile.gid] or {} + table.insert(self.tileInstances[tile.gid], tab) + end + end + + layer.batches = batches +end + +--- Create a Custom Layer to place userdata in (such as player sprites) +-- @param name Name of Custom Layer +-- @param index Draw order within Layer stack +-- @return table Custom Layer +function Map:addCustomLayer(name, index) + index = index or #self.layers + 1 + local layer = { + type = "customlayer", + name = name, + visible = true, + opacity = 1, + properties = {}, + } + + function layer.draw() end + function layer.update() end + + table.insert(self.layers, index, layer) + self.layers[name] = self.layers[index] + + return layer +end + +--- Convert another Layer into a Custom Layer +-- @param index Index or name of Layer to convert +-- @return table Custom Layer +function Map:convertToCustomLayer(index) + local layer = assert(self.layers[index], "Layer not found: " .. index) + + layer.type = "customlayer" + layer.x = nil + layer.y = nil + layer.width = nil + layer.height = nil + layer.encoding = nil + layer.data = nil + layer.objects = nil + layer.image = nil + + function layer.draw() end + function layer.update() end + + return layer +end + +--- Remove a Layer from the Layer stack +-- @param index Index or name of Layer to convert +-- @return nil +function Map:removeLayer(index) + local layer = assert(self.layers[index], "Layer not found: " .. index) + + if type(index) == "string" then + for i, l in ipairs(self.layers) do + if l.name == index then + table.remove(self.layers, i) + self.layers[index] = nil + break + end + end + else + local name = self.layers[index].name + table.remove(self.layers, index) + self.layers[name] = nil + end + + -- Remove tile instances + if layer.batches then + for _, tiles in pairs(self.tileInstances) do + for i = #tiles, 1, -1 do + local tile = tiles[i] + if tile.layer == layer then + table.remove(tiles, i) + end + end + end + end + + -- Remove objects + if layer.objects then + for i, object in pairs(self.objects) do + if object.layer == layer then + self.objects[i] = nil + end + end + end +end + +--- Animate Tiles and update every Layer +-- @param dt Delta Time +-- @return nil +function Map:update(dt) + for _, tile in pairs(self.tiles) do + local update = false + + if tile.animation then + tile.time = tile.time + dt * 1000 + + while tile.time > tonumber(tile.animation[tile.frame].duration) do + update = true + tile.time = tile.time - tonumber(tile.animation[tile.frame].duration) + tile.frame = tile.frame + 1 + + if tile.frame > #tile.animation then tile.frame = 1 end + end + + if update and self.tileInstances[tile.gid] then + for _, j in pairs(self.tileInstances[tile.gid]) do + local t = self.tiles[tonumber(tile.animation[tile.frame].tileid) + self.tilesets[tile.tileset].firstgid] + j.batch:set(j.id, t.quad, j.x, j.y, j.r, tile.sx, tile.sy, 0, j.oy) + end + end + end + end + + for _, layer in ipairs(self.layers) do + layer:update(dt) + end +end + +--- Draw every Layer +-- @return nil +function Map:draw() + local current_canvas = lg.getCanvas() + lg.setCanvas(self.canvas) + lg.clear() + + for _, layer in ipairs(self.layers) do + if layer.visible and layer.opacity > 0 then + self:drawLayer(layer) + end + end + + lg.setCanvas(current_canvas) + lg.push() + lg.origin() + lg.draw(self.canvas) + lg.pop() +end + +--- Draw an individual Layer +-- @param layer The Layer to draw +-- @return nil +function Map:drawLayer(layer) + local r,g,b,a = lg.getColor() + lg.setColor(r, g, b, a * layer.opacity) + layer:draw() + lg.setColor(r,g,b,a) +end + +--- Default draw function for Tile Layers +-- @param layer The Tile Layer to draw +-- @return nil +function Map:drawTileLayer(layer) + if type(layer) == "string" or type(layer) == "number" then + layer = self.layers[layer] + end + + assert(layer.type == "tilelayer", "Invalid layer type: " .. layer.type .. ". Layer must be of type: tilelayer") + + for _, batch in pairs(layer.batches) do + lg.draw(batch, floor(layer.x), floor(layer.y)) + end +end + +--- Default draw function for Object Layers +-- @param layer The Object Layer to draw +-- @return nil +function Map:drawObjectLayer(layer) + if type(layer) == "string" or type(layer) == "number" then + layer = self.layers[layer] + end + + assert(layer.type == "objectgroup", "Invalid layer type: " .. layer.type .. ". Layer must be of type: objectgroup") + + local line = { 160, 160, 160, 255 * layer.opacity } + local fill = { 160, 160, 160, 255 * layer.opacity * 0.5 } + local r,g,b,a = lg.getColor() + local reset = { r, g, b, a * layer.opacity } + + local function sortVertices(obj) + local vertex = {} + + for _, v in ipairs(obj) do + table.insert(vertex, v.x) + table.insert(vertex, v.y) + end + + return vertex + end + + local function drawShape(obj, shape) + local vertex = sortVertices(obj) + + if shape == "polyline" then + lg.setColor(line) + lg.line(vertex) + return + elseif shape == "polygon" then + lg.setColor(fill) + if not love.math.isConvex(vertex) then + local triangles = love.math.triangulate(vertex) + for _, triangle in ipairs(triangles) do + lg.polygon("fill", triangle) + end + else + lg.polygon("fill", vertex) + end + else + lg.setColor(fill) + lg.polygon("fill", vertex) + end + + lg.setColor(line) + lg.polygon("line", vertex) + end + + for _, object in ipairs(layer.objects) do + if object.shape == "rectangle" and not object.gid then + drawShape(object.rectangle, "rectangle") + elseif object.shape == "ellipse" then + drawShape(object.ellipse, "ellipse") + elseif object.shape == "polygon" then + drawShape(object.polygon, "polygon") + elseif object.shape == "polyline" then + drawShape(object.polyline, "polyline") + end + end + + lg.setColor(reset) + for _, batch in pairs(layer.batches) do + lg.draw(batch, 0, 0) + end + lg.setColor(r,g,b,a) +end + +--- Default draw function for Image Layers +-- @param layer The Image Layer to draw +-- @return nil +function Map:drawImageLayer(layer) + if type(layer) == "string" or type(layer) == "number" then + layer = self.layers[layer] + end + + assert(layer.type == "imagelayer", "Invalid layer type: " .. layer.type .. ". Layer must be of type: imagelayer") + + if layer.image ~= "" then + lg.draw(layer.image, layer.x, layer.y) + end +end + +--- Resize the drawable area of the Map +-- @param w The new width of the drawable area (in pixels) +-- @param h The new Height of the drawable area (in pixels) +-- @return nil +function Map:resize(w, h) + if lg.isCreated() then + w = w or lg.getWidth() + h = h or lg.getHeight() + + self.canvas = lg.newCanvas(w, h) + self.canvas:setFilter("nearest", "nearest") + end +end + +--- Create flipped or rotated Tiles based on bitop flags +-- @param gid The flagged Global ID +-- @return table Flipped Tile +function Map:setFlippedGID(gid) + local bit31 = 2147483648 + local bit30 = 1073741824 + local bit29 = 536870912 + local flipX = false + local flipY = false + local flipD = false + local realgid = gid + + if realgid >= bit31 then + realgid = realgid - bit31 + flipX = not flipX + end + + if realgid >= bit30 then + realgid = realgid - bit30 + flipY = not flipY + end + + if realgid >= bit29 then + realgid = realgid - bit29 + flipD = not flipD + end + + local tile = self.tiles[realgid] + local data = { + id = tile.id, + gid = gid, + tileset = tile.tileset, + frame = tile.frame, + time = tile.time, + width = tile.width, + height = tile.height, + offset = tile.offset, + quad = tile.quad, + properties = tile.properties, + terrain = tile.terrain, + animation = tile.animation, + sx = tile.sx, + sy = tile.sy, + r = tile.r, + } + + if flipX then + if flipY and flipD then + data.r = math.rad(-90) + data.sy = -1 + elseif flipY then + data.sx = -1 + data.sy = -1 + elseif flipD then + data.r = math.rad(90) + else + data.sx = -1 + end + elseif flipY then + if flipD then + data.r = math.rad(-90) + else + data.sy = -1 + end + elseif flipD then + data.r = math.rad(90) + data.sy = -1 + end + + self.tiles[gid] = data + + return self.tiles[gid] +end + +--- Get custom properties from Layer +-- @param layer The Layer +-- @return table List of properties +function Map:getLayerProperties(layer) + local l = self.layers[layer] + + if not l then + return {} + end + + return l.properties +end + +--- Get custom properties from Tile +-- @param layer The Layer that the Tile belongs to +-- @param x The X axis location of the Tile (in tiles) +-- @param y The Y axis location of the Tile (in tiles) +-- @return table List of properties +function Map:getTileProperties(layer, x, y) + local tile = self.layers[layer].data[y][x] + + if not tile then + return {} + end + + return tile.properties +end + +--- Get custom properties from Object +-- @param layer The Layer that the Object belongs to +-- @param object The index or name of the Object +-- @return table List of properties +function Map:getObjectProperties(layer, object) + local o = self.layers[layer].objects + + if type(object) == "number" then + o = o[object] + else + for _, v in ipairs(o) do + if v.name == object then + o = v + break + end + end + end + + if not o then + return {} + end + + return o.properties +end + +--- Swap a tile in a spritebatch +-- @param instance The current Instance object we want to replace +-- @param tile The Tile object we want to use +-- @return none +function Map:swapTile(instance, tile) + -- Update sprite batch + + if instance.batch then + instance.batch:set( + instance.id, + tile.quad, + instance.x, + instance.y, + tile.r, + tile.sx, + tile.sy + ) + end + + -- Add new tile instance + table.insert(self.tileInstances[tile.gid], { + layer = instance.layer, + batch = instance.batch, + id = instance.id, + gid = tile.gid, + x = instance.x, + y = instance.y, + r = tile.r, + oy = tile.r ~= 0 and tile.height or 0 + }) + + -- Remove old tile instance + for i, ins in ipairs(self.tileInstances[instance.gid]) do + if ins.batch == instance.batch and ins.id == instance.id then + table.remove(self.tileInstances[instance.gid], i) + break + end + end +end + +--- Convert tile location to pixel location +-- @param x The X axis location of the point (in tiles) +-- @param y The Y axis location of the point (in tiles) +-- @return number The X axis location of the point (in pixels) +-- @return number The Y axis location of the point (in pixels) +function Map:convertTileToPixel(x,y) + if self.orientation == "orthogonal" then + local tileW = self.tilewidth + local tileH = self.tileheight + return + x * tileW, + y * tileH + elseif self.orientation == "isometric" then + local mapH = self.height + local tileW = self.tilewidth + local tileH = self.tileheight + local offsetX = mapH * tileW / 2 + return + (x - y) * tileW / 2 + offsetX, + (x + y) * tileH / 2 + elseif self.orientation == "staggered" or + self.orientation == "hexagonal" then + local tileW = self.tilewidth + local tileH = self.tileheight + local sideLen = self.hexsidelength or 0 + + if self.staggeraxis == "x" then + return + x * tileW, + ceil(y) * (tileH + sideLen) + (ceil(y) % 2 == 0 and tileH or 0) + else + return + ceil(x) * (tileW + sideLen) + (ceil(x) % 2 == 0 and tileW or 0), + y * tileH + end + end +end + +--- Convert pixel location to tile location +-- @param x The X axis location of the point (in pixels) +-- @param y The Y axis location of the point (in pixels) +-- @return number The X axis location of the point (in tiles) +-- @return number The Y axis location of the point (in tiles) +function Map:convertPixelToTile(x, y) + if self.orientation == "orthogonal" then + local tileW = self.tilewidth + local tileH = self.tileheight + return + x / tileW, + y / tileH + elseif self.orientation == "isometric" then + local mapH = self.height + local tileW = self.tilewidth + local tileH = self.tileheight + local offsetX = mapH * tileW / 2 + return + y / tileH + (x - offsetX) / tileW, + y / tileH - (x - offsetX) / tileW + elseif self.orientation == "staggered" then + local staggerX = self.staggeraxis == "x" + local even = self.staggerindex == "even" + + local function topLeft(x, y) + if staggerX then + if ceil(x) % 2 == 1 and even then + return x - 1, y + else + return x - 1, y - 1 + end + else + if ceil(y) % 2 == 1 and even then + return x, y - 1 + else + return x - 1, y - 1 + end + end + end + + local function topRight(x, y) + if staggerX then + if ceil(x) % 2 == 1 and even then + return x + 1, y + else + return x + 1, y - 1 + end + else + if ceil(y) % 2 == 1 and even then + return x + 1, y - 1 + else + return x, y - 1 + end + end + end + + local function bottomLeft(x, y) + if staggerX then + if ceil(x) % 2 == 1 and even then + return x - 1, y + 1 + else + return x - 1, y + end + else + if ceil(y) % 2 == 1 and even then + return x, y + 1 + else + return x - 1, y + 1 + end + end + end + + local function bottomRight(x, y) + if staggerX then + if ceil(x) % 2 == 1 and even then + return x + 1, y + 1 + else + return x + 1, y + end + else + if ceil(y) % 2 == 1 and even then + return x + 1, y + 1 + else + return x, y + 1 + end + end + end + + local tileW = self.tilewidth + local tileH = self.tileheight + + if staggerX then + x = x - (even and tileW / 2 or 0) + else + y = y - (even and tileH / 2 or 0) + end + + local halfH = tileH / 2 + local ratio = tileH / tileW + local referenceX = ceil(x / tileW) + local referenceY = ceil(y / tileH) + local relativeX = x - referenceX * tileW + local relativeY = y - referenceY * tileH + + if (halfH - relativeX * ratio > relativeY) then + return topLeft(referenceX, referenceY) + elseif (-halfH + relativeX * ratio > relativeY) then + return topRight(referenceX, referenceY) + elseif (halfH + relativeX * ratio < relativeY) then + return bottomLeft(referenceX, referenceY) + elseif (halfH * 3 - relativeX * ratio < relativeY) then + return bottomRight(referenceX, referenceY) + end + + return referenceX, referenceY + elseif self.orientation == "hexagonal" then + local staggerX = self.staggeraxis == "x" + local even = self.staggerindex == "even" + local tileW = self.tilewidth + local tileH = self.tileheight + local sideLenX = 0 + local sideLenY = 0 + + if staggerX then + sideLenX = self.hexsidelength + x = x - (even and tileW or (tileW - sideLenX) / 2) + else + sideLenY = self.hexsidelength + y = y - (even and tileH or (tileH - sideLenY) / 2) + end + + local colW = ((tileW - sideLenX) / 2) + sideLenX + local rowH = ((tileH - sideLenY) / 2) + sideLenY + local referenceX = ceil(x) / (colW * 2) + local referenceY = ceil(y) / (rowH * 2) + local relativeX = x - referenceX * colW * 2 + local relativeY = y - referenceY * rowH * 2 + local centers + + if staggerX then + local left = sideLenX / 2 + local centerX = left + colW + local centerY = tileH / 2 + + centers = { + { x = left, y = centerY }, + { x = centerX, y = centerY - rowH }, + { x = centerX, y = centerY + rowH }, + { x = centerX + colW, y = centerY }, + } + else + local top = sideLenY / 2 + local centerX = tileW / 2 + local centerY = top + rowH + + centers = { + { x = centerX, y = top }, + { x = centerX - colW, y = centerY }, + { x = centerX + colW, y = centerY }, + { x = centerX, y = centerY + rowH } + } + end + + local nearest = 0 + local minDist = math.huge + + local function len2(ax, ay) + return ax * ax + ay * ay + end + + for i = 1, 4 do + local dc = len2(centers[i].x - relativeX, centers[i].y - relativeY) + + if dc < minDist then + minDist = dc + nearest = i + end + end + + local offsetsStaggerX = { + { x = 0, y = 0 }, + { x = 1, y = -1 }, + { x = 1, y = 0 }, + { x = 2, y = 0 }, + } + + local offsetsStaggerY = { + { x = 0, y = 0 }, + { x = -1, y = 1 }, + { x = 0, y = 1 }, + { x = 0, y = 2 }, + } + + local offsets = staggerX and offsetsStaggerX or offsetsStaggerY + + return + referenceX + offsets[nearest].x, + referenceY + offsets[nearest].y + end +end + +--- A list of individual layers indexed both by draw order and name +-- @table Map.layers +-- @see TileLayer +-- @see ObjectLayer +-- @see ImageLayer +-- @see CustomLayer + +--- A list of individual tiles indexed by Global ID +-- @table Map.tiles +-- @see Tile +-- @see Map.tileInstances + +--- A list of tile instances indexed by Global ID +-- @table Map.tileInstances +-- @see TileInstance +-- @see Tile +-- @see Map.tiles + +--- A list of individual objects indexed by Global ID +-- @table Map.objects +-- @see Object + +--- @table TileLayer +-- @field name The name of the layer +-- @field x Position on the X axis (in pixels) +-- @field y Position on the Y axis (in pixels) +-- @field width Width of layer (in tiles) +-- @field height Height of layer (in tiles) +-- @field visible Toggle if layer is visible or hidden +-- @field opacity Opacity of layer +-- @field properties Custom properties +-- @field data A tileWo dimensional table filled with individual tiles indexed by [y][x] (in tiles) +-- @field update Update function +-- @field draw Draw function +-- @see Map.layers +-- @see Tile + +--- @table ObjectLayer +-- @field name The name of the layer +-- @field x Position on the X axis (in pixels) +-- @field y Position on the Y axis (in pixels) +-- @field visible Toggle if layer is visible or hidden +-- @field opacity Opacity of layer +-- @field properties Custom properties +-- @field objects List of objects indexed by draw order +-- @field update Update function +-- @field draw Draw function +-- @see Map.layers +-- @see Object + +--- @table ImageLayer +-- @field name The name of the layer +-- @field x Position on the X axis (in pixels) +-- @field y Position on the Y axis (in pixels) +-- @field visible Toggle if layer is visible or hidden +-- @field opacity Opacity of layer +-- @field properties Custom properties +-- @field image Image to be drawn +-- @field update Update function +-- @field draw Draw function +-- @see Map.layers + +--- Custom Layers are used to place userdata such as sprites within the draw order of the map. +-- @table CustomLayer +-- @field name The name of the layer +-- @field x Position on the X axis (in pixels) +-- @field y Position on the Y axis (in pixels) +-- @field visible Toggle if layer is visible or hidden +-- @field opacity Opacity of layer +-- @field properties Custom properties +-- @field update Update function +-- @field draw Draw function +-- @see Map.layers +-- @usage +-- -- Create a Custom Layer +-- local spriteLayer = map:addCustomLayer("Sprite Layer", 3) +-- +-- -- Add data to Custom Layer +-- spriteLayer.sprites = { +-- player = { +-- image = lg.newImage("assets/sprites/player.png"), +-- x = 64, +-- y = 64, +-- r = 0, +-- } +-- } +-- +-- -- Update callback for Custom Layer +-- function spriteLayer:update(dt) +-- for _, sprite in pairs(self.sprites) do +-- sprite.r = sprite.r + math.rad(90 * dt) +-- end +-- end +-- +-- -- Draw callback for Custom Layer +-- function spriteLayer:draw() +-- for _, sprite in pairs(self.sprites) do +-- local x = math.floor(sprite.x) +-- local y = math.floor(sprite.y) +-- local r = sprite.r +-- lg.draw(sprite.image, x, y, r) +-- end +-- end + +--- @table Tile +-- @field id Local ID within Tileset +-- @field gid Global ID +-- @field tileset Tileset ID +-- @field quad Quad object +-- @field properties Custom properties +-- @field terrain Terrain data +-- @field animation Animation data +-- @field frame Current animation frame +-- @field time Time spent on current animation frame +-- @field width Width of tile +-- @field height Height of tile +-- @field sx Scale value on the X axis +-- @field sy Scale value on the Y axis +-- @field r Rotation of tile (in radians) +-- @field offset Offset drawing position +-- @field offset.x Offset value on the X axis +-- @field offset.y Offset value on the Y axis +-- @see Map.tiles + +--- @table TileInstance +-- @field batch Spritebatch the Tile Instance belongs to +-- @field id ID within the spritebatch +-- @field gid Global ID +-- @field x Position on the X axis (in pixels) +-- @field y Position on the Y axis (in pixels) +-- @see Map.tileInstances +-- @see Tile + +--- @table Object +-- @field id Global ID +-- @field name Name of object (non-unique) +-- @field shape Shape of object +-- @field x Position of object on X axis (in pixels) +-- @field y Position of object on Y axis (in pixels) +-- @field width Width of object (in pixels) +-- @field height Heigh tof object (in pixels) +-- @field rotation Rotation of object (in radians) +-- @field visible Toggle if object is visible or hidden +-- @field properties Custom properties +-- @field ellipse List of verticies of specific shape +-- @field rectangle List of verticies of specific shape +-- @field polygon List of verticies of specific shape +-- @field polyline List of verticies of specific shape +-- @see Map.objects + +return setmetatable({}, STI) diff --git a/imperium-porcorum.love/libs/sti/plugins/box2d.lua b/imperium-porcorum.love/libs/sti/plugins/box2d.lua new file mode 100644 index 0000000..f222885 --- /dev/null +++ b/imperium-porcorum.love/libs/sti/plugins/box2d.lua @@ -0,0 +1,278 @@ +--- Box2D plugin for STI +-- @module box2d +-- @author Landon Manning +-- @copyright 2017 +-- @license MIT/X11 + +local utils = require((...):gsub('plugins.box2d', 'utils')) + +return { + box2d_LICENSE = "MIT/X11", + box2d_URL = "https://github.com/karai17/Simple-Tiled-Implementation", + box2d_VERSION = "2.3.2.5", + box2d_DESCRIPTION = "Box2D hooks for STI.", + + --- Initialize Box2D physics world. + -- @param world The Box2D world to add objects to. + -- @return nil + box2d_init = function(map, world) + assert(love.physics, "To use the Box2D plugin, please enable the love.physics module.") + + local body = love.physics.newBody(world, map.offsetx, map.offsety) + local collision = { + body = body, + } + + local function addObjectToWorld(objshape, vertices, userdata, object) + local shape + + if objshape == "polyline" then + if #vertices == 4 then + shape = love.physics.newEdgeShape(unpack(vertices)) + else + shape = love.physics.newChainShape(false, unpack(vertices)) + end + else + shape = love.physics.newPolygonShape(unpack(vertices)) + end + + local fixture = love.physics.newFixture(body, shape) + + fixture:setUserData(userdata) + + if userdata.properties.sensor == true then + fixture:setSensor(true) + end + + local obj = { + object = object, + shape = shape, + fixture = fixture, + } + + table.insert(collision, obj) + end + + local function getPolygonVertices(object) + local vertices = {} + for _, vertex in ipairs(object.polygon) do + table.insert(vertices, vertex.x) + table.insert(vertices, vertex.y) + end + + return vertices + end + + local function calculateObjectPosition(object, tile) + local o = { + shape = object.shape, + x = (object.dx or object.x) + map.offsetx, + y = (object.dy or object.y) + map.offsety, + w = object.width, + h = object.height, + polygon = object.polygon or object.polyline or object.ellipse or object.rectangle + } + + local userdata = { + object = o, + properties = object.properties + } + + if o.shape == "rectangle" then + o.r = object.rotation or 0 + local cos = math.cos(math.rad(o.r)) + local sin = math.sin(math.rad(o.r)) + local oy = 0 + + if object.gid then + local tileset = map.tilesets[map.tiles[object.gid].tileset] + local lid = object.gid - tileset.firstgid + local t = {} + + -- This fixes a height issue + o.y = o.y + map.tiles[object.gid].offset.y + oy = tileset.tileheight + + for _, tt in ipairs(tileset.tiles) do + if tt.id == lid then + t = tt + break + end + end + + if t.objectGroup then + for _, obj in ipairs(t.objectGroup.objects) do + -- Every object in the tile + calculateObjectPosition(obj, object) + end + + return + else + o.w = map.tiles[object.gid].width + o.h = map.tiles[object.gid].height + end + end + + o.polygon = { + { x=o.x+0, y=o.y+0 }, + { x=o.x+o.w, y=o.y+0 }, + { x=o.x+o.w, y=o.y+o.h }, + { x=o.x+0, y=o.y+o.h } + } + + for _, vertex in ipairs(o.polygon) do + vertex.x, vertex.y = utils.rotate_vertex(map, vertex, o.x, o.y, cos, sin, oy) + end + + local vertices = getPolygonVertices(o) + addObjectToWorld(o.shape, vertices, userdata, tile or object) + elseif o.shape == "ellipse" then + if not o.polygon then + o.polygon = utils.convert_ellipse_to_polygon(o.x, o.y, o.w, o.h) + end + local vertices = getPolygonVertices(o) + local triangles = love.math.triangulate(vertices) + + for _, triangle in ipairs(triangles) do + addObjectToWorld(o.shape, triangle, userdata, tile or object) + end + elseif o.shape == "polygon" then + local vertices = getPolygonVertices(o) + local triangles = love.math.triangulate(vertices) + + for _, triangle in ipairs(triangles) do + addObjectToWorld(o.shape, triangle, userdata, tile or object) + end + elseif o.shape == "polyline" then + local vertices = getPolygonVertices(o) + addObjectToWorld(o.shape, vertices, userdata, tile or object) + end + end + + for _, tile in pairs(map.tiles) do + if map.tileInstances[tile.gid] then + for _, instance in ipairs(map.tileInstances[tile.gid]) do + -- Every object in every instance of a tile + if tile.objectGroup then + for _, object in ipairs(tile.objectGroup.objects) do + if object.properties.collidable == true then + object.dx = instance.x + object.x + object.dy = instance.y + object.y + calculateObjectPosition(object, instance) + end + end + end + + -- Every instance of a tile + if tile.properties.collidable == true then + local object = { + shape = "rectangle", + x = instance.x, + y = instance.y, + width = map.tilewidth, + height = map.tileheight, + properties = tile.properties + } + + calculateObjectPosition(object, instance) + end + end + end + end + + for _, layer in ipairs(map.layers) do + -- Entire layer + if layer.properties.collidable == true then + if layer.type == "tilelayer" then + for gid, tiles in pairs(map.tileInstances) do + local tile = map.tiles[gid] + local tileset = map.tilesets[tile.tileset] + + for _, instance in ipairs(tiles) do + if instance.layer == layer then + local object = { + shape = "rectangle", + x = instance.x, + y = instance.y, + width = tileset.tilewidth, + height = tileset.tileheight, + properties = tile.properties + } + + calculateObjectPosition(object, instance) + end + end + end + elseif layer.type == "objectgroup" then + for _, object in ipairs(layer.objects) do + calculateObjectPosition(object) + end + elseif layer.type == "imagelayer" then + local object = { + shape = "rectangle", + x = layer.x or 0, + y = layer.y or 0, + width = layer.width, + height = layer.height, + properties = layer.properties + } + + calculateObjectPosition(object) + end + end + + -- Individual objects + if layer.type == "objectgroup" then + for _, object in ipairs(layer.objects) do + if object.properties.collidable == true then + calculateObjectPosition(object) + end + end + end + end + + map.box2d_collision = collision + end, + + --- Remove Box2D fixtures and shapes from world. + -- @param index The index or name of the layer being removed + -- @return nil + box2d_removeLayer = function(map, index) + local layer = assert(map.layers[index], "Layer not found: " .. index) + local collision = map.box2d_collision + + -- Remove collision objects + for i = #collision, 1, -1 do + local obj = collision[i] + + if obj.object.layer == layer then + obj.fixture:destroy() + table.remove(collision, i) + end + end + end, + + --- Draw Box2D physics world. + -- @return nil + box2d_draw = function(map) + local collision = map.box2d_collision + + for _, obj in ipairs(collision) do + local points = {collision.body:getWorldPoints(obj.shape:getPoints())} + local shape_type = obj.shape:getType() + + if shape_type == "edge" or shape_type == "chain" then + love.graphics.line(points) + elseif shape_type == "polygon" then + love.graphics.polygon("line", points) + else + error("sti box2d plugin does not support "..shape_type.." shapes") + end + end + end, +} + +--- Custom Properties in Tiled are used to tell this plugin what to do. +-- @table Properties +-- @field collidable set to true, can be used on any Layer, Tile, or Object +-- @field sensor set to true, can be used on any Tile or Object that is also collidable diff --git a/imperium-porcorum.love/libs/sti/plugins/bump.lua b/imperium-porcorum.love/libs/sti/plugins/bump.lua new file mode 100644 index 0000000..8877c49 --- /dev/null +++ b/imperium-porcorum.love/libs/sti/plugins/bump.lua @@ -0,0 +1,177 @@ +--- Bump.lua plugin for STI +-- @module bump.lua +-- @author David Serrano (BobbyJones|FrenchFryLord) +-- @copyright 2016 +-- @license MIT/X11 + +return { + + bump_LICENSE = "MIT/X11", + bump_URL = "https://github.com/karai17/Simple-Tiled-Implementation", + bump_VERSION = "3.1.6.0", + bump_DESCRIPTION = "Bump hooks for STI.", + + + --- Adds each collidable tile to the Bump world. + -- @param world The Bump world to add objects to. + -- @return collidables table containing the handles to the objects in the Bump world. + bump_init = function(map, world) + local collidables = {} + + for _, tileset in ipairs(map.tilesets) do + for _, tile in ipairs(tileset.tiles) do + local gid = tileset.firstgid + tile.id + + if map.tileInstances[gid] then + for _, instance in ipairs(map.tileInstances[gid]) do + -- Every object in every instance of a tile + if tile.objectGroup then + for _, object in ipairs(tile.objectGroup.objects) do + if object.properties.collidable == true then + local t = { + x = instance.x + map.offsetx + object.x, + y = instance.y + map.offsety + object.y, + width = object.width, + height = object.height, + layer = instance.layer, + properties = object.properties + + } + + world:add(t, t.x, t.y, t.width, t.height) + table.insert(collidables, t) + end + end + end + if tile.properties ~= nil then -- Every instance of a tile if properties exsit + -- Every instance of a tile + if tile.properties.collidable == true then + local t = { + x = instance.x + map.offsetx, + y = instance.y + map.offsety, + width = map.tilewidth, + height = map.tileheight, + layer = instance.layer, + properties = tile.properties + } + + world:add(t, t.x, t.y, t.width, t.height) + table.insert(collidables, t) + end + end + end + end + end + end + + for _, layer in ipairs(map.layers) do + -- Entire layer + if layer.properties.collidable == true then + if layer.type == "tilelayer" then + for y, tiles in ipairs(layer.data) do + for x, tile in pairs(tiles) do + + if tile.objectGroup then + for _, object in ipairs(tile.objectGroup.objects) do + if object.properties.collidable == true then + local t = { + x = ((x-1) * map.tilewidth + tile.offset.x + map.offsetx) + object.x, + y = ((y-1) * map.tileheight + tile.offset.y + map.offsety) + object.y, + width = object.width, + height = object.height, + layer = layer, + properties = object.properties + } + + world:add(t, t.x, t.y, t.width, t.height) + table.insert(collidables, t) + end + end + end + + + local t = { + x = (x-1) * map.tilewidth + tile.offset.x + map.offsetx, + y = (y-1) * map.tileheight + tile.offset.y + map.offsety, + width = tile.width, + height = tile.height, + layer = layer, + properties = tile.properties + } + + world:add(t, t.x, t.y, t.width, t.height) + table.insert(collidables, t) + end + end + elseif layer.type == "imagelayer" then + world:add(layer, layer.x, layer.y, layer.width, layer.height) + table.insert(collidables, layer) + end + end + + -- individual collidable objects in a layer that is not "collidable" + -- or whole collidable objects layer + if layer.type == "objectgroup" then + for _, obj in ipairs(layer.objects) do + if layer.properties.collidable == true or obj.properties.collidable == true then + if obj.shape == "rectangle" then + local t = { + x = obj.x + map.offsetx, + y = obj.y + map.offsety, + width = obj.width, + height = obj.height, + layer = layer, + properties = obj.properties + } + + if obj.gid then + t.y = t.y - obj.height + end + + world:add(t, t.x, t.y, t.width, t.height) + table.insert(collidables, t) + end -- TODO implement other object shapes? + end + end + end + + end + map.bump_collidables = collidables + end, + + --- Remove layer + -- @param index to layer to be removed + -- @param world bump world the holds the tiles + -- @return nil + bump_removeLayer = function(map, index, world) + local layer = assert(map.layers[index], "Layer not found: " .. index) + local collidables = map.bump_collidables + + -- Remove collision objects + for i = #collidables, 1, -1 do + local obj = collidables[i] + + if obj.layer == layer + and ( + layer.properties.collidable == true + or obj.properties.collidable == true + ) then + world:remove(obj) + table.remove(collidables, i) + end + end + end, + + --- Draw bump collisions world. + -- @param world bump world holding the tiles geometry + -- @return nil + bump_draw = function(map, world) + for _, collidable in pairs(map.bump_collidables) do + love.graphics.rectangle("line", world:getRect(collidable)) + end + end +} + +--- Custom Properties in Tiled are used to tell this plugin what to do. +-- @table Properties +-- @field collidable set to true, can be used on any Layer, Tile, or Object diff --git a/imperium-porcorum.love/libs/sti/utils.lua b/imperium-porcorum.love/libs/sti/utils.lua new file mode 100644 index 0000000..0e13a73 --- /dev/null +++ b/imperium-porcorum.love/libs/sti/utils.lua @@ -0,0 +1,220 @@ +-- Some utility functions that shouldn't be exposed. + +local ffi = require "ffi" +local utils = {} + +-- https://github.com/stevedonovan/Penlight/blob/master/lua/pl/path.lua#L286 +function utils.format_path(path) + local np_gen1,np_gen2 = '[^SEP]+SEP%.%.SEP?','SEP+%.?SEP' + local np_pat1, np_pat2 = np_gen1:gsub('SEP','/'), np_gen2:gsub('SEP','/') + local k + + repeat -- /./ -> / + path,k = path:gsub(np_pat2,'/') + until k == 0 + + repeat -- A/../ -> (empty) + path,k = path:gsub(np_pat1,'') + until k == 0 + + if path == '' then path = '.' end + + return path +end + +-- Compensation for scale/rotation shift +function utils.compensate(tile, tileX, tileY, tileW, tileH) + local origx = tileX + local origy = tileY + local compx = 0 + local compy = 0 + + if tile.sx < 0 then compx = tileW end + if tile.sy < 0 then compy = tileH end + + if tile.r > 0 then + tileX = tileX + tileH - compy + tileY = tileY + tileH + compx - tileW + elseif tile.r < 0 then + tileX = tileX + compy + tileY = tileY - compx + tileH + else + tileX = tileX + compx + tileY = tileY + compy + end + + return tileX, tileY +end + +-- Cache images in main STI module +function utils.cache_image(sti, path) + if love.graphics.isCreated() then + local image = love.graphics.newImage(path) + image:setFilter("nearest", "nearest") + sti.cache[path] = image + end +end + +-- We just don't know. +function utils.get_tiles(imageW, tileW, margin, spacing) + imageW = imageW - margin + local n = 0 + + while imageW >= tileW do + imageW = imageW - tileW + if n ~= 0 then imageW = imageW - spacing end + if imageW >= 0 then n = n + 1 end + end + + return n +end + +-- Decompress tile layer data +function utils.get_decompressed_data(data) + local d = {} + local decoded = ffi.cast("uint32_t*", data) + + for i = 0, data:len() / ffi.sizeof("uint32_t") do + table.insert(d, tonumber(decoded[i])) + end + + return d +end + +-- Convert a Tiled ellipse object to a LOVE polygon +function utils.convert_ellipse_to_polygon(x, y, w, h, max_segments) + local ceil = math.ceil + local cos = math.cos + local sin = math.sin + + local function calc_segments(segments) + local function vdist(a, b) + local c = { + x = a.x - b.x, + y = a.y - b.y, + } + + return c.x * c.x + c.y * c.y + end + + segments = segments or 64 + local vertices = {} + + local v = { 1, 2, ceil(segments/4-1), ceil(segments/4) } + + local m + if love and love.physics then + m = love.physics.getMeter() + else + m = 32 + end + + for _, i in ipairs(v) do + local angle = (i / segments) * math.pi * 2 + local px = x + w / 2 + cos(angle) * w / 2 + local py = y + h / 2 + sin(angle) * h / 2 + + table.insert(vertices, { x = px / m, y = py / m }) + end + + local dist1 = vdist(vertices[1], vertices[2]) + local dist2 = vdist(vertices[3], vertices[4]) + + -- Box2D threshold + if dist1 < 0.0025 or dist2 < 0.0025 then + return calc_segments(segments-2) + end + + return segments + end + + local segments = calc_segments(max_segments) + local vertices = {} + + table.insert(vertices, { x = x + w / 2, y = y + h / 2 }) + + for i = 0, segments do + local angle = (i / segments) * math.pi * 2 + local px = x + w / 2 + cos(angle) * w / 2 + local py = y + h / 2 + sin(angle) * h / 2 + + table.insert(vertices, { x = px, y = py }) + end + + return vertices +end + +function utils.rotate_vertex(map, vertex, x, y, cos, sin) + if map.orientation == "isometric" then + x, y = utils.convert_isometric_to_screen(map, x, y) + vertex.x, vertex.y = utils.convert_isometric_to_screen(map, vertex.x, vertex.y) + end + + vertex.x = vertex.x - x + vertex.y = vertex.y - y + + return + x + cos * vertex.x - sin * vertex.y, + y + sin * vertex.x + cos * vertex.y +end + +--- Project isometric position to cartesian position +function utils.convert_isometric_to_screen(map, x, y) + local mapH = map.height + local tileW = map.tilewidth + local tileH = map.tileheight + local tileX = x / tileH + local tileY = y / tileH + local offsetX = mapH * tileW / 2 + + return + (tileX - tileY) * tileW / 2 + offsetX, + (tileX + tileY) * tileH / 2 +end + +function utils.hexToColor(Hex) + + if Hex:sub(1, 1) == "#" then + + Hex = Hex:sub(2) + + end + + return { tonumber( Hex:sub(1, 2), 16 ), tonumber( Hex:sub(3, 4), 16 ), tonumber( Hex:sub(5, 6), 16 ) } + +end + +function utils.pixelFunction(x, y, r, g, b, a) + + local maskedColor = utils.transparentColor + + if r == maskedColor[1] and g == maskedColor[2] and b == maskedColor[3] then + + return r, g, b, 0 + + end + + return r, g, b, a + +end + +function utils.fixTransparentColor(tileset) + + if love.graphics.isCreated() then + + if tileset.transparentcolor then + + utils.transparentColor = utils.hexToColor(tileset.transparentcolor) + + local ImageData = tileset.image:getData() + + ImageData:mapPixel(utils.pixelFunction) + tileset.image = love.graphics.newImage(ImageData) + + end + + end + +end + +return utils diff --git a/imperium-porcorum.love/libs/utils/draw.lua b/imperium-porcorum.love/libs/utils/draw.lua new file mode 100644 index 0000000..8ca9762 --- /dev/null +++ b/imperium-porcorum.love/libs/utils/draw.lua @@ -0,0 +1,35 @@ +local Draw = {} + +function Draw.resetColor() + love.graphics.setColor(1,1,1,1) +end +function Draw.setColor(r, g, b, a) + local alpha = a or 255 + love.graphics.setColor(r/255,g/255,b/255,a/255) +end + +function Draw.box(x, y, w, h, r, g, b, a) + local x = math.floor(x) + local y = math.floor(y) + local w = math.floor(w) + local h = math.floor(h) + local a = a or 1 + + love.graphics.setColor(r, g, b, 0.3 * a) + love.graphics.rectangle("fill", x, y, w, h) + + love.graphics.setColor(r, g, b, 1 * a) + love.graphics.rectangle("line", x, y, w, h) + + Draw.resetColor() +end + +function Draw.printShadow(string,x,y) + local Color = love.graphics.getColor() + love.graphics.setColor({0,0,0}) + love.graphics.print(string,x+1,y+1) + love.graphics.setColor(Color) + love.graphics.print(string,x,y) +end + +return Draw diff --git a/imperium-porcorum.love/libs/utils/init.lua b/imperium-porcorum.love/libs/utils/init.lua new file mode 100644 index 0000000..53152d7 --- /dev/null +++ b/imperium-porcorum.love/libs/utils/init.lua @@ -0,0 +1,7 @@ +local cwd = (...):gsub('%.init$', '') .. "." + +return { + math = require(cwd .. "math"), + draw = require(cwd .. "draw"), + sensors = require(cwd .. "sensors") +} diff --git a/imperium-porcorum.love/libs/utils/math.lua b/imperium-porcorum.love/libs/utils/math.lua new file mode 100644 index 0000000..ff9751d --- /dev/null +++ b/imperium-porcorum.love/libs/utils/math.lua @@ -0,0 +1,162 @@ +local Math = {} + +function Math.wrap(x, max) + -- Wrap the number in order to be between 0 and the maximum + while x > max do + x = x - max + end + + while x < 0 do + x = x + max + end + + return x +end + +function Math.sign(x) + if (x < 0) then + return -1 + elseif (x > 0) then + return 1 + else + return 0 + end +end + +function Math.round(num) + return math.floor(num + 0.5) +end + +function Math.roundAngle(angle, num) + -- Note : cette fonction arrondi un angle à un certain nombre de position + local angle = angle + local num = num + --num = math.floor(360 / num) + angle = Math.round(angle / num) * num + return angle +end + +function Math.vector(x1, y1, x2, y2) + local vecx, vecy + + vecx = x2 - x1 + vexy = y2 - y1 + + return vecx, vecy +end + +function Math.getMiddlePoint(x1, y1, x2, y2) + local newx, newy, vecx, vecy + + vecx = math.max(x1, x2) - math.min(x1, x2) + vecy = math.max(y1, y2) - math.min(y1, y2) + + newx = math.min(x1, x2) + (vecx / 2) + newy = math.min(y1, y2) + (vecy / 2) + + return newx, newy +end + +function Math.pointDistance(x1, y1, x2, y2) + local vecx, vecy + + vecx = math.max(x1, x2) - math.min(x1, x2) + vexy = math.max(y1, y2) - math.min(y1, y2) + + return math.sqrt(vecx^2 + vecy^2) + +end + +function Math.pointDirection(x1,y1,x2,y2) + local vecx, vecy, angle + vecy = y2 - y1 -- On inverse y pour que les calculs correspondent à notre manière de fonctionner + vecx = x2 - x1 + angle = math.atan2(vecy, vecx) + angle = math.deg(angle) + --print(x2 .. "-" .. x1 .. "=" .. vecx .. " ; " .. + -- y2 .. "-" .. y1 .. "=" .. vecy .. " -> " .. angle) + + return angle +end + +function Math.wrapAngle(angle) + return Math.wrap(angle, 360) +end + +function Math.getMode(angle) + local angle = Math.wrapAngle(angle) + local mode + if (angle <= 45) or (angle >= 315) then + mode = 0 + elseif (angle > 45) and (angle < 135) then + mode = 1 + elseif (angle >= 135) and (angle <= 225) then + mode = 2 + elseif (angle > 225) and (angle < 315) then + mode = 3 + end + mode = mode * 90 + return mode +end + +function Math.getModeCoord(x, y, angle, dist) + local mode = Math.getMode(angle) + local x, y = x, y + if (mode == 0) then + x = x + dist + y = y + elseif (mode == 90) then + x = x + y = y + dist + elseif (mode == 180) then + x = x - dist + y = y + elseif (mode == 270) then + x = x + y = y - dist + end + return x, y +end + +function Math.numberToString(x, length) + local length = length or 1 + local string = "" + local x = x + if (x >= math.pow(10, length)) then + x = unitsNumber*10 - 1 + string = string .. x + else + for i=1, (length-1) do + if (x < math.pow(10, length-i)) then + string = string .. "0" + end + end + string = string .. x + end + return string +end + +function Math.invertBool(bool) + if bool == true then + bool = false + else + bool = true + end + + return bool +end + +function Math.floorCoord(x, y) + return math.floor(x), math.floor(y) +end + +function Math.pixeliseCoord(x, y, factor) + x, y = Math.floorCoord(x / factor, y / factor) + + x = x * factor + y = y * factor + + return x, y +end + +return Math diff --git a/imperium-porcorum.love/libs/utils/sensors.lua b/imperium-porcorum.love/libs/utils/sensors.lua new file mode 100644 index 0000000..f5ebd07 --- /dev/null +++ b/imperium-porcorum.love/libs/utils/sensors.lua @@ -0,0 +1,81 @@ +local Sensors = {} + +function Sensors.fake() + local sensorData = {} + sensorData.lenght = 0 + sensorData.x = 0 + sensorData.y = 0 + sensorData.terrain = 0 + sensorData.slope = 0 + sensorData.startx = 0 + sensorData.starty = 0 + sensorData.debugName = "" + sensorData.angle = 0 + + return sensorData +end + +function Sensors.getShortest(sensorList) + local sensorList = sensorList or {} + local sensor = sensorList[1] + for i,v in ipairs(sensorList) do + if (v.lenght < sensor.lenght) and (v.terrain ~= 0) then + sensor = v + end + i = i + 1 + end + return sensor +end + +function Sensors.getMainGroundSensor(sensorList) + local sensorList = sensorList or {} + local sensor = sensorList[1] + for i,v in ipairs(sensorList) do + if (v.lenght < sensor.lenght) and ((v.lenght > 1) or (v.angle ~=0)) and (v.terrain ~= 0) then + sensor = v + end + i = i + 1 + end + return sensor +end + +function Sensors.haveTerrain(sensorList) + local sensorList = sensorList or {} + local bool = false + for i,v in ipairs(sensorList) do + if (v.terrain ~= 0) then + bool = true + break; + end + i = i + 1 + end + return bool +end + +function Sensors.haveNoTerrain(sensorList) + local sensorList = sensorList or {} + local bool = false + for i,v in ipairs(sensorList) do + if (v.terrain == 0) then + bool = true + break; + end + i = i + 1 + end + return bool +end + +function Sensors.haveAllTerrain(sensorList) + local sensorList = sensorList or {} + local bool = true + for i,v in ipairs(sensorList) do + if (v.terrain == 0) then + bool = false + break; + end + i = i + 1 + end + return bool +end + +return Sensors diff --git a/imperium-porcorum.love/main.lua b/imperium-porcorum.love/main.lua new file mode 100644 index 0000000..27fb5de --- /dev/null +++ b/imperium-porcorum.love/main.lua @@ -0,0 +1,45 @@ +-- On commence par charger les différentes librairies utilisées par le jeu, +-- afin d'y avoir accès dans toutes les scènes et les modules du jeu + +Gamestate = require "libs.hump.gamestate" +Camera = require "libs.hump.camera" + +Object = require "libs.classic" +Sti = require "libs.sti" +Bump = require "libs.bump" +anim8 = require "libs.anim8" +lovebird = require "libs.lovebird" +CScreen = require "libs.cscreen" + +-- On charge ensuite les données du jeu, qui peuvent être accédées +-- à tous moment à l'aide des variables "assets" et "datas" + +datas = require "datas" + +-- On charge ensuite les différents modules, qui contiennnent les fonctionnalités +-- utiles internes au jeu, tel que le moteur de menu. + +utils = require "libs.utils" +menus = require "modules.menus" +assets = require "modules.assets" +save = require "modules.savegame" +vpad = require "modules.vpad" + +-- On charge après cela les différentes scènes, qui sont les différents types +-- d'écrant avec lesquels le joueur interagira +require "scenes" + +love.graphics.setDefaultFilter( "nearest", "nearest", 1 ) +io.stdout:setvbuf("no") + +function love.load() -- On charge la scene de départ (pour l'instant le menu, bientôt une scene spéciale pour ça) + assets:init() + save:init("save1") + + virtualpad = vpad() + Gamestate.registerEvents() + save:reset() + save:addPig("cochon") + Gamestate.switch(stateDebugMenu) + CScreen.init(480, 272, true) +end diff --git a/imperium-porcorum.love/modules/assets/fonts.lua b/imperium-porcorum.love/modules/assets/fonts.lua new file mode 100644 index 0000000..c2d7a0c --- /dev/null +++ b/imperium-porcorum.love/modules/assets/fonts.lua @@ -0,0 +1,43 @@ +Font = Object:extend() + +function Assets:clearFonts() + self.fonts = {} +end + +function Font:new(filename, glyphs, extraspacing) + local filename = "assets/fonts/" .. filename .. ".png" + self.font = love.graphics.newImageFont(filename, glyphs, extraspacing) +end + +function Font:set() + love.graphics.setFont(self.font) +end + +function Assets:addFont(filename, glyphs, extraspacing) + local font = Font(filename, glyphs, extraspacing) + self.fonts[filename] = font +end + +function Assets:addFontFromFile(filename) + local data = require("assets/fonts/" .. filename .. ".lua") + local font = Font(data.filename, data.glyphs, data.extraspacing) + self.fonts[filename] = font +end + +function Assets:getFont(filename) + return self.fonts[filename] +end + +function Font:getHeight() + local font = self.font + return font:getHeight() +end + +function Font:getWidth(string) + local width = self.font:getWidth(string) + return width +end + +function Font:setLineHeight(height) + self.font:setLineHeight(height) +end diff --git a/imperium-porcorum.love/modules/assets/init.lua b/imperium-porcorum.love/modules/assets/init.lua new file mode 100644 index 0000000..0093788 --- /dev/null +++ b/imperium-porcorum.love/modules/assets/init.lua @@ -0,0 +1,91 @@ +local e = + { + class = 'assets', + } +e.__index = e +e.new = function() + local t = + { + sprites = {}, + background = nil, + fonts = {} + } + return setmetatable(t,e) +end + +-- Ceci est un test + +Assets = Object:extend() + +require "modules.assets.sprites" +require "modules.assets.fonts" +require "modules.assets.textbox" +require "modules.assets.progressbar" + +function Assets:new() + self.sprites = {} + self.sfx = {} + self.fonts = {} + self.textbox = {} + self.progressbar= {} + self.music = nil + self.background = nil + self:clearFonts() +end + +function Assets:init() + self.sprites = {} + self.sfx = {} + self.fonts = {} + self.textbox = {} + self.progressbar= {} + self.music = nil + self.background = nil + self:clearFonts() +end + +function Assets:update(dt) + self:animationsUpdate(dt) +end + +function Assets:newSFX(filename) + self.sfx[filename] = love.audio.newSource( "assets/sfx/" .. filename .. ".wav", "static" ) +end + +function Assets:clearSFX() + love.audio.stop( ) + self.sfx = {} +end + +function Assets:setMusic(filename) + love.audio.stop( ) + self.music = love.audio.newSource( "assets/music/" .. filename, "stream" ) +end + +function Assets:playSFX(filename) + if not (self.sfx[filename] == nil) then + self.sfx[filename]:stop() + love.audio.play( self.sfx[filename] ) + end +end + +function Assets:playMusic() + if not (self.music == nil) then + love.audio.play(self.music) + end +end + +function Assets:silence() + love.audio.stop() +end + +function Assets:setBackground(background) + self.background = love.graphics.newImage("assets/backgrounds/".. background ..".png") +end + +function Assets:drawBackground() + resetColor() + love.graphics.draw(self.background, 0, 0) +end + +return Assets diff --git a/imperium-porcorum.love/modules/assets/progressbar.lua b/imperium-porcorum.love/modules/assets/progressbar.lua new file mode 100644 index 0000000..a6184ae --- /dev/null +++ b/imperium-porcorum.love/modules/assets/progressbar.lua @@ -0,0 +1,69 @@ +ProgressBar = Object:extend() + +function Assets:addProgressBar(sprite, outerfont, innerfont) + self.progressbar[sprite] = ProgressBar(sprite, outerfont, innerfont) +end + +function Assets:clearProgressBar() + self.progressbar = {} +end + +function ProgressBar:new(sprite, outerfont, innerfont) + self.sprite = Sprite(sprite, 1, 12, "gui/progressbar/") + self.sprite:newAnimation(1, 1, 0.8) + self.sprite:newAnimation(2, 1, 0.8) + self.sprite:newAnimation(3, 1, 0.8) + self.sprite:newAnimation(4, 1, 0.8) + self.sprite:newAnimation(5, 1, 0.8) + + self.backsprite = Sprite("backbar", 1, 12, "gui/progressbar/") + self.backsprite:newAnimation(1, 1, 0.8) + self.backsprite:newAnimation(2, 1, 0.8) + self.backsprite:newAnimation(3, 1, 0.8) + self.backsprite:newAnimation(4, 1, 0.8) + self.backsprite:newAnimation(5, 1, 0.8) + + self.outerfont = assets.fonts[outerfont] + self.innerfont = assets.fonts[innerfont] +end + +function ProgressBar:draw(label, x, y, w, stat, innerlabel) + resetColor() + + local wLabel = self.outerfont:getWidth(label) + local hLabel = self.outerfont:getHeight() + love.graphics.printf(label, x - wLabel, y + 7, wLabel, "right", 0, 1, 1, 0, hLabel/2) + + + local innerlabel = innerlabel or "" + local stat = math.min(1, stat) + local w2 = math.ceil(w * stat) + for i=1, w do + if (i == 1) then + self.backsprite:draw(1, x+i, y) + elseif (i == 2) then + self.backsprite:draw(2, x+i, y) + elseif (i == (w-1)) then + self.backsprite:draw(4, x+i, y) + elseif (i == (w)) then + self.backsprite:draw(5, x+i, y) + else + self.backsprite:draw(3, x+i, y) + end + end + + for i=1, w2 do + if (i == 1) then + self.sprite:draw(1, x+i, y) + elseif (i == 2) then + self.sprite:draw(2, x+i, y) + elseif (i == (w2-1)) then + self.sprite:draw(4, x+i, y) + elseif (i == (w2)) then + self.sprite:draw(5, x+i, y) + else + self.sprite:draw(3, x+i, y) + end + end + +end diff --git a/imperium-porcorum.love/modules/assets/sprites.lua b/imperium-porcorum.love/modules/assets/sprites.lua new file mode 100644 index 0000000..98503d7 --- /dev/null +++ b/imperium-porcorum.love/modules/assets/sprites.lua @@ -0,0 +1,74 @@ +Sprite = Object:extend() + +function Assets:addSprite(name, width, height, subfolder) + self.sprites[name] = Sprite(name, width, height, subfolder) +end + +function Assets:clearSprites() + self.sprites = {} +end + +function Assets:animationsUpdate(dt) + for i,v in pairs(self.sprites) do + v:update(dt) + end +end + +function Sprite:new(name, width, heigth, subfolder) + self.name = name + self.subfolder = subfolder or "" + self.image = love.graphics.newImage( 'assets/sprites/' .. self.subfolder .. self.name .. '.png') + self.width = width + self.height = height + self.grid = anim8.newGrid(width, heigth, + self.image:getWidth(), self.image:getHeight()) + self.animations = {} +end + +function Sprite:newAnimation(x, y, speed, onLoop) + local onLoop = onLoop or nil + table.insert( self.animations, + anim8.newAnimation(self.grid(x,y), speed, onLoop) ) +end + +function Sprite:update(dt) + for i=1, #self.animations do + self.animations[i]:update(dt) + end +end + +function Sprite:resetAnimation(id) + self.animations[id]:gotoFrame(1) + self.animations[id]:resume() +end + +function Sprite:cloneAnimation(id) + local clone = self.animations[id]:clone() + + return clone +end + +function Sprite:draw(id, x, y, angle, sx, sy, ox, oy, kx, ky) + local angle = angle or 0 + local sx = sx or 1 + local sy = sy or 1 + local ox = ox or 0 + local ox = ox or 0 + local kx = kx or 0 + local kx = kx or 0 + local angle = math.rad(angle) + x, y = floorCoord(x, y) + self.animations[id]:draw(self.image, x, y, angle, sx, sy, ox, oy, kx, ky) +end + +function Sprite:drawIcon(id, x, y, angle, sx, sy, ox, oy, kx, ky) + love.graphics.setColor(0, 0, 0) + self:draw(id, x+1, y+1, angle, sx, sy, ox, oy, kx, ky) + resetColor() + self:draw(id, x, y, angle, sx, sy, ox, oy, kx, ky) +end + + +function Sprite:getAnimationDuration(id) + return self.animations[id].intervals[#self.animations[id].intervals] +end diff --git a/imperium-porcorum.love/modules/assets/textbox.lua b/imperium-porcorum.love/modules/assets/textbox.lua new file mode 100644 index 0000000..957a465 --- /dev/null +++ b/imperium-porcorum.love/modules/assets/textbox.lua @@ -0,0 +1,57 @@ +TextBox = Object:extend() + +function Assets:addTextBox(sprite) + self.textbox[sprite] = TextBox(sprite) +end + +function Assets:clearTextBox() + self.textbox = {} +end + + +function TextBox:new(sprite) + self.sprite = Sprite(sprite, 8, 8, "gui/textbox/") + self.sprite:newAnimation(1, 1, 0.8) + self.sprite:newAnimation(2, 1, 0.8) + self.sprite:newAnimation(3, 1, 0.8) + + self.sprite:newAnimation(1, 2, 0.8) + self.sprite:newAnimation(2, 2, 0.8) + self.sprite:newAnimation(3, 2, 0.8) + + self.sprite:newAnimation(1, 3, 0.8) + self.sprite:newAnimation(2, 3, 0.8) + self.sprite:newAnimation(3, 3, 0.8) +end + +function TextBox:draw(x, y, w, h) + resetColor() + local w = math.floor(w / 8) * 8 + local h = math.floor(h / 8) * 8 + local x1, x2, y1, y2 + x1 = x - 8 + x2 = x + w + y1 = y - 8 + y2 = y + h + + self.sprite:draw(1, x1, y1) + self.sprite:draw(7, x1, y2) + self.sprite:draw(3, x2, y1) + self.sprite:draw(9, x2, y2) + local w2, h2 + w2 = math.floor((w) / 8) + h2 = math.floor((h) / 8) + for i=1, w2 do + self.sprite:draw(2, x1+i*8, y1) + self.sprite:draw(8, x1+i*8, y2) + for j=1,h2 do + self.sprite:draw(5, x1+i*8, y1+j*8) + end + end + + for i=1, h2 do + self.sprite:draw(4, x1, y1+i*8) + self.sprite:draw(6, x2, y1+i*8) + end + +end diff --git a/imperium-porcorum.love/modules/functions/draw.lua b/imperium-porcorum.love/modules/functions/draw.lua new file mode 100644 index 0000000..ef3a9d3 --- /dev/null +++ b/imperium-porcorum.love/modules/functions/draw.lua @@ -0,0 +1,34 @@ +function resetColor() + love.graphics.setColor(255,255,255) +end + +function drawBox(x, y, w, h, r, g, b) + x, y = floorCoord(x, y) + w, h = floorCoord(w, h) + + love.graphics.setColor(r, g, b, 80) + love.graphics.rectangle("fill", x, y, w, h) + + love.graphics.setColor(r, g, b, 255) + love.graphics.rectangle("line", x, y, w, h) + + resetColor() +end + +function numberToString(x, unitsNumber) + local unitsNumber = unitsNumber or 1 + local string = "" + local x = x + if (x >= math.pow(10, unitsNumber)) then + x = unitsNumber*10 - 1 + string = string .. x + else + for i=1, (unitsNumber-1) do + if (x < math.pow(10, unitsNumber-i)) then + string = string .. "0" + end + end + string = string .. x + end + return string +end diff --git a/imperium-porcorum.love/modules/functions/init.lua b/imperium-porcorum.love/modules/functions/init.lua new file mode 100644 index 0000000..84480df --- /dev/null +++ b/imperium-porcorum.love/modules/functions/init.lua @@ -0,0 +1,48 @@ +require "modules.functions.draw" + +function invertBool(bool) + if bool == true then + bool = false + else + bool = true + end + + return bool +end + +function floorCoord(x, y) + return math.floor(x), math.floor(y) +end + +function pixeliseCoord(x, y, factor) + x, y = floorCoord(x / factor, y / factor) + + x = x * factor + y = y * factor + + return x, y +end + +function math.sign(x) + if (x > 0) then return 1 end + if (x < 0) then return -1 end + if (x == 0) then return 0 end +end + +function sortByUpdateOrder(a, b) + return a:getUpdateOrder() < b:getUpdateOrder() +end + +function wrap(variable, max) + if (max > 0) then + while variable > max do + variable = variable - max + end + while variable < 0 do + variable = variable + max + end + return variable + else + return -1 + end +end diff --git a/imperium-porcorum.love/modules/menus/flowbox.lua b/imperium-porcorum.love/modules/menus/flowbox.lua new file mode 100644 index 0000000..6074d98 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/flowbox.lua @@ -0,0 +1,160 @@ +FlowBox = Menu:extend() + +function FlowBox:new(x,y,w,h,slots_hor,slots_vert) + ListBox.super.new(self, x, y, w, h) + self.slots = slots_hor * slots_vert + self.slots_hor = slots_hor + self.slots_vert = slots_vert + self.begin = 1 + self.widgetsH = math.floor( self.h / slots_vert ) + self.widgetsW = math.floor( self.w / slots_hor ) + self.h = slots_vert * self.widgetsH -- On fait en sorte que la hauteur + self.w = slots_hor * self.widgetsW -- et la largeur + -- soit un multiple du nombre de slot et de leur dimensions +end + +function FlowBox:update(dt) + local col, line = self:getCoord(self.selected) + local begincol, beginline = self:getCoord(self.begin) + + if line < beginline then + beginline = line + end + + if line > beginline + self.slots_vert - 1 then + beginline = line - self.slots_vert + 1 + end + + if beginline < 0 then + beginline = 0 + end + + self.begin = beginline * self.slots_hor + 1 +end + +function FlowBox:getCoord(id_selected) + id_selected = id_selected - 1 -- On simplifie les calcul en prenant 0 comme départ + local line, col + line = math.floor(id_selected / self.slots_hor) + col = id_selected - (line * self.slots_hor) + return col, line +end + +function FlowBox:moveCursor(new_col, new_line) + local col, line = self:getCoord(self.selected) + local lastcol, lastline = self:getCoord(#self.listWidget) + + + if new_line < 0 then + new_line = lastline + end + + if new_line > lastline then + new_line = 0 + end + + if (new_line == lastline) then + if new_col < 0 then + new_col = lastcol + end + + if new_col > lastcol then + if (line == lastline) then + new_col = 0 + else + new_col = lastcol + end + end + else + if new_col < 0 then + new_col = self.slots_hor - 1 + end + + if new_col == self.slots_hor then + new_col = 0 + end + end + + self.selected = (new_line * self.slots_hor) + new_col + 1 +end + +function FlowBox:keyreleased(key, code) + local col, line = self:getCoord(self.selected) + if key == 'left' then + self:moveCursor(col - 1, line) + end + + if key == 'right' then + self:moveCursor(col + 1, line) + end + + if key == 'up' then + self:moveCursor(col, line - 1) + end + + if key == 'down' then + self:moveCursor(col, line + 1) + end + + if key == "A" then + self.listWidget[self.selected]:action() + end +end + +function FlowBox:mousemoved(x, y) + local col, line = self:getCoord(self.selected) + local begincol, beginline = self:getCoord(self.begin) + local newcol, newline + + newline = beginline + math.floor(y / self.widgetsH) + newcol = math.floor(x / self.widgetsW) + self.selected = (newline * self.slots_hor) + newcol + 1 + + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end +end + +function FlowBox:mousepressed(x, y, button, isTouch) + local col, line = self:getCoord(self.selected) + local begincol, beginline = self:getCoord(self.begin) + local newline, newcol + + newline = beginline + math.floor(y / self.widgetsH) + newcol = math.floor(x / self.widgetsW) + self.selected = (newline * self.slots_hor) + newcol + 1 + + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end + + if #self.listWidget > 0 then + self.listWidget[self.selected]:action() + end +end + +function FlowBox:draw() + local widgety = self.y + local widgetx = self.x + for i,v in ipairs(self.listWidget) do + if (i >= self.begin) and (i < self.begin + self.slots) then + v:draw(widgetx, widgety, self.widgetsW, self.widgetsH) + if self.selected == i and self.focus == true then + v:drawSelected(widgetx, widgety, self.widgetsW, self.widgetsH) + else + v:draw(widgetx, widgety, self.widgetsW, self.widgetsH) + end + widgetx = widgetx + self.widgetsW + if widgetx == (self.x + self.w) then + widgetx = self.x + widgety = widgety + self.widgetsH + end + end + end +end diff --git a/imperium-porcorum.love/modules/menus/grid.lua b/imperium-porcorum.love/modules/menus/grid.lua new file mode 100644 index 0000000..ee57746 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/grid.lua @@ -0,0 +1,227 @@ +GridBox = Menu:extend() + +function GridBox:new(x,y,w,h,slots_hor,slots_vert) + ListBox.super.new(self, x, y, w, h) + self.slots = slots_hor * slots_vert + self.slots_hor = slots_hor + self.slots_vert = slots_vert + self.begin = 1 + self.widgetsH = math.floor( self.h / slots_vert ) + self.widgetsW = math.floor( self.w / slots_hor ) + self.h = slots_vert * self.widgetsH -- On fait en sorte que la hauteur + self.w = slots_hor * self.widgetsW -- et la largeur + -- soit un multiple du nombre de slot et de leur dimensions + self.cursor = {} + self.cursor.x = 0 + self.cursor.y = 0 + + -- La gridbox possède la particularité de pouvoir fusioner des slots, on fait + -- donc une liste de slots disponibles, qui serviront par la suite. + self.listSlot = {} + for i= 1, self.slots do + self.listSlot[i] = {} + self.listSlot[i].sizeH = 1 + self.listSlot[i].sizeW = 1 + self.listSlot[i].isSlave = 0 + self.listSlot[i].widgetID = i + end +end + +function GridBox:update(dt) + self.begin = 1 + local slotID = self:getSlotbyCoord(self.cursor.x, self.cursor.y) + if self.listSlot[slotID].isSlave > 0 then + slotID = self.listSlot[slotID].isSlave + end + self.selected = self.listSlot[slotID].widgetID + self.cursor.x, self.cursor.y = self:getCoord(slotID) +end + +function GridBox:regenSlots() + local widgetID = 1 + for i,v in ipairs(self.listSlot) do + if v.isSlave == 0 and (widgetID <= #self.listWidget) then + self.listSlot[i].widgetID = widgetID + widgetID = widgetID + 1 + end + end +end + +function GridBox:addCol(slotID) + local col, line = self:getCoord(slotID) + if (col + self.listSlot[slotID].sizeW + 1) <= self.slots_hor then + slotSlave = slotID + self.listSlot[slotID].sizeW + for i = 1, self.listSlot[slotID].sizeH do + self.listSlot[slotSlave + ((i-1)* self.slots_hor)].isSlave = slotID + end + self.listSlot[slotID].sizeW = self.listSlot[slotID].sizeW + 1 + end +end + +function GridBox:addLine(slotID) + local col, line = self:getCoord(slotID) + if (line + self.listSlot[slotID].sizeH + 1) <= self.slots_vert then + slotSlave = slotID + (self.listSlot[slotID].sizeH * self.slots_hor) + for i = 1, self.listSlot[slotID].sizeW do + self.listSlot[slotSlave + (i-1)].isSlave = slotID + end + self.listSlot[slotID].sizeH = self.listSlot[slotID].sizeH + 1 + end +end + +function GridBox:getCoord(id_selected) + id_selected = id_selected - 1 -- On simplifie les calcul en prenant 0 comme départ + local line, col + line = math.floor(id_selected / self.slots_hor) + col = id_selected - (line * self.slots_hor) + return col, line +end + +function GridBox:getSlotbyCoord(col, line) + return (line * self.slots_hor) + col + 1 +end + +function GridBox:getSlot(widgetID) + local slotID + for i,v in ipairs(self.listSlot) do + if v.widgetID == widgetID then + return i + end + end + return 0 +end + +function GridBox:moveCursor(newcol, newline) + local col, line = self.cursor.x, self.cursor.y + local relcol, relline = newcol - col, newline - line + self.cursor.x, self.cursor.y = newcol, newline + + while self.cursor.y < 0 do + self.cursor.y = self.cursor.y + self.slots_vert + end + + while self.cursor.x < 0 do + self.cursor.x = self.cursor.x + self.slots_hor + end + + while self.cursor.y >= self.slots_vert do + self.cursor.y = self.cursor.y - self.slots_vert + end + + while self.cursor.x >= self.slots_hor do + self.cursor.x = self.cursor.x - self.slots_hor + end + previousSlot = self:getSlotbyCoord(col, line) + newSlot = self:getSlotbyCoord(self.cursor.x, self.cursor.y) + + if (self.listSlot[newSlot].isSlave > 0) or (self.listSlot[newSlot].widgetID > #self.listWidget) then + if (self.listSlot[newSlot].isSlave == previousSlot) or (self.listSlot[newSlot].widgetID > #self.listWidget) then + self:moveCursor(self.cursor.x + relcol, self.cursor.y + relline) + end + end + +end + +function GridBox:keyreleased(key, code) + slotID = self:getSlot(self.selected) + local col, line = self.cursor.x, self.cursor.y + if key == 'left' then + --self:moveCol(-1) + self:moveCursor(col - 1, line) + end + + if key == 'right' then + --self:moveCol(1) + self:moveCursor(col + 1, line) + end + + if key == 'up' then + self:moveCursor(col, line - 1) + end + + if key == 'down' then + self:moveCursor(col, line + 1) + end + + if key == "A" and self.selected <= #self.listWidget then + self.listWidget[self.selected]:action() + end +end + +function GridBox:mousemoved(x, y) + local col, line = self:getCoord(self.selected) + local begincol, beginline = self:getCoord(self.begin) + local newcol, newline + local newselect, slotID + + newline = beginline + math.floor(y / self.widgetsH) + newcol = math.floor(x / self.widgetsW) + self.cursor.x = newcol + self.cursor.y = newline + + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end + +end + +function GridBox:mousepressed(x, y, button, isTouch) + local col, line = self:getCoord(self.selected) + local begincol, beginline = self:getCoord(self.begin) + local newcol, newline + local newselect, slotID + + newline = beginline + math.floor(y / self.widgetsH) + newcol = math.floor(x / self.widgetsW) + newselect = (newline * self.slots_hor) + newcol + 1 + + if self.listSlot[newselect].isSlave > 0 then + slotID = self.listSlot[newselect].isSlave + else + slotID = newselect + end + + self.selected = self.listSlot[slotID].widgetID + + if #self.listWidget > 0 and self.selected > 1 and self.selected <= #self.listWidget then + self.listWidget[self.selected]:action() + end +end + +function GridBox:draw() + local widgety = self.y + local widgetx = self.x + + self:regenSlots() -- On reget les slots au cas où :p + for i,v in ipairs(self.listSlot) do + if (v.isSlave == 0) and (v.widgetID <= #self.listWidget) then + --self.listWidget[v.widgetID]:draw(widgetx, widgety, self.widgetsW * v.sizeW, self.widgetsH * v.sizeH) + if self.selected == v.widgetID and self.focus == true then + self.listWidget[v.widgetID]:drawSelected(widgetx, widgety, self.widgetsW * v.sizeW, self.widgetsH * v.sizeH) + else + self.listWidget[v.widgetID]:draw(widgetx, widgety, self.widgetsW * v.sizeW, self.widgetsH * v.sizeH) + end + end + if (v.isSlave > 0) and false then + love.graphics.setColor(255,255,255,128) + love.graphics.rectangle("fill", widgetx, widgety, self.widgetsW, self.widgetsH) + end + local col, line = self:getCoord(i) + + if (col == self.cursor.x) and (line == self.cursor.y) and false then + love.graphics.setColor(255,255,0,128) + love.graphics.rectangle("fill", widgetx, widgety, self.widgetsW, self.widgetsH) + end + + --love.graphics.setColor(0,0,0,10) + --love.graphics.rectangle("line", widgetx, widgety, self.widgetsW, self.widgetsH) + widgetx = widgetx + self.widgetsW + if widgetx == (self.x + self.w) then + widgetx = self.x + widgety = widgety + self.widgetsH + end + end +end diff --git a/imperium-porcorum.love/modules/menus/init.lua b/imperium-porcorum.love/modules/menus/init.lua new file mode 100644 index 0000000..bcfdc7c --- /dev/null +++ b/imperium-porcorum.love/modules/menus/init.lua @@ -0,0 +1,86 @@ +MenuController = Object:extend() + +require "modules.menus.menu" +require "modules.menus.widgets" +require "modules.menus.listbox" +require "modules.menus.flowbox" +require "modules.menus.grid" +require "modules.menus.textmenu" + + +function MenuController:new() + self.menus = {} +end + +function MenuController:reset() + self.menus = {} +end + +function MenuController:addMenu(menu) + table.insert(self.menus, menu) +end + +function MenuController:update() + self:clear() + for i,v in ipairs(self.menus) do + v.id = i + v:update(dt) + v:updateWidgets(dt) + end +end + +function MenuController:clear() + -- On retire les entitées marquées comme supprimées + for i,v in ipairs(self.menus) do + if (v.destroyed == true) then + table.remove(self.menus, i) + end + end +end + +function MenuController:updateList() + for i,v in ipairs(self.menus) do + v.id = i + end +end + +function MenuController:keyreleased(key, code) + for i,v in ipairs(self.menus) do + if v.focus == true then + v:keyreleased(key, code) + end + end +end + +function MenuController:mousemoved(x, y, dx, dy) + for i,v in ipairs(self.menus) do + if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then + v:mousemoved(x - v.x, y - v.y) + for j,u in ipairs(self.menus) do + u.focus = false + end + v.focus = true + end + end +end + +function MenuController:mousepressed( x, y, button, istouch ) + for i,v in ipairs(self.menus) do + if (x > v.x) and (x < v.x + v.w) and (y > v.y) and (y < v.y + v.h) then + v:mousepressed(x - v.x, y - v.y, button, istouch ) + for j,u in ipairs(self.menus) do + u.focus = false + end + v.focus = true + end + end +end + +function MenuController:draw(dt) -- On dessine les entitées + for i,v in ipairs(self.menus) do + v.id = i + v:draw(dt) + end +end + +return MenuController diff --git a/imperium-porcorum.love/modules/menus/listbox.lua b/imperium-porcorum.love/modules/menus/listbox.lua new file mode 100644 index 0000000..fdba4a8 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/listbox.lua @@ -0,0 +1,77 @@ +ListBox = Menu:extend() + +function ListBox:new(x,y,w,h,slots) + ListBox.super.new(self, x, y, w, h) + self.slots = slots + self.begin = 1 + self.widgetsH = math.floor( self.h / slots ) + self.h = slots * self.widgetsH -- On fait en sorte que la hauteur + -- soit un multiple du nombre de slot et de leur hauteur +end + +function ListBox:update(dt) + if self.selected < self.begin then + self.begin = self.selected + end + if self.selected > self.begin + self.slots - 1 then + self.begin = self.selected - self.slots + 1 + end + + if self.begin < 1 then + self.begin = 1 + end +end + +function ListBox:keyreleased(key, code) + + if key == 'up' then + self:moveCursor(self.selected - 1) + end + + if key == 'down' then + self:moveCursor(self.selected + 1) + end + + if key == "A" then + self.listWidget[self.selected]:action() + end + +end + +function ListBox:mousemoved(x, y) + self.selected = self.begin + math.floor(y / self.widgetsH) + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end +end + +function ListBox:mousepressed(x, y, button, isTouch) + self.selected = self.begin + math.floor(y / self.widgetsH) + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end + if #self.listWidget > 0 then + self.listWidget[self.selected]:action() + end +end + +function ListBox:draw() + local widgety = self.y + for i,v in ipairs(self.listWidget) do + if (i >= self.begin) and (i < self.begin + self.slots) then + v:draw(self.x, widgety, self.w, self.widgetsH) + if self.selected == i and self.focus == true then + v:drawSelected(self.x, widgety, self.w, self.widgetsH) + else + v:draw(self.x, widgety, self.w, self.widgetsH) + end + widgety = widgety + self.widgetsH + end + end +end diff --git a/imperium-porcorum.love/modules/menus/menu.lua b/imperium-porcorum.love/modules/menus/menu.lua new file mode 100644 index 0000000..c14c495 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/menu.lua @@ -0,0 +1,97 @@ +Menu = Object:extend() + +function Menu:new(x,y,w,h) + self.x = x + self.y = y + self.w = w + self.h = h + self.listWidget = {} + self.selected = 0 + self.selectedPrevious = 0 + + self.destroyed = false + self.focus = false + self.cancel = 0 + self.virtualpad = vpad() +end + +function Menu:setLastWidgetCancel() + self.cancel = #self.listWidget +end + +function Menu:cancelAction() + if (self.cancel ~= 0) then + self.listWidget[self.cancel]:action() + end +end + +function Menu:update(dt) + -- Cette fonction ne contient rien par défaut +end + +function Menu:empty() + self.listWidget = {} + self.cancel = 0 +end + +function Menu:resize(x,y,w,h) + self.x = x + self.y = y + self.w = w + self.h = h +end + +function Menu:destroy() + self.destroyed = true +end + +function Menu:draw() + -- Cette fonction ne contient rien par défaut +end + +function Menu:keyreleased(key, code) + -- Cette fonction ne contient rien par défaut +end + +function Menu:mousemoved(x, y) + -- Cette fonction ne contient rien par défaut +end + +function Menu:mousepressed( x, y, button, istouch ) + -- Cette fonction ne contient rien par défaut +end + +function Menu:addWidget(newwidget) + if #self.listWidget == 0 then + self.selected = 1 + end + table.insert(self.listWidget, newwidget) +end + +function Menu:updateWidgets(dt) + self:clearWidgets() + for i,v in ipairs(self.listWidget) do + v.id = i + v:update(dt) + end +end + +function Menu:clearWidgets() -- On retire les widgets marquées comme supprimées + for i,v in ipairs(self.listWidget) do + if (v.destroyed == true) then + table.remove(self.listWidget, i) + end + end +end + +function Menu:moveCursor(new_selected) + if new_selected < 1 then + self.selected = #self.listWidget + new_selected + else + if new_selected > #self.listWidget then + self.selected = new_selected - #self.listWidget + else + self.selected = new_selected + end + end +end diff --git a/imperium-porcorum.love/modules/menus/textmenu.lua b/imperium-porcorum.love/modules/menus/textmenu.lua new file mode 100644 index 0000000..7647b51 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/textmenu.lua @@ -0,0 +1,111 @@ +TextMenu = Menu:extend() + +function TextMenu:new(x, y, font, slots) + TextMenu.super.new(self, x, y, 0, 0) + self.font = assets:getFont(font) + self.center = false + self.widgetsH = self.font:getHeight() + self.slots = slots + self.h = self.widgetsH * self.slots + self.begin = 1 + self.fixedWidth = false +end + +function TextMenu:centerText(width) + self.fixedWidth = true + self.center = true + self.w = width +end + +function TextMenu:update(dt) + if (self.fixedWidth == false) then + self:getWidth() + end + + if self.selected < self.begin then + self.begin = self.selected + end + if self.selected > self.begin + self.slots - 1 then + self.begin = self.selected - self.slots + 1 + end + + if self.begin < 1 then + self.begin = 1 + end +end + +function TextMenu:getWidth() + local width = self.w + + + for i,v in ipairs(self.listWidget) do + local stringWidth = self.font:getWidth(v.label) + width = math.max(stringWidth, width) + end + + self.w = width +end + +function TextMenu:keyreleased(key, code) + key = self.virtualpad:translateAction(1, key) + + if key == 'up' then + self:moveCursor(self.selected - 1) + end + + if key == 'down' then + self:moveCursor(self.selected + 1) + end + + if key == "A" then + self.listWidget[self.selected]:action() + end + + if key == "B" then + self:cancelAction() + end + +end + +function TextMenu:mousemoved(x, y) + self.selected = self.begin + math.floor(y / self.widgetsH) + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end +end + +function TextMenu:mousepressed(x, y, button, isTouch) + self.selected = self.begin + math.floor(y / self.widgetsH) + if self.selected < 1 then + self.selected = 1 + end + if self.selected > #self.listWidget then + self.selected = #self.listWidget + end + if #self.listWidget > 0 then + self.listWidget[self.selected]:action() + end +end + +function TextMenu:draw() + local widgety = self.y + self.font:set() + for i,v in ipairs(self.listWidget) do + if (i >= self.begin) and (i < self.begin + self.slots) then + if self.selected == i and self.focus == true then + love.graphics.setColor(85, 170, 255) + else + resetColor() + end + if (self.center) then + love.graphics.printf(v.label, self.x, widgety, self.w, "center") + else + love.graphics.print(v.label, self.x, widgety) + end + widgety = widgety + self.widgetsH + end + end +end diff --git a/imperium-porcorum.love/modules/menus/widgets/init.lua b/imperium-porcorum.love/modules/menus/widgets/init.lua new file mode 100644 index 0000000..c174954 --- /dev/null +++ b/imperium-porcorum.love/modules/menus/widgets/init.lua @@ -0,0 +1,114 @@ +Widget = Object:extend() +DummyWidget = Widget:extend() + +function Widget:new() + self.destroyed = false + self.selectable = false + self.selection_margin = 0 + self.margin = 2 + self.label = "" +end + +function Widget:selectAction() + -- Do nothing +end + +function DummyWidget:new() + DummyWidget.super.new(self) + self.r = love.math.random(128) + self.g = love.math.random(128) + self.b = love.math.random(128) + self.selectable = true + self.label = "DUMMY WIDGET (see modules.menus.widget)" +end + +function DummyWidget:draw(x, y, w, h) + x = x + self.margin + y = y + self.margin + w = w - self.margin * 2 + h = h - self.margin * 2 + + love.graphics.setColor(self.r,self.g,self.b,70) + love.graphics.rectangle("fill", x, y, w, h) + love.graphics.setColor(self.r,self.g,self.b) + love.graphics.rectangle("line", x, y, w, h) +end + +function Widget:drawSelected(x,y,w,h) + self:draw(x, y, w, h) + x = x + self.selection_margin + y = y + self.selection_margin + w = w - self.selection_margin * 2 + h = h - self.selection_margin * 2 + + love.graphics.setColor(0,0,0) + love.graphics.rectangle("fill", x, y, 4, 8) + love.graphics.rectangle("fill", x, y, 8, 4) + + love.graphics.rectangle("fill", x + w, y, -4, 8) + love.graphics.rectangle("fill", x + w, y, -8, 4) + + love.graphics.rectangle("fill", x, y + h, 4, -8) + love.graphics.rectangle("fill", x, y + h, 8, -4) + + love.graphics.rectangle("fill", x + w, y + h, -4, -8) + love.graphics.rectangle("fill", x + w, y + h, -8, -4) + + love.graphics.setColor(255,255,255) + love.graphics.rectangle("fill", x + 1, y + 1, 2, 6) + love.graphics.rectangle("fill", x + 1, y + 1, 6, 2) + + love.graphics.rectangle("fill", x + w - 1, y + 1, -2, 6) + love.graphics.rectangle("fill", x + w - 1, y + 1, -6, 2) + + love.graphics.rectangle("fill", x + 1, y + h - 1, 2, -6) + love.graphics.rectangle("fill", x + 1, y + h - 1, 6, -2) + + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -2, -6) + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -6, -2) + +end + +function Widget:draw(x, y, w, h) +end + +function Widget:update(dt) + -- N/A +end + +function Widget:action() + self:destroy() +end + +function Widget:destroy() + self.destroyed = true +end + +function drawWidget_selected(x, y, w, h) + love.graphics.setColor(0,0,0) + love.graphics.rectangle("fill", x, y, 4, 8) + love.graphics.rectangle("fill", x, y, 8, 4) + + love.graphics.rectangle("fill", x + w, y, -4, 8) + love.graphics.rectangle("fill", x + w, y, -8, 4) + + love.graphics.rectangle("fill", x, y + h, 4, -8) + love.graphics.rectangle("fill", x, y + h, 8, -4) + + love.graphics.rectangle("fill", x + w, y + h, -4, -8) + love.graphics.rectangle("fill", x + w, y + h, -8, -4) + + love.graphics.setColor(255,255,255) + love.graphics.rectangle("fill", x + 1, y + 1, 2, 6) + love.graphics.rectangle("fill", x + 1, y + 1, 6, 2) + + love.graphics.rectangle("fill", x + w - 1, y + 1, -2, 6) + love.graphics.rectangle("fill", x + w - 1, y + 1, -6, 2) + + love.graphics.rectangle("fill", x + 1, y + h - 1, 2, -6) + love.graphics.rectangle("fill", x + 1, y + h - 1, 6, -2) + + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -2, -6) + love.graphics.rectangle("fill", x + w - 1, y + h - 1, -6, -2) + +end diff --git a/imperium-porcorum.love/modules/savegame/init.lua b/imperium-porcorum.love/modules/savegame/init.lua new file mode 100644 index 0000000..fd6a523 --- /dev/null +++ b/imperium-porcorum.love/modules/savegame/init.lua @@ -0,0 +1,60 @@ +Savegame = Object:extend() + +local binser = require "libs.binser" + +require "modules.savegame.pigs" + +function Savegame:new(filename) + self:reset() +end + +function Savegame:init(filename) + self:reset() + self.name = filename + self.slot = 1 -- le slot 0 signifie qu'on ne peut pas sauvegarder. +end + +function Savegame:reload() + self:read(self.name) +end + +function Savegame:getSaveFile(saveslot, absolute) + local dir = "" + if absolute then + dir = love.filesystem.getSaveDirectory() .. "/" + if not love.filesystem.exists(dir) then + love.filesystem.createDirectory( "" ) + end + end + + local filepath = dir .. "save" .. saveslot .. ".save" + + return filepath +end + +function Savegame:read() + if self.slot > 0 then + filepath = self:getSaveFile(self.slot, true) + if love.filesystem.exists("save" .. self.slot .. ".save") then + local loadedDatas = binser.readFile(filepath) + self.data = loadedDatas[1] + else + end + end +end + +function Savegame:write() + if self.slot > 0 then + filepath = self:getSaveFile(self.slot, true) + binser.writeFile(filepath, self.data) + end +end + +function Savegame:reset() + self.name = "" + self.data = {} + self.slot = 1 + self:resetPigs() +end + +return Savegame diff --git a/imperium-porcorum.love/modules/savegame/inventory.lua b/imperium-porcorum.love/modules/savegame/inventory.lua new file mode 100644 index 0000000..5424df3 --- /dev/null +++ b/imperium-porcorum.love/modules/savegame/inventory.lua @@ -0,0 +1,27 @@ +function Savegame:resetInventory() + self.save.weapons = {} + self.save.items = {} + self.save.shields = {} + self.save.hats = {} +end + +function Savegame:addItem(name) + + if (self.save.items[name] == nil) then + self.save.items[name] = 0 + end + + self.save.items[name] = self.save.items[name] + 1 + +end + +function Savegame:getPig(pigID) + if pigID == nil then + error("Error in module savegame : pigID can't be nil") + end + pigData = self.save.pigs[pigID] + if pigData == nil then + error("savegame pig data " .. pigID .. " is empty") + end + return pigData +end diff --git a/imperium-porcorum.love/modules/savegame/keyboard.lua b/imperium-porcorum.love/modules/savegame/keyboard.lua new file mode 100644 index 0000000..f9f156f --- /dev/null +++ b/imperium-porcorum.love/modules/savegame/keyboard.lua @@ -0,0 +1,9 @@ +local defaultKeyboard = require "datas.keyboard" + +function Savegame:initKeyboard() + self.save.keyboard = defaultKeyboard +end + +function Savegame:getKeyboard(playerID) + return self.save.keyboard[playerID] +end diff --git a/imperium-porcorum.love/modules/savegame/pigs.lua b/imperium-porcorum.love/modules/savegame/pigs.lua new file mode 100644 index 0000000..2974b04 --- /dev/null +++ b/imperium-porcorum.love/modules/savegame/pigs.lua @@ -0,0 +1,36 @@ +function Savegame:resetPigs() + self.data.pigs = {} +end + +function Savegame:addPig(race) + local pig = {} + pig.race = race + pig.name = "Pigguy" + + pig.atk = 1 + pig.def = 1 + pig.int = 1 + pig.spd = 1 + pig.mag = 1 + + pig.maxHP = 20 + pig.maxMP = 5 + + pig.weaponList = {1, 2, 1, 1} + pig.hat = 0 + pig.equip = 0 + pig.shield = 0 + + table.insert(self.data.pigs, pig) +end + +function Savegame:getPig(pigID) + if pigID == nil then + error("Error in module savegame : pigID can't be nil") + end + pigData = self.data.pigs[pigID] + if pigData == nil then + error("savegame pig data " .. pigID .. " is empty") + end + return pigData +end diff --git a/imperium-porcorum.love/modules/vpad.lua b/imperium-porcorum.love/modules/vpad.lua new file mode 100644 index 0000000..4de7f25 --- /dev/null +++ b/imperium-porcorum.love/modules/vpad.lua @@ -0,0 +1,37 @@ +local VPad = Object:extend() +local defaultVPad = require "datas.vpad" + +function VPad:new() + self.keyboard = defaultVPad +end + +function VPad:getData(playerID) + return self.keyboard[playerID] +end + +function VPad:translateAction(playerID, key) + local padkey = "" + for k,v in pairs(self.keyboard[playerID]) do + if v == key then padkey = k end + end + return padkey +end + +function VPad:getKey(playerID, padkey) + local padkey = padkey + for k,v in pairs(self.keyboard[playerID]) do + if (k == padkey) then key = v end + end + return key +end + +function VPad:isDown(playerID, padkey) + local isdown = false + local key = self:getKey(playerID, padkey) + + isdown = love.keyboard.isDown(key) + + return isdown +end + +return VPad diff --git a/imperium-porcorum.love/scenes/characterselect/init.lua b/imperium-porcorum.love/scenes/characterselect/init.lua new file mode 100644 index 0000000..7034f48 --- /dev/null +++ b/imperium-porcorum.love/scenes/characterselect/init.lua @@ -0,0 +1,84 @@ +stateDebugMenu = {} + +require "scenes.characterselect.controller" + +local bannerAnim = 0 + +function stateDebugMenu:init(previous) + assets:setBackground( "back" ) +end + +function stateDebugMenu:enter(previous) + assets:setBackground( "back" ) + menus:reset() + assets:clearFonts() + assets:addFont("small", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", 1) + assets:addFont("medium", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|} ", 1) + assets:addFont("large", " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", 1) + assets:silence() + assets:setMusic("options.ogg") + assets:playMusic() + + assets:clearSprites() + assets:addSprite("emblem", 330, 192) + assets.sprites["emblem"]:newAnimation(1, 1, 0.08) + assets:addSprite("banner", 480, 34) + assets.sprites["banner"]:newAnimation(1, 1, 0.08) + assets:addSprite("hborder", 48, 32) + assets.sprites["hborder"]:newAnimation(1, 1, 0.08) + assets.sprites["hborder"]:newAnimation(1, 2, 0.08) + + assets:clearTextBox() + assets:addTextBox("bluetextbox") +end + +function stateDebugMenu:update(dt) + lovebird.update() + menus:update() + bannerAnim = (bannerAnim + (dt*32*1.5)) % 32 +end + +function stateDebugMenu:keyreleased(key, code) + menus:keyreleased(key, code) +end + +function stateDebugMenu:mousemoved(x, y, dx, dy) + local x, y = CScreen.project(x, y) + local dx, dy = CScreen.project(dx, dy) + menus:mousemoved(x, y, dx, dy) +end + +function stateDebugMenu:mousepressed( x, y, button, istouch ) + local x, y = CScreen.project(x, y) + menus:mousepressed( x, y, button, istouch ) +end + +function stateDebugMenu:draw(dt) + CScreen:apply() + assets:drawBackground() + assets.sprites["emblem"]:draw(1, 240, 272/2-32, 0, 1, 1, 330/2, 192/2) + + + for i=1,12 do + assets.sprites["hborder"]:draw(1, 16, (i*32)-64+bannerAnim) + assets.sprites["hborder"]:draw(2, 480-16, (i*32)-64-bannerAnim, 0, -1, 1) + end + love.graphics.setColor(170, 0, 0) + love.graphics.rectangle("fill", 0, 0, 16, 272) + love.graphics.setColor(0, 170, 0) + love.graphics.rectangle("fill", 480-16, 0, 16, 272) + resetColor() + + assets.fonts["large"]:set() + assets.sprites["banner"]:draw(1, 0, 8) + love.graphics.printf(debugmenu.label, 0, 14, 480, "center") + + + menus:draw() + + assets.fonts["small"]:set() + assets.fonts["small"]:setLineHeight(1.2) + assets.textbox["bluetextbox"]:draw(120, 216, 240, 42) + love.graphics.printf(debugmenu.description, 120, 216, 240, "left") + CScreen:cease() +end diff --git a/imperium-porcorum.love/scenes/debugmenu/controller/init.lua b/imperium-porcorum.love/scenes/debugmenu/controller/init.lua new file mode 100644 index 0000000..a63ad66 --- /dev/null +++ b/imperium-porcorum.love/scenes/debugmenu/controller/init.lua @@ -0,0 +1,70 @@ +local DebugMenu = Object:extend() +local Widgets = require "scenes.debugmenu.controller.widgets" + +function DebugMenu:new() + self.menuID = 1 + self.menuValue = 0 + self.label = "" + menus:reset() + self.menu = TextMenu(0, 88, "medium", 6) + self.menu:centerText(480) + self.menu.focus = true + menus:addMenu(self.menu) + self:selectMenu(self.menuID) + self.description = "Hello World, i'm a test message for the description system :D" + self.previousCursor = 1 +end + +function DebugMenu:refreshMenu() + self:selectMenu(self.menuID, self.menuValue) +end + +function DebugMenu:selectMenu(id, menuValue) + self.menuID = id + self.menuValue = menuValue or 1 + self.menu:empty() + if (id == 1) then + self.label = "Imperium Porcorum" + --self.menu:addWidget(Widgets.Menu(self,"Story Mode", 1)) + self.menu:addWidget(Widgets.Menu(self,"Level Select",2)) + self.menu:addWidget(Widgets.Menu(self,"Debug Mode",3)) + self.menu:addWidget(Widgets.Menu(self,"Options",6)) + self.menu:addWidget(Widgets.Menu(self,"Bonus",1)) + self.menu:addWidget(Widgets.Exit(self)) + elseif (id == 2) then + self.label = "Select a Level" + for i,v in ipairs(datas.levels) do + self.menu:addWidget(Widgets.Menu(self,v.realm .. " - " .. v.name, 4, i)) + end + self.menu:addWidget(Widgets.Menu(self,"Back",1)) + self.menu:setLastWidgetCancel() + elseif (id == 3) then + self.label = "Manage your save data" + self.menu:addWidget(Widgets.Menu(self,"Manage Pigs",5)) + self.menu:addWidget(Widgets.Menu(self,"Manage Inventory",1)) + self.menu:addWidget(Widgets.Menu(self,"Back",1)) + self.menu:setLastWidgetCancel() + elseif (id == 4) then + self.label = "Select your Mission" + for i,v in ipairs(datas.levels[self.menuValue].missions) do + self.menu:addWidget(Widgets.Mission(self,v.missionName, self.menuValue, i)) + end + self.menu:addWidget(Widgets.Menu(self,"Back",2)) + self.menu:setLastWidgetCancel() + elseif (id == 5) then + self.label = "Select a pig to edit" + self.menu:addWidget(Widgets.AddPig(self)) + for i,v in ipairs(save.data.pigs) do + self.menu:addWidget(Widgets.Menu(self,i .. "- " .. v.name .. " the " .. v.race, 1, i)) + end + self.menu:addWidget(Widgets.Menu(self,"Back",3)) + self.menu:setLastWidgetCancel() + elseif (id == 6) then + self.menu:addWidget(Widgets.Save(self)) + self.menu:addWidget(Widgets.Load(self)) + self.menu:addWidget(Widgets.Menu(self,"Back",1)) + self.menu:setLastWidgetCancel() + end +end + +return DebugMenu diff --git a/imperium-porcorum.love/scenes/debugmenu/controller/widgets.lua b/imperium-porcorum.love/scenes/debugmenu/controller/widgets.lua new file mode 100644 index 0000000..d16dc14 --- /dev/null +++ b/imperium-porcorum.love/scenes/debugmenu/controller/widgets.lua @@ -0,0 +1,76 @@ +local Widgets = {} +Widgets.Menu = Widget:extend() +Widgets.Exit = Widget:extend() +Widgets.Mission = Widget:extend() +Widgets.AddPig = Widget:extend() +Widgets.Save = Widget:extend() +Widgets.Load = Widget:extend() + +function Widgets.Menu:new(menusystem, label, menuID, menuValue) + Widgets.Menu.super.new(self) + self.menuID = menuID + self.menuValue = menuValue or 1 + self.label = label + self.menusystem = menusystem +end + +function Widgets.Menu:action() + self.menusystem:selectMenu(self.menuID, self.menuValue) +end + +---- + +function Widgets.Exit:new(menussytem) + Widgets.Exit.super.new(self) + self.label = "Exit" + self.menusystem = menusystem +end + +function Widgets.Exit:action() + love.event.quit() +end + +function Widgets.Mission:new(menussytem, name, levelID, missionID) + Widgets.Mission.super.new(self) + self.label = name + self.menusystem = menusystem + self.levelID = levelID + self.missionID = missionID +end + +function Widgets.Mission:action() + Gamestate.switch(stateLevel, self.levelID, self.missionID) +end + +function Widgets.AddPig:new(menusystem) + Widgets.AddPig.super.new(self) + self.label = "Add Pig" + self.menusystem = menusystem +end + +function Widgets.AddPig:action() + save:addPig("cochon") + self.menusystem:refreshMenu() +end + +function Widgets.Load:new(menusystem) + Widgets.Load.super.new(self) + self.label = "Load Game" + self.menusystem = menusystem +end + +function Widgets.Load:action() + save:reload() +end + +function Widgets.Save:new(menusystem) + Widgets.Save.super.new(self) + self.label = "Save Game" + self.menusystem = menusystem +end + +function Widgets.Save:action() + save:write() +end + +return Widgets diff --git a/imperium-porcorum.love/scenes/debugmenu/init.lua b/imperium-porcorum.love/scenes/debugmenu/init.lua new file mode 100644 index 0000000..3740c49 --- /dev/null +++ b/imperium-porcorum.love/scenes/debugmenu/init.lua @@ -0,0 +1,85 @@ +stateDebugMenu = {} + +local DebugMenu = require "scenes.debugmenu.controller" + +local bannerAnim = 0 + +function stateDebugMenu:init(previous) + assets:setBackground( "back" ) +end + +function stateDebugMenu:enter(previous) + assets:setBackground( "back" ) + menus:reset() + assets:clearFonts() + assets:addFont("small", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", 1) + assets:addFont("medium", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|} ", 1) + assets:addFont("large", " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", 1) + self.debugmenu = DebugMenu() + assets:silence() + assets:setMusic("options.ogg") + assets:playMusic() + + assets:clearSprites() + assets:addSprite("emblem", 330, 192, "gui/") + assets.sprites["emblem"]:newAnimation(1, 1, 0.08) + assets:addSprite("banner", 480, 34, "gui/") + assets.sprites["banner"]:newAnimation(1, 1, 0.08) + assets:addSprite("hborder", 48, 32, "gui/") + assets.sprites["hborder"]:newAnimation(1, 1, 0.08) + assets.sprites["hborder"]:newAnimation(1, 2, 0.08) + + assets:clearTextBox() + assets:addTextBox("bluetextbox") +end + +function stateDebugMenu:update(dt) + lovebird.update() + menus:update() + bannerAnim = (bannerAnim + (dt*32*1.5)) % 32 +end + +function stateDebugMenu:keyreleased(key, code) + menus:keyreleased(key, code) +end + +function stateDebugMenu:mousemoved(x, y, dx, dy) + local x, y = CScreen.project(x, y) + local dx, dy = CScreen.project(dx, dy) + menus:mousemoved(x, y, dx, dy) +end + +function stateDebugMenu:mousepressed( x, y, button, istouch ) + local x, y = CScreen.project(x, y) + menus:mousepressed( x, y, button, istouch ) +end + +function stateDebugMenu:draw(dt) + CScreen:apply() + assets:drawBackground() + assets.sprites["emblem"]:draw(1, 240, 272/2-32, 0, 1, 1, 330/2, 192/2) + + + for i=1,12 do + assets.sprites["hborder"]:draw(1, 16, (i*32)-64+bannerAnim) + assets.sprites["hborder"]:draw(2, 480-16, (i*32)-64-bannerAnim, 0, -1, 1) + end + love.graphics.setColor(170, 0, 0) + love.graphics.rectangle("fill", 0, 0, 16, 272) + love.graphics.setColor(0, 170, 0) + love.graphics.rectangle("fill", 480-16, 0, 16, 272) + utils.draw.resetColor() + + assets.fonts["large"]:set() + assets.sprites["banner"]:draw(1, 0, 8) + love.graphics.printf(self.debugmenu.label, 0, 14, 480, "center") + + + menus:draw() + + assets.fonts["small"]:set() + assets.fonts["small"]:setLineHeight(1.2) + assets.textbox["bluetextbox"]:draw(120, 216, 240, 42) + love.graphics.printf(self.debugmenu.description, 120, 216, 240, "left") + CScreen:cease() +end diff --git a/imperium-porcorum.love/scenes/init.lua b/imperium-porcorum.love/scenes/init.lua new file mode 100644 index 0000000..b586c12 --- /dev/null +++ b/imperium-porcorum.love/scenes/init.lua @@ -0,0 +1,9 @@ +--[[ Imperium Porcorum :: scenes + +Ce script se contente de charger les différentes scenes que le jeu comporte. + +]] + +require "scenes.mainmenu" +require "scenes.levels" +require "scenes.debugmenu" diff --git a/imperium-porcorum.love/scenes/levels/controller/camera.lua b/imperium-porcorum.love/scenes/levels/controller/camera.lua new file mode 100644 index 0000000..36fd39f --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/camera.lua @@ -0,0 +1,122 @@ +function Level:initCamera(x, y) + self.camera = Camera(x, y, 1, 0, true) + --local width, height = love.graphics.getDimensions() + local width, height, flags = love.window.getMode( ) + self.screenWidth = width + self.screenHeight = height + self.cameraWidth = 480 + self.cameraHeight = 272 + + self.resolution = self.screenWidth / self.cameraWidth + self:limitCamera() +end + +function Level:floorCameraCoord() + self.camera.x, self.camera.y = floorCoord(self.camera.x, self.camera.y) + print(self.camera.x .. ";" .. self.camera.y) +end + +function Level:updateCamera(dt) + self:cameraFollowPlayer(self.activePlayer) + self:limitCamera() + self:floorCameraCoord() +end + +function Level:cameraFollowPlayer(id) + local player = self:getPlayerByID(id) + + if (player ~= nil) then + local playx, playy = floorCoord(player.center.x, + player.center.y) + + local camx, camy = self.camera.x + (self.cameraWidth/2), + self.camera.y + (self.cameraHeight/2) + + + playx, playy = self:cameraCoords(playx, playy) + playx = playx - (self.cameraWidth/2) + playy = playy - (self.cameraHeight/2) + + if (math.abs(playx) > 8) then + camx = camx + (playx - (8*math.sign(playx))) + end + + if (playy > 16) then + camy = camy + (playy - 16) + elseif (playy < -64) then + camy = camy + (playy + 64) + end + + self.camera.x, self.camera.y = camx - (self.cameraWidth/2), + camy - (self.cameraHeight/2) + end +end + +function Level:debugDrawCameraPlayerZone() + -- +end + +function Level:moveCamera(x, y) + self.camera.x = x + self.camera.y = y + + self:limitCamera() +end + +function Level:limitCamera() + local camx, camy = self.camera.x, self.camera.y + local camMinX, camMinY = (self.screenWidth/2), (self.screenHeight/2) + + local camMaxX, camMaxY = self.map.width * self.map.tilewidth, + self.map.height * self.map.tileheight + + if (self.resolution == 1) then + camMaxX, camMaxY = camMaxX - camMinX, camMaxY - camMinY + end + + + camx = math.max(camx, camMinX) + camx = math.min(camx, camMaxX) + + camy = math.max(camy, camMinY) + camy = math.min(camy, camMaxY) + + self.camera.x, self.camera.y = camx, camy +end + +function Level:getCameraCoord() + local camx, camy, camh, camw + camx = self.camera.x - (self.cameraWidth/2) + camy = self.camera.y - (self.cameraHeight/2) + + camw = self.cameraWidth + camh = self.cameraHeight + return camx, camy, camw, camh +end + +function Level:getScreenCoord() + local camx, camy, camh, camw + camx = self.camera.x - (self.screenWidth/2) + camy = self.camera.y - (self.screenHeight/2) + + camw = self.screenWidth + camh = self.screenHeight + return camx, camy, camw, camh +end + + +function Level:cameraWorldCoord(x, y, ox, oy, w, h) + ox, oy = ox or 0, oy or 0 + w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight() + return self.camera:worldCoords(x, y, ox, oy, w, h) +end + +function Level:cameraCoords(x, y) + return self.camera:cameraCoords(x, y, ox, oy, w, h) +end + +function Level:getVisibleEntities() + local camx, camy, camw, camh = self:getScreenCoord() + local visibleThings, len = self.world:queryRect(camx-64, camy-64, camw+128, camh+128) + return visibleThings, len +end diff --git a/imperium-porcorum.love/scenes/levels/controller/debug.lua b/imperium-porcorum.love/scenes/levels/controller/debug.lua new file mode 100644 index 0000000..8b0d360 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/debug.lua @@ -0,0 +1,66 @@ + function Level:setDebugMode(debugmode) + self.debugmode = debugmode + self.drawdebug = false + end + + function Level:debugKey(key) + if (key == "l") and self.drawdebug then + local mousex, mousey = self:cameraWorldCoord(love.mouse.getPosition()) + mousex, mousey = pixeliseCoord(mousex, mousey, 16) + Loot(self.world, 0, 0, mousex, mousey) + end + + if (key == "r") and self.drawdebug then + self:launchMission() + end + + if (key == "tab") then + self.drawdebug = invertBool(self.drawdebug) + end + end + + function Level:debugPlayerCoord() + local playerList = self:getPlayers() + local string = "total players : " .. #playerList .. "\n" + for i,v in ipairs(playerList) do + v.id = i + local x, y = floorCoord(v.x, v.y) + string = string .. "p" .. v.id .. " : " .. x .. ";" .. y .. "\n" + end + return string + end + + function Level:drawHitbox(box, r, g, b) + drawBox(box.x, box.y, box.w, box.h, r, g, b) + end + + function Level:debugDrawCursor() + local mousex, mousey = self:cameraWorldCoord(love.mouse.getPosition()) + mousex, mousey = pixeliseCoord(mousex, mousey, 16) + mousex, mousey = self:cameraCoords(mousex, mousey) + color = {255,255,255} + + drawBox(mousex, mousey, 16, 16, 255, 255, 255) + end + +function Level:drawCollisions() + if (self.drawdebug == true) then + for _,block in ipairs(self.blocks) do + if (block.collType == "wall") then + self:drawHitbox(block, 0,0,0) + elseif (block.collType == "platform") then + self:drawHitbox(block, 64, 64, 64) + end + end + end +end + +function Level:drawDebugHUD() + if (self.drawdebug == true) then + self:debugDrawCursor() + assets.fonts["small"]:set() + local playercoord = self:debugPlayerCoord() + local entityNumbers = self.world:countItems() + love.graphics.print(playercoord .. self.activeObjects .. "/" .. entityNumbers, 8, 8) + end +end diff --git a/imperium-porcorum.love/scenes/levels/controller/draw.lua b/imperium-porcorum.love/scenes/levels/controller/draw.lua new file mode 100644 index 0000000..c5f3404 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/draw.lua @@ -0,0 +1,55 @@ +function Level:draw(dt) + love.graphics.setColor(255, 255, 255, 255) -- On reset la couleur. + + -- Ona attache puis détache la caméra pour dessiner le monde, afin que celui + -- reste "fixe" tandis que le jouer bouge. + self:floorCameraCoord() + self:drawBackgroundColor() + self.camera:attach() + + self.map:draw() + self:drawCollisions() + self:worldDraw() + + self.camera:detach() + if (self.pause == false) then + self:drawHUD() + end + self:drawDebugHUD() +end + +function Level:drawBackgroundColor() + local r, g, b = self.backcolor + love.graphics.setColor(r, g, b) + love.graphics.rectangle("fill", 0, 0, 480, 272) + resetColor() +end + +function Level:drawHUD(dt) + resetColor() + local hp = 0 + local mp = 0 + local weapon = 0 + assets.textbox["yellowbox"]:draw(16,16,24,24) + + if self:playerHaveObject(1) then + local player = self:getPlayerByID(1) + hp = player.hp / player.stats.maxHP + mp = player.mp / player.stats.maxMP + weapon = player.weapon + end + + if (weapon ~= 0) and (weapon ~= nil) then + assets.sprites["weapon"]:drawIcon(weapon,28,28,0,1,1,8,8) + end + assets.progressbar["greenbar"]:draw("HP", 68, 14, 96, hp, "") + assets.progressbar["bluebar"]:draw("MP", 68, 30, 96, mp, "") + + assets.fonts["medium"]:set() + + love.graphics.printf( numberToString(self.score, 6), 373, 10, 96, "right") + love.graphics.printf( numberToString(self.gold, 4), 373, 25, 96-18, "right") + love.graphics.setColor(255, 255, 85) + love.graphics.printf( "G", 373, 25, 96, "right") + resetColor() +end diff --git a/imperium-porcorum.love/scenes/levels/controller/entities.lua b/imperium-porcorum.love/scenes/levels/controller/entities.lua new file mode 100644 index 0000000..b8fea4b --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/entities.lua @@ -0,0 +1,45 @@ +function Level:loadEntities() + for k, objectlayer in pairs(self.map.layers) do + if (self:isEntityLayer(objectlayer.name)) then + for k, object in pairs(objectlayer.objects) do + self:addEntityByNameOnGrid( objectlayer.name, object.x, object.y, + object.width, object.height ) + end + self.map:removeLayer(objectlayer.name) + end + end +end + +function Level:addEntityByNameOnGrid(name, x, y, w, h) + local layerdata = datas.entities + local objWidth, objHeight = layerdata[name].w, layerdata[name].h + local cellHor = math.ceil(w / objWidth) + local cellVert = math.ceil(h / objHeight) + for i=1, cellHor do + for j=1, cellVert do + self:addEntityByName(name, x + (i-1)*objWidth, y + (j-1)*objHeight) + end + end + +end + + +function Level:addEntityByName(name, x, y) + if name == "coin" then + Loot(self, "coin", 1, x, y) + end + if name == "block" then + Block(self, 0, x, y) + end +end + +function Level:isEntityLayer(layername) + local layerdata = datas.entities + local isEntityLayer = false + + if not (layerdata[layername] == nil) then + isEntityLayer = true + end + + return isEntityLayer +end diff --git a/imperium-porcorum.love/scenes/levels/controller/init.lua b/imperium-porcorum.love/scenes/levels/controller/init.lua new file mode 100644 index 0000000..3ffc065 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/init.lua @@ -0,0 +1,109 @@ +Level = Object:extend() -- On créer la classe des entitées, c'est la classe de base + +require "scenes.levels.controller.update" +require "scenes.levels.controller.draw" + +require "scenes.levels.controller.virtualpad" + +require "scenes.levels.controller.world" +require "scenes.levels.controller.camera" +require "scenes.levels.controller.players" +require "scenes.levels.controller.entities" +require "scenes.levels.controller.debug" + +function Level:new() + self.levelRealm = "" + self.levelName = "" + self.missionName = "" + self.missionDesc = "" + self.mapfile = "level1" + self.gravity = 0 + self.autorun = 1 + self.objectiveID = 0 + self.startx = 32 + self.starty = 420/2 + + self.pause = false + self.map = nil + self.backcolor = {0, 0, 0} + + self.itemList = {} + self.score = 0 + self.gold = 0 + + self:resetPlayers() + self:resetPads() + self:setDebugMode(true) +end + +function Level:reset() + self.levelRealm = "" + self.levelName = "" + self.missionName = "" + self.missionDesc = "" + self.mapfile = "level1" + self.gravity = 0 + self.autorun = 1 + self.objectiveID = 0 + self.startx = 32 + self.starty = 420/2 + + self.pause = false + self.map = nil + self.backcolor = {0, 0, 0} + + self.itemList = {} + self.score = 0 + self.gold = 0 + + self:resetPlayers() + self:resetPads() + self:setDebugMode(true) +end + +function Level:loadMission(levelID, missionID) + local leveldatas, missiondatas + leveldatas = datas.levels[levelID] + missiondatas = leveldatas.missions[missionID] + self.levelRealm = leveldatas.realm + self.levelName = leveldatas.name + self.missionName = missiondatas.missionName + self.missionDesc = missiondatas.description + self.mapfile = missiondatas.mapfile + self.gravity = missiondatas.gravity + self.autorun = missiondatas.autorun + self.objectiveID = missiondatas.objectiveID + self.startx = missiondatas.startx + self.starty = missiondatas.starty + + self:initWorld() + assets:setMusic(missiondatas.music) + + self:launchMission() +end + +function Level:launchMission() + self:resetPlayers() + self:resetPads() + --self:resetSpawnAndEntities() + assets:silence() + assets:playMusic() + + self:initCamera(0, 0) + + self:addPlayer(1) + self:spawnPlayer(1) + + local padid = self:addPad(Pad(1)) + self.virtualpads[padid]:addKey("up","up") + self.virtualpads[padid]:addKey("down","down") + self.virtualpads[padid]:addKey("left","left") + self.virtualpads[padid]:addKey("right","right") + + self.virtualpads[padid]:addKey("a","A") + self.virtualpads[padid]:addKey("z","B") + self.virtualpads[padid]:addKey("e","C") + + self.score = 0 + self.gold = 0 +end diff --git a/imperium-porcorum.love/scenes/levels/controller/pause.lua b/imperium-porcorum.love/scenes/levels/controller/pause.lua new file mode 100644 index 0000000..86d393c --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/pause.lua @@ -0,0 +1,2 @@ +function Level:pauseUpdate() +end diff --git a/imperium-porcorum.love/scenes/levels/controller/players.lua b/imperium-porcorum.love/scenes/levels/controller/players.lua new file mode 100644 index 0000000..d1e8089 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/players.lua @@ -0,0 +1,77 @@ +function Level:resetPlayers(player) + self.players = {} + self.deathTimer = -100 + self.activePlayer = -1 +end + +function Level:addPlayer(pigID) + -- Enregistrer le joueur n'est pas le rajouter à une liste des objets qui existe, + -- mais juste insérer ses informations les plus importantes afin d'aider le jeu + -- à pouvoir le reconstruire. + local play = {} + play.pigID = pigID + play.isDead = 0 + + table.insert(self.players, play) +end + +function Level:spawnPlayer(playerID) + local play = self.players[playerID] + Player(self, playerID, self.startx, self.starty) + self.activePlayer = playerID +end + +function Level:getPlayers() + local itemList = self:getEntities() + local playerList = {} + + for i,v in ipairs(itemList) do + if (v.playerID > 0) then + table.insert(playerList, v) + end + end + + return playerList +end + +function Level:getPlayerByID(id) + local itemList = self:getEntities() + local player + + for i,v in ipairs(itemList) do + if (v.playerID == id) then + player = v + end + end + + return player +end + +function Level:playerExist(id) + return (self.players[id] ~= nil) +end + +function Level:setDeathTimer(timer) + self.deathTimer = timer +end + +function Level:playerHaveObject(id) + player = self:getPlayerByID(id) + + if (player == nil) then + return false + else + return true + end +end + +function Level:updatePlayerSystem(dt) + self:updatePads(dt) + + if (self.deathTimer > 0) then + self.deathTimer = self.deathTimer - dt + elseif (self.deathTimer > -100) then + self:spawnPlayer(self.activePlayer) + self.deathTimer = -100 + end +end diff --git a/imperium-porcorum.love/scenes/levels/controller/update.lua b/imperium-porcorum.love/scenes/levels/controller/update.lua new file mode 100644 index 0000000..040ce1c --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/update.lua @@ -0,0 +1,10 @@ +function Level:update(dt) + self:updateMap(dt) + + if (self.pause == false) then + self:updatePlayerSystem(dt) + self:worldUpdate(dt) + assets:update(dt) + self:updateCamera(dt) + end +end diff --git a/imperium-porcorum.love/scenes/levels/controller/virtualpad.lua b/imperium-porcorum.love/scenes/levels/controller/virtualpad.lua new file mode 100644 index 0000000..e7c6fc0 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/virtualpad.lua @@ -0,0 +1,53 @@ +--[[ scenes.levels.controller.virtualpad + +Ce fichier va contenir le système de détection des touches, indispensables +pour pouvoir envoyer les actions au joueur. Il détecte les touches sur lesquels +le joueur appue, et les retranscrit en tant que touche megadrive, afin de +permettre au joueur de pouvoir agir sur le joueur. + +Chaque "manette virtuelle" est enregistrée séparément, et les moyens de l'activer +peuvent être différentes, suivant les touches] + +--]] + +Pad = Object:extend() + +function Level:resetPads() + self.virtualpads = {} +end + +function Level:addPad(pad) + table.insert(self.virtualpads, pad) + return #self.virtualpads +end + +function Level:updatePads() + for i,v in ipairs(self.virtualpads) do + local player = self:getPlayerByID(self.activePlayer) + if (player ~= nil) then + for k, u in pairs(v.keys) do + if virtualpad:isDown(1, u.padTouch) then + player:padPush(u.padTouch, true) + else + player:padPush(u.padTouch, false) + end + end + end + end +end + +function Pad:new(playerid) + self.keys = {} + self.playerID = playerid +end + +function Pad:addKey(key, padTouch) + local id = #self.keys + 1 + self.keys[id] = {} + self.keys[id].key = key + self.keys[id].padTouch = padTouch +end + +function Pad:update(dt) + +end diff --git a/imperium-porcorum.love/scenes/levels/controller/world.lua b/imperium-porcorum.love/scenes/levels/controller/world.lua new file mode 100644 index 0000000..fcd00cf --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/controller/world.lua @@ -0,0 +1,99 @@ +function Level:initWorld() + self.map = Sti("assets/maps/" .. self.mapfile .. ".lua") + self.world = Bump.newWorld(50) + self.backcolor = self.map.backgroundcolor or {0, 0, 0} + self.blocks = {} -- On vide la liste des blocks + + self.activeObjects = 0 + + self:loadCollisions()-- On charge les collisions + self:loadEntities() + self:getStartPosition() +end + +function Level:getStartPosition() + for k, objectlayer in pairs(self.map.layers) do + if objectlayer.name == "playerstart" then + for k, object in pairs(objectlayer.objects) do + self.startx = object.x + (object.width/2) + self.starty = object.y + (object.height) - 12 + end + self.map:removeLayer("playerstart") + end + end + return self.startx, self.starty +end + +function Level:loadCollisions() + for k, objectlayer in pairs(self.map.layers) do + if self:isCollisionLayer(objectlayer.name) then + for k, object in pairs(objectlayer.objects) do + self:addCollision(objectlayer.name,object.x,object.y,object.width,object.height) + end + self.map:removeLayer(objectlayer.name) + end + end +end + +function Level:addCollision(name, x, y, w, h) -- Rajouter un block solide dans le monde physique + --block.collType = name + if w == 0 then + w = 1 + end + local block = Collision(self, name, x, y, w, h)--{x=x,y=y,w=w,h=h,solid=1} + self.blocks[#self.blocks+1] = block -- On ajoute le block à la liste des blocks + + --self:addPhysicalObject(block, x,y,w,h) -- On le rajoute au monde physique +end + +function Level:isCollisionLayer(layername) + layerdata = datas.layers + local isCollisionLayer = false + + for k, validname in pairs(layerdata) do + if (layername == validname) then + isCollisionLayer = true + end + end + + return isCollisionLayer +end + +function Level:addPhysicalObject(object, x, y, w, h) + return self.world:add(object, x, y, w, h) -- On le rajoute au monde physique +end + +function Level:movePhysicalObject(object, x, y, filter) + self:addBlock(0,0,1,1) + return world:move(object, x, y, filter) +end + +function Level:worldUpdate(dt) + --l,t,w,h = l or 0, t or 0, w or self.width, h or self.height + local visibleThings, len = self:getVisibleEntities() + --table.sort(visibleThings, sortByUpdateOrder) + + for i=1, len do + visibleThings[i]:update(dt) + end + + self.activeObjects = len +end + +function Level:worldDraw(dt) + --l,t,w,h = l or 0, t or 0, w or self.width, h or self.height + local visibleThings, len = self:getVisibleEntities() + --table.sort(visibleThings, sortByUpdateOrder) + + for i=1, len do + visibleThings[i]:draw(dt) + end +end + +function Level:updateMap(dt) + self.map:update(dt) +end + +function Level:getEntities() + return self.world:getItems() +end diff --git a/imperium-porcorum.love/scenes/levels/entities/block.lua b/imperium-porcorum.love/scenes/levels/entities/block.lua new file mode 100644 index 0000000..73420db --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/block.lua @@ -0,0 +1,25 @@ +Block = Entity:extend() + +function Block:new(level, item, x ,y) + Block.super.new(self, level, x, y, 16, 16) + self.item = item or 0 + self.collType = "block" +end + +function Block:draw(dt) + assets.sprites["block"]:draw(1, self.x, self.y) +end + +function Block:breakBlock() + local x, y = self:getCenter() + local spd, duration = 250, 5 + local dist = 0 + Debris(self.level, x+dist, y-dist, spd, 270+45, duration) + Debris(self.level, x+dist, y+dist, spd, 45, duration) + Debris(self.level, x-dist, y+dist, spd, 180+45, duration) + Debris(self.level, x-dist, y-dist, spd, 180-45, duration) + GFX(self.level, "poof", 1, self.x+8, self.y+8) + assets:playSFX("break") + self.level.score = self.level.score + 10 + self:destroy() +end diff --git a/imperium-porcorum.love/scenes/levels/entities/bullet.lua b/imperium-porcorum.love/scenes/levels/entities/bullet.lua new file mode 100644 index 0000000..af92619 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/bullet.lua @@ -0,0 +1,44 @@ +Bullet = Entity:extend() + +function Bullet:new(level, x, y, w, h, speed, dir) + Bullet.super.new(self, level, x - (w / 2), y - (h / 2), w, h) + self.life = 0; + --world:add(self, self.x, self.y, self.w, self.h) + self.collType="bullet" + self:setMotionDirection(dir, speed) +end + +function Bullet:setFilter() + self.filter = function(item, other) + if (other.collType=="wall") then + return 'touch' + else + return nil + end + end +end + +function Bullet:update(dt) + self:setFilter() + + --self.x, self.y, cols, cols_len = currentLevel.world:move(self, self.x + self.xsp*dt, self.y + self.ysp*dt, bulletFilter) + cols, cols_len = self:move(dt) + + for j=1,cols_len do + local other = cols[j].other + if other.collType=="wall" and (self.life == 1) then + self:destroy() + end + end + + self.life = 1 + + local localx, localy = currentLevel:cameraCoords(self.x, self.y) + if (localx < 0) or (localx > 480) or (localy < 0) or (localy > (272)) or (self.xsp == 0) then + self:destroy() + end +end + +function Bullet:draw(dt) + currentLevel:drawHitbox(self, 0,128,0) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/collision.lua b/imperium-porcorum.love/scenes/levels/entities/collision.lua new file mode 100644 index 0000000..1ae058a --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/collision.lua @@ -0,0 +1,8 @@ +Collision = Entity:extend() + +function Collision:new(level, collType, x, y, w, h) + Collision.super.new(self, level, x, y, w, h) + self.collType = collType + + self:setDebugColor(0,0,0) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/debris.lua b/imperium-porcorum.love/scenes/levels/entities/debris.lua new file mode 100644 index 0000000..dfc9d6d --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/debris.lua @@ -0,0 +1,54 @@ +Debris = Entity:extend() + +function Debris:new(level, x, y, speed, dir, timelimit) + Debris.super.new(self, level, x - 4, y - 4, 8, 8) + self.life = 0; + self.timer = 0 + self.timelimit = timelimit + --world:add(self, self.x, self.y, self.w, self.h) + self.collType = "debris" + self:setMotionDirection(dir, speed) + self.grav = 1 + self.bounce = 0.5 + self.frc = 0.046875*60*1.5 + self.rotation = love.math.random(0, 360) +end + +function Debris:setFilter() + self.filter = function(item, other) + if ((other.collType=="wall")) then + return 'bounce' + else + return nil + end + end +end + +function Debris:update(dt) + self:setFilter() + self:gravity(dt) + self:friction(dt) + + --self.x, self.y, cols, cols_len = currentLevel.world:move(self, self.x + self.xsp*dt, self.y + self.ysp*dt, bulletFilter) + cols, cols_len = self:move(dt) + + self.life = 1 + + local localx, localy = self.level:cameraCoords(self.x, self.y) + if (localx < 0) or (localx > 480) or (localy < 0) or (localy > (272)) or (self.xsp == 0) then + self:destroy() + end + + self.timer = self.timer + dt + if (self.timer >= self.timelimit) then + self:destroy() + end + +end + +function Debris:draw(dt) + local rotation = math.floor(self.rotation/45)*45 + drawx, drawy = self:getCenter() + assets.sprites["debris"]:draw(1, drawx, drawy, rotation, + 1, 1, 4, 4) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/gfx.lua b/imperium-porcorum.love/scenes/levels/entities/gfx.lua new file mode 100644 index 0000000..cfd2659 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/gfx.lua @@ -0,0 +1,27 @@ +GFX = Entity:extend() + +function GFX:new(level, spritename, animID,x,y) + local width, height + self.name = spritename + self.animID = animID + self.animation = assets.sprites[spritename]:cloneAnimation(animID) + width = 16--assets.sprites[spritename].width + height = 16--assets.sprites[spritename].height + GFX.super.new(self, level, x - (width/2), y - (height/2), width, height) + self.collType = "gfx" + self.duration = assets.sprites[spritename]:getAnimationDuration(animID) + self.timer = 0 + --world:add(self, self.x, self.y, self.w, self.h) +end + +function GFX:update(dt) + self.timer = self.timer + dt + self.animation:update(dt) + if (self.timer >= self.duration) then + self:destroy() + end +end + +function GFX:draw(dt) + self.animation:draw(assets.sprites[self.name].image, self.x, self.y) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/init.lua b/imperium-porcorum.love/scenes/levels/entities/init.lua new file mode 100644 index 0000000..e887bb9 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/init.lua @@ -0,0 +1,154 @@ +Entity = Object:extend() -- On créer la classe des entitées, c'est la classe de base + +-- On charge toutes les différentes types d'entitées +require "scenes.levels.entities.collision" +require "scenes.levels.entities.block" +require "scenes.levels.entities.bullet" +require "scenes.levels.entities.loot" +require "scenes.levels.entities.weapon" +require "scenes.levels.entities.gfx" +require "scenes.levels.entities.debris" +require "scenes.levels.entities.player" + +function Entity:new(level, x, y, w, h) -- On enregistre une nouvelle entité, avec par défaut sa hitbox. + self:initPhysics(level, x, y, w, h) + self.destroyed = false + self.registered = false + self:setDebugColor(0,0,0) +end + +function Entity:initPhysics(level, x, y, w, h) + self.level = level + self.world = level.world + self.collType = "" + + self.gacc = 500 + self.xsp = 0 + self.ysp = 0 + + self.bounce = 0 + self.grav = 0 + self.frc = 0 + + self.x = x or 0 + self.y = y or 0 + self.w = w or 16 + self.h = h or 16 + self.onGround = false + + self.playerID = -1 + + self:register() +end + +function Entity:setDebugColor(r,g,b) + self.debug = {} + self.debug.r = r + self.debug.g = r + self.debug.b = r +end + +function Entity:update(dt) + +end + +function Entity:register() -- On enregistre la hitbox dans le monde, pour l'instant les deux parties du programmes sont séparé (génération et enregistrement, peut-être qu'elles seront fusionnées) + self.world:add(self, self.x, self.y, self.w, self.h) +end + +function Entity:destroy() + self.world:remove(self) +end + +function Entity:canBounce(bounce) + self.bounce = bounce +end + +function Entity:setMotion(xsp, ysp) + self.xsp, self.ysp = xsp, ysp +end + +function Entity:setMotionDirection(dir,spd) + local dir = math.rad(dir) -- On commence par convertir la vitesse en radians + + local xsp, ysp, cos, sin + cos = math.cos(dir) + sin = math.sin(dir) + xsp = (spd * cos) + ysp = (spd * sin) + + self.xsp, self.ysp = xsp, ysp +end + +function Entity:gravity(dt) + self.ysp = self.ysp + self.gacc * self.grav * dt +end + +function Entity:friction(dt) + if (math.abs(self.xsp) <= self.frc) then + self.xsp = 0 + else + self.xsp = self.xsp - (self.frc * math.sign(self.xsp)) + end +end + +function Entity:changeSpeedToCollisionNormal(nx, ny) + local xsp, ysp = self.xsp, self.ysp + + if (nx < 0 and xsp > 0) or (nx > 0 and xsp < 0) then + xsp = -xsp * self.bounce + end + + if (ny < 0 and ysp > 0) or (ny > 0 and ysp < 0) then + ysp = -ysp * self.bounce + end + + self.xsp, self.ysp = xsp, ysp +end + +function Entity:getCenter() + return self.x + self.w / 2, + self.y + self.h / 2 +end + +function Entity:purge() + self.world:remove(self) +end + +function Entity:setFilter() + self.filter = function(item, other) + return nil + end +end + +function Entity:checkGround(ny) + if not (self.grav == 0) then + if ny < 0 then self.onGround = true end + end +end + +function Entity:move(dt) + self.onGround = false + local xsp, ysp = self.xsp * dt, self.ysp * dt + self.x, self.y, cols, cols_len = self.world:move(self, self.x + xsp, self.y + ysp, self.filter) + + for i=1, cols_len do + local col = cols[i] + if (col.type == "touch") or (col.type == "bounce") or (col.type == "slide") then + self:changeSpeedToCollisionNormal(col.normal.x, col.normal.y) + self:checkGround(col.normal.y) + end + end + + return cols, cols_len +end + +function Entity:getDirection() + if not (math.sign(self.xsp) == 0) then + self.direction = math.sign(self.xsp) + end +end + +function Entity:draw() + -- Cette fonction en contient rien par défaut +end diff --git a/imperium-porcorum.love/scenes/levels/entities/loot.lua b/imperium-porcorum.love/scenes/levels/entities/loot.lua new file mode 100644 index 0000000..06ab46e --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/loot.lua @@ -0,0 +1,26 @@ +Loot = Entity:extend() +Coin = Loot:extend() +WeaponLoot = Loot:extend() + +function Loot:new(level, name, value, x, y) + Loot.super.new(self, level, x, y, 16, 16) + self.value = value + self.collType = "loot" + self.name = name +end + +function Loot:takeLoot() + GFX(self.level, "sparkle", 1, self.x+8, self.y+8) + self:destroy() + self.level.gold = self.level.gold + 1 + assets:playSFX("collectcoin") +end + +function Loot:update(dt) + Loot.super.update(self, dt) +end + +function Loot:draw() + --local localx, localy = currentLevel.camera:cameraCoords(self.x, self.y) + assets.sprites[self.name]:draw(2, self.x, self.y) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/actions.lua b/imperium-porcorum.love/scenes/levels/entities/player/actions.lua new file mode 100644 index 0000000..5fd26af --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/actions.lua @@ -0,0 +1,59 @@ +function Player:shoot() + if self.gamepad.buttons["B"].press then + self:launchWeapon() + end + if self.gamepad.buttons["C"].press then + self:changeWeapon(self.weaponID+1) + end +end + +function Player:actionMove(dt) + local dx, dy = 0, 0 + + if self.gamepad.buttons["right"].down and not (self.gamepad.buttons["left"].down) then + if (self.xsp < self.topsp) then + if (self.xsp < 0) then + self.xsp = self.xsp + self.dec + else + self.xsp = self.xsp + self.acc + end + end + elseif self.gamepad.buttons["left"].down and not (self.gamepad.buttons["right"].down) then + if (self.xsp > -self.topsp) then + if (self.xsp > 0) then + self.xsp = self.xsp - self.dec + else + self.xsp = self.xsp - self.acc + end + end + else + self:friction(dt) + end + + if (self.grav == 0) then + if self.gamepad.buttons["down"].down and (self.y < 1000) then + self.ysp = 160 + elseif self.gamepad.buttons["up"].down and (self.y > 0) then + self.ysp = -160 + end + end + + if (self.onGround == true) then + self.isJumping = false + end + + multijump = true + + if ((self.onGround == true) or multijump) and self.gamepad.buttons["A"].press then + self.ysp = self.jmp + self.isJumping = true + assets:playSFX("jump") + assets.sprites["cochon"]:resetAnimation(self.animations["jump"]) + end + + if (self.isJumping == true) and (self.ysp < (-4 * 60)) and (not (self.gamepad.buttons["A"].down)) then + self.ysp = -4 * 60 + end + + return dx, dy +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/collisions.lua b/imperium-porcorum.love/scenes/levels/entities/player/collisions.lua new file mode 100644 index 0000000..74c640d --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/collisions.lua @@ -0,0 +1,22 @@ +function Player:resolveCollisions(cols, cols_len) + local cols, cols_len = cols, cols_len + for j=1,cols_len do + local other = cols[j].other + if (other.collType == "loot") then + other:takeLoot() + end + end +end + +function Player:setFilter() + self.filter = function(item, other) + if (other.collType == "wall") then return 'slide' + elseif (other.collType == "block") then return 'slide' + elseif (other.collType == "platform") and + (self.ysp > 0) and + ((self.y+24) <= other.y) then return 'slide' + elseif (other.collType == "loot") then return 'cross' + else return nil + end + end +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/draw.lua b/imperium-porcorum.love/scenes/levels/entities/player/draw.lua new file mode 100644 index 0000000..1f4b07d --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/draw.lua @@ -0,0 +1,44 @@ +function Player:initAnimations() + self.animations = {} + self.animations["idle"] = 1 + self.animations["walk"] = 2 + self.animations["brake"] = 3 + self.animations["jump"] = 4 + self.animations["fall"] = 5 +end + +function Player:getAnimation() +local animation = 1 + + if (self.onGround) then + if (self.xsp == 0) then + animation = "idle" + else + if (self.gamepad.buttons["left"].down and (self.xsp > 0)) or + (self.gamepad.buttons["right"].down and (self.xsp < 0)) then + animation = "brake" + else + animation = "walk" + end + end + else + if (self.ysp < 0) and (self.isJumping) then + animation = "jump" + else + animation = "fall" + end + end + + if (self.animations[animation] == nil) then + animation = "idle" + end + + return self.animations[animation] +end + +function Player:draw(dt) + local drawx, drawy = floorCoord(self.center.x, self.center.y) + local animation = self:getAnimation() + --if (self.direction == -1) then drawx = drawx + self.w end + assets.sprites[self.stats.race]:draw(animation, drawx, drawy, 0, self.direction, 1, 16, 36) +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/init.lua b/imperium-porcorum.love/scenes/levels/entities/player/init.lua new file mode 100644 index 0000000..dc37180 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/init.lua @@ -0,0 +1,47 @@ +Player = Entity:extend() + +require "scenes.levels.entities.player.draw" +require "scenes.levels.entities.player.actions" +require "scenes.levels.entities.player.collisions" +require "scenes.levels.entities.player.update" +require "scenes.levels.entities.player.pad" +require "scenes.levels.entities.player.movement" +require "scenes.levels.entities.player.life" +require "scenes.levels.entities.player.weapon" + +function Player:new(level, playerID, x, y) + + local w, h = 32, 24 + self.direction = 1 + + self.startx, self.starty = x, y + + self:initAnimations() + + Player.super.new(self, level, x - (w / 2), y - (h / 2), w, h) + + self.center = { + x = self.x, + y = self.y, + } + + self.stats = {} + self:getStats(playerID) + self:lifeInit() + self:initWeapon() + + self.currentWeapon = 1 + + self:initMovement() + self:padInit() + + self:setDebugColor(0,255,0) + self.collType = "player" + +end + +function Player:getStats(playerID) + self.pigID = self.level.players[playerID].pigID + self.stats = save:getPig(1) + self.playerID = playerID +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/life.lua b/imperium-porcorum.love/scenes/levels/entities/player/life.lua new file mode 100644 index 0000000..cdf969f --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/life.lua @@ -0,0 +1,23 @@ +function Player:lifeInit() + self.hp = self.stats.maxHP + self.mp = self.stats.maxMP +end + +function Player:takeHit(damage) + if (self.hp <= damage) then + self:die() + else + self.hp = self.hp - damage + end +end + +function Player:die() + --self.hp = self.stats.maxHP + --self.x = self.startx-16 + --self.y = self.starty-12 + --self.xsp = 0 + --self.ysp = 0 + --currentLevel.world:update(self, self.x,self.y) + self.level:setDeathTimer(1) + self:destroy() +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/movement.lua b/imperium-porcorum.love/scenes/levels/entities/player/movement.lua new file mode 100644 index 0000000..116a5e8 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/movement.lua @@ -0,0 +1,22 @@ +function Player:initMovement() + self.maxxsp = 16*60 + self.maxysp = self.maxxsp + self.topsp = 4.5*60 + self.acc = 0.046875*60*1.5 + self.dec = 0.5*60 + self.frc = self.acc + self.grav = 1 + self.jmp = - 6*60 + + self.isJumping = false +end + +function Player:limitMovement() + if (math.abs(self.xsp) >= self.maxxsp) then + self.xsp = self.maxxsp * math.sign(self.xsp) + end + + if (math.abs(self.ysp) >= self.maxysp) then + self.ysp = self.maxysp * math.sign(self.ysp) + end +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/pad.lua b/imperium-porcorum.love/scenes/levels/entities/player/pad.lua new file mode 100644 index 0000000..e77f807 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/pad.lua @@ -0,0 +1,74 @@ +function Player:padInit() + + self:padReset() + + self:padAddTouch("up") + self:padAddTouch("left") + self:padAddTouch("right") + self:padAddTouch("down") + + self:padAddTouch("A") + self:padAddTouch("B") + self:padAddTouch("C") + + self:padAddAnalogue() + + self:padAddTouch("select") + +end + +function Player:padReset() + self.gamepad = {} + self.gamepad.buttons = {} + self.gamepad.analogs = {} +end + +function Player:padAddTouch(touchname) + self.gamepad.buttons[touchname] = {} + self.gamepad.buttons[touchname].down = false + self.gamepad.buttons[touchname].rel = false + self.gamepad.buttons[touchname].press = false +end + +function Player:padAddAnalogue() + local id = #self.gamepad.analogs + 1 + self.gamepad.analogs[id] = {} + self.gamepad.analogs[id].angle = 0 + self.gamepad.analogs[id].strenght = 0 +end + +function Player:padPush(touchname, value) + if (value == true) then + -- Si le bouton est enfoncé, alors on ne peut pas l'avoir relaché + self.gamepad.buttons[touchname].rel = false + + + if (self.gamepad.buttons[touchname].down == true) then + -- Si le bouton était déjà pressé au début, alors on indique + -- qu'il ne vient pas d'être pressé. + self.gamepad.buttons[touchname].down = true + self.gamepad.buttons[touchname].press = false + else + -- Sinon, on indique qu'il viens d'être pressé, et + -- qu'il est enfoncé + self.gamepad.buttons[touchname].down = true + self.gamepad.buttons[touchname].press = true + end + + else + -- Si le bouton est relaché, alors on ne peut pas l'avoir pressé + self.gamepad.buttons[touchname].press = false + + if (self.gamepad.buttons[touchname].down == true) then + -- Si le bouton était déjà pressé au début, alors on indique + -- qu'il vient d'être relaché, et qu'il n'est plus enfoncé + self.gamepad.buttons[touchname].down = false + self.gamepad.buttons[touchname].rel = true + else + -- Sinon, on indique qu'il ne viens plus d'être relaché, et + -- qu'il n'est pas enfoncé, au cas ou. + self.gamepad.buttons[touchname].down = false + self.gamepad.buttons[touchname].rel = false + end + end +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/update.lua b/imperium-porcorum.love/scenes/levels/entities/player/update.lua new file mode 100644 index 0000000..6737f2a --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/update.lua @@ -0,0 +1,20 @@ +function Player:update(dt) + self:actionMove(dt) + + self:shoot(dt) + + self:gravity(dt) + self:limitMovement() + self:setFilter() + local cols, cols_len = self:move(dt) + + self:resolveCollisions(cols, cols_len) + + self.center.x, self.center.y = self:getCenter() + + self:getDirection() + + if self.y >= ((self.level.map.height * self.level.map.tileheight) + 64) then + self:die() + end +end diff --git a/imperium-porcorum.love/scenes/levels/entities/player/weapon.lua b/imperium-porcorum.love/scenes/levels/entities/player/weapon.lua new file mode 100644 index 0000000..90a3cb3 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/player/weapon.lua @@ -0,0 +1,18 @@ +function Player:initWeapon() + self.weaponID = 1 + self:setWeapon() +end + +function Player:launchWeapon() + Weapon(self.level, self.weapon, self.center.x, self.center.y, 350 * math.sign(self.direction)) +end + +function Player:changeWeapon(id) + local maxWeapon = #self.stats.weaponList + self.weaponID = wrap(id, maxWeapon) + self:setWeapon() +end + +function Player:setWeapon() + self.weapon = self.stats.weaponList[self.weaponID] +end diff --git a/imperium-porcorum.love/scenes/levels/entities/weapon.lua b/imperium-porcorum.love/scenes/levels/entities/weapon.lua new file mode 100644 index 0000000..12936df --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/entities/weapon.lua @@ -0,0 +1,58 @@ +Weapon = Entity:extend() + +function Weapon:new(level, id, x, y, xsp) + Weapon.super.new(self, level, x-8, y - 8, 16, 16) + self.weaponid = id + self.collType="weapon" + self.xsp = xsp + self.ysp = 0 + self.rotation = 0 +end + +function Weapon:setFilter() + self.filter = function(item, other) + if (other.collType=="wall") then + return 'touch' + elseif (other.collType=="block") then + return "touch" + else + return nil + end + end +end + +function Weapon:update(dt) + self:setFilter() + + self.rotation = self.rotation + (dt * 90)*8 + + --self.x, self.y, cols, cols_len = currentLevel.world:move(self, self.x + self.xsp*dt, self.y + self.ysp*dt, bulletFilter) + cols, cols_len = self:move(dt) + + for j=1,cols_len do + local other = cols[j].other + if other.collType=="wall" and (self.life == 1) then + self:destroy() + end + if other.collType=="block" and (self.life == 1) then + self:destroy() + other:breakBlock() + end + end + + self.life = 1 + + local localx, localy = self.level:cameraCoords(self.x, self.y) + if (localx < 0) or (localx > 480) or (localy < 0) or (localy > (272)) then + self:destroy() + end + + self:getDirection() +end + +function Weapon:draw(dt) + local rotation = math.floor(self.rotation/45)*45 + drawx, drawy = self:getCenter() + assets.sprites["weapon"]:draw(self.weaponid, drawx, drawy, rotation, + self.direction, 1, 8, 8) +end diff --git a/imperium-porcorum.love/scenes/levels/init.lua b/imperium-porcorum.love/scenes/levels/init.lua new file mode 100644 index 0000000..7a1f54e --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/init.lua @@ -0,0 +1,73 @@ +-- On charge les fichiers contenant les script gérant le gameplay +require "scenes.levels.sounds" +require "scenes.levels.sprites" + +require "scenes.levels.controller" +require "scenes.levels.entities" + +-- On commence par générer la scene : +stateLevel = {} +local currentLevel = Level() +local previousMenu + +-- On initialise les variables +--local map -- la carte + +-- Le code dédié à la génération du niveau commence ici -- + +-- levelLoad(mapName) est appellé à chaque fois qu'un niveau doit être chargé. +-- Cette fonction s'occupe de choisir le niveau et de changer de scene automatiquement +-- Cela permet de réduire la présence de la variable d'état à se fichier, et de communiquer +-- uniquement avec cette fonction + +function levelLoad(levelID, missionID) + level_loadSounds() + loadSprites() + + currentLevel:loadMission(levelID, missionID) + Gamestate.switch(stateLevel) +end + +function stateLevel:enter(previous, levelID, missionID) + level_loadSounds() + loadSprites() + previousMenu = previous + currentLevel:loadMission(levelID, missionID) +end + +function stateLevel:update(dt) + lovebird.update() + currentLevel:update(dt) +end + +function stateLevel:keypressed(key) + if (currentLevel.pause == true) then + if key == "escape" then + exitLevel() + end + end + -- Exit test + + if (key == "return") then + currentLevel.pause = invertBool(currentLevel.pause) + end +end + +function stateLevel:draw(dt) + CScreen:apply() + currentLevel:draw(dt) + CScreen:cease() +end + +function stateLevel:leave() + currentLevel:reset() +end + +function love.resize(w, h) + currentLevel.map:resize(w, h) +end + +function exitLevel() + currentLevel:reset() + Gamestate.switch(stateDebugMenu) +end diff --git a/imperium-porcorum.love/scenes/levels/sounds.lua b/imperium-porcorum.love/scenes/levels/sounds.lua new file mode 100644 index 0000000..c0af131 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/sounds.lua @@ -0,0 +1,6 @@ +function level_loadSounds() + assets:clearSFX() + assets:newSFX("jump") + assets:newSFX("break") + assets:newSFX("collectcoin") +end diff --git a/imperium-porcorum.love/scenes/levels/sprites.lua b/imperium-porcorum.love/scenes/levels/sprites.lua new file mode 100644 index 0000000..5d4b630 --- /dev/null +++ b/imperium-porcorum.love/scenes/levels/sprites.lua @@ -0,0 +1,53 @@ +function loadSprites() + assets:clearSprites() + + assets:addSprite("coin", 16, 16) + assets.sprites["coin"]:newAnimation(1, '1-4', 0.2) + assets.sprites["coin"]:newAnimation(2, '1-4', 0.2) + assets.sprites["coin"]:newAnimation(3, '1-4', 0.2) + + assets:addSprite("weapon", 16, 16) + assets.sprites["weapon"]:newAnimation(1, 2, 0.1) + assets.sprites["weapon"]:newAnimation(2, 2, 0.1) + + assets:addSprite("sparkle", 16, 16) + assets.sprites["sparkle"]:newAnimation('1-5', 1, 0.08, 'pauseAtEnd') + + loadCochonSprites("cochon") + loadCochonSprites("bling-bling") + + assets:addSprite("block", 16, 16) + assets.sprites["block"]:newAnimation(1, 1, 0.08) + assets.sprites["block"]:newAnimation(2, 1, 0.08) + assets.sprites["block"]:newAnimation(3, 1, 0.08) + assets.sprites["block"]:newAnimation(4, 1, 0.08) + assets.sprites["block"]:newAnimation(5, 1, 0.08) + + assets:addSprite("debris", 8, 8) + assets.sprites["debris"]:newAnimation(1, 1, 0.08) + + assets:addSprite("poof", 16, 16) + assets.sprites["poof"]:newAnimation('1-6', 1, 0.08, 'pauseAtEnd') + + assets:addSprite("lifeicons", 16, 16, "pigs/") + assets.sprites["lifeicons"]:newAnimation(1, 1, 0.08) + assets.sprites["lifeicons"]:newAnimation(2, 1, 0.08) + assets.sprites["lifeicons"]:newAnimation(3, 1, 0.08) + + assets:clearFonts() + assets:addFont("medium", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|} ", 1) + assets:addFont("small", "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ", 1) + + assets:addTextBox("yellowbox") + assets:addProgressBar("greenbar", "medium", "small") + assets:addProgressBar("bluebar", "medium", "small") +end + +function loadCochonSprites(name) + assets:addSprite(name, 32, 48, "pigs/") + assets.sprites[name]:newAnimation(2, 1, 0.2) + assets.sprites[name]:newAnimation('1-4', 1, 0.1) + assets.sprites[name]:newAnimation(5, 1, 0.2) + assets.sprites[name]:newAnimation('7-8', 1, 0.03, 'pauseAtEnd') + assets.sprites[name]:newAnimation(7, 1, 0.2) +end diff --git a/imperium-porcorum.love/scenes/mainmenu/init.lua b/imperium-porcorum.love/scenes/mainmenu/init.lua new file mode 100644 index 0000000..f9997d0 --- /dev/null +++ b/imperium-porcorum.love/scenes/mainmenu/init.lua @@ -0,0 +1,58 @@ +stateMainMenu = {} + +local backy +local menuID = 0 -- on met un fallback à 0 au cas-où + +function stateMainMenu:enter(previous) + assets:setBackground("back") + menus:reset() + mainmenu = GridBox(48, 48, 480-(48+48), 274-(48+32), 4, 4) + menus:addMenu(mainmenu) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + mainmenu:addWidget(DummyWidget()) + + mainmenu.focus = true + mainmenu:addCol(1) + mainmenu:addLine(1) + mainmenu:addCol(3) + mainmenu:addCol(7) + mainmenu:addLine(9) + mainmenu:addLine(10) + + --mainmenu:expandHorizontal(1) + --mainmenu:expandCol(1) + --mainmenu:expandCol(2) +end + +function stateMainMenu:update() + menus:update() +end + +function stateMainMenu:keyreleased(key, code) + menus:keyreleased(key, code) +end + +function stateMainMenu:mousemoved(x, y, dx, dy) + menus:mousemoved(x, y, dx, dy) +end + +function stateMainMenu:mousepressed( x, y, button, istouch ) + menus:mousepressed( x, y, button, istouch ) +end + +function stateMainMenu:draw(dt) + assets:drawBackground() + + menus:draw() +end