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 @@
+
+
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 @@
+
+
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