summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKikooDX <kikoodx@paranoici.org>2021-02-15 20:24:49 +0100
committerKikooDX <kikoodx@paranoici.org>2021-02-15 20:52:28 +0100
commitc69ea6a11b16076b5dc4229f26fb47bebfff0f6f (patch)
treea2925f3c59e4bc6a729e68174fae2d206014f781
downloaddisk-mayhem-c69ea6a11b16076b5dc4229f26fb47bebfff0f6f.tar.gz
Initial commit (it's pretty damn big).
Enjoy
-rw-r--r--.editorconfig13
-rw-r--r--.gitignore2
-rw-r--r--Boon.toml80
-rw-r--r--LICENSE29
-rw-r--r--README.md38
-rw-r--r--assets/art/animations/321GO.pngbin0 -> 253 bytes
-rw-r--r--assets/art/animations/jump_particle.pngbin0 -> 155 bytes
-rw-r--r--assets/art/animations/lava.pngbin0 -> 144 bytes
-rw-r--r--assets/art/animations/particles.pngbin0 -> 238 bytes
-rw-r--r--assets/art/animations/slash.pngbin0 -> 425 bytes
-rw-r--r--assets/art/animations/slime.pngbin0 -> 165 bytes
-rw-r--r--assets/art/animations/walk_particle.pngbin0 -> 139 bytes
-rw-r--r--assets/art/animations/water.pngbin0 -> 156 bytes
-rw-r--r--assets/art/characters/brave-scientist/brave-scientist-1b.pngbin0 -> 300 bytes
-rw-r--r--assets/art/characters/brave-scientist/brave-scientist-full.pngbin0 -> 3223 bytes
-rw-r--r--assets/art/characters/brave-scientist/brave-scientist-lose.pngbin0 -> 892 bytes
-rw-r--r--assets/art/characters/brave-scientist/brave-scientist-win.pngbin0 -> 1078 bytes
-rw-r--r--assets/art/characters/brave-scientist/brave-scientist.pngbin0 -> 286 bytes
-rw-r--r--assets/art/characters/jean-luc/jean-luc-1b.pngbin0 -> 284 bytes
-rw-r--r--assets/art/characters/jean-luc/jean-luc-full.pngbin0 -> 1725 bytes
-rw-r--r--assets/art/characters/jean-luc/jean-luc-lose.pngbin0 -> 606 bytes
-rw-r--r--assets/art/characters/jean-luc/jean-luc-win.pngbin0 -> 599 bytes
-rw-r--r--assets/art/characters/jean-luc/jean-luc.pngbin0 -> 250 bytes
-rw-r--r--assets/art/characters/neon/neon-1b.pngbin0 -> 285 bytes
-rw-r--r--assets/art/characters/neon/neon-full.pngbin0 -> 4308 bytes
-rw-r--r--assets/art/characters/neon/neon-lose.pngbin0 -> 1538 bytes
-rw-r--r--assets/art/characters/neon/neon-win.pngbin0 -> 1344 bytes
-rw-r--r--assets/art/characters/neon/neon.pngbin0 -> 294 bytes
-rw-r--r--assets/art/characters/saw-man/saw-man-1b.pngbin0 -> 306 bytes
-rw-r--r--assets/art/characters/saw-man/saw-man-full.pngbin0 -> 3022 bytes
-rw-r--r--assets/art/characters/saw-man/saw-man-lose.pngbin0 -> 1247 bytes
-rw-r--r--assets/art/characters/saw-man/saw-man-win.pngbin0 -> 1355 bytes
-rw-r--r--assets/art/characters/saw-man/saw-man.pngbin0 -> 295 bytes
-rw-r--r--assets/art/characters/scarlet/scarlet-1b.pngbin0 -> 294 bytes
-rw-r--r--assets/art/characters/scarlet/scarlet-full.pngbin0 -> 4407 bytes
-rw-r--r--assets/art/characters/scarlet/scarlet-lose.pngbin0 -> 1507 bytes
-rw-r--r--assets/art/characters/scarlet/scarlet-win.pngbin0 -> 1399 bytes
-rw-r--r--assets/art/characters/scarlet/scarlet.pngbin0 -> 293 bytes
-rw-r--r--assets/art/characters/theophile/theophile-1b.pngbin0 -> 303 bytes
-rw-r--r--assets/art/characters/theophile/theophile-full.pngbin0 -> 5118 bytes
-rw-r--r--assets/art/characters/theophile/theophile-lose.pngbin0 -> 1360 bytes
-rw-r--r--assets/art/characters/theophile/theophile-win.pngbin0 -> 1290 bytes
-rw-r--r--assets/art/characters/theophile/theophile.pngbin0 -> 302 bytes
-rw-r--r--assets/art/menu/bg-itch.pngbin0 -> 39172 bytes
-rw-r--r--assets/art/menu/character-selected.pngbin0 -> 1425 bytes
-rw-r--r--assets/art/menu/characters.pngbin0 -> 660 bytes
-rw-r--r--assets/art/menu/cover-itch.pngbin0 -> 3156 bytes
-rw-r--r--assets/art/menu/cursor.pngbin0 -> 256 bytes
-rw-r--r--assets/art/menu/jean-luc_likes_baguette.pngbin0 -> 827 bytes
-rw-r--r--assets/art/menu/logo-itch.pngbin0 -> 5440 bytes
-rw-r--r--assets/art/menu/logo.pngbin0 -> 5089 bytes
-rw-r--r--assets/art/menu/menu-discroom.pngbin0 -> 476 bytes
-rw-r--r--assets/art/menu/menu-fire.pngbin0 -> 945 bytes
-rw-r--r--assets/art/menu/menu-jungle.pngbin0 -> 638 bytes
-rw-r--r--assets/art/menu/menu-nothern.pngbin0 -> 686 bytes
-rw-r--r--assets/art/menu/menu-sky.pngbin0 -> 613 bytes
-rw-r--r--assets/art/menu/menu-weirdo.pngbin0 -> 281 bytes
-rw-r--r--assets/art/menu/scarlet_the_sheep_killer.pngbin0 -> 2990 bytes
-rw-r--r--assets/art/menu/title.pngbin0 -> 390 bytes
-rw-r--r--assets/art/objects/disk.pngbin0 -> 285 bytes
-rw-r--r--assets/art/objects/disk_highlight.pngbin0 -> 285 bytes
-rw-r--r--assets/art/objects/disk_white.pngbin0 -> 303 bytes
-rw-r--r--assets/art/tileset/disk-of-doom-bg.pngbin0 -> 675 bytes
-rw-r--r--assets/art/tileset/disk-of-doom.pngbin0 -> 681 bytes
-rw-r--r--assets/art/tileset/hyperion-bg.pngbin0 -> 2347 bytes
-rw-r--r--assets/art/tileset/hyperion.pngbin0 -> 3873 bytes
-rw-r--r--assets/art/tileset/nothern-fortress-bg.pngbin0 -> 1681 bytes
-rw-r--r--assets/art/tileset/nothern-fortress.pngbin0 -> 3939 bytes
-rw-r--r--assets/art/tileset/objects.pngbin0 -> 134 bytes
-rw-r--r--assets/art/tileset/qujna-bg.pngbin0 -> 2106 bytes
-rw-r--r--assets/art/tileset/qujna.pngbin0 -> 3038 bytes
-rw-r--r--assets/art/tileset/thermopolis-bg.pngbin0 -> 3202 bytes
-rw-r--r--assets/art/tileset/thermopolis.pngbin0 -> 3174 bytes
-rw-r--r--assets/art/tileset/weirdo.pngbin0 -> 707 bytes
-rw-r--r--assets/art/ui/tag.pngbin0 -> 134 bytes
-rw-r--r--assets/art/ui/uip1.asebin0 -> 1021 bytes
-rw-r--r--assets/art/ui/uip1.pngbin0 -> 222 bytes
-rw-r--r--assets/art/ui/uip2.asebin0 -> 1030 bytes
-rw-r--r--assets/art/ui/uip2.pngbin0 -> 216 bytes
-rw-r--r--assets/fonts/m04b.TTFbin0 -> 14480 bytes
-rw-r--r--assets/sfx/bounce.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/bounce.wavbin0 -> 5168 bytes
-rw-r--r--assets/sfx/cancel.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/cancel.wavbin0 -> 5952 bytes
-rw-r--r--assets/sfx/confirm.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/confirm.wavbin0 -> 11120 bytes
-rw-r--r--assets/sfx/death.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/death.wavbin0 -> 63764 bytes
-rw-r--r--assets/sfx/hurt.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/hurt.wavbin0 -> 13532 bytes
-rw-r--r--assets/sfx/jump.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/jump.wavbin0 -> 15506 bytes
-rw-r--r--assets/sfx/select.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/select.wavbin0 -> 3432 bytes
-rw-r--r--assets/sfx/throw.mkvbin0 -> 105 bytes
-rw-r--r--assets/sfx/throw.wavbin0 -> 27864 bytes
-rw-r--r--conf.lua15
-rw-r--r--favicon.pngbin0 -> 535 bytes
-rw-r--r--libs/anim8.lua302
-rw-r--r--libs/baton.lua368
-rw-r--r--libs/classic.lua68
-rw-r--r--libs/deep.lua83
-rw-r--r--libs/push.lua281
-rw-r--r--libs/shack.lua146
-rw-r--r--libs/vector.lua211
-rw-r--r--main.lua178
-rw-r--r--menu_conf.lua42
-rw-r--r--player_conf.lua61
-rw-r--r--src/count.lua9
-rw-r--r--src/debugdisp.lua31
-rw-r--r--src/disk.lua125
-rw-r--r--src/diskspawner.lua46
-rw-r--r--src/entity.lua64
-rw-r--r--src/force.lua11
-rw-r--r--src/hitbox.lua36
-rw-r--r--src/lava.lua18
-rw-r--r--src/liquid.lua13
-rw-r--r--src/menu/mainmenu.lua417
-rw-r--r--src/menu/pause.lua137
-rw-r--r--src/menu/results.lua98
-rw-r--r--src/music.lua26
-rw-r--r--src/object.lua16
-rw-r--r--src/particle.lua62
-rw-r--r--src/particule.lua1
-rw-r--r--src/play_sfx.lua8
-rw-r--r--src/player.lua327
-rw-r--r--src/screenshake.lua5
-rw-r--r--src/sign.lua5
-rw-r--r--src/slash.lua97
-rw-r--r--src/slime.lua18
-rw-r--r--src/solid.lua21
-rw-r--r--src/stage.lua190
-rw-r--r--src/tileentity.lua10
-rw-r--r--src/ui.lua52
-rw-r--r--src/walk_particle.lua50
-rw-r--r--src/water.lua31
-rw-r--r--stages/discroom.lua234
-rw-r--r--stages/discroom.tmx111
-rw-r--r--stages/disk-of-doom.tsx4
-rw-r--r--stages/fire.lua246
-rw-r--r--stages/fire.tmx111
-rw-r--r--stages/hyperion.tsx4
-rw-r--r--stages/jungle.lua263
-rw-r--r--stages/jungle.tmx113
-rw-r--r--stages/mainmenu.lua171
-rw-r--r--stages/mainmenu.tmx87
-rw-r--r--stages/nothern.lua372
-rw-r--r--stages/nothern.tmx160
-rw-r--r--stages/nothern.tsx4
-rw-r--r--stages/objects.tsx4
-rw-r--r--stages/objecttypes.xml21
-rw-r--r--stages/qujna.tsx4
-rw-r--r--stages/sky.lua293
-rw-r--r--stages/sky.tmx129
-rw-r--r--stages/thermopolis.tsx4
-rw-r--r--stages/weirdo.lua351
-rw-r--r--stages/weirdo.tmx147
-rw-r--r--stages/weirdo.tsx4
158 files changed, 6678 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..57dc925
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+# editorconfig.org
+
+root = true
+
+[*]
+end_of_line = rf
+insert_final_newline = true
+
+[*.lua]
+charset = utf-8
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7cbb165
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+main.sublime-workspace
+release
diff --git a/Boon.toml b/Boon.toml
new file mode 100644
index 0000000..6c05891
--- /dev/null
+++ b/Boon.toml
@@ -0,0 +1,80 @@
+#
+# General project settings
+#
+[project]
+# Author information. If you have a company, then use that in this
+# field instead.
+authors = "KikooDX & Masséna"
+
+# A description of your game. Not used in all builds.
+description = "Slice your friends in half in this chaotic 2D platformer fighter!"
+
+# An email to contact for support or more information. Not used
+# in all builds.
+email = "kikoodx@paranoici.org"
+
+# A short abbreviated name. Ideally, it should not contain spaces
+# or other special characters, though they can be used. On Windows,
+# this will end up as the name of the executable file.
+# Example: "My Game" and package_name="my_game" becomes "my_game.exe"
+package_name = "disk_mayhem"
+
+# The name of your game. This will be used when distributing the Game
+# as a zip file. On macOS, this is also used as the app file name.
+title = "Disk Mayhem"
+
+# The website associated with your game. Not used in all builds.
+url = "https://owo-team.itch.io/disk-mayhem/"
+
+# The Uniform Type Identifier for your game. This is required for the
+# macOS build of the game.
+uti = "com.owoteam.diskmayhem"
+
+# An arbitrary version for the current iteration of the game. Can use
+# any desired version format. This will be used to differentiate the
+# resulting build files.
+version = "free-build-1"
+
+#
+# Build settings
+#
+[build]
+# The name of the directory where releases will be placed after building.
+# IMPORTANT: If you change this from the default, you should also change it in
+# IMPORTANT: ignore_list so that you do not add prebuilt files to your build.
+output_directory = "release"
+
+# List of patterns to exclude when building. Each item is a regular
+# expression, which when matched, will exclude the matched file or
+# directory from the build.
+ignore_list = [
+ # Git
+ "^.git.*",
+
+ # Binary files
+ ".zip$",
+ ".tar.gz$",
+ ".love$",
+ ".exe$",
+
+ # Tiled files
+ ".tmx$",
+ ".tsx$",
+
+ # Aseprite files
+ ".ase$",
+ ".aseprite$",
+
+ # Boon-specific files and directories
+ "Boon.toml",
+ "release",
+ ".editorconfig",
+
+ # user scripts
+ ".sh$",
+]
+
+# If this is set to true, then the default ignore list will not be
+# merged with the project specific ignore list. This allows the
+# ignore list to be completely overwritten.
+exclude_default_ignore_list = false
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..40bff6d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+THE FOLLOWING LICENSE APPLIES TO ANY AND ALL SOURCE CODE PRESENT IN THIS REPOSITORY
+
+Copyright © 2020-2021 KikooDX, Massena
+
+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.
+
+
+THE FOLLOWING LICENSE APPLIES TO ALL GRAPHICAL (except fonts), AUDIO AND LEVEL ASSETS PRESENT IN THIS REPOSITORY
+
+Copyright © 2020-2021 Massena, KikooDX
+
+This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
+To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or
+send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..184242e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,38 @@
+# Disk Mayhem
+Disk Mayhem is a fun two players platformer fighter, where the last slicer alive wins.
+Quickly chaotic, each of the six arenas will put your skills to the test in a different way.
+Jump, slash and throw saws to the win. And most importantly, have fun!
+
+To play the game quickly, you can clone this repository and run it with LÖVE:
+```sh
+$ git clone <this repo clone URL> disk-mayhem
+$ love disk-mayhem
+```
+Two gamepads is the recommanded way to play.
+The jam build is also available at owo-team.itch.io
+
+# Who made this?
+This game was made by KikooDX (~kikoodx) and Massena (~massenouille) for the Disc Room
+game jam. It was integraly made in two weeks, and mistakes were made organisation wise.
+We hope than making this project free and open source will be appreciated.
+
+# How?
+For a framework we choosed LÖVE and amazing MIT libraries.
+We used sfxr for audio, Aseprite for graphics and Tiled for level design.
+
+## Libraries used
+- https://github.com/kikito/anim8
+- https://github.com/tesselode/baton
+- https://github.com/rxi/classic/
+- https://github.com/Nikaoto/deep
+- https://github.com/Ulydev/push
+- https://github.com/Ulydev/shack
+- https://github.com/themousery/vector.lua
+
+Big thank you to the LÖVE contributors and LÖVE libraries creators.
+
+# Assets used
+http://mfs.jp.org/ font.
+
+# License
+The code is licensed under MIT license, the rest is CC-BY-SA 4.0. See LICENSE for more details.
diff --git a/assets/art/animations/321GO.png b/assets/art/animations/321GO.png
new file mode 100644
index 0000000..13ff51a
--- /dev/null
+++ b/assets/art/animations/321GO.png
Binary files differ
diff --git a/assets/art/animations/jump_particle.png b/assets/art/animations/jump_particle.png
new file mode 100644
index 0000000..304da2b
--- /dev/null
+++ b/assets/art/animations/jump_particle.png
Binary files differ
diff --git a/assets/art/animations/lava.png b/assets/art/animations/lava.png
new file mode 100644
index 0000000..12c3925
--- /dev/null
+++ b/assets/art/animations/lava.png
Binary files differ
diff --git a/assets/art/animations/particles.png b/assets/art/animations/particles.png
new file mode 100644
index 0000000..2b007b7
--- /dev/null
+++ b/assets/art/animations/particles.png
Binary files differ
diff --git a/assets/art/animations/slash.png b/assets/art/animations/slash.png
new file mode 100644
index 0000000..3ac337f
--- /dev/null
+++ b/assets/art/animations/slash.png
Binary files differ
diff --git a/assets/art/animations/slime.png b/assets/art/animations/slime.png
new file mode 100644
index 0000000..19d929f
--- /dev/null
+++ b/assets/art/animations/slime.png
Binary files differ
diff --git a/assets/art/animations/walk_particle.png b/assets/art/animations/walk_particle.png
new file mode 100644
index 0000000..5f00eed
--- /dev/null
+++ b/assets/art/animations/walk_particle.png
Binary files differ
diff --git a/assets/art/animations/water.png b/assets/art/animations/water.png
new file mode 100644
index 0000000..a088081
--- /dev/null
+++ b/assets/art/animations/water.png
Binary files differ
diff --git a/assets/art/characters/brave-scientist/brave-scientist-1b.png b/assets/art/characters/brave-scientist/brave-scientist-1b.png
new file mode 100644
index 0000000..710e1cc
--- /dev/null
+++ b/assets/art/characters/brave-scientist/brave-scientist-1b.png
Binary files differ
diff --git a/assets/art/characters/brave-scientist/brave-scientist-full.png b/assets/art/characters/brave-scientist/brave-scientist-full.png
new file mode 100644
index 0000000..034d968
--- /dev/null
+++ b/assets/art/characters/brave-scientist/brave-scientist-full.png
Binary files differ
diff --git a/assets/art/characters/brave-scientist/brave-scientist-lose.png b/assets/art/characters/brave-scientist/brave-scientist-lose.png
new file mode 100644
index 0000000..e465986
--- /dev/null
+++ b/assets/art/characters/brave-scientist/brave-scientist-lose.png
Binary files differ
diff --git a/assets/art/characters/brave-scientist/brave-scientist-win.png b/assets/art/characters/brave-scientist/brave-scientist-win.png
new file mode 100644
index 0000000..ebb5463
--- /dev/null
+++ b/assets/art/characters/brave-scientist/brave-scientist-win.png
Binary files differ
diff --git a/assets/art/characters/brave-scientist/brave-scientist.png b/assets/art/characters/brave-scientist/brave-scientist.png
new file mode 100644
index 0000000..35bd76e
--- /dev/null
+++ b/assets/art/characters/brave-scientist/brave-scientist.png
Binary files differ
diff --git a/assets/art/characters/jean-luc/jean-luc-1b.png b/assets/art/characters/jean-luc/jean-luc-1b.png
new file mode 100644
index 0000000..8be970e
--- /dev/null
+++ b/assets/art/characters/jean-luc/jean-luc-1b.png
Binary files differ
diff --git a/assets/art/characters/jean-luc/jean-luc-full.png b/assets/art/characters/jean-luc/jean-luc-full.png
new file mode 100644
index 0000000..a090ed5
--- /dev/null
+++ b/assets/art/characters/jean-luc/jean-luc-full.png
Binary files differ
diff --git a/assets/art/characters/jean-luc/jean-luc-lose.png b/assets/art/characters/jean-luc/jean-luc-lose.png
new file mode 100644
index 0000000..e919b34
--- /dev/null
+++ b/assets/art/characters/jean-luc/jean-luc-lose.png
Binary files differ
diff --git a/assets/art/characters/jean-luc/jean-luc-win.png b/assets/art/characters/jean-luc/jean-luc-win.png
new file mode 100644
index 0000000..9c7de9d
--- /dev/null
+++ b/assets/art/characters/jean-luc/jean-luc-win.png
Binary files differ
diff --git a/assets/art/characters/jean-luc/jean-luc.png b/assets/art/characters/jean-luc/jean-luc.png
new file mode 100644
index 0000000..5f941e6
--- /dev/null
+++ b/assets/art/characters/jean-luc/jean-luc.png
Binary files differ
diff --git a/assets/art/characters/neon/neon-1b.png b/assets/art/characters/neon/neon-1b.png
new file mode 100644
index 0000000..2dad255
--- /dev/null
+++ b/assets/art/characters/neon/neon-1b.png
Binary files differ
diff --git a/assets/art/characters/neon/neon-full.png b/assets/art/characters/neon/neon-full.png
new file mode 100644
index 0000000..ec0edd6
--- /dev/null
+++ b/assets/art/characters/neon/neon-full.png
Binary files differ
diff --git a/assets/art/characters/neon/neon-lose.png b/assets/art/characters/neon/neon-lose.png
new file mode 100644
index 0000000..97067e3
--- /dev/null
+++ b/assets/art/characters/neon/neon-lose.png
Binary files differ
diff --git a/assets/art/characters/neon/neon-win.png b/assets/art/characters/neon/neon-win.png
new file mode 100644
index 0000000..3d2747c
--- /dev/null
+++ b/assets/art/characters/neon/neon-win.png
Binary files differ
diff --git a/assets/art/characters/neon/neon.png b/assets/art/characters/neon/neon.png
new file mode 100644
index 0000000..f75299a
--- /dev/null
+++ b/assets/art/characters/neon/neon.png
Binary files differ
diff --git a/assets/art/characters/saw-man/saw-man-1b.png b/assets/art/characters/saw-man/saw-man-1b.png
new file mode 100644
index 0000000..63ff60f
--- /dev/null
+++ b/assets/art/characters/saw-man/saw-man-1b.png
Binary files differ
diff --git a/assets/art/characters/saw-man/saw-man-full.png b/assets/art/characters/saw-man/saw-man-full.png
new file mode 100644
index 0000000..73bb772
--- /dev/null
+++ b/assets/art/characters/saw-man/saw-man-full.png
Binary files differ
diff --git a/assets/art/characters/saw-man/saw-man-lose.png b/assets/art/characters/saw-man/saw-man-lose.png
new file mode 100644
index 0000000..e09fcb4
--- /dev/null
+++ b/assets/art/characters/saw-man/saw-man-lose.png
Binary files differ
diff --git a/assets/art/characters/saw-man/saw-man-win.png b/assets/art/characters/saw-man/saw-man-win.png
new file mode 100644
index 0000000..2c0431f
--- /dev/null
+++ b/assets/art/characters/saw-man/saw-man-win.png
Binary files differ
diff --git a/assets/art/characters/saw-man/saw-man.png b/assets/art/characters/saw-man/saw-man.png
new file mode 100644
index 0000000..3bdcb66
--- /dev/null
+++ b/assets/art/characters/saw-man/saw-man.png
Binary files differ
diff --git a/assets/art/characters/scarlet/scarlet-1b.png b/assets/art/characters/scarlet/scarlet-1b.png
new file mode 100644
index 0000000..f42d551
--- /dev/null
+++ b/assets/art/characters/scarlet/scarlet-1b.png
Binary files differ
diff --git a/assets/art/characters/scarlet/scarlet-full.png b/assets/art/characters/scarlet/scarlet-full.png
new file mode 100644
index 0000000..58019a8
--- /dev/null
+++ b/assets/art/characters/scarlet/scarlet-full.png
Binary files differ
diff --git a/assets/art/characters/scarlet/scarlet-lose.png b/assets/art/characters/scarlet/scarlet-lose.png
new file mode 100644
index 0000000..3c96768
--- /dev/null
+++ b/assets/art/characters/scarlet/scarlet-lose.png
Binary files differ
diff --git a/assets/art/characters/scarlet/scarlet-win.png b/assets/art/characters/scarlet/scarlet-win.png
new file mode 100644
index 0000000..160940c
--- /dev/null
+++ b/assets/art/characters/scarlet/scarlet-win.png
Binary files differ
diff --git a/assets/art/characters/scarlet/scarlet.png b/assets/art/characters/scarlet/scarlet.png
new file mode 100644
index 0000000..88f55fc
--- /dev/null
+++ b/assets/art/characters/scarlet/scarlet.png
Binary files differ
diff --git a/assets/art/characters/theophile/theophile-1b.png b/assets/art/characters/theophile/theophile-1b.png
new file mode 100644
index 0000000..b3e6306
--- /dev/null
+++ b/assets/art/characters/theophile/theophile-1b.png
Binary files differ
diff --git a/assets/art/characters/theophile/theophile-full.png b/assets/art/characters/theophile/theophile-full.png
new file mode 100644
index 0000000..3dad93d
--- /dev/null
+++ b/assets/art/characters/theophile/theophile-full.png
Binary files differ
diff --git a/assets/art/characters/theophile/theophile-lose.png b/assets/art/characters/theophile/theophile-lose.png
new file mode 100644
index 0000000..bcc7440
--- /dev/null
+++ b/assets/art/characters/theophile/theophile-lose.png
Binary files differ
diff --git a/assets/art/characters/theophile/theophile-win.png b/assets/art/characters/theophile/theophile-win.png
new file mode 100644
index 0000000..a315904
--- /dev/null
+++ b/assets/art/characters/theophile/theophile-win.png
Binary files differ
diff --git a/assets/art/characters/theophile/theophile.png b/assets/art/characters/theophile/theophile.png
new file mode 100644
index 0000000..a4b83a2
--- /dev/null
+++ b/assets/art/characters/theophile/theophile.png
Binary files differ
diff --git a/assets/art/menu/bg-itch.png b/assets/art/menu/bg-itch.png
new file mode 100644
index 0000000..73e5de5
--- /dev/null
+++ b/assets/art/menu/bg-itch.png
Binary files differ
diff --git a/assets/art/menu/character-selected.png b/assets/art/menu/character-selected.png
new file mode 100644
index 0000000..fda3dfb
--- /dev/null
+++ b/assets/art/menu/character-selected.png
Binary files differ
diff --git a/assets/art/menu/characters.png b/assets/art/menu/characters.png
new file mode 100644
index 0000000..d611abe
--- /dev/null
+++ b/assets/art/menu/characters.png
Binary files differ
diff --git a/assets/art/menu/cover-itch.png b/assets/art/menu/cover-itch.png
new file mode 100644
index 0000000..7d9b964
--- /dev/null
+++ b/assets/art/menu/cover-itch.png
Binary files differ
diff --git a/assets/art/menu/cursor.png b/assets/art/menu/cursor.png
new file mode 100644
index 0000000..de3349c
--- /dev/null
+++ b/assets/art/menu/cursor.png
Binary files differ
diff --git a/assets/art/menu/jean-luc_likes_baguette.png b/assets/art/menu/jean-luc_likes_baguette.png
new file mode 100644
index 0000000..2f85f2f
--- /dev/null
+++ b/assets/art/menu/jean-luc_likes_baguette.png
Binary files differ
diff --git a/assets/art/menu/logo-itch.png b/assets/art/menu/logo-itch.png
new file mode 100644
index 0000000..5143b9e
--- /dev/null
+++ b/assets/art/menu/logo-itch.png
Binary files differ
diff --git a/assets/art/menu/logo.png b/assets/art/menu/logo.png
new file mode 100644
index 0000000..380659e
--- /dev/null
+++ b/assets/art/menu/logo.png
Binary files differ
diff --git a/assets/art/menu/menu-discroom.png b/assets/art/menu/menu-discroom.png
new file mode 100644
index 0000000..ef10052
--- /dev/null
+++ b/assets/art/menu/menu-discroom.png
Binary files differ
diff --git a/assets/art/menu/menu-fire.png b/assets/art/menu/menu-fire.png
new file mode 100644
index 0000000..0b3c592
--- /dev/null
+++ b/assets/art/menu/menu-fire.png
Binary files differ
diff --git a/assets/art/menu/menu-jungle.png b/assets/art/menu/menu-jungle.png
new file mode 100644
index 0000000..ac78beb
--- /dev/null
+++ b/assets/art/menu/menu-jungle.png
Binary files differ
diff --git a/assets/art/menu/menu-nothern.png b/assets/art/menu/menu-nothern.png
new file mode 100644
index 0000000..b4f2e8c
--- /dev/null
+++ b/assets/art/menu/menu-nothern.png
Binary files differ
diff --git a/assets/art/menu/menu-sky.png b/assets/art/menu/menu-sky.png
new file mode 100644
index 0000000..2094f8e
--- /dev/null
+++ b/assets/art/menu/menu-sky.png
Binary files differ
diff --git a/assets/art/menu/menu-weirdo.png b/assets/art/menu/menu-weirdo.png
new file mode 100644
index 0000000..60017d9
--- /dev/null
+++ b/assets/art/menu/menu-weirdo.png
Binary files differ
diff --git a/assets/art/menu/scarlet_the_sheep_killer.png b/assets/art/menu/scarlet_the_sheep_killer.png
new file mode 100644
index 0000000..0eec4cc
--- /dev/null
+++ b/assets/art/menu/scarlet_the_sheep_killer.png
Binary files differ
diff --git a/assets/art/menu/title.png b/assets/art/menu/title.png
new file mode 100644
index 0000000..0d85137
--- /dev/null
+++ b/assets/art/menu/title.png
Binary files differ
diff --git a/assets/art/objects/disk.png b/assets/art/objects/disk.png
new file mode 100644
index 0000000..ee07862
--- /dev/null
+++ b/assets/art/objects/disk.png
Binary files differ
diff --git a/assets/art/objects/disk_highlight.png b/assets/art/objects/disk_highlight.png
new file mode 100644
index 0000000..6b22304
--- /dev/null
+++ b/assets/art/objects/disk_highlight.png
Binary files differ
diff --git a/assets/art/objects/disk_white.png b/assets/art/objects/disk_white.png
new file mode 100644
index 0000000..386e60f
--- /dev/null
+++ b/assets/art/objects/disk_white.png
Binary files differ
diff --git a/assets/art/tileset/disk-of-doom-bg.png b/assets/art/tileset/disk-of-doom-bg.png
new file mode 100644
index 0000000..418edc6
--- /dev/null
+++ b/assets/art/tileset/disk-of-doom-bg.png
Binary files differ
diff --git a/assets/art/tileset/disk-of-doom.png b/assets/art/tileset/disk-of-doom.png
new file mode 100644
index 0000000..2774a2b
--- /dev/null
+++ b/assets/art/tileset/disk-of-doom.png
Binary files differ
diff --git a/assets/art/tileset/hyperion-bg.png b/assets/art/tileset/hyperion-bg.png
new file mode 100644
index 0000000..ee250d5
--- /dev/null
+++ b/assets/art/tileset/hyperion-bg.png
Binary files differ
diff --git a/assets/art/tileset/hyperion.png b/assets/art/tileset/hyperion.png
new file mode 100644
index 0000000..26bf032
--- /dev/null
+++ b/assets/art/tileset/hyperion.png
Binary files differ
diff --git a/assets/art/tileset/nothern-fortress-bg.png b/assets/art/tileset/nothern-fortress-bg.png
new file mode 100644
index 0000000..e9ac997
--- /dev/null
+++ b/assets/art/tileset/nothern-fortress-bg.png
Binary files differ
diff --git a/assets/art/tileset/nothern-fortress.png b/assets/art/tileset/nothern-fortress.png
new file mode 100644
index 0000000..b1b7b45
--- /dev/null
+++ b/assets/art/tileset/nothern-fortress.png
Binary files differ
diff --git a/assets/art/tileset/objects.png b/assets/art/tileset/objects.png
new file mode 100644
index 0000000..f0a18e6
--- /dev/null
+++ b/assets/art/tileset/objects.png
Binary files differ
diff --git a/assets/art/tileset/qujna-bg.png b/assets/art/tileset/qujna-bg.png
new file mode 100644
index 0000000..54dbe73
--- /dev/null
+++ b/assets/art/tileset/qujna-bg.png
Binary files differ
diff --git a/assets/art/tileset/qujna.png b/assets/art/tileset/qujna.png
new file mode 100644
index 0000000..a143321
--- /dev/null
+++ b/assets/art/tileset/qujna.png
Binary files differ
diff --git a/assets/art/tileset/thermopolis-bg.png b/assets/art/tileset/thermopolis-bg.png
new file mode 100644
index 0000000..11c8a80
--- /dev/null
+++ b/assets/art/tileset/thermopolis-bg.png
Binary files differ
diff --git a/assets/art/tileset/thermopolis.png b/assets/art/tileset/thermopolis.png
new file mode 100644
index 0000000..f4cdc2f
--- /dev/null
+++ b/assets/art/tileset/thermopolis.png
Binary files differ
diff --git a/assets/art/tileset/weirdo.png b/assets/art/tileset/weirdo.png
new file mode 100644
index 0000000..04552d9
--- /dev/null
+++ b/assets/art/tileset/weirdo.png
Binary files differ
diff --git a/assets/art/ui/tag.png b/assets/art/ui/tag.png
new file mode 100644
index 0000000..9883d2a
--- /dev/null
+++ b/assets/art/ui/tag.png
Binary files differ
diff --git a/assets/art/ui/uip1.ase b/assets/art/ui/uip1.ase
new file mode 100644
index 0000000..2de6e12
--- /dev/null
+++ b/assets/art/ui/uip1.ase
Binary files differ
diff --git a/assets/art/ui/uip1.png b/assets/art/ui/uip1.png
new file mode 100644
index 0000000..2260583
--- /dev/null
+++ b/assets/art/ui/uip1.png
Binary files differ
diff --git a/assets/art/ui/uip2.ase b/assets/art/ui/uip2.ase
new file mode 100644
index 0000000..e2d2141
--- /dev/null
+++ b/assets/art/ui/uip2.ase
Binary files differ
diff --git a/assets/art/ui/uip2.png b/assets/art/ui/uip2.png
new file mode 100644
index 0000000..2ead398
--- /dev/null
+++ b/assets/art/ui/uip2.png
Binary files differ
diff --git a/assets/fonts/m04b.TTF b/assets/fonts/m04b.TTF
new file mode 100644
index 0000000..52f9b03
--- /dev/null
+++ b/assets/fonts/m04b.TTF
Binary files differ
diff --git a/assets/sfx/bounce.mkv b/assets/sfx/bounce.mkv
new file mode 100644
index 0000000..20545e1
--- /dev/null
+++ b/assets/sfx/bounce.mkv
Binary files differ
diff --git a/assets/sfx/bounce.wav b/assets/sfx/bounce.wav
new file mode 100644
index 0000000..c37ed02
--- /dev/null
+++ b/assets/sfx/bounce.wav
Binary files differ
diff --git a/assets/sfx/cancel.mkv b/assets/sfx/cancel.mkv
new file mode 100644
index 0000000..7e3f2ab
--- /dev/null
+++ b/assets/sfx/cancel.mkv
Binary files differ
diff --git a/assets/sfx/cancel.wav b/assets/sfx/cancel.wav
new file mode 100644
index 0000000..a2ca484
--- /dev/null
+++ b/assets/sfx/cancel.wav
Binary files differ
diff --git a/assets/sfx/confirm.mkv b/assets/sfx/confirm.mkv
new file mode 100644
index 0000000..c64739a
--- /dev/null
+++ b/assets/sfx/confirm.mkv
Binary files differ
diff --git a/assets/sfx/confirm.wav b/assets/sfx/confirm.wav
new file mode 100644
index 0000000..78e9f0e
--- /dev/null
+++ b/assets/sfx/confirm.wav
Binary files differ
diff --git a/assets/sfx/death.mkv b/assets/sfx/death.mkv
new file mode 100644
index 0000000..7f32272
--- /dev/null
+++ b/assets/sfx/death.mkv
Binary files differ
diff --git a/assets/sfx/death.wav b/assets/sfx/death.wav
new file mode 100644
index 0000000..7c6aa5f
--- /dev/null
+++ b/assets/sfx/death.wav
Binary files differ
diff --git a/assets/sfx/hurt.mkv b/assets/sfx/hurt.mkv
new file mode 100644
index 0000000..197d360
--- /dev/null
+++ b/assets/sfx/hurt.mkv
Binary files differ
diff --git a/assets/sfx/hurt.wav b/assets/sfx/hurt.wav
new file mode 100644
index 0000000..c122cbb
--- /dev/null
+++ b/assets/sfx/hurt.wav
Binary files differ
diff --git a/assets/sfx/jump.mkv b/assets/sfx/jump.mkv
new file mode 100644
index 0000000..31cb497
--- /dev/null
+++ b/assets/sfx/jump.mkv
Binary files differ
diff --git a/assets/sfx/jump.wav b/assets/sfx/jump.wav
new file mode 100644
index 0000000..6c0a1f8
--- /dev/null
+++ b/assets/sfx/jump.wav
Binary files differ
diff --git a/assets/sfx/select.mkv b/assets/sfx/select.mkv
new file mode 100644
index 0000000..3ac0eb3
--- /dev/null
+++ b/assets/sfx/select.mkv
Binary files differ
diff --git a/assets/sfx/select.wav b/assets/sfx/select.wav
new file mode 100644
index 0000000..adacee2
--- /dev/null
+++ b/assets/sfx/select.wav
Binary files differ
diff --git a/assets/sfx/throw.mkv b/assets/sfx/throw.mkv
new file mode 100644
index 0000000..02718ea
--- /dev/null
+++ b/assets/sfx/throw.mkv
Binary files differ
diff --git a/assets/sfx/throw.wav b/assets/sfx/throw.wav
new file mode 100644
index 0000000..aa0e451
--- /dev/null
+++ b/assets/sfx/throw.wav
Binary files differ
diff --git a/conf.lua b/conf.lua
new file mode 100644
index 0000000..f07726c
--- /dev/null
+++ b/conf.lua
@@ -0,0 +1,15 @@
+function love.conf(t)
+ t.accelerometerjoystick = false
+ t.window.title = 'Disk Mayhem'
+ t.audio.mic = false
+ t.window.vsync = false
+ t.window.width, t.window.height = 640, 352
+ t.window.icon = 'favicon.png'
+
+ t.modules.physics = false
+ t.modules.thread = false
+ t.modules.touch = false
+ t.modules.video = false
+
+ TILE_SIDE = 8
+end
diff --git a/favicon.png b/favicon.png
new file mode 100644
index 0000000..44381c6
--- /dev/null
+++ b/favicon.png
Binary files differ
diff --git a/libs/anim8.lua b/libs/anim8.lua
new file mode 100644
index 0000000..9969deb
--- /dev/null
+++ b/libs/anim8.lua
@@ -0,0 +1,302 @@
+local anim8 = {
+ _VERSION = 'anim8 v2.3.1',
+ _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/libs/baton.lua b/libs/baton.lua
new file mode 100644
index 0000000..75c5f4b
--- /dev/null
+++ b/libs/baton.lua
@@ -0,0 +1,368 @@
+local baton = {
+ _VERSION = 'Baton v1.0.1',
+ _DESCRIPTION = 'Input library for LÖVE.',
+ _URL = 'https://github.com/tesselode/baton',
+ _LICENSE = [[
+ MIT License
+
+ Copyright (c) 2019 Andrew Minnich
+
+ 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.
+ ]]
+}
+
+-- string parsing functions --
+
+-- splits a source definition into type and value
+-- example: 'button:a' -> 'button', 'a'
+local function parseSource(source)
+ return source:match '(.+):(.+)'
+end
+
+-- splits an axis value into axis and direction
+-- example: 'leftx-' -> 'leftx', '-'
+local function parseAxis(value)
+ return value:match '(.+)([%+%-])'
+end
+
+-- splits a joystick hat value into hat number and direction
+-- example: '2rd' -> '2', 'rd'
+local function parseHat(value)
+ return value:match '(%d)(.+)'
+end
+
+--[[
+ -- source functions --
+
+ each source function checks the state of one type of input
+ and returns a value from 0 to 1. for binary controls, such
+ as keyboard keys and gamepad buttons, they return 1 if the
+ input is held down and 0 if not. for analog controls, such
+ as "leftx+" (the left analog stick held to the right), they
+ return a number from 0 to 1.
+
+ source functions are split into keyboard/mouse functions
+ and joystick/gamepad functions. baton treats these two
+ categories slightly differently.
+]]
+
+local sourceFunction = {keyboardMouse = {}, joystick = {}}
+
+-- checks whether a keyboard key is down or not
+function sourceFunction.keyboardMouse.key(key)
+ return love.keyboard.isDown(key) and 1 or 0
+end
+
+-- checks whether a keyboard key is down or not,
+-- but it takes a scancode as an input
+function sourceFunction.keyboardMouse.sc(sc)
+ return love.keyboard.isScancodeDown(sc) and 1 or 0
+end
+
+-- checks whether a mouse buttons is down or not.
+-- note that baton doesn't detect mouse movement, just the buttons
+function sourceFunction.keyboardMouse.mouse(button)
+ return love.mouse.isDown(tonumber(button)) and 1 or 0
+end
+
+-- checks the position of a joystick axis
+function sourceFunction.joystick.axis(joystick, value)
+ local axis, direction = parseAxis(value)
+ -- "a and b or c" is ok here because b will never be boolean
+ value = tonumber(axis) and joystick:getAxis(tonumber(axis))
+ or joystick:getGamepadAxis(axis)
+ if direction == '-' then value = -value end
+ return value > 0 and value or 0
+end
+
+-- checks whether a joystick button is held down or not
+-- can take a number or a GamepadButton string
+function sourceFunction.joystick.button(joystick, button)
+ -- i'm intentionally not using the "a and b or c" idiom here
+ -- because joystick.isDown returns a boolean
+ if tonumber(button) then
+ return joystick:isDown(tonumber(button)) and 1 or 0
+ else
+ return joystick:isGamepadDown(button) and 1 or 0
+ end
+end
+
+-- checks the direction of a joystick hat
+function sourceFunction.joystick.hat(joystick, value)
+ local hat, direction = parseHat(value)
+ return joystick:getHat(hat) == direction and 1 or 0
+end
+
+--[[
+ -- player class --
+
+ the player object takes a configuration table and handles input
+ accordingly. it's called a "player" because it makes sense to use
+ multiple of these for each player in a multiplayer game, but
+ you can use separate player objects to organize inputs
+ however you want.
+]]
+
+local Player = {}
+Player.__index = Player
+
+-- internal functions --
+
+-- sets the player's config to a user-defined config table
+-- and sets some defaults if they're not already defined
+function Player:_loadConfig(config)
+ if not config then
+ error('No config table provided', 4)
+ end
+ if not config.controls then
+ error('No controls specified', 4)
+ end
+ config.pairs = config.pairs or {}
+ config.deadzone = config.deadzone or .5
+ config.squareDeadzone = config.squareDeadzone or false
+ self.config = config
+end
+
+-- initializes a control object for each control defined in the config
+function Player:_initControls()
+ self._controls = {}
+ for controlName, sources in pairs(self.config.controls) do
+ self._controls[controlName] = {
+ sources = sources,
+ rawValue = 0,
+ value = 0,
+ down = false,
+ downPrevious = false,
+ pressed = false,
+ released = false,
+ }
+ end
+end
+
+-- initializes an axis pair object for each axis pair defined in the config
+function Player:_initPairs()
+ self._pairs = {}
+ for pairName, controls in pairs(self.config.pairs) do
+ self._pairs[pairName] = {
+ controls = controls,
+ rawX = 0,
+ rawY = 0,
+ x = 0,
+ y = 0,
+ down = false,
+ downPrevious = false,
+ pressed = false,
+ released = false,
+ }
+ end
+end
+
+function Player:_init(config)
+ self:_loadConfig(config)
+ self:_initControls()
+ self:_initPairs()
+ self._activeDevice = 'none'
+end
+
+--[[
+ detects the active device (keyboard/mouse or joystick).
+ if the keyboard or mouse is currently being used, joystick
+ inputs will be ignored. this is to prevent slight axis movements
+ from adding errant inputs when someone's using the keyboard.
+
+ the active device is saved to player._activeDevice, which is then
+ used throughout the rest of the update loop to check only
+ keyboard or joystick inputs.
+]]
+function Player:_setActiveDevice()
+ for _, control in pairs(self._controls) do
+ for _, source in ipairs(control.sources) do
+ local type, value = parseSource(source)
+ if sourceFunction.keyboardMouse[type] then
+ if sourceFunction.keyboardMouse[type](value) > self.config.deadzone then
+ self._activeDevice = 'kbm'
+ return
+ end
+ elseif self.config.joystick and sourceFunction.joystick[type] then
+ if sourceFunction.joystick[type](self.config.joystick, value) > self.config.deadzone then
+ self._activeDevice = 'joy'
+ end
+ end
+ end
+ end
+end
+
+--[[
+ gets the value of a control by running the appropriate source functions
+ for all of its sources. does not apply deadzone.
+]]
+function Player:_getControlRawValue(control)
+ local rawValue = 0
+ for _, source in ipairs(control.sources) do
+ local type, value = parseSource(source)
+ if sourceFunction.keyboardMouse[type] and self._activeDevice == 'kbm' then
+ if sourceFunction.keyboardMouse[type](value) == 1 then
+ return 1
+ end
+ elseif sourceFunction.joystick[type] and self._activeDevice == 'joy' then
+ rawValue = rawValue + sourceFunction.joystick[type](self.config.joystick, value)
+ if rawValue >= 1 then
+ return 1
+ end
+ end
+ end
+ return rawValue
+end
+
+--[[
+ updates each control in a player. saves the value with and without deadzone
+ and the down/pressed/released state.
+]]
+function Player:_updateControls()
+ for _, control in pairs(self._controls) do
+ control.rawValue = self:_getControlRawValue(control)
+ control.value = control.rawValue >= self.config.deadzone and control.rawValue or 0
+ control.downPrevious = control.down
+ control.down = control.value > 0
+ control.pressed = control.down and not control.downPrevious
+ control.released = control.downPrevious and not control.down
+ end
+end
+
+--[[
+ updates each axis pair in a player. saves the value with and without deadzone
+ and the down/pressed/released state.
+]]
+function Player:_updatePairs()
+ for _, pair in pairs(self._pairs) do
+ -- get raw x and y
+ local l = self._controls[pair.controls[1]].rawValue
+ local r = self._controls[pair.controls[2]].rawValue
+ local u = self._controls[pair.controls[3]].rawValue
+ local d = self._controls[pair.controls[4]].rawValue
+ pair.rawX, pair.rawY = r - l, d - u
+
+ -- limit to 1
+ local len = math.sqrt(pair.rawX^2 + pair.rawY^2)
+ if len > 1 then
+ pair.rawX, pair.rawY = pair.rawX / len, pair.rawY / len
+ end
+
+ -- deadzone
+ if self.config.squareDeadzone then
+ pair.x = math.abs(pair.rawX) > self.config.deadzone and pair.rawX or 0
+ pair.y = math.abs(pair.rawY) > self.config.deadzone and pair.rawY or 0
+ else
+ pair.x = len > self.config.deadzone and pair.rawX or 0
+ pair.y = len > self.config.deadzone and pair.rawY or 0
+ end
+
+ -- down/pressed/released
+ pair.downPrevious = pair.down
+ pair.down = pair.x ~= 0 or pair.y ~= 0
+ pair.pressed = pair.down and not pair.downPrevious
+ pair.released = pair.downPrevious and not pair.down
+ end
+end
+
+-- public API --
+
+-- checks for changes in inputs
+function Player:update()
+ self:_setActiveDevice()
+ self:_updateControls()
+ self:_updatePairs()
+end
+
+-- gets the value of a control or axis pair without deadzone applied
+function Player:getRaw(name)
+ if self._pairs[name] then
+ return self._pairs[name].rawX, self._pairs[name].rawY
+ elseif self._controls[name] then
+ return self._controls[name].rawValue
+ else
+ error('No control with name "' .. name .. '" defined', 3)
+ end
+end
+
+-- gets the value of a control or axis pair with deadzone applied
+function Player:get(name)
+ if self._pairs[name] then
+ return self._pairs[name].x, self._pairs[name].y
+ elseif self._controls[name] then
+ return self._controls[name].value
+ else
+ error('No control with name "' .. name .. '" defined', 3)
+ end
+end
+
+-- gets whether a control or axis pair is "held down"
+function Player:down(name)
+ if self._pairs[name] then
+ return self._pairs[name].down
+ elseif self._controls[name] then
+ return self._controls[name].down
+ else
+ error('No control with name "' .. name .. '" defined', 3)
+ end
+end
+
+-- gets whether a control or axis pair was pressed this frame
+function Player:pressed(name)
+ if self._pairs[name] then
+ return self._pairs[name].pressed
+ elseif self._controls[name] then
+ return self._controls[name].pressed
+ else
+ error('No control with name "' .. name .. '" defined', 3)
+ end
+end
+
+-- gets whether a control or axis pair was released this frame
+function Player:released(name)
+ if self._pairs[name] then
+ return self._pairs[name].released
+ elseif self._controls[name] then
+ return self._controls[name].released
+ else
+ error('No control with name "' .. name .. '" defined', 3)
+ end
+end
+
+--[[
+ gets the currently active device (either "kbm", "joy", or "none").
+ this is useful for displaying instructional text. you may have
+ a menu that says "press ENTER to confirm" or "press A to confirm"
+ depending on whether the player is using their keyboard or gamepad.
+ this function allows you to detect which they used most recently.
+]]
+function Player:getActiveDevice()
+ return self._activeDevice
+end
+
+-- main functions --
+
+-- creates a new player with the user-provided config table
+function baton.new(config)
+ local player = setmetatable({}, Player)
+ player:_init(config)
+ return player
+end
+
+return baton
diff --git a/libs/classic.lua b/libs/classic.lua
new file mode 100644
index 0000000..cbd6f81
--- /dev/null
+++ b/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/libs/deep.lua b/libs/deep.lua
new file mode 100644
index 0000000..ffd545c
--- /dev/null
+++ b/libs/deep.lua
@@ -0,0 +1,83 @@
+local deep = {
+ _VERSION = "deep v2.0.3",
+ _DESCRIPTION = "Queue and execute actions in sequence (can add Z axis to 2D graphics frameworks)",
+ _URL = "https://github.com/Nikaoto/deep",
+ _LICENSE = [[
+ Copyright (c) 2017 Nikoloz Otiashvili
+
+ 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 execQueue = {}
+local maxIndex = 1
+local minIndex = 1
+
+-- for compatibility with Lua 5.1/5.2
+local unpack = rawget(table, "unpack") or unpack
+
+deep.queue = function(i, fun, ...)
+ if type(i) ~= "number" then
+ print("Error: deep.queue(): passed index is not a number")
+ return nil
+ end
+
+ if type(fun) ~= "function" then
+ print("Error: deep.queue(): passed action is not a function")
+ return nil
+ end
+
+ local arg = { ... }
+
+ if i < minIndex then
+ minIndex = i
+ elseif i > maxIndex then
+ maxIndex = i
+ end
+
+ if arg and #arg > 0 then
+ local t = function() return fun(unpack(arg)) end
+
+ if execQueue[i] == nil then
+ execQueue[i] = { t }
+ else
+ table.insert(execQueue[i], t)
+ end
+ else
+ if execQueue[i] == nil then
+ execQueue[i] = { fun }
+ else
+ table.insert(execQueue[i], fun)
+ end
+ end
+end
+
+deep.execute = function()
+ for i = minIndex, maxIndex do
+ if execQueue[i] then
+ for _, fun in pairs(execQueue[i]) do
+ fun()
+ end
+ end
+ end
+
+ execQueue = {}
+end
+
+return deep
diff --git a/libs/push.lua b/libs/push.lua
new file mode 100644
index 0000000..27fd2e7
--- /dev/null
+++ b/libs/push.lua
@@ -0,0 +1,281 @@
+-- push.lua v0.4
+
+-- Copyright (c) 2020 Ulysse Ramage
+-- 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 love11 = love.getVersion() == 11
+local getDPI = love11 and love.window.getDPIScale or love.window.getPixelScale
+local windowUpdateMode = love11 and love.window.updateMode or function(width, height, settings)
+ local _, _, flags = love.window.getMode()
+ for k, v in pairs(settings) do flags[k] = v end
+ love.window.setMode(width, height, flags)
+end
+
+local push = {
+
+ defaults = {
+ fullscreen = false,
+ resizable = false,
+ pixelperfect = false,
+ highdpi = true,
+ canvas = true,
+ stencil = true
+ }
+
+}
+setmetatable(push, push)
+
+function push:applySettings(settings)
+ for k, v in pairs(settings) do
+ self["_" .. k] = v
+ end
+end
+
+function push:resetSettings() return self:applySettings(self.defaults) end
+
+function push:setupScreen(WWIDTH, WHEIGHT, RWIDTH, RHEIGHT, settings)
+
+ settings = settings or {}
+
+ self._WWIDTH, self._WHEIGHT = WWIDTH, WHEIGHT
+ self._RWIDTH, self._RHEIGHT = RWIDTH, RHEIGHT
+
+ self:applySettings(self.defaults) --set defaults first
+ self:applySettings(settings) --then fill with custom settings
+
+ windowUpdateMode(self._RWIDTH, self._RHEIGHT, {
+ fullscreen = self._fullscreen,
+ resizable = self._resizable,
+ highdpi = self._highdpi
+ })
+
+ self:initValues()
+
+ if self._canvas then
+ self:setupCanvas({ "default" }) --setup canvas
+ end
+
+ self._borderColor = {0, 0, 0}
+
+ self._drawFunctions = {
+ ["start"] = self.start,
+ ["end"] = self.finish
+ }
+
+ return self
+end
+
+function push:setupCanvas(canvases)
+ table.insert(canvases, { name = "_render", private = true }) --final render
+
+ self._canvas = true
+ self.canvases = {}
+
+ for i = 1, #canvases do
+ push:addCanvas(canvases[i])
+ end
+
+ return self
+end
+function push:addCanvas(params)
+ table.insert(self.canvases, {
+ name = params.name,
+ private = params.private,
+ shader = params.shader,
+ canvas = love.graphics.newCanvas(self._WWIDTH, self._WHEIGHT),
+ stencil = params.stencil or self._stencil
+ })
+end
+
+function push:setCanvas(name)
+ if not self._canvas then return true end
+ local canvasTable = self:getCanvasTable(name)
+ return love.graphics.setCanvas({ canvasTable.canvas, stencil = canvasTable.stencil })
+end
+function push:getCanvasTable(name)
+ for i = 1, #self.canvases do
+ if self.canvases[i].name == name then
+ return self.canvases[i]
+ end
+ end
+end
+function push:setShader(name, shader)
+ if not shader then
+ self:getCanvasTable("_render").shader = name
+ else
+ self:getCanvasTable(name).shader = shader
+ end
+end
+
+function push:initValues()
+ self._PSCALE = (not love11 and self._highdpi) and getDPI() or 1
+
+ self._SCALE = {
+ x = self._RWIDTH/self._WWIDTH * self._PSCALE,
+ y = self._RHEIGHT/self._WHEIGHT * self._PSCALE
+ }
+
+ if self._stretched then --if stretched, no need to apply offset
+ self._OFFSET = {x = 0, y = 0}
+ else
+ local scale = math.min(self._SCALE.x, self._SCALE.y)
+ if self._pixelperfect then scale = math.floor(scale) end
+
+ self._OFFSET = {x = (self._SCALE.x - scale) * (self._WWIDTH/2), y = (self._SCALE.y - scale) * (self._WHEIGHT/2)}
+ self._SCALE.x, self._SCALE.y = scale, scale --apply same scale to X and Y
+ end
+
+ self._GWIDTH = self._RWIDTH * self._PSCALE - self._OFFSET.x * 2
+ self._GHEIGHT = self._RHEIGHT * self._PSCALE - self._OFFSET.y * 2
+end
+
+function push:apply(operation, shader)
+ self._drawFunctions[operation](self, shader)
+end
+
+function push:start()
+ if self._canvas then
+ love.graphics.push()
+ love.graphics.setCanvas({ self.canvases[1].canvas, stencil = self.canvases[1].stencil })
+
+ else
+ love.graphics.translate(self._OFFSET.x, self._OFFSET.y)
+ love.graphics.setScissor(self._OFFSET.x, self._OFFSET.y, self._WWIDTH*self._SCALE.x, self._WHEIGHT*self._SCALE.y)
+ love.graphics.push()
+ love.graphics.scale(self._SCALE.x, self._SCALE.y)
+ end
+end
+
+function push:applyShaders(canvas, shaders)
+ local _shader = love.graphics.getShader()
+ if #shaders <= 1 then
+ love.graphics.setShader(shaders[1])
+ love.graphics.draw(canvas)
+ else
+ local _canvas = love.graphics.getCanvas()
+
+ local _tmp = self:getCanvasTable("_tmp")
+ if not _tmp then --create temp canvas only if needed
+ self:addCanvas({ name = "_tmp", private = true, shader = nil })
+ _tmp = self:getCanvasTable("_tmp")
+ end
+
+ love.graphics.push()
+ love.graphics.origin()
+ local outputCanvas
+ for i = 1, #shaders do
+ local inputCanvas = i % 2 == 1 and canvas or _tmp.canvas
+ outputCanvas = i % 2 == 0 and canvas or _tmp.canvas
+ love.graphics.setCanvas(outputCanvas)
+ love.graphics.clear()
+ love.graphics.setShader(shaders[i])
+ love.graphics.draw(inputCanvas)
+ love.graphics.setCanvas(inputCanvas)
+ end
+ love.graphics.pop()
+
+ love.graphics.setCanvas(_canvas)
+ love.graphics.draw(outputCanvas)
+ end
+ love.graphics.setShader(_shader)
+end
+
+function push:finish(shader)
+ love.graphics.setBackgroundColor(unpack(self._borderColor))
+ if self._canvas then
+ local _render = self:getCanvasTable("_render")
+
+ love.graphics.pop()
+
+ local white = love11 and 1 or 255
+ love.graphics.setColor(white, white, white)
+
+ --draw canvas
+ love.graphics.setCanvas(_render.canvas)
+ for i = 1, #self.canvases do --do not draw _render yet
+ local _table = self.canvases[i]
+ if not _table.private then
+ local _canvas = _table.canvas
+ local _shader = _table.shader
+ self:applyShaders(_canvas, type(_shader) == "table" and _shader or { _shader })
+ end
+ end
+ love.graphics.setCanvas()
+
+ --draw render
+ love.graphics.translate(self._OFFSET.x, self._OFFSET.y)
+ local shader = shader or _render.shader
+ love.graphics.push()
+ love.graphics.scale(self._SCALE.x, self._SCALE.y)
+ self:applyShaders(_render.canvas, type(shader) == "table" and shader or { shader })
+ love.graphics.pop()
+
+ --clear canvas
+ for i = 1, #self.canvases do
+ love.graphics.setCanvas(self.canvases[i].canvas)
+ love.graphics.clear()
+ end
+
+ love.graphics.setCanvas()
+ love.graphics.setShader()
+ else
+ love.graphics.pop()
+ love.graphics.setScissor()
+ end
+end
+
+function push:setBorderColor(color, g, b)
+ self._borderColor = g and {color, g, b} or color
+end
+
+function push:toGame(x, y)
+ x, y = x - self._OFFSET.x, y - self._OFFSET.y
+ local normalX, normalY = x / self._GWIDTH, y / self._GHEIGHT
+
+ x = (x >= 0 and x <= self._WWIDTH * self._SCALE.x) and normalX * self._WWIDTH or nil
+ y = (y >= 0 and y <= self._WHEIGHT * self._SCALE.y) and normalY * self._WHEIGHT or nil
+
+ return x, y
+end
+
+function push:toReal(x, y)
+ realX = self._OFFSET.x + (self._GWIDTH * x)/self._WWIDTH
+ realY = self._OFFSET.y + (self._GHEIGHT * y)/self._WHEIGHT
+ return realX, realY
+end
+
+function push:switchFullscreen(winw, winh)
+ self._fullscreen = not self._fullscreen
+ local windowWidth, windowHeight = love.window.getDesktopDimensions()
+
+ if self._fullscreen then --save windowed dimensions for later
+ self._WINWIDTH, self._WINHEIGHT = self._RWIDTH, self._RHEIGHT
+ elseif not self._WINWIDTH or not self._WINHEIGHT then
+ self._WINWIDTH, self._WINHEIGHT = windowWidth * .5, windowHeight * .5
+ end
+
+ self._RWIDTH = self._fullscreen and windowWidth or winw or self._WINWIDTH
+ self._RHEIGHT = self._fullscreen and windowHeight or winh or self._WINHEIGHT
+
+ self:initValues()
+
+ love.window.setFullscreen(self._fullscreen, "desktop")
+ if not self._fullscreen and (winw or winh) then
+ windowUpdateMode(self._RWIDTH, self._RHEIGHT) --set window dimensions
+ end
+end
+
+function push:resize(w, h)
+ if self._highdpi then w, h = w / self._PSCALE, h / self._PSCALE end
+ self._RWIDTH = w
+ self._RHEIGHT = h
+ self:initValues()
+end
+
+function push:getWidth() return self._WWIDTH end
+function push:getHeight() return self._WHEIGHT end
+function push:getDimensions() return self._WWIDTH, self._WHEIGHT end
+
+return push
diff --git a/libs/shack.lua b/libs/shack.lua
new file mode 100644
index 0000000..337bc09
--- /dev/null
+++ b/libs/shack.lua
@@ -0,0 +1,146 @@
+-- shack.lua v0.1
+
+-- Copyright (c) 2015 Ulysse Ramage
+-- 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 shack = {
+ shaking = 0,
+ shakingTarget = 0,
+
+ rotation = 0,
+ rotationTarget = 0,
+
+ scale = { x = 1, y = 1 },
+ scaleTarget = { x = 1, y = 1 },
+
+ shear = { x = 0, y = 0 },
+ shearTarget = { x = 0, y = 0 },
+
+ width = love.graphics.getWidth(),
+ height = love.graphics.getHeight()
+}
+setmetatable(shack, shack)
+
+--[[ Private ]]--
+
+local function lerp(a, b, k) --smooth transitions
+ if a == b then
+ return a
+ else
+ if math.abs(a-b) < 0.005 then return b else return a * (1-k) + b * k end
+ end
+end
+
+--[[ Public ]]--
+
+function shack:setDimensions(width, height)
+ self.width, self.height = width, height
+ return self
+end
+
+function shack:update(dt)
+
+ local _speed = 7
+
+ self.shaking = lerp(self.shaking, self.shakingTarget, _speed*dt)
+ self.rotation = lerp(self.rotation, self.rotationTarget, _speed*dt)
+
+ self.scale.x = lerp(self.scale.x, self.scaleTarget.x, _speed*dt)
+ self.scale.y = lerp(self.scale.y, self.scaleTarget.y, _speed*dt)
+
+ self.shear.x = lerp(self.shear.x, self.shearTarget.x, _speed*dt)
+ self.shear.y = lerp(self.shear.y, self.shearTarget.y, _speed*dt)
+
+end
+
+function shack:apply()
+ love.graphics.translate(self.width*.5, self.height*.5)
+ love.graphics.rotate((math.random()-.5)*self.rotation)
+ love.graphics.scale(self.scale.x, self.scale.y)
+ love.graphics.translate(-self.width*.5, -self.height*.5)
+
+ love.graphics.translate((math.random()-.5)*self.shaking, (math.random()-.5)*self.shaking)
+
+ love.graphics.shear(self.shear.x*.01, self.shear.y*.01)
+
+ return self
+end
+
+--
+
+function shack:setShake(shaking)
+ self.shaking = shaking or 0
+ return self
+end
+
+function shack:setRotation(rotation)
+ self.rotation = rotation or 0
+ return self
+end
+
+function shack:setShear(x, y)
+ self.shear = { x = x or 0, y = y or 0 }
+ return self
+end
+
+function shack:setScale(x, y)
+ if not y then
+ local _s = x or 1
+ self.scale = { x = _s, y = _s }
+ else
+ self.scale = { x = x or 1, y = y or 1 }
+ end
+ return self
+end
+
+function shack:setShakeTarget(shaking)
+ self.shakingTarget = shaking or 0
+ return self
+end
+
+function shack:setRotationTarget(rotation)
+ self.rotationTarget = rotation or 0
+ return self
+end
+
+function shack:setScaleTarget(x, y)
+ if not y then
+ local _s = x or 1
+ self.scaleTarget = { x = _s, y = _s }
+ else
+ self.scaleTarget = { x = x or 1, y = y or 1 }
+ end
+ return self
+end
+
+function shack:setShearTarget(x, y)
+ self.shearTarget = { x = x or 0, y = y or 0 }
+ return self
+end
+
+--
+
+function shack:getShake() return self.shaking end
+function shack:getShakeTarget() return self.shakingTarget end
+
+function shack:getRotation() return self.rotation end
+function shack:getRotationTarget() return self.rotationTarget end
+
+function shack:getScale() return self.scale.x, self.scale.y end
+function shack:getScaleTarget() return self.scaleTarget.x, self.scaleTarget.y end
+
+function shack:getShear() return self.shear.x, self.shear.y end
+function shack:getShearTarget() return self.shearTarget.x, self.shearTarget.y end
+
+--[[ Aliases ]]--
+
+function shack:shake(...) return self:setShake(...) end
+function shack:rotate(...) return self:setRotation(...) end
+function shack:zoom(...) return self:setScale(...) end
+function shack:tilt(...) return self:setShear(...) end
+
+--[[ End ]]--
+
+return shack \ No newline at end of file
diff --git a/libs/vector.lua b/libs/vector.lua
new file mode 100644
index 0000000..cf665e8
--- /dev/null
+++ b/libs/vector.lua
@@ -0,0 +1,211 @@
+local module = {
+ _version = "vector.lua v2019.14.12",
+ _description = "a simple vector library for Lua based on the PVector class from processing",
+ _url = "https://github.com/themousery/vector.lua",
+ _license = [[
+ Copyright (c) 2018 themousery
+
+ 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.
+ ]]
+}
+
+-- create the module
+local vector = {}
+vector.__index = vector
+
+-- get a random function from Love2d or base lua, in that order.
+local rand = math.random
+if love and love.math then rand = love.math.random end
+
+-- makes a new vector
+local function new(x,y)
+ return setmetatable({x=x or 0, y=y or 0}, vector)
+end
+
+-- makes a new vector from an angle
+local function fromAngle(theta)
+ return new(math.cos(theta), -math.sin(theta))
+end
+
+-- makes a vector with a random direction
+local function random()
+ return fromAngle(rand() * math.pi*2)
+end
+
+-- check if an object is a vector
+local function isvector(t)
+ return getmetatable(t) == vector
+end
+
+-- set the values of the vector to something new
+function vector:set(x,y)
+ if isvector(x) then self.x, self.y = x.x, x.y;return end
+ self.x, self.y = x or self.x, y or self.y
+ return self
+end
+
+-- replace the values of a vector with the values of another vector
+function vector:replace(v)
+ assert(isvector(v), "replace: wrong argument type: (expected <vector>, got "..type(v)..")")
+ self.x, self.y = v.x, v.y
+ return self
+end
+
+-- returns a copy of a vector
+function vector:clone()
+ return new(self.x, self.y)
+end
+
+-- get the magnitude of a vector
+function vector:getmag()
+ return math.sqrt(self.x^2 + self.y^2)
+end
+
+-- get the magnitude squared of a vector
+function vector:magSq()
+ return self.x^2 + self.y^2
+end
+
+-- set the magnitude of a vector
+function vector:setmag(mag)
+ self:norm()
+ local v = self * mag
+ self:replace(v)
+ return self
+end
+
+-- meta function to make vectors negative
+-- ex: (negative) -vector(5,6) is the same as vector(-5,-6)
+function vector.__unm(v)
+ return new(-v.x, -v.y)
+end
+
+-- meta function to add vectors together
+-- ex: (vector(5,6) + vector(6,5)) is the same as vector(11,11)
+function vector.__add(a,b)
+ assert(isvector(a) and isvector(b), "add: wrong argument types: (expected <vector> and <vector>)")
+ return new(a.x+b.x, a.y+b.y)
+end
+
+-- meta function to subtract vectors
+function vector.__sub(a,b)
+ assert(isvector(a) and isvector(b), "sub: wrong argument types: (expected <vector> and <vector>)")
+ return new(a.x-b.x, a.y-b.y)
+end
+
+-- meta function to multiply vectors
+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(a.x * b, a.y * b)
+ else
+ assert(isvector(a) and isvector(b), "mul: wrong argument types: (expected <vector> or <number>)")
+ return new(a.x*b.x, a.y*b.y)
+ end
+end
+
+-- meta function to divide vectors
+function vector.__div(a,b)
+ assert(isvector(a) and type(b) == "number", "div: wrong argument types (expected <vector> and <number>)")
+ return new(a.x/b, a.y/b)
+end
+
+-- meta function to check if vectors have the same values
+function vector.__eq(a,b)
+ assert(isvector(a) and isvector(b), "eq: wrong argument types (expected <vector> and <vector>)")
+ return a.x==b.x and a.y==b.y
+end
+
+-- meta function to change how vectors appear as string
+-- ex: print(vector(2,8)) - this prints '(2,8)'
+function vector:__tostring()
+ return "("..self.x..", "..self.y..")"
+end
+
+-- get the distance between two vectors
+function vector.dist(a,b)
+ assert(isvector(a) and isvector(b), "dist: wrong argument types (expected <vector> and <vector>)")
+ return math.sqrt((a.x-b.x)^2 + (a.y-b.y)^2)
+end
+
+-- return the dot product of the vector
+function vector:dot(v)
+ assert(isvector(v), "dot: wrong argument type (expected <vector>)")
+ return self.x * v.x + self.y * v.y
+end
+
+-- normalize the vector (give it a magnitude of 1)
+function vector:norm()
+ local m = self:getmag()
+ if m~=0 then
+ self:replace(self / m)
+ end
+ return self
+end
+
+-- limit the vector to a certain amount
+function vector:limit(max)
+ assert(type(max) == 'number', "limit: wrong argument type (expected <number>)")
+ local mSq = self:magSq()
+ if mSq > max^2 then
+ self:setmag(max)
+ end
+ return self
+end
+
+-- Clamp each axis between max and min's corresponding axis
+function vector:clamp(min, max)
+ assert(isvector(min) and isvector(max), "clamp: wrong argument type (expected <vector>) and <vector>")
+ local x = math.min( math.max( self.x, min.x ), max.x )
+ local y = math.min( math.max( self.y, min.y ), max.y )
+ self:set(x,y)
+ return self
+end
+
+-- get the heading (direction) of a vector
+function vector:heading()
+ return -math.atan2(self.y, self.x)
+end
+
+-- rotate a vector by a certain number of degrees
+function vector:rotate(theta)
+ local m = self:getmag()
+ self:replace(fromAngle(self:heading() + theta))
+ self:setmag(m)
+ return self
+end
+
+-- return x and y of vector as a regular array
+function vector:array()
+ return {self.x, self.y}
+end
+
+-- return x and y of vector, unpacked from table
+function vector:unpack()
+ return self.x, self.y
+end
+
+
+-- pack up and return module
+module.new = new
+module.random = random
+module.fromAngle = fromAngle
+module.isvector = isvector
+return setmetatable(module, {__call = function(_,...) return new(...) end})
diff --git a/main.lua b/main.lua
new file mode 100644
index 0000000..4a43eac
--- /dev/null
+++ b/main.lua
@@ -0,0 +1,178 @@
+--require'libs/lovedebug'
+stage = {} --dirty lazy boy
+deep = require'libs/deep'
+push = require'libs/push'
+screen = require'libs/shack'
+local baton = require'libs/baton'
+local Hitbox = require'src/hitbox'
+local Player = require'src/player'
+local Disk = require'src/disk'
+local Stage = require'src/stage'
+local MainMenu = require'src/menu/mainmenu'
+local DebugDisp = require'src/debugdisp'
+count = require'src/count'
+
+function love.load()
+ --WARNING ENTERING GLOBALS ZONE
+
+ --nerd stats
+ stats = {
+ --p1
+ {
+ throw = 0,
+ slash = 0,
+ slash_success = 0,
+ jump = 0,
+ },
+ --p2
+ {
+ throw = 0,
+ slash = 0,
+ slash_success = 0,
+ jump = 0,
+ },
+ }
+
+ --FPS cap
+ min_dt = 1/60
+ next_time = love.timer.getTime()
+
+ --nearest neighbor
+ love.graphics.setDefaultFilter("nearest", "nearest")
+
+ gameWidth, gameHeight = 320, 176
+ tileSize = 8
+
+ --push setup
+ local windowWidth, windowHeight = gameWidth * 2, gameHeight * 2
+ push:setupScreen(gameWidth, gameHeight, windowWidth, windowHeight, {
+ fullscreen = false,
+ resizable = true, --I disable it for easy testing on i3
+ canvas = true,
+ pixelperfect = false, --strive for perfection
+ })
+
+ --shack setup
+ screen:setDimensions(push:getDimensions())
+
+ --debug setting
+ DEBUG = false
+ debug_input = baton.new{
+ controls = {
+ pause = {},--{'key:f1'},
+ toggle = {},--{'key:f3'},
+ restart = {},--{'key:f5'},
+ spawn_player = {},
+ }
+ }
+
+ --entities setup
+ entities = {}
+
+ --globals
+ pause = false
+ sound = true
+ screenshake = true
+ particles = true
+
+ --load stage
+ --stage = Stage'fire'
+ --stage = Stage'jungle'
+ --stage = Stage'nothern'
+ --stage = Stage'sky'
+ --stage = Stage'weirdo'
+ stage = Stage'mainmenu'
+
+ --wins count
+ win_streak = {0, 0}
+end
+
+function love.update()
+ --FPS cap
+ next_time = next_time + min_dt
+ local dt = min_dt
+
+ --update entities
+ for _, v in pairs(entities) do
+ if v.update then
+ v:update(dt)
+ end
+ end
+
+ --update shack
+ screen:update(dt)
+
+
+ --debug fonctions
+ debug_input:update()
+ if debug_input:pressed'toggle' then
+ DEBUG = not DEBUG
+ end
+ if debug_input:pressed'pause' then
+ pause = not pause
+ end
+ if debug_input:pressed'restart' then
+ love.event.quit'restart'
+ end
+ --add a player to the scene
+ if debug_input:pressed'spawn_player' then
+ table.insert(entities, Player(62, 125, Hitbox(4, 5, 4, 6), 1))
+ end
+end
+
+function love.draw()
+ --draw stage
+ deep.queue(0, Stage.draw, stage)
+
+ --draw entities
+ for _, v in pairs(entities) do
+ if v.draw then
+ deep.queue(v.draw_layer, v.draw, v)
+ end
+ end
+
+ --draw debug stuff (like hitboxes)
+ if DEBUG then
+ for _, v in pairs(entities) do
+ if v.draw_debug then
+ deep.queue(2, v.draw_debug, v)
+ end
+ end
+ end
+
+ --draw guis
+ for _, v in pairs(entities) do
+ if v.draw_gui then
+ deep.queue(10, v.draw_gui, v)
+ end
+ end
+
+ --apply shack and push tranforms
+ screen:apply()
+ push:start()
+ deep.execute()
+ push:finish()
+
+ if DEBUG then
+ --draw debug guis (like FPS)
+ for _, v in pairs(entities) do
+ if v.draw_gui_debug then
+ deep.queue(2, v.draw_gui_debug, v)
+ end
+ end
+ end
+
+ deep.execute()
+
+ --FPS cap
+ local cur_time = love.timer.getTime()
+ if next_time <= cur_time then
+ next_time = cur_time
+ return
+ end
+ love.timer.sleep(next_time - cur_time)
+end
+
+function love.resize(w, h)
+ push:resize(w, h)
+end
diff --git a/menu_conf.lua b/menu_conf.lua
new file mode 100644
index 0000000..1d75a86
--- /dev/null
+++ b/menu_conf.lua
@@ -0,0 +1,42 @@
+local menu_conf = {
+ --configure input
+ controls = {
+ { --p1
+ controls = {
+ left = {'key:q', 'key:left', 'axis:leftx-', 'button:dpleft'},
+ right = {'key:d', 'key:right', 'axis:leftx+', 'button:dpright'},
+ up = {'key:z', 'key:up', 'axis:lefty-', 'button:dpup'},
+ down = {'key:s', 'key:down', 'axis:lefty+', 'button:dpdown'},
+ no = {'key:g', 'button:b', 'key:escape', 'button:start'},
+ yes = {'key:v', 'key:return', 'button:a'},
+ pause = {'key:escape', 'key:p', 'button:start'},
+ },
+ pairs = {
+ move = {'left', 'right', 'up', 'down'}
+ },
+ joystick = love.joystick.getJoysticks()[2],
+ },
+ { --p2
+ controls = {
+ left = {'key:j', 'axis:leftx-', 'button:dpleft'},
+ right = {'key:l', 'axis:leftx+', 'button:dpright'},
+ up = {'key:i', 'axis:lefty-', 'button:dpup'},
+ down = {'key:k', 'axis:lefty+', 'button:dpdown'},
+ no = {'key:rshift', 'button:b', 'button:start'},
+ yes = {'key:rctrl', 'button:a'},
+ },
+ pairs = {
+ move = {'left', 'right', 'up', 'down'}
+ },
+ joystick = love.joystick.getJoysticks()[1],
+ },
+ },
+}
+
+menu_conf.controls[3] = {
+ controls = menu_conf.controls[1].controls,
+ pairs = menu_conf.controls[1].pairs,
+ joystick = love.joystick.getJoysticks()[2]
+}
+
+return menu_conf
diff --git a/player_conf.lua b/player_conf.lua
new file mode 100644
index 0000000..fcd9487
--- /dev/null
+++ b/player_conf.lua
@@ -0,0 +1,61 @@
+local player_conf = {
+ acceleration = 0.36,
+ friction = 0.15,
+ jump_spd = -4.2,
+ jump_buffering = 8,
+ coyote_time = 5,
+ gravity = 0.2,
+ gravity_fastfall = 0.6,
+ vertical_friction = 0.02,
+ texture_width = 12,
+ hp = 8,
+ invulnerability_on_hit = 30,
+ disk_cooldown = 34,
+ disk_cooldown_margin = 4,
+ conveyor_speed = 0.25,
+ particle_delay = 3,
+ --colors
+ color = {
+ {1, 0, 77/255},
+ {6/255, 90/255, 181/255},
+ },
+ --configure input
+ controls = {
+ {
+ controls = {
+ left = {'key:q', 'key:a', 'axis:leftx-', 'button:dpleft'},
+ right = {'key:d', 'axis:leftx+', 'button:dpright'},
+ up = {'key:z', 'key:w', 'axis:lefty-', 'button:dpup'},
+ down = {'key:s', 'axis:lefty+', 'button:dpdown'},
+ jump = {'key:g', 'button:b'},
+ action = {'key:v', 'button:a'},
+ slash = {'key:c', 'key:f', 'button:y', 'button:x'},
+ suicide = {},
+ pause = {'key:escape', 'key:p', 'button:start'},
+ },
+ pairs = {
+ move = {'left', 'right', 'up', 'down'}
+ },
+ joystick = love.joystick.getJoysticks()[2],
+ },
+ {
+ controls = {
+ left = {'key:j', 'axis:leftx-', 'button:dpleft'},
+ right = {'key:l', 'axis:leftx+', 'button:dpright'},
+ up = {'key:i', 'axis:lefty-', 'button:dpup'},
+ down = {'key:k', 'axis:lefty+', 'button:dpdown'},
+ jump = {'key:rshift', 'button:b'},
+ action = {'key:rctrl', 'button:a'},
+ slash = {'key:left', 'button:y', 'button:x'},
+ suicide = {},
+ pause = {'key:escape', 'key:p', 'button:start'},
+ },
+ pairs = {
+ move = {'left', 'right', 'up', 'down'}
+ },
+ joystick = love.joystick.getJoysticks()[1],
+ },
+ },
+}
+
+return player_conf
diff --git a/src/count.lua b/src/count.lua
new file mode 100644
index 0000000..172950b
--- /dev/null
+++ b/src/count.lua
@@ -0,0 +1,9 @@
+return function(object)
+ local n = 0
+ for _, v in pairs(entities) do
+ if v:is(object) then
+ n = n + 1
+ end
+ end
+ return n
+end
diff --git a/src/debugdisp.lua b/src/debugdisp.lua
new file mode 100644
index 0000000..2123173
--- /dev/null
+++ b/src/debugdisp.lua
@@ -0,0 +1,31 @@
+local Object = require'src/object'
+
+local DebugDisp = Object:extend()
+
+function DebugDisp:new()
+end
+
+function DebugDisp:draw_gui()
+ if (true) then return nil end
+ --draw collision map
+ love.graphics.setColor(1, 0, 0, 0.5)
+ for x = 0, gameWidth, TILE_SIDE do
+ for y = 0, gameHeight, TILE_SIDE do
+ if stage:tile_at_pixel(x, y) then
+ love.graphics.print(stage:tile_at_pixel(x, y), x - 1, y - 2)
+ end
+ end
+ end
+end
+
+function DebugDisp:draw_gui_debug()
+ love.graphics.setColor(1, 1, 1, 0.5)
+ love.graphics.print(love.timer.getFPS(), 0, 0)
+ local count = 0
+ for _, _ in pairs(entities) do
+ count = count + 1
+ end
+ love.graphics.print(count, 0, 10)
+end
+
+return DebugDisp
diff --git a/src/disk.lua b/src/disk.lua
new file mode 100644
index 0000000..8a55439
--- /dev/null
+++ b/src/disk.lua
@@ -0,0 +1,125 @@
+local anim8 = require'libs/anim8'
+local Entity = require'src/entity'
+local Hitbox = require'src/hitbox'
+local Particle = require'src/particle'
+local Force = require'src/force'
+local Liquid = require'src/water'
+local sign = require'src/sign'
+local play_sfx = require'src/play_sfx'
+local player_conf = require'player_conf'
+
+local Disk = Entity:extend()
+
+Disk.draw_layer = 2
+Disk.bounce_sfx =
+ love.audio.newSource('assets/sfx/bounce.wav', 'static')
+
+Disk.images = {
+ normal = love.graphics.newImage'assets/art/objects/disk.png',
+ highlight =
+ love.graphics.newImage'assets/art/objects/disk_highlight.png',
+}
+local g = anim8.newGrid(12, 12, Disk.images.normal:getWidth(),
+ Disk.images.normal:getHeight())
+
+local true_hitbox = Hitbox(4, 4, 4, 4)
+local disabled_hitbox = Hitbox(0, 0, 0, 0)
+
+function Disk:new(x, y, dx, dy)
+ Disk.super.new(self, x, y, disabled_hitbox)
+ self.x = x or 0
+ self.y = y or 0
+ self.dx = dx or 0
+ self.dy = dy or 0
+ self.animation = anim8.newAnimation(g('1-5', 1), 2)
+ self.animation_speed = 1 --between 0 and 1
+ self.inactive = true
+ self.state = 'normal' --other state 'highlight'
+ self.countdown = 0
+end
+
+function Disk:update()
+ if pause then return nil end
+
+ --avoid killing the thrower lol
+ local Player = require'src/player'
+ self.hitbox = true_hitbox
+ if self.inactive and not self:collide(Player) then
+ self.inactive = false
+ end
+
+ self.animation:update(self.animation_speed)
+
+ --add speed modifiers
+ --forces
+ local mspd = {x = self.dx, y = self.dy}
+ local force = self:collide(Force)
+ if force then
+ mspd.x = mspd.x + force.dx
+ mspd.y = mspd.y + force.dy
+ end
+ if mspd.x == 0 and mspd.y == 0 then
+ mspd.x = sign(force.dx) / 10
+ mspd.y = sign(force.dy) / 10
+ end
+ local liquid = self:collide(Liquid)
+ if liquid then
+ mspd.x = mspd.x / liquid.modifier
+ mspd.y = mspd.y / liquid.modifier
+ end
+ if mspd.x == 0 then mspd.x = nil end
+ if mspd.y == 0 then mspd.y = nil end
+ --DISABLE MSPD.Y CAUSE IT = BAD
+ mspd.y = self.dy
+
+ if not self:move(mspd.x) then
+ self.dx = -self.dx
+ table.insert(entities, Particle(self.x, self.y, sign(-mspd.x), 0))
+ if sound then
+ Disk.bounce_sfx:stop()
+ Disk.bounce_sfx:play()
+ end
+ end
+ if not self:move(0, mspd.y) then
+ self.dy = -self.dy
+ table.insert(entities, Particle(self.x, self.y, 0, sign(-mspd.y)))
+ if sound then
+ Disk.bounce_sfx:stop()
+ Disk.bounce_sfx:play()
+ end
+ end
+
+ --change state with cooldown
+ if self.countdown > 0 then
+ self.countdown = self.countdown - 1
+ if self.countdown == 0 then
+ self.state = 'normal'
+ end
+ end
+
+ if self.inactive then
+ self.hitbox = disabled_hitbox
+ end
+end
+
+function Disk:draw_debug()
+ Disk.super.draw_debug(self, nil, nil, 1, 0, 0)
+end
+
+function Disk:draw()
+ local liquid = self:collide(Liquid)
+ if not liquid then liquid = self end
+ local alpha = 1
+ if DEBUG or self.inactive then
+ alpha = 0.5
+ end
+ love.graphics.setColor(liquid.color or {1, 1, 1}, alpha)
+ if current_stage == "discroom" then
+ love.graphics.setColor(0, 0, 0, 1)
+ end
+ self.animation:draw(Disk.images[self.state], math.floor(self.x),
+ math.floor(self.y))
+ --love.graphics.draw(Disk.spr, math.floor(self.x), math.floor(self.y))
+end
+
+return Disk
diff --git a/src/diskspawner.lua b/src/diskspawner.lua
new file mode 100644
index 0000000..89dca8c
--- /dev/null
+++ b/src/diskspawner.lua
@@ -0,0 +1,46 @@
+local Vector = require'libs/vector'
+local anim8 = require'libs/anim8'
+local Object = require'src/object'
+local Disk = require'src/disk'
+local play_sfx = require'src/play_sfx'
+
+local DiskSpawner = Object:extend()
+
+DiskSpawner.draw_layer = 5
+
+local g = anim8.newGrid(12, 12, Disk.images.normal:getWidth(),
+ Disk.images.normal:getHeight())
+function DiskSpawner:new(x, y, spawn_speed, disk_speed, delay, disk)
+ self.x = x or 0
+ self.y = y or 0
+ self.spawn_speed = 60 / (spawn_speed or 1)
+ self.disk_speed = disk_speed or 2
+ self.disk = disk or Disk
+ self.delay = self.spawn_speed + 60 * delay or 0
+ self.animation = anim8.newAnimation(g('1-5', 1), 2)
+end
+
+function DiskSpawner:update()
+ if pause then return nil end
+
+ self.animation:update(1)
+ self.delay = self.delay - 1
+ if self.delay <= 0 then
+ local direction = Vector.random()
+ table.insert(entities, self.disk(self.x, self.y,
+ direction.x * self.disk_speed, direction.y * self.disk_speed))
+ self.delay = self.spawn_speed
+ play_sfx'throw'
+ end
+end
+
+function DiskSpawner:draw()
+ love.graphics.setColor(1, 1, 1, 1 - self.delay / self.spawn_speed)
+ if current_stage == "discroom" then
+ love.graphics.setColor(0, 0, 0, 1 - self.delay / self.spawn_speed)
+ end
+ self.animation:draw(self.disk.images.normal, math.floor(self.x),
+ math.floor(self.y))
+end
+
+return DiskSpawner
diff --git a/src/entity.lua b/src/entity.lua
new file mode 100644
index 0000000..2e03b92
--- /dev/null
+++ b/src/entity.lua
@@ -0,0 +1,64 @@
+--base for all objects with position and hitbox
+local Object = require'src/object'
+local Hitbox = require'src/hitbox'
+local sign = require'src/sign'
+
+local Entity = Object:extend()
+
+Entity.draw_layer = 0
+
+function Entity:new(x, y, hitbox)
+ self.x = x or 0
+ self.y = y or 0
+ self.hitbox = hitbox or Hitbox()
+end
+
+function Entity:draw_debug(offx, offy, r, g, b, a)
+ self.hitbox:draw(math.floor(self.x), math.floor(self.y), r, g, b, a)
+end
+
+function Entity:collide(type, position, exclude)
+ local position = position or {x = self.x, y = self.y}
+ local exclude = exclude or {}
+ for _, v in pairs(entities) do
+ if v:is(type) and not exclude[v] and
+ self.hitbox:collide(position.x, position.y, v.hitbox, v.x, v.y)
+ then
+ return v
+ end
+ end
+ return nil
+end
+
+function Entity:collide_solid(position)
+ local position = position or {x = self.x, y = self.y}
+ local sx = position.x + self.hitbox.sx
+ local sy = position.y + self.hitbox.sy
+ return stage:tile_at_pixel(sx, sy) ~= 0 or
+ stage:tile_at_pixel(sx + self.hitbox.width - 1, sy) ~= 0 or
+ stage:tile_at_pixel(sx, sy + self.hitbox.height - 1) ~= 0 or
+ stage:tile_at_pixel(sx + self.hitbox.width - 1,
+ sy + self.hitbox.height - 1) ~= 0
+end
+
+function Entity:move(spd_x, spd_y)
+ if self:collide_solid() then
+ return false
+ end
+ local spd_x = spd_x or 0
+ local spd_y = spd_y or 0
+ self.x = self.x + spd_x
+ self.y = self.y + spd_y
+ if self:collide_solid() then
+ local sign_x = sign(spd_x) / 10
+ local sign_y = sign(spd_y) / 10
+ while self:collide_solid() and security ~= 0 do
+ self.x = self.x - sign_x
+ self.y = self.y - sign_y
+ end
+ return false
+ end
+ return true
+end
+
+return Entity
diff --git a/src/force.lua b/src/force.lua
new file mode 100644
index 0000000..0fc3098
--- /dev/null
+++ b/src/force.lua
@@ -0,0 +1,11 @@
+local TileEntity = require'src/tileentity'
+
+local Force = TileEntity:extend()
+
+function Force:new(x, y, width, height, spdx, spdy)
+ Force.super.new(self, x, y, width, height)
+ self.dx = spdx or 0
+ self.dy = spdy or 0
+end
+
+return Force
diff --git a/src/hitbox.lua b/src/hitbox.lua
new file mode 100644
index 0000000..a2b62ae
--- /dev/null
+++ b/src/hitbox.lua
@@ -0,0 +1,36 @@
+local Object = require'libs/classic'
+
+local Hitbox = Object:extend()
+
+function Hitbox:new(sx, sy, width, height)
+ self.sx = sx or 0
+ self.sy = sy or 0
+ self.width = width or 8
+ self.height = height or 8
+end
+
+function Hitbox:draw(offx, offy, r, g, b, a)
+ local offx = offx or 0
+ local offy = offy or 0
+ local r = r or 0
+ local g = g or 0
+ local b = b or 1
+ local a = a or 0.5
+ love.graphics.setColor(r, g, b, a)
+ love.graphics.rectangle("fill", self.sx + offx, self.sy + offy,
+ self.width, self.height)
+end
+
+function Hitbox:collide(x, y, other, ox, oy)
+ --calculate starting x/y with offset
+ local x = x + self.sx
+ local y = y + self.sy
+ local ox = ox + other.sx
+ local oy = oy + other.sy
+ return x < ox + other.width and
+ x + self.width > ox and
+ y < oy + other.height and
+ y + self.height > oy
+end
+
+return Hitbox
diff --git a/src/lava.lua b/src/lava.lua
new file mode 100644
index 0000000..5674c4c
--- /dev/null
+++ b/src/lava.lua
@@ -0,0 +1,18 @@
+local anim8 = require'libs/anim8'
+local Water = require'src/water'
+
+local Lava = Water:extend()
+
+Lava.image = love.graphics.newImage'assets/art/animations/lava.png'
+local g = anim8.newGrid(8, 6, Lava.image:getWidth(),
+ Lava.image:getHeight())
+
+function Lava:new(x, y, width)
+ Lava.super.new(self, x, y, width, 16)
+ self.color = {1, 0, 0}
+ self.alpha = 1
+ self.image = Lava.image
+ self.modifier = 3
+end
+
+return Lava
diff --git a/src/liquid.lua b/src/liquid.lua
new file mode 100644
index 0000000..8dd3385
--- /dev/null
+++ b/src/liquid.lua
@@ -0,0 +1,13 @@
+local anim8 = require'libs/anim8'
+local Entity = require'src/entity'
+local Hitbox = require'src/hitbox'
+
+local Liquid = Entity:extend()
+Liquid.draw_layer = 3
+
+function Liquid:new(x, y, width)
+ self.width = width or 8
+ Liquid.super.new(self, x, y, Hitbox(0, 2, self.width, 6))
+end
+
+return Liquid
diff --git a/src/menu/mainmenu.lua b/src/menu/mainmenu.lua
new file mode 100644
index 0000000..603ab4a
--- /dev/null
+++ b/src/menu/mainmenu.lua
@@ -0,0 +1,417 @@
+local anim8 = require'libs/anim8'
+local baton = require'libs/baton'
+local Object = require'src/object'
+local MainMenu = Object:extend()
+local conf = require'menu_conf'
+local shake = require'src/screenshake'
+local play_sfx = require'src/play_sfx'
+
+--I will never code after that.
+--kill me plz
+--this code really need some OPTIMIZATIONZ:tm:
+
+function MainMenu:new()
+ --creation du menu
+ --LOADING IMAGES
+ self.character = {"saw-man", "neon", "scarlet", "theophile",
+ "jean-luc", "brave-scientist"}
+ self.arena = {"jungle", "nothern", "fire", "sky", "weirdo",
+ "discroom"}
+ self.character_logo = {}
+ self.character_full = {}
+ self.character_walking = {}
+ self.character_walking_red = {}
+ for i = 1, 6, 1 do
+ local path = 'assets/art/characters/' .. self.character[i] .. '/' ..
+ self.character[i]
+ self.character_full[i] = love.graphics.newImage(path..'-full.png')
+ self.character_walking[i]= love.graphics.newImage(path..'.png')
+ self.character_walking_red[i] =
+ love.graphics.newImage(path..'-1b.png')
+ end
+ self.level = {}
+ for i = 1, 6,1 do
+ self.level[i] = love.graphics.newImage('assets/art/menu/menu-' ..
+ self.arena[i] .. '.png')
+ end
+ self.title = love.graphics.newImage'assets/art/menu/title.png'
+ self.selec_disk =
+ love.graphics.newImage'assets/art/objects/disk_white.png'
+ self.chara_selec_screen =
+ love.graphics.newImage'assets/art/menu/character-selected.png'
+ self.chara_selec =
+ love.graphics.newImage'assets/art/menu/characters.png'
+ self.cursor = love.graphics.newImage'assets/art/menu/cursor.png'
+ self.scarlet =
+ love.graphics.newImage'assets/art/menu/scarlet_the_sheep_killer.png'
+ self.jeanluc =
+ love.graphics.newImage'assets/art/menu/jean-luc_likes_baguette.png'
+ --DECLARING OTHER VARIABLES
+ self.menu, self.line, self.i = -1, 1, 1
+ self.timer = {
+ title = love.timer.getTime(),
+ keys = love.timer.getTime()
+ }
+ self.title_position = 20
+ self.player1_temp, self.player2_temp = {}, {}
+ self.player1_temp.id, self.player2_temp.id = 1, 2
+ self.player1_temp.x, self.player1_temp.y = 0, 0
+ self.player2_temp.x, self.player2_temp.y = 1, 0
+ self.player1, self.player2 = nil, nil
+ self.i1, self.i2 = -1, -1
+ self.alpha = 0
+ self.menu_selected = 1
+ self.bye = false
+ already_played = already_played or false
+ --ANIM(ES)ATIONS ARE REAL
+ local g2 = anim8.newGrid(12, 12, self.selec_disk:getWidth(),
+ self.selec_disk:getHeight())
+ local g3 = anim8.newGrid(12, 12, self.character_walking[1]:getWidth(),
+ self.character_walking[1]:getHeight())
+ g4 = anim8.newGrid(64, 128, self.character_full[1]:getWidth(),
+ self.character_full[1]:getHeight())
+ local g5 = anim8.newGrid(28, 28, self.cursor:getWidth(),
+ self.cursor:getHeight())
+ self.animation2 = anim8.newAnimation(g2('1-6', 1), 1)
+ self.animation3 = anim8.newAnimation(g3('1-5', 1), 5)
+ self.animation4_1 = anim8.newAnimation(g4('1-2', 1), 3)
+ self.animation4_2 = anim8.newAnimation(g4('1-2', 1), 3)
+ self.animation5_1 = anim8.newAnimation(g5('1-2', 1), 1,
+ 'pauseAtStart')
+ self.animation5_2 = anim8.newAnimation(g5('1-2', 1), 1,
+ 'pauseAtStart')
+ --FONT
+ self.m04b = love.graphics.newFont('assets/fonts/m04b.TTF', 8)
+ --INPUT
+ self.input1 = baton.new(conf.controls[1])
+ self.input2 = baton.new(conf.controls[2])
+end
+
+function MainMenu:update(dt)
+ if pause then return nil end
+
+ --step event
+ local player_ex = self.player1
+ local input1, input2 = self.input1, self.input2
+ input1:update()
+ input2:update()
+ --we use frame timed animations, more consistent
+ self.animation2:update(1)
+ self.animation3:update(1)
+ --P1
+ if self.i1 == -1 then
+ self.animation4_1:pauseAtStart()
+ elseif self.i1 == 0 then
+ self.animation4_1 = anim8.newAnimation(g4(3, 1), 1)
+ else self.i1 = self.i1 - 1
+ end
+ --P2
+ self.animation4_1:update(1)
+ if self.i2 == -1 then
+ self.animation4_2:pauseAtStart()
+ elseif self.i2 == 0 then
+ self.animation4_2 = anim8.newAnimation(g4(3, 1), 1)
+ else self.i2 = self.i2 - 1
+ end
+ self.animation4_1:update(1)
+ self.animation4_2:update(1)
+ self.animation5_1:update(1)
+ self.animation5_2:update(1)
+
+ --MAIN MENU
+ if self.menu == 0 then
+ --logo move
+ if love.timer.getTime() - self.timer.title > 1 then
+ if self.title_position ~= 22 and self.title_position ~= 18 then
+ self.title_position = self.title_position - self.i
+ else
+ self.i = -self.i
+ self.title_position = self.title_position - self.i
+ end
+ self.timer.title = love.timer.getTime()
+ end
+ --input
+ if love.timer.getTime() - self.timer.keys > 0.1 then
+ --down
+ if input1:pressed'down' and self.line ~= 3 then
+ self.line = self.line + 1
+ self.timer.keys = love.timer.getTime()
+ play_sfx('select', 1)
+ end
+ --up
+ if input1:pressed'up' and self.line ~= 1 then
+ self.line = self.line - 1
+ self.timer.keys = love.timer.getTime()
+ play_sfx('select', 1)
+ end
+ end
+ end
+ --INTRO
+ if self.menu == -1 and (self.alpha > 2 or input1:pressed'yes') then
+ self.menu = 0
+ shake(5)
+ self.alpha = 1
+ self.timer.keys = love.timer.getTime()
+ play_sfx('select', 1)
+ end
+ --CHARACTER SELECT
+ if self.menu == 1 then
+ --player 1 input
+ if not self.player1 then
+ --P1 up
+ if input1:pressed'up' and self.player1_temp.id > 2 then
+ self.player1_temp.id = self.player1_temp.id - 2
+ self.player1_temp.y = self.player1_temp.y - 1
+ play_sfx('select', 1)
+ end
+ --P1 down
+ if input1:pressed'down' and self.player1_temp.id < 5 then
+ self.player1_temp.id = self.player1_temp.id + 2
+ self.player1_temp.y = self.player1_temp.y + 1
+ play_sfx('select', 1)
+ end
+ --P1 left
+ if input1:pressed'left' and self.player1_temp.id % 2 == 0 then
+ self.player1_temp.id = self.player1_temp.id - 1
+ self.player1_temp.x = self.player1_temp.x - 1
+ play_sfx('select', 1)
+ end
+ --P1 right
+ if input1:pressed'right' and self.player1_temp.id % 2 == 1 then
+ self.player1_temp.id = self.player1_temp.id + 1
+ self.player1_temp.x = self.player1_temp.x + 1
+ play_sfx('select', 1)
+ end
+ --P1 yes
+ if input1:pressed'yes' and not self.player1 then
+ self.player1 = self.player1_temp.id
+ self.i1 = 20
+ self.animation4_1:resume()
+ self.animation5_1:pauseAtEnd()
+ self.timer.keys = love.timer.getTime()
+ play_sfx('confirm', 1.1)
+ end
+ end
+ if input1:pressed'no' then
+ if self.player1 then self.timer.keys = love.timer.getTime() end
+ self.player1 = nil
+ self.i1 = -1
+ self.animation4_1 = anim8.newAnimation(g4('1-2', 1), 3)
+ self.animation5_1:pauseAtStart()
+ play_sfx('cancel', 1)
+ end
+ --player 2 input
+ if not self.player2 then
+ --P2 up
+ if input2:pressed'up' and self.player2_temp.id > 2 then
+ self.player2_temp.id = self.player2_temp.id - 2
+ self.player2_temp.y = self.player2_temp.y - 1
+ play_sfx('select', 1)
+ end
+ --P2 down
+ if input2:pressed'down' and self.player2_temp.id < 5 then
+ self.player2_temp.id = self.player2_temp.id + 2
+ self.player2_temp.y = self.player2_temp.y + 1
+ play_sfx('select', 1)
+ end
+ --P2 left
+ if input2:pressed'left' and self.player2_temp.id % 2 == 0 then
+ self.player2_temp.id = self.player2_temp.id - 1
+ self.player2_temp.x = self.player2_temp.x - 1
+ play_sfx('select', 1)
+ end
+ --P2 right
+ if input2:pressed'right' and self.player2_temp.id % 2 == 1 then
+ self.player2_temp.id = self.player2_temp.id + 1
+ self.player2_temp.x = self.player2_temp.x + 1
+ play_sfx('select', 1)
+ end
+ --P2 yes
+ if input2:pressed'yes' and not self.player2 then
+ self.player2 = self.player2_temp.id
+ self.i2 = 20
+ self.animation4_2:resume()
+ self.animation5_2:pauseAtEnd()
+ play_sfx('confirm', 1.1)
+ end
+ end
+ if input2:pressed'no' then
+ self.player2 = nil
+ self.i2 = -1
+ self.animation4_2 = anim8.newAnimation(g4('1-2', 1), 3)
+ self.animation5_2:pauseAtStart()
+ play_sfx('cancel', 1)
+ end
+ end
+ --STAGE SELECT
+ if self.menu == 4 then
+ if not self.bye then
+ if input1:pressed'up' and self.menu_selected ~= 1 then
+ self.menu_selected = self.menu_selected - 1
+ self.timer.keys = love.timer.getTime()
+ play_sfx('select', 1)
+ end
+ if input1:pressed'down' and self.menu_selected ~= 6 then
+ self.menu_selected = self.menu_selected + 1
+ self.timer.keys = love.timer.getTime()
+ play_sfx('select', 1)
+ end
+ if input1:pressed'yes' then
+ self.bye = true
+ play_sfx('confirm', 1.4)
+ end
+ end
+ if self.bye then
+ self.alpha = self.alpha - 8/255
+ if self.alpha < 0 then
+ skins = {
+ self.character[self.player1],
+ self.character[self.player2],
+ self.player1,
+ self.player2
+ }
+ --print(skins[1], skins[2])
+ current_stage = self.arena[self.menu_selected]
+ local Stage = require'src/stage'
+ shake(5)
+ stage = Stage(self.arena[self.menu_selected])
+ end
+
+ end
+ end
+ --GLOBAL ACCEPT/RETURN
+ if love.timer.getTime() - self.timer.keys > 0.1 then
+ --accept (yes)
+ if input1:pressed'yes' then
+ if self.menu ~= 2 then
+ if self.menu == 0 then
+ self.menu = self.line
+ self.player1, self.player2 = nil, nil
+ self.i1, self.i2 = -1, -1
+ self.animation4_2 = anim8.newAnimation(g4('1-2', 1), 3)
+ self.animation5_2:pauseAtStart()
+ play_sfx('confirm', 1)
+ end
+ if self.menu == 1 and self.player1 and self.player2 then
+ self.menu = self.menu + 3
+ play_sfx('confirm', 1.2)
+ end
+ shake(3)
+ self.timer.keys = love.timer.getTime()
+ end
+ end
+ if input2:pressed'yes' then
+ shake(3)
+ end
+ --return (no)
+ --print(player_ex)
+ if input1:pressed'no' and self.menu ~= 0 then
+ if (self.menu == 1 and not player_ex) or (self.menu == 2) then
+ --print'hello'
+ self.menu = 0
+ play_sfx('cancel', 1)
+ end
+ if self.menu == 4 then self.menu = 1; play_sfx('cancel', 1) end
+ shake(3)
+ self.timer.keys = love.timer.getTime()
+ end
+ end
+ if self.menu == 3 then os.exit() end
+end
+
+function MainMenu:draw_gui()
+ --draw event
+ --black
+ love.graphics.setColor(0, 0, 0, 1)
+ love.graphics.rectangle('fill', 0, 0, gameWidth, gameHeight)
+ --INTRO
+ if self.menu == -1 then
+ if self.alpha < 1 then
+ love.graphics.setColor(1, 1, 1, self.alpha)
+ else
+ love.graphics.setColor(1, 1, 1, 1)
+ end
+ love.graphics.draw(self.scarlet, 16, 48)
+ love.graphics.draw(self.jeanluc, 160, 48)
+ if self.alpha ~= 2 then self.alpha = self.alpha + 2/255 end
+ end
+ --red (using color mask)
+ love.graphics.setColor(1, 0, 77/255, 1)
+ --MAIN MENU
+ if self.menu == 0 then
+ self.animation2:draw(self.selec_disk, 110, 108 + self.line * 10)
+ self.animation2:draw(self.selec_disk,
+ gameWidth - 122,
+ 108 + self.line * 10)
+ love.graphics.draw(self.title, 64, self.title_position, 0, 2, 2)
+ love.graphics.setFont(self.m04b)
+ --reset color mask
+ love.graphics.setColorMask(true, true, true, true)
+ --such text
+ love.graphics.printf('Fight', 0, 120,
+ gameWidth, 'center')
+ love.graphics.printf('Options', 0, 130,
+ gameWidth, 'center')
+ love.graphics.printf('Quit', 0, 140,
+ gameWidth, 'center')
+ end
+ --CHARA SELECT
+ if self.menu == 1 then
+ love.graphics.draw(self.chara_selec_screen, 0, 0)
+ love.graphics.draw(self.chara_selec_screen, gameWidth, 0, 0, - 1, 1)
+ love.graphics.draw(self.chara_selec, 133, 73)
+ --P1
+ if not self.player1 then
+ self.animation4_1:draw(self.character_full[self.player1_temp.id], 45, 22)
+ self.animation3:draw(self.character_walking_red[self.player1_temp.id], 128, 30, 0, 2, 2)
+ end
+ if self.player1 and self.i1 ~= -1 then
+ if self.i1 ~= 0 then love.graphics.setColor(1, 0, 77/255, 1) else love.graphics.setColor(1, 1, 1, 1) end
+ self.animation4_1:draw(self.character_full[self.player1], 45, 22)
+ --white
+ love.graphics.setColor(1, 1, 1, 1)
+ self.animation3:draw(self.character_walking[self.player1_temp.id], 128, 30, 0, 2, 2)
+ end
+ love.graphics.setColor(1, 0, 77/255, 1)
+ self.animation5_1:draw(self.cursor, 132 + self.player1_temp.x * 28, 72 + self.player1_temp.y * 28)
+ --P2
+ if not self.player2 then
+ self.animation4_2:draw(self.character_full[self.player2_temp.id], 275, 22, 0, -1, 1)
+ self.animation3:draw(self.character_walking_red[self.player2_temp.id], 192, 30, 0, -2, 2)
+ end
+ if self.player2 and self.i2 ~= -1 then
+ if self.i2 ~= 0 then love.graphics.setColor(1, 0, 77/255, 1) else love.graphics.setColor(1, 1, 1, 1) end
+ self.animation4_2:draw(self.character_full[self.player2], 275, 22, 0, -1, 1)
+ --white
+ love.graphics.setColor(1, 1, 1, 1)
+ self.animation3:draw(self.character_walking[self.player2_temp.id], 192, 30, 0, -2, 2)
+ end
+ love.graphics.setColor(1, 0, 77/255, 1)
+ self.animation5_2:draw(self.cursor, 132 + self.player2_temp.x * 28 + 28, 72 + self.player2_temp.y * 28, 0, -1, 1)
+ love.graphics.printf('Choose your slicer !', 0, 4, gameWidth, 'center')
+ love.graphics.printf(self.character[self.player1_temp.id], 0, 160, 149, 'center')
+ love.graphics.printf(self.character[self.player2_temp.id], 171, 160, 149, 'center')
+ if self.player1 and self.player2 then love.graphics.printf("Start", 0, 160, gameWidth, 'center') end
+ end
+ --WORLD
+ if self.menu == 4 then
+ if self.alpha > 0 then love.graphics.setColor(1, 0, 77/255, self.alpha) else love.graphics.setColor(0, 0, 0, 0) end
+ love.graphics.printf('Select a stage', 0, 4, gameWidth, 'center')
+ self.animation2:draw(self.selec_disk, 56, self.menu_selected * 26 - 4)
+ self.animation2:draw(self.selec_disk, 264, self.menu_selected * 26 - 4)
+ --white plz
+ if self.alpha > 0 then love.graphics.setColor(1, 1, 1, self.alpha) else love.graphics.setColor(0, 0, 0, 0) end
+ for i = 1, 6, 1 do
+ love.graphics.draw(self.level[i], 80, i * 26 - 10)
+ end
+ end
+ --OPTIONS
+ if self.menu == 2 then
+ pause = true
+ end
+end
+
+function MainMenu:draw_gui_debug()
+ --dessin des infos de debug
+end
+return MainMenu
diff --git a/src/menu/pause.lua b/src/menu/pause.lua
new file mode 100644
index 0000000..4f66ee2
--- /dev/null
+++ b/src/menu/pause.lua
@@ -0,0 +1,137 @@
+local anim8 = require'libs/anim8'
+local baton = require'libs/baton'
+local Object = require'src/object'
+local MainMenu = require'src/menu/mainmenu'
+local play_sfx = require'src/play_sfx'
+
+local PauseMenu = Object:extend()
+
+PauseMenu.draw_layer = 100
+
+sound = true
+screenshake = true
+
+local pause_input = baton.new(require'menu_conf'.controls[1])
+
+function PauseMenu:new()
+ self.entries = {
+ {stage.name == 'mainmenu' and 'continue' or 'return', nil,
+ function()
+ pause = false
+ if stage.name == 'mainmenu' then
+ local menu
+ for _, v in pairs(entities) do
+ if v:is(MainMenu) then
+ menu = v
+ break
+ end
+ end
+ menu.menu = 0
+ end
+ end},
+ {'fullscreen ', love.window.getFullscreen(),
+ function()
+ love.window.setFullscreen(not love.window.getFullscreen())
+ end
+ },
+ {'sound ', sound,
+ function()
+ sound = not sound
+ end},
+ {'screenshake ', screenshake,
+ function()
+ screenshake = not screenshake
+ end
+ },
+ {'particles ', particles,
+ function()
+ particles = not particles
+ end
+ },
+ stage.name == 'mainmenu' and
+ {'return to title screen', nil,
+ function()
+ --si on désactive pas le menu quand on le quitte ça oblige à
+ --appuyer sur continue pour revenir au main menu
+ pause, aldready_played = false, false
+ local Stage = require'src/stage'
+ stage = Stage'mainmenu'
+ end
+ } or nil,
+}
+
+ self.selec_disk =
+ love.graphics.newImage'assets/art/objects/disk_white.png'
+ local g2 = anim8.newGrid(12, 12, self.selec_disk:getWidth(),
+ self.selec_disk:getHeight())
+ self.animation2 = anim8.newAnimation(g2('1-6', 1), 1)
+ self.cursor = 1
+end
+
+function PauseMenu:update()
+ if not pause then return nil end --don't process if not paused
+ self.animation2:update(1)
+
+ --update inputs
+ pause_input:update()
+
+ --move cursor
+ if pause_input:pressed'up' then
+ self.cursor = self.cursor - 1
+ play_sfx('select', 1)
+ end
+ if pause_input:pressed'down' then
+ self.cursor = self.cursor + 1
+ play_sfx('select', 1)
+ end
+ if self.cursor < 1 then
+ self.cursor = #self.entries
+ end
+ if self.cursor > #self.entries then
+ self.cursor = 1
+ end
+
+ --if the player confirms, then process the function
+ if pause_input:pressed'yes' then
+ play_sfx('confirm', 1)
+ self.entries[self.cursor][3]()
+ end
+
+ --if the player wants to exit, so should they
+ --if pause_input:pressed'no' then
+ -- play_sfx('cancel', 1)
+ -- pause = false
+ --end
+
+ self.entries[2][2] = love.window.getFullscreen()
+ self.entries[3][2] = sound
+ self.entries[4][2] = screenshake
+ self.entries[5][2] = particles
+end
+
+function PauseMenu:draw()
+ if not pause then return nil end --don't draw if not paused
+ love.graphics.setColor(0, 0, 0, 1)
+ love.graphics.rectangle('fill', 0, 0, gameWidth, gameHeight)
+ love.graphics.setColor(1, 0, 77/255, 1)
+
+ self.animation2:draw(self.selec_disk, 50, 58 + self.cursor * 10)
+ self.animation2:draw(self.selec_disk,
+ gameWidth - 62,
+ 58 + self.cursor * 10)
+
+ love.graphics.printf(stage.name == 'mainmenu' and '-options-' or
+ '-pause-', 0, 50, gameWidth, 'center')
+ --print()
+ for i, v in ipairs(self.entries) do
+ love.graphics.printf((v[1] ..
+ (self.entries[i][2] ~= nil and (self.entries[i][2] and ' on' or 'off') or '')),
+ 0, 60 + 10 * i, gameWidth, 'center')
+ --print((self.cursor == i and '⟩ ' or ' ') ..
+ -- v[1] ..
+ -- (self.entries[i][2] ~= nil and
+ -- (self.entries[i][2] and 'on' or 'off') or ''))
+ end
+end
+
+return PauseMenu
diff --git a/src/menu/results.lua b/src/menu/results.lua
new file mode 100644
index 0000000..96e24c5
--- /dev/null
+++ b/src/menu/results.lua
@@ -0,0 +1,98 @@
+local baton = require'libs/baton'
+local Object = require'src/object'
+local Player = require'src/player'
+local count = require'src/count' --count the number of instances
+local shake = require'src/screenshake'
+local PauseMenu = require'src/menu/pause'
+local conf = require'menu_conf'
+
+local Results = Object:extend()
+
+function Results:new()
+ self.active = false
+ self.candraw = false
+ self.character = {"saw-man", "neon", "scarlet", "theophile",
+ "jean-luc", "brave-scientist"}
+ self.character_win = {}
+ self.character_lose = {}
+ for i = 1, 6, 1 do
+ local path = 'assets/art/characters/' .. self.character[i] .. '/' ..
+ self.character[i]
+ self.character_win[i] = love.graphics.newImage(path..'-win.png')
+ self.character_lose[i]= love.graphics.newImage(path..'-lose.png')
+ end
+ self.input = baton.new(conf.controls[1])
+end
+
+function Results:update()
+ self.input:update()
+ if not self.active then
+ self.active = count(Player) < 2
+ self.timer = love.timer.getTime()
+ end
+ if self.active and love.timer.getTime() - self.timer > 1 then
+ pause = true
+
+ for _, v in pairs(entities) do
+ if v:is(PauseMenu) then
+ v:destroy()
+ end
+ end
+ for _, v in pairs(entities) do
+ if v:is(Player) then
+ self.winner = v.player_id
+ break
+ end
+ end
+ if not self.candraw then
+ win_streak[self.winner] = win_streak[self.winner] + 1
+ shake(5)
+ end
+ self.candraw = true
+ if self.input:pressed'yes' then
+ already_started = true
+ pause = false
+ local Stage = require'src/stage'
+ stage = Stage'mainmenu'
+ end
+ end
+end
+
+function Results:draw_gui()
+ if self.candraw then
+ love.graphics.setColor(0, 0, 0, 1)
+ love.graphics.rectangle('fill', 0, 0, gameWidth, gameHeight)
+ love.graphics.setColor(1, 1, 1, 1)
+ love.graphics.draw(self.character_win[skins[self.winner + 2]]
+ , 50, 20)
+ love.graphics.draw(self.character_lose[skins[
+ (self.winner == 1 and 2 or 1) + 2]],
+ 40, 90)
+ love.graphics.setColor(1, 0, 77/255, 1)
+ love.graphics.printf('-Results-', 0, 4,
+ gameWidth, 'center')
+ love.graphics.printf('Press enter or action', 0, 160, gameWidth, 'center')
+ love.graphics.print('Player ' .. self.winner .. ' wins !', 124, 22)
+ love.graphics.print('Player ' .. (self.winner == 1 and 2 or 1) ..
+ ' loses !', 114, 92)
+ love.graphics.print(skins[self.winner], 124, 32)
+ love.graphics.print(skins[self.winner == 1 and 2 or 1], 114, 102)
+ love.graphics.print('Wins- ' .. win_streak[self.winner], 124, 42)
+ love.graphics.print('Wins- ' .. win_streak
+ [self.winner == 1 and 2 or 1], 114, 112)
+ love.graphics.print('disk thrown- ' .. stats[self.winner].throw, 124, 52)
+ love.graphics.print('disk thrown- ' .. stats[self.winner == 1 and 2 or 1].throw, 114, 122)
+ love.graphics.print('slash precision- ' ..
+ math.floor(stats[self.winner].slash_success / (stats[self.winner].slash ~= 0
+ and stats[self.winner].slash or 1) * 100),
+ 124, 62)
+ love.graphics.print('slash precision- ' ..
+ math.floor(stats[self.winner == 1 and 2 or 1].slash_success / (stats[self.winner == 1 and 2 or 1].slash~= 0
+ and stats[self.winner == 1 and 2 or 1].slash or 1) * 100),
+ 114, 132)
+ love.graphics.print('jumps- ' .. stats[self.winner].jump, 124, 72)
+ love.graphics.print('jumps- ' .. stats[self.winner == 1 and 2 or 1].jump, 114, 142)
+ end
+end
+
+return Results
diff --git a/src/music.lua b/src/music.lua
new file mode 100644
index 0000000..42dec6c
--- /dev/null
+++ b/src/music.lua
@@ -0,0 +1,26 @@
+--play music
+
+local musics = {
+ --nothern = {
+ -- name = 'Chasing Phantoms (The Core).mp3',
+ -- volume = 0.5
+ --},
+ --jungle = {
+ -- name = 'That\'s The Spirit (Final Battle).mp3',
+ -- volume = 0.5
+ --}
+}
+
+return function(stage)
+ if playing then
+ playing:stop()
+ end
+ if musics[stage] then
+ playing = love.audio.newSource(
+ 'assets/music/'..musics[stage].name,
+ 'stream')
+ playing:setLooping(true)
+ playing:setVolume(musics[stage].volume)
+ playing:play()
+ end
+end
diff --git a/src/object.lua b/src/object.lua
new file mode 100644
index 0000000..8b1a3ef
--- /dev/null
+++ b/src/object.lua
@@ -0,0 +1,16 @@
+--we use this to give basic features to all objects
+
+local Object = require'libs/classic'
+
+local MyObject = require'libs/classic'
+
+function MyObject:destroy()
+ for i, v in pairs(entities) do
+ if v == self then
+ entities[i] = nil
+ return
+ end
+ end
+end
+
+return MyObject
diff --git a/src/particle.lua b/src/particle.lua
new file mode 100644
index 0000000..d3543d4
--- /dev/null
+++ b/src/particle.lua
@@ -0,0 +1,62 @@
+local anim8 = require'libs/anim8'
+local Object = require'src/object'
+
+local Particle = Object:extend()
+
+Particle.draw_layer = 10
+
+Particle.image =
+ love.graphics.newImage'assets/art/animations/particles.png'
+local g = anim8.newGrid(16, 16, Particle.image:getWidth(),
+ Particle.image:getHeight())
+
+function Particle:new(x, y, dx, dy)
+ if not particles then
+ return nil
+ end
+ self.x = x or 0
+ self.y = y or 0
+ dx = dx or 0
+ dy = dy or 0
+ self.duration = 20
+ self.rotation = dx * math.rad(90) + (dy == 1 and math.rad(180) or 0)
+ if dx == -1 then
+ self.y = self.y + 13
+ elseif dx == 1 then
+ self.x = self.x + 12
+ self.y = self.y - 3
+ elseif dy == -1 then
+ self.x = self.x - 2
+ elseif dy == 1 then
+ self.y = self.y + 12
+ self.x = self.x + 14
+ end
+ self.x = math.floor(self.x)
+ self.y = math.floor(self.y)
+ self.animation = anim8.newAnimation(g('1-5', 1), 4, 'pauseAtEnd')
+end
+
+function Particle:update()
+ if not particles then
+ self:destroy()
+ return nil
+ end
+
+ if pause then return nil end
+
+ self.animation:update(1)
+ self.duration = self.duration - 1
+ if self.duration == 0 then
+ self:destroy()
+ end
+end
+
+function Particle:draw()
+ love.graphics.setColor(1, 1, 1, 1)
+ if current_stage == "discroom" then
+ love.graphics.setColor(0, 0, 0, 1)
+ end
+ self.animation:draw(Particle.image, self.x, self.y, self.rotation)
+end
+
+return Particle
diff --git a/src/particule.lua b/src/particule.lua
new file mode 100644
index 0000000..1430edd
--- /dev/null
+++ b/src/particule.lua
@@ -0,0 +1 @@
+local Object = require'src/object'
diff --git a/src/play_sfx.lua b/src/play_sfx.lua
new file mode 100644
index 0000000..787aaeb
--- /dev/null
+++ b/src/play_sfx.lua
@@ -0,0 +1,8 @@
+return function(sound_name, pitch)
+ if sound then
+ local sound_path = 'assets/sfx/'..sound_name..'.wav'
+ local sound = love.audio.newSource(sound_path, 'static')
+ sound:setPitch(pitch or (0.9 + love.math.random() * 0.2))
+ sound:play()
+ end
+end
diff --git a/src/player.lua b/src/player.lua
new file mode 100644
index 0000000..124fa1d
--- /dev/null
+++ b/src/player.lua
@@ -0,0 +1,327 @@
+local baton = require'libs/baton'
+local anim8 = require'libs/anim8'
+local play_sfx = require'src/play_sfx'
+local Entity = require'src/entity'
+local Disk = require'src/disk'
+local Slash = require'src/slash'
+local Force = require'src/force'
+local Liquid = require'src/liquid'
+local Water = require'src/water'
+local Lava = require'src/lava'
+local Slime = require'src/slime'
+local WalkParticle = require'src/walk_particle'
+local conf = require'player_conf'
+local sign = require'src/sign'
+local shake = require'src/screenshake'
+local count = require'src/count'
+
+local Player = Entity:extend()
+
+Player.draw_layer = 0
+Player.tag_image = love.graphics.newImage'assets/art/ui/tag.png'
+
+function Player:new(x, y, hitbox, player_id, skin, xscale)
+ Player.super.new(self, x, y, hitbox)
+ self.spd = {
+ x = 0,
+ y = 0
+ }
+ self.pressed_jump = 0 --jump buffering
+ self.can_jump = 0 --also used for coyote jumps
+ self.fastfall = true
+ self.jumping = false
+ self.fastfall_jumping = false
+ self.xscale = xscale or 1
+ self.player_id = player_id or 1
+ self.invulnerable = 0 --make the player invulnerable
+ self.hurt = 0 --red flash animation
+ self.disk_cooldown = 0 --protect Jean-Luc at all costs
+ self.state = 'stand'
+ self.hp = conf.hp
+ --set skin
+ self.skin = skin or 'jean-luc'
+ if skins then
+ self.skin = skins[self.player_id]
+ end
+ self.color = conf.color[self.player_id] or {0, 0, 0, 1}
+ --create animations
+ self.image = love.graphics.newImage(
+ 'assets/art/characters/'..self.skin..'/'..self.skin..'.png')
+ local g = anim8.newGrid(12, 12, self.image:getWidth(),
+ self.image:getHeight())
+ self.animations = {
+ stand = anim8.newAnimation(g('1-1', 1, '8-8', 1), 40),
+ walk = anim8.newAnimation(g('1-5', 1), 3),
+ jump = anim8.newAnimation(g('6-6', 1), 1),
+ look_up = anim8.newAnimation(g('7-7', 1), 1),
+ crouch = anim8.newAnimation(g('8-8', 1), 1),
+ }
+ --create input manager
+ self.input = baton.new(conf.controls[self.player_id])
+ --load sfxs
+ local newSource = love.audio.newSource
+
+ --particle limiter
+ self.particle_delay = 0
+
+ --reset nerd stats
+ stats[self.player_id] = {
+ throw = 0,
+ slash = 0,
+ slash_success = 0,
+ jump = 0,
+ }
+end
+
+function Player:update()
+ if pause then return nil end
+
+ --if the other player is dead, make me invulnerable
+ if count(Player) < 2 then
+ self.invulnerable = 42
+ end
+
+ --shortcuts
+ local input = self.input
+ local spd = self.spd
+ --update inputs
+ if input then
+ input:update()
+ end
+
+ --calculate direction
+ local move = {
+ x = (input:down'right' and 1 or 0) -
+ (input:down'left' and 1 or 0),
+ y = (input:down'down' and 1 or 0) -
+ (input:down'up' and 1 or 0)
+ }
+
+ local fluid = self:collide(Liquid) or self
+ local fluid_modifier = fluid.modifier or 1
+
+ --acceleration
+ spd.x = spd.x + move.x * conf.acceleration
+ --friction
+ spd.x = spd.x * (1 - conf.friction * fluid_modifier)
+
+ --gravity
+ spd.y = spd.y + ((self.fastfall or self.fastfall_jumping) and
+ conf.gravity_fastfall or conf.gravity)
+ --vertical friction (fall speed cap)
+ spd.y = spd.y * (1 - conf.vertical_friction)
+ --jump
+ if input:pressed'jump' then
+ self.pressed_jump = conf.jump_buffering
+ elseif self.pressed_jump > 0 then
+ self.pressed_jump = self.pressed_jump - 1
+ end
+ if self.pressed_jump > 0 and input:down'jump' and
+ self.can_jump > 0 then
+ stats[self.player_id].jump = stats[self.player_id].jump + 1
+ spd.y = conf.jump_spd /
+ ((fluid_modifier ~= 1) and (0.25 + fluid_modifier / 2) or 1)
+ self.jumping = true
+ self.can_jump = 0
+ play_sfx'jump'
+ end
+ --fastfall
+ if self.jumping and input:released'jump' then
+ self.fastfall_jumping = true
+ end
+ if not self.jumping and input:pressed'down' then
+ self.fastfall = true
+ end
+
+ --if the player is at it's jump peak, he can't stop fastfalling
+ if self.fastfall_jumping and spd.y >= 0 then
+ self.fastfall_jumping = false
+ end
+
+ --forces
+ local mspd = {x = 0, y = 0}
+ local force = self:collide(Force)
+ if force then
+ mspd.x = mspd.x + force.dx
+ mspd.y = mspd.y + force.dy
+ end
+
+ if mspd.x == 0 then mspd.x = nil end
+ if mspd.y == 0 then mspd.y = nil end
+ if mspd.x then self:move(mspd.x) end
+ if mspd.y then spd.y = spd.y + mspd.y / 4 end
+
+ --move the player horizontaly
+ spd.x = self:move(spd.x) and spd.x or 0
+ --move the player verticaly
+ local result_move_y = self:move(0, spd.y)
+ if not result_move_y then
+ --player hit the ground?
+ if spd.y > 0 then
+ --disable fastfall
+ self.fastfall = false
+ self.jumping = false
+ --the player can jump
+ self.can_jump = conf.coyote_time
+ end
+ spd.y = 0 --reset vertical speed anyway
+ elseif self.can_jump > 0 then --the player is in the air
+ self.can_jump = self.can_jump - 1
+ end
+
+ --xscale (for draw)
+ if move.x ~= 0 then
+ self.xscale = move.x
+ end
+
+ --disk throw
+ if self.disk_cooldown > 0 then
+ self.disk_cooldown = self.disk_cooldown - 1
+ end
+ if self.input:pressed'action' and
+ self.disk_cooldown <= conf.disk_cooldown_margin then
+ stats[self.player_id].throw = stats[self.player_id].throw + 1
+ self.disk_cooldown = conf.disk_cooldown
+ local disk_spd = {x = 0, y = 0}
+ disk_spd.x, disk_spd.y = move.x, move.y
+ if disk_spd.x == 0 and disk_spd.y == 0 then
+ disk_spd.x = self.xscale
+ end
+ local knockback = {}
+ for i, v in pairs(disk_spd) do
+ disk_spd[i] = v * 2
+ knockback[i] = -v * 3
+ end
+ table.insert(entities,
+ Disk(self.x, self.y + 1,disk_spd.x, disk_spd.y))
+ self:move(knockback.x)
+ self:move(nil, knockback.y)
+ play_sfx'throw'
+ end
+
+ --slash!
+ if self.input:pressed'slash' and
+ self.disk_cooldown <= conf.disk_cooldown_margin then
+ stats[self.player_id].slash = stats[self.player_id].slash + 1
+ self.disk_cooldown = conf.disk_cooldown
+ local slash_x, slash_y = move.x, move.y
+ if slash_y ~= 0 then
+ slash_x = 0
+ elseif slash_x == 0 then
+ slash_x = self.xscale
+ end
+ table.insert(entities,
+ Slash(self, self.x, self.y, slash_x, slash_y))
+ end
+
+ --change state
+ local previous_state = self.state
+ if self.jumping then
+ self.state = 'jump'
+ elseif move.x ~= 0 then
+ self.state = 'walk'
+ elseif move.y == -1 then
+ self.state = 'look_up'
+ elseif move.y == 1 then
+ self.state = 'crouch'
+ else
+ self.state = 'stand'
+ end
+ if self.state ~= previous_state then
+ self.animations[self.state]:gotoFrame(1)
+ end
+
+ --update animation
+ self.animations[self.state]:update(1)
+
+ --update invulnerability
+ if self.invulnerable > 0 then
+ self.invulnerable = self.invulnerable - 1
+ end
+ if self.hurt > 0 then
+ self.hurt = self.hurt - 1
+ elseif self.hp == 1 then
+ self.hurt = conf.invulnerability_on_hit
+ end
+
+ --particle effects
+ --walk
+ if self.can_jump > 0 then
+ if self.particle_delay > 0 then
+ self.particle_delay = self.particle_delay - 1
+ elseif move.x ~= 0 then
+ table.insert(entities, WalkParticle(self.x, self.y, move.x))
+ self.particle_delay = conf.particle_delay
+ end
+ else
+ self.particle_delay = 0
+ end
+
+ --take damage and ***die***
+ --collide with disk
+ local disk = self:collide(Disk)
+ local lava = self:collide(Lava)
+ while disk or lava do
+ if disk then disk:destroy() end
+ lava = nil
+ if self.invulnerable == 0 then
+ self.hp = self.hp - 1
+ self.invulnerable = conf.invulnerability_on_hit
+ self.hurt = self.invulnerable
+ shake(3)
+ --play sfx
+ if self.hp == 0 then
+ play_sfx'death'
+ else
+ play_sfx'hurt'
+ end
+ end
+ disk = self:collide(Disk)
+ end
+ if self.input:pressed'suicide' or self.hp == 0 then
+ shake(5)
+ self:destroy()
+ end
+
+ --pause the game
+ if self.input:pressed'pause' then
+ pause = true
+ end
+end
+
+function Player:draw()
+ local function draw_player()
+ self.animations[self.state]:draw(self.image,
+ math.floor(self.x - (self.xscale - 1) * conf.texture_width / 2),
+ math.floor(self.y), 0, self.xscale, 1)
+ end
+
+ local fluid = self:collide(Liquid) or self
+ local color = fluid:is(Liquid) and fluid.color or {1, 1, 1}
+ local alpha = self.hurt / conf.invulnerability_on_hit
+ love.graphics.setColor(color[1], color[2], color[3],
+ DEBUG and 0.5 or 1)
+ --hello kikoo
+ if current_stage == "discroom" then
+ love.graphics.setColor(0, 0, 0, 1)
+ end
+ draw_player()
+ love.graphics.setColor(1, 0, 0, alpha / (DEBUG and 2 or 1))
+ draw_player()
+end
+
+function Player:draw_gui()
+ local color = {unpack(self.color)}
+ for i, v in pairs(color) do
+ color[i] = v * (1 - self.disk_cooldown / conf.disk_cooldown)
+ if self.disk_cooldown > 0 and
+ self.disk_cooldown <= conf.disk_cooldown_margin then
+ color[i] = 1
+ end
+ end
+ love.graphics.setColor(color, 1)
+ love.graphics.draw(Player.tag_image,
+ math.floor(self.x) + 2 + self.xscale, math.floor(self.y) - 10)
+end
+
+return Player
diff --git a/src/screenshake.lua b/src/screenshake.lua
new file mode 100644
index 0000000..9a6d1a3
--- /dev/null
+++ b/src/screenshake.lua
@@ -0,0 +1,5 @@
+return function(n)
+ if screenshake then
+ screen:setShake(n)
+ end
+end
diff --git a/src/sign.lua b/src/sign.lua
new file mode 100644
index 0000000..b14b8f2
--- /dev/null
+++ b/src/sign.lua
@@ -0,0 +1,5 @@
+local function sign(n)
+ return n > 0 and 1 or n < 0 and -1 or 0
+end
+
+return sign
diff --git a/src/slash.lua b/src/slash.lua
new file mode 100644
index 0000000..32d2c19
--- /dev/null
+++ b/src/slash.lua
@@ -0,0 +1,97 @@
+local anim8 = require'libs/anim8'
+local Entity = require'src/entity'
+local Hitbox = require'src/hitbox'
+local Disk = require'src/disk'
+local sign = require'src/sign'
+local play_sfx = require'src/play_sfx'
+local conf = require'player_conf'
+
+local Slash = Entity:extend()
+
+Slash.image =
+ love.graphics.newImage'assets/art/animations/slash.png'
+local g = anim8.newGrid(16, 18, Slash.image:getWidth(),
+ Slash.image:getHeight())
+
+function Slash:new(parent, x, y, dx, dy)
+ self.parent = parent
+ local dx, dy = dx and sign(dx) or 0, dy and sign(dy) or 0
+ self.rotation = math.rad(90 * dy)
+ self.scale = {x = 1, y = 1}
+ self.offset = {x = 8, y = -2}
+ local hbox = {sx = 2, sy = -2, width = 20, height = 16}
+ if dx == 1 then
+ hbox.width, hbox.height = hbox.height, hbox.width
+ elseif dx == -1 then
+ self.offset.x = 4
+ self.scale.x = -1
+ hbox.width, hbox.height = hbox.height, hbox.width
+ hbox.sx = -17
+ elseif dy == 1 then
+ self.offset.x = 14
+ self.offset.y = 7
+ hbox.sy = 1
+ hbox.sx = -18
+ elseif dy == -1 then
+ self.offset.x = -2
+ self.offset.y = 4
+ hbox.sy = -18
+ hbox.sx = -2
+ end
+ self.dx, self.dy = dx, dy
+ --animation
+ self.animation = anim8.newAnimation(g('1-10', 1), 1, 'pauseAtEnd')
+ self.duration = 10
+ --create hitbox
+ Slash.super.new(self, x, y,
+ Hitbox(hbox.sx, hbox.sy, hbox.width, hbox.height))
+end
+
+function Slash:update()
+ if pause then return nil end
+
+ self.x = math.floor(self.parent.x) + self.offset.x
+ self.y = math.floor(self.parent.y) + self.offset.y
+ self.animation:update(1)
+ self.duration = self.duration - 1
+ local disk = self:collide(Disk)
+ local collided = {}
+ while disk do
+ collided[disk] = true
+ --change disk image
+ disk.state = 'highlight'
+ disk.countdown = 12 --revert to default after x frames
+
+ if self.duration ~= 0 then
+ self.duration = 0
+ play_sfx'throw'
+ self.parent.disk_cooldown = conf.disk_cooldown_margin
+ stats[self.parent.player_id].slash_success =
+ stats[self.parent.player_id].slash_success + 1
+ end
+ if self.dx ~= 0 then
+ disk.dx = (math.abs(disk.dx) + 0.1) * self.dx
+ if math.abs(disk.dx) < math.abs(self.dx) then
+ disk.dx = self.dx
+ end
+ end
+ if self.dy ~= 0 then
+ disk.dy = (math.abs(disk.dy) + 0.1) * self.dy
+ if math.abs(disk.dy) < math.abs(self.dy) then
+ disk.dy = self.dy
+ end
+ end
+ disk = self:collide(Disk, nil, collided)
+ end
+ if self.duration == 0 then
+ self:destroy()
+ end
+end
+
+function Slash:draw()
+ love.graphics.setColor(1, 1, 1, 1)
+ self.animation:draw(Slash.image, self.x, self.y, self.rotation,
+ self.scale.x, 1)
+end
+
+return Slash
diff --git a/src/slime.lua b/src/slime.lua
new file mode 100644
index 0000000..85df2da
--- /dev/null
+++ b/src/slime.lua
@@ -0,0 +1,18 @@
+local anim8 = require'libs/anim8'
+local Water = require'src/water'
+
+local Slime = Water:extend()
+
+Slime.image = love.graphics.newImage'assets/art/animations/slime.png'
+local g = anim8.newGrid(8, 6, Slime.image:getWidth(),
+ Slime.image:getHeight())
+
+function Slime:new(x, y, width)
+ Slime.super.new(self, x, y, width, 32)
+ self.color = {0, 1, 0}
+ self.alpha = 0.9
+ self.image = Slime.image
+ self.modifier = 4
+end
+
+return Slime
diff --git a/src/solid.lua b/src/solid.lua
new file mode 100644
index 0000000..db49414
--- /dev/null
+++ b/src/solid.lua
@@ -0,0 +1,21 @@
+local baton = require'libs/baton'
+local Entity = require'src/entity'
+local Hitbox = require'src/hitbox'
+
+local Solid = Entity:extend()
+
+Solid.draw_layer = 3
+
+function Solid:new(x, y, hitbox)
+ Solid.super.new(self, x, y)
+ self.hitbox = hitbox or Hitbox(0, 0, tileSize, tileSize)
+end
+
+function Solid:draw()
+ self.hitbox:draw(self.x, self.y, 0.5, 0.5, 0.5, 1)
+end
+
+function Solid:draw_debug()
+end
+
+return Solid
diff --git a/src/stage.lua b/src/stage.lua
new file mode 100644
index 0000000..13bc851
--- /dev/null
+++ b/src/stage.lua
@@ -0,0 +1,190 @@
+local Object = require'src/object'
+local Hitbox = require'src/hitbox'
+local DebugDisp = require'src/debugdisp'
+local TileEntity = require'src/tileentity'
+local PauseMenu = require'src/menu/pause'
+local Player = require'src/player'
+local Results = require'src/menu/results'
+local UI = require'src/ui'
+local play_music = require'src/music'
+local count = require'src/count'
+
+local Stage = Object:extend()
+
+local objects = {
+ Player = {
+ type = require'src/player',
+ offset = {
+ x = -6,
+ y = -11
+ },
+ properties = {
+ {'hitbox', Hitbox(4, 5, 4, 6)},
+ {'player_id', 1},
+ {'skin', nil},
+ {'xscale', 1},
+ }
+ },
+ Disk = {type = require'src/disk', properties = {}},
+ MainMenu = {type = require'src/menu/mainmenu', properties = {}},
+ DiskSpawner = {
+ type = require'src/diskspawner',
+ offset = {
+ x = -6,
+ y = -6
+ },
+ properties = {
+ {'spawn_speed', 1},
+ {'disk_speed', 1},
+ {'delay', 0},
+ {'disk', nil},
+ }
+ },
+ Force = {
+ type = require'src/force',
+ properties = {
+ {'width', 0},
+ {'height', 0},
+ {'spdx', 0},
+ {'spdy', 0},
+ }
+ },
+ Water = {
+ type = require'src/water',
+ properties = {
+ {'width', 8},
+ }
+ },
+ Lava = {
+ type = require'src/lava',
+ properties = {
+ {'width', 8},
+ }
+ },
+ Slime = {
+ type = require'src/slime',
+ properties = {
+ {'width', 8},
+ }
+ },
+}
+
+function Stage:new(level)
+ self.name = level
+
+ --destroy all entities
+ for i, _ in pairs(entities) do
+ entities[i] = nil
+ end
+ --load content
+ self.content = require('stages/'..level)
+ local solid_layer = self.content.layers[3]
+ self.width = solid_layer.width
+ self.height = solid_layer.height
+ self.solid_data = solid_layer.data
+ self.foreground_data = self.content.layers[4].data
+ self.background_data = self.content.layers[2].data
+ local tileset = self.content.tilesets[1] and
+ self.content.tilesets[1].name
+ if tileset then
+ tileset_path = 'assets/art/tileset/'..self.content.tilesets[1].name
+ self.tileset = love.graphics.newImage(tileset_path..'.png')
+ local bg_path = self.content.layers[1].image
+ bg_path = bg_path:sub(4)
+ self.bg_image = love.graphics.newImage(bg_path)
+ self.quads = {}
+ --generate quads
+ local tw, th = self.tileset:getDimensions()
+ local sw, sh = tw / TILE_SIDE, th / TILE_SIDE
+ for i=0, sw * sh, 1 do
+ self.quads[i] = love.graphics.newQuad(
+ i % sw * TILE_SIDE,
+ math.floor(i / sw) * TILE_SIDE,
+ TILE_SIDE, TILE_SIDE, tw, th)
+ end
+ end
+ --spawn all objects
+ table.insert(entities, PauseMenu()) --pause menus are very nice
+ table.insert(entities, DebugDisp()) --we always need a DebugDisp
+ self.objects = self.content.layers[5].objects
+ for _, v in ipairs(self.objects) do
+ --get properties of v
+ local object = objects[v.type]
+ if not object then
+ --print('Wrong object type')
+ for i, v in pairs(v) do
+ --print(i)
+ --print(v)
+ --print()
+ end
+ end
+ --get "properties"
+ --copy object.properties into properties
+ local properties = {}
+ for i, p in ipairs(object.properties) do
+ table.insert(properties,
+ v[p[1]] and {p[1], v[p[1]]} or
+ v.properties[p[1]] and {p[1], v.properties[p[1]]} or
+ {unpack(p)})
+ end
+ --get all the arguments into one table
+ local arguments = {}
+ for _, v in pairs(properties) do
+ table.insert(arguments, v[2])
+ end
+ --spawn object at x, y
+ local x, y = v.x, v.y
+ if object.offset then
+ x, y = x + object.offset.x, y + object.offset.y
+ end
+ if properties.height then
+ --y = y - properties.height
+ end
+ table.insert(entities,
+ object.type(x, y, unpack(arguments)))
+ end
+ if count(Player) > 0 then
+ table.insert(entities, Results())
+ table.insert(entities, UI())
+ end
+ --play music
+ play_music(level)
+end
+
+function Stage:draw(level)
+ if not self.tileset then return nil end
+ --local function to avoid duplicating code
+ local function draw_layer(layer_data)
+ love.graphics.setColor(1, 1, 1, 1)
+ --cycle through all the cells and draw corresponding quad
+ for y=0, self.height-1, 1 do
+ for x=0, self.width-1, 1 do
+ local cell = layer_data[x + 1 + y * self.width] - 1
+ if cell > -1 then
+ love.graphics.draw(self.tileset, self.quads[cell],
+ x * TILE_SIDE, y * TILE_SIDE)
+ end
+ end
+ end
+ end
+
+ love.graphics.setColor(1, 1, 1, 1)
+ love.graphics.draw(self.bg_image)
+ --background before anything
+ draw_layer(self.background_data)
+ --then draw solid layer
+ draw_layer(self.solid_data)
+ --finally foreground layer
+ draw_layer(self.foreground_data)
+end
+
+function Stage:tile_at_pixel(x, y)
+ local x = x or 0
+ local y = y or 0
+ local x = math.floor(x / TILE_SIDE)
+ local y = math.floor(y / TILE_SIDE)
+ local pos = x + 1 + y * self.width
+ return self.solid_data[pos]
+end
+
+return Stage
diff --git a/src/tileentity.lua b/src/tileentity.lua
new file mode 100644
index 0000000..96e4aaf
--- /dev/null
+++ b/src/tileentity.lua
@@ -0,0 +1,10 @@
+local Entity = require'src/entity'
+local Hitbox = require'src/hitbox'
+
+local TileEntity = Entity:extend()
+
+function TileEntity:new(x, y, width, height)
+ TileEntity.super.new(self, x, y, Hitbox(0, 0, width, height))
+end
+
+return TileEntity
diff --git a/src/ui.lua b/src/ui.lua
new file mode 100644
index 0000000..dc34b23
--- /dev/null
+++ b/src/ui.lua
@@ -0,0 +1,52 @@
+local Object = require'src/object'
+local Player = require'src/player'
+local count = require'src/count'
+
+local UI = Object:extend()
+
+UI.image = {}
+UI.image[1] = love.graphics.newImage'assets/art/ui/uip1.png'
+UI.image[2] = love.graphics.newImage'assets/art/ui/uip2.png'
+
+local ui_image_width = UI.image[1]:getWidth()
+local ui_width = ui_image_width / 9
+local ui_height = UI.image[1]:getHeight()
+--generate quads
+UI.quads = {}
+for x=0, ui_image_width - ui_width, ui_width do
+ table.insert(UI.quads,
+ love.graphics.newQuad(x, 0, ui_width, ui_height,
+ ui_image_width, ui_height))
+end
+--print(#UI.quads)
+
+function UI:new()
+ self.players = {}
+ for _, v in pairs(entities) do
+ if v:is(Player) then
+ table.insert(self.players, v)
+ end
+ end
+
+ for i, v in ipairs(self.players) do
+ --print(i, v)
+ end
+end
+
+function UI:draw_gui()
+ for i, p in ipairs(self.players) do
+ local x = (i == 1 and 0 or gameWidth) + 0 * (i == 1 and 1 or -1) +
+ ui_width * (i == 1 and 0 or -1)
+ local y = gameHeight - ui_height
+ if stage.name == 'weirdo' or stage.name == 'discroom' then
+ love.graphics.setColor(0, 0, 0, 0)
+ else
+ love.graphics.setColor(p.color)
+ end
+ love.graphics.rectangle('fill', x, y, ui_width, ui_height)
+ love.graphics.setColor(1, 1, 1, 1)
+ love.graphics.draw(UI.image[i], UI.quads[p.hp + 1], x, y)
+ end
+end
+
+return UI
diff --git a/src/walk_particle.lua b/src/walk_particle.lua
new file mode 100644
index 0000000..edb81d4
--- /dev/null
+++ b/src/walk_particle.lua
@@ -0,0 +1,50 @@
+local anim8 = require'libs/anim8'
+local Object = require'src/object'
+
+local Particle = Object:extend()
+
+Particle.draw_layer = 10
+
+Particle.image =
+ love.graphics.newImage'assets/art/animations/walk_particle.png'
+local g = anim8.newGrid(8, 8, Particle.image:getWidth(),
+ Particle.image:getHeight())
+
+function Particle:new(x, y, dx)
+ if not particles then
+ return nil
+ end
+ self.x = x or 0
+ self.x = self.x + (dx < 0 and 7 or 0)
+ self.y = (y or 0) + 4
+ dx = dx or 0
+ self.duration = 18
+ self.x = math.floor(self.x)
+ self.y = math.floor(self.y)
+ self.animation = anim8.newAnimation(g('1-6', 1), 3, 'pauseAtEnd')
+end
+
+function Particle:update()
+ if not particles then
+ self:destroy()
+ return nil
+ end
+
+ if pause then return nil end
+
+ self.animation:update(1)
+ self.duration = self.duration - 1
+ if self.duration == 0 then
+ self:destroy()
+ end
+end
+
+function Particle:draw()
+ love.graphics.setColor(1, 1, 1, 1)
+ if current_stage == "discroom" then
+ love.graphics.setColor(0, 0, 0, 1)
+ end
+ self.animation:draw(Particle.image, self.x, self.y, 0, dx, 1)
+end
+
+return Particle
diff --git a/src/water.lua b/src/water.lua
new file mode 100644
index 0000000..ad03764
--- /dev/null
+++ b/src/water.lua
@@ -0,0 +1,31 @@
+local anim8 = require'libs/anim8'
+local Liquid = require'src/liquid'
+
+local Water = Liquid:extend()
+
+Water.image = love.graphics.newImage'assets/art/animations/water.png'
+local g = anim8.newGrid(8, 6, Water.image:getWidth(),
+ Water.image:getHeight())
+
+
+function Water:new(x, y, width, flow_speed)
+ Water.super.new(self, x, y, width)
+ self.animation = anim8.newAnimation(g('1-4', 1), flow_speed or 8)
+ self.color = {0, 0.5, 1}
+ self.alpha = 0.8
+ self.image = Water.image
+ self.modifier = 2
+end
+
+function Water:update()
+ self.animation:update(1)
+end
+
+function Water:draw()
+ love.graphics.setColor(1, 1, 1, self.alpha)
+ for x = self.x, self.x + self.width - 1, 8 do
+ self.animation:draw(self.image, x, self.y + 3)
+ end
+end
+
+return Water
diff --git a/stages/discroom.lua b/stages/discroom.lua
new file mode 100644
index 0000000..312e31c
--- /dev/null
+++ b/stages/discroom.lua
@@ -0,0 +1,234 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 6,
+ nextobjectid = 5,
+ properties = {},
+ tilesets = {
+ {
+ name = "disk-of-doom",
+ firstgid = 1,
+ filename = "disk-of-doom.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 9,
+ image = "../assets/art/tileset/disk-of-doom.png",
+ imagewidth = 72,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 72,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/disk-of-doom-bg.png",
+ id = 5,
+ name = "Calque d'Images 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 0, 0, 13, 14, 15, 16, 0, 0, 49, 50, 51, 50, 50, 50, 50, 50, 50, 50, 50, 49, 50, 51, 0, 0, 13, 14, 15, 16, 0, 0, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 60, 0, 0, 22, 23, 24, 25, 0, 0, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 58, 59, 51, 0, 0, 22, 23, 24, 25, 0, 0, 58, 50, 50, 50, 50,
+ 50, 50, 59, 0, 0, 0, 0, 31, 32, 33, 34, 0, 0, 58, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 60, 0, 0, 31, 32, 33, 34, 0, 0, 0, 0, 50, 50, 50,
+ 50, 50, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 50, 50,
+ 50, 50, 59, 42, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0, 40, 41, 41, 41, 42, 0, 0, 40, 41, 41, 41, 42, 0, 0, 0, 0, 4, 5, 6, 7, 0, 8, 40, 50, 50, 50,
+ 50, 50, 59, 50, 0, 0, 13, 41, 41, 41, 41, 42, 0, 0, 49, 49, 49, 50, 51, 0, 0, 49, 49, 49, 50, 51, 0, 0, 40, 41, 41, 41, 14, 16, 0, 17, 50, 50, 50, 50,
+ 50, 50, 59, 60, 0, 0, 22, 49, 49, 49, 50, 51, 0, 0, 58, 50, 59, 59, 60, 0, 0, 58, 41, 41, 59, 60, 0, 0, 49, 49, 49, 50, 51, 25, 0, 0, 58, 50, 50, 50,
+ 50, 50, 59, 0, 0, 0, 31, 58, 59, 59, 59, 60, 0, 0, 0, 0, 17, 18, 0, 0, 0, 0, 0, 17, 18, 0, 0, 0, 58, 41, 41, 41, 60, 34, 0, 0, 0, 50, 50, 50,
+ 50, 50, 59, 50, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 50, 50, 50, 50,
+ 50, 50, 59, 50, 51, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 50, 50, 50,
+ 50, 50, 59, 50, 60, 18, 0, 0, 0, 0, 0, 0, 0, 40, 41, 41, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 58, 50, 50, 50, 50,
+ 50, 50, 59, 0, 0, 0, 0, 0, 8, 9, 0, 0, 4, 49, 41, 49, 50, 51, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 41, 41, 42, 0, 0, 0, 50, 50, 50,
+ 50, 50, 59, 26, 27, 0, 40, 41, 41, 41, 42, 0, 13, 49, 50, 49, 50, 51, 18, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 49, 50, 49, 50, 51, 0, 26, 27, 50, 50, 50,
+ 50, 50, 59, 35, 36, 0, 49, 49, 49, 50, 51, 0, 22, 49, 50, 49, 50, 51, 0, 0, 0, 0, 40, 50, 49, 50, 42, 0, 0, 49, 50, 49, 50, 51, 0, 35, 36, 50, 50, 50,
+ 50, 59, 59, 50, 42, 0, 41, 41, 41, 41, 51, 0, 40, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 49, 50, 51, 0, 0, 49, 50, 49, 50, 51, 0, 40, 50, 50, 50, 50,
+ 50, 50, 50, 59, 59, 0, 50, 50, 40, 41, 50, 50, 50, 50, 50, 51, 0, 0, 0, 0, 0, 0, 49, 50, 50, 50, 50, 50, 50, 50, 50, 51, 50, 50, 41, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 49, 50, 51, 50, 50, 50, 0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 2,
+ name = "Solid",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 47, 47,
+ 47, 47, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 47, 47,
+ 47, 47, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 0, 0, 47, 47,
+ 47, 38, 38, 39, 0, 0, 0, 46, 47, 48, 0, 0, 0, 28, 46, 47, 38, 38, 38, 38, 38, 38, 38, 46, 47, 48, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, 37, 38, 47, 47,
+ 47, 47, 47, 48, 0, 0, 0, 46, 47, 48, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 47, 38, 38, 38, 38, 38, 38, 47, 48, 39, 0, 0, 46, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 3,
+ name = "Foreground",
+ 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
+ }
+ },
+ {
+ type = "objectgroup",
+ draworder = "topdown",
+ id = 4,
+ name = "Objets",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 8,
+ properties = {},
+ objects = {
+ {
+ id = 1,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 64,
+ y = 120,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["skin"] = "brave-scientist"
+ }
+ },
+ {
+ id = 2,
+ name = "Player 2",
+ type = "Player",
+ shape = "point",
+ x = 256,
+ y = 112,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 4,
+ name = "Disk spawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 88,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["disk_speed"] = 2,
+ ["spawn_speed"] = 0.5
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/stages/discroom.tmx b/stages/discroom.tmx
new file mode 100644
index 0000000..dfb7efb
--- /dev/null
+++ b/stages/discroom.tmx
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="6" nextobjectid="5">
+ <editorsettings>
+ <export target="discroom.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="disk-of-doom.tsx"/>
+ <imagelayer id="5" name="Calque d'Images 1">
+ <image source="../assets/art/tileset/disk-of-doom-bg.png" width="320" height="176"/>
+ </imagelayer>
+ <layer id="1" name="Background" width="40" height="22">
+ <data encoding="csv">
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
+50,50,50,50,50,0,0,13,14,15,16,0,0,49,50,51,50,50,50,50,50,50,50,50,49,50,51,0,0,13,14,15,16,0,0,50,50,50,50,50,
+50,50,50,50,60,0,0,22,23,24,25,0,0,49,49,49,49,49,49,49,49,49,49,49,58,59,51,0,0,22,23,24,25,0,0,58,50,50,50,50,
+50,50,59,0,0,0,0,31,32,33,34,0,0,58,41,41,41,41,41,41,41,41,41,41,41,41,60,0,0,31,32,33,34,0,0,0,0,50,50,50,
+50,50,59,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50,
+50,50,59,42,0,0,4,5,6,7,0,0,0,0,40,41,41,41,42,0,0,40,41,41,41,42,0,0,0,0,4,5,6,7,0,8,40,50,50,50,
+50,50,59,50,0,0,13,41,41,41,41,42,0,0,49,49,49,50,51,0,0,49,49,49,50,51,0,0,40,41,41,41,14,16,0,17,50,50,50,50,
+50,50,59,60,0,0,22,49,49,49,50,51,0,0,58,50,59,59,60,0,0,58,41,41,59,60,0,0,49,49,49,50,51,25,0,0,58,50,50,50,
+50,50,59,0,0,0,31,58,59,59,59,60,0,0,0,0,17,18,0,0,0,0,0,17,18,0,0,0,58,41,41,41,60,34,0,0,0,50,50,50,
+50,50,59,50,42,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,50,50,50,50,
+50,50,59,50,51,9,0,0,0,0,0,0,0,0,0,8,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,50,50,50,
+50,50,59,50,60,18,0,0,0,0,0,0,0,40,41,41,41,42,0,0,0,0,0,0,0,0,0,0,0,0,8,9,0,0,0,58,50,50,50,50,
+50,50,59,0,0,0,0,0,8,9,0,0,4,49,41,49,50,51,9,0,0,0,0,0,0,0,0,0,0,40,41,41,41,42,0,0,0,50,50,50,
+50,50,59,26,27,0,40,41,41,41,42,0,13,49,50,49,50,51,18,0,0,0,4,5,6,7,0,0,0,49,50,49,50,51,0,26,27,50,50,50,
+50,50,59,35,36,0,49,49,49,50,51,0,22,49,50,49,50,51,0,0,0,0,40,50,49,50,42,0,0,49,50,49,50,51,0,35,36,50,50,50,
+50,59,59,50,42,0,41,41,41,41,51,0,40,49,50,50,50,50,50,50,50,50,50,50,49,50,51,0,0,49,50,49,50,51,0,40,50,50,50,50,
+50,50,50,59,59,0,50,50,40,41,50,50,50,50,50,51,0,0,0,0,0,0,49,50,50,50,50,50,50,50,50,51,50,50,41,50,50,50,50,50,
+50,50,50,50,50,50,50,50,49,50,51,50,50,50,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
+50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50
+</data>
+ </layer>
+ <layer id="2" name="Solid" width="40" height="22">
+ <data encoding="csv">
+47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,
+47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,
+47,47,47,48,0,0,0,0,0,0,0,0,0,0,46,46,46,46,46,46,46,46,46,46,47,48,0,0,0,0,0,0,0,0,0,0,46,47,47,47,
+47,47,56,57,0,0,0,0,0,0,0,0,0,0,46,56,56,56,56,56,56,56,56,56,56,48,0,0,0,0,0,0,0,0,0,0,55,56,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,55,56,56,56,56,56,56,56,56,56,56,57,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,65,66,0,0,0,0,0,0,0,0,0,0,0,0,64,65,66,0,0,0,0,64,65,66,0,0,0,0,0,0,0,0,0,0,0,0,64,65,47,
+47,47,0,0,0,0,0,0,64,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,65,66,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,65,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,37,38,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,0,0,0,0,0,0,0,46,47,48,0,0,0,0,0,0,0,0,0,0,0,0,0,37,38,39,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,37,38,39,0,0,0,0,46,47,48,0,0,0,0,0,0,0,0,0,0,0,0,0,46,47,48,0,0,0,0,0,47,47,
+47,47,0,0,0,0,0,46,47,48,0,0,0,0,46,47,48,0,0,0,0,0,0,37,38,39,0,0,0,0,46,47,48,0,0,0,0,0,47,47,
+47,38,38,39,0,0,0,46,47,48,0,0,0,28,46,47,38,38,38,38,38,38,38,46,47,48,0,0,0,0,46,47,48,0,0,0,37,38,47,47,
+47,47,47,48,0,0,0,46,47,48,38,38,38,38,38,38,38,38,38,38,38,38,38,38,47,38,38,38,38,38,38,47,48,39,0,0,46,47,47,47,
+47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,
+47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47
+</data>
+ </layer>
+ <layer id="3" name="Foreground" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="4" name="Objets" offsetx="0" offsety="8">
+ <object id="1" name="Player 1" type="Player" x="64" y="120">
+ <properties>
+ <property name="skin" value="brave-scientist"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="2" name="Player 2" type="Player" x="256" y="112">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="4" name="Disk spawner" type="DiskSpawner" x="160" y="88">
+ <properties>
+ <property name="disk_speed" type="float" value="2"/>
+ <property name="spawn_speed" type="float" value="0.5"/>
+ </properties>
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/disk-of-doom.tsx b/stages/disk-of-doom.tsx
new file mode 100644
index 0000000..48c59b8
--- /dev/null
+++ b/stages/disk-of-doom.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="disk-of-doom" tilewidth="8" tileheight="8" tilecount="72" columns="9">
+ <image source="../assets/art/tileset/disk-of-doom.png" width="72" height="64"/>
+</tileset>
diff --git a/stages/fire.lua b/stages/fire.lua
new file mode 100644
index 0000000..00d135f
--- /dev/null
+++ b/stages/fire.lua
@@ -0,0 +1,246 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 6,
+ nextobjectid = 12,
+ properties = {},
+ tilesets = {
+ {
+ name = "thermopolis",
+ firstgid = 1,
+ filename = "thermopolis.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 16,
+ image = "../assets/art/tileset/thermopolis.png",
+ imagewidth = 128,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 128,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/thermopolis-bg.png",
+ id = 5,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 0, 30, 31, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 29, 29, 30, 31, 0, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 29, 29, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 44, 0, 29, 30, 16, 31, 0, 44, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 44, 0, 29, 32, 30, 31, 0, 44, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 30, 31, 0, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 44, 0, 29, 30, 30, 31, 0, 44, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 30, 31, 0, 0, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 44, 0, 29, 30, 30, 31, 0, 44, 0, 0, 0, 60, 0, 0, 0, 60, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 31, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 29, 30, 30, 31, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 43, 75, 76, 77, 78, 79, 80, 43, 0, 0, 44, 0, 29, 30, 30, 31, 0, 44, 0, 0, 43, 75, 76, 77, 78, 79, 80, 43, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 91, 92, 93, 94, 95, 96, 59, 0, 0, 60, 0, 30, 30, 30, 31, 0, 60, 0, 0, 59, 91, 92, 93, 94, 95, 96, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 107, 108, 109, 110, 111, 112, 59, 0, 0, 0, 0, 30, 30, 30, 31, 0, 0, 0, 0, 59, 107, 108, 109, 110, 111, 112, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 61, 29, 30, 30, 31, 64, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 29, 16, 30, 31, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 32, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 48, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 30, 31, 31, 0, 0, 0, 0, 0, 0, 0, 123, 124, 128, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 123, 127, 128, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 14, 14,
+ 0, 30, 31, 0, 0, 123, 126, 128, 0, 123, 0, 0, 0, 128, 0, 123, 0, 0, 29, 30, 30, 31, 0, 0, 128, 0, 123, 0, 0, 0, 128, 0, 123, 126, 128, 0, 0, 29, 0, 0,
+ 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 2,
+ name = "Solid",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 86, 87, 50, 51, 19, 49, 19, 19, 3, 2, 17, 2, 33, 33, 20, 20, 18, 19, 18, 20, 19, 36, 19, 36, 1, 4, 49, 1, 18, 34, 49, 49, 20, 1, 2, 17, 3, 36, 85, 86,
+ 86, 87, 50, 3, 35, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 34, 36, 2, 85, 86,
+ 86, 87, 33, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 52, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 113, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 53, 54, 54, 54, 54, 54, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 54, 54, 54, 54, 54, 55, 0, 0, 0, 0, 85, 86,
+ 86, 87, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 99, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 90, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 70, 70, 70, 70, 70, 70, 70, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 102, 102, 102, 102, 102, 102, 102, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 54, 55, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 53, 54, 85, 86,
+ 86, 87, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 53, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 36, 52, 121, 122, 34, 34, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 6, 6, 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 21, 22, 22, 22, 22, 22, 8, 23, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 87, 0, 0, 0, 0, 0, 0, 0, 0, 21, 24, 23, 0, 0, 0, 21, 40, 22, 22, 40, 22, 22, 23, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86,
+ 86, 86, 70, 71, 0, 5, 6, 7, 0, 5, 9, 22, 10, 7, 0, 5, 9, 22, 22, 8, 22, 22, 24, 10, 7, 0, 5, 9, 8, 10, 7, 0, 5, 6, 7, 0, 69, 70, 86, 86,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 3,
+ name = "Foreground",
+ 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
+ }
+ },
+ {
+ type = "objectgroup",
+ draworder = "topdown",
+ id = 4,
+ name = "Objets",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 4,
+ name = "Lava",
+ type = "Lava",
+ shape = "rectangle",
+ x = 0,
+ y = 160,
+ width = 320,
+ height = 8,
+ rotation = 0,
+ visible = true,
+ properties = {}
+ },
+ {
+ id = 6,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 52,
+ y = 112,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["skin"] = "scarlet"
+ }
+ },
+ {
+ id = 7,
+ name = "Player 2",
+ type = "Player",
+ shape = "point",
+ x = 268,
+ y = 112,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 10,
+ name = "DiskSpawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 32,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spawn_speed"] = 0.1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/stages/fire.tmx b/stages/fire.tmx
new file mode 100644
index 0000000..de7469e
--- /dev/null
+++ b/stages/fire.tmx
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="6" nextobjectid="12">
+ <editorsettings>
+ <export target="fire.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="thermopolis.tsx"/>
+ <imagelayer id="5" name="Background">
+ <image source="../assets/art/tileset/thermopolis-bg.png" width="320" height="176"/>
+ </imagelayer>
+ <layer id="1" name="Background" width="40" height="22">
+ <data encoding="csv">
+0,30,31,0,0,0,0,60,0,0,0,60,0,0,0,0,0,0,29,29,30,31,0,0,0,0,0,60,0,0,0,60,0,0,0,0,0,29,29,0,
+0,30,31,0,0,0,0,0,60,0,0,0,60,0,0,0,44,0,29,30,16,31,0,44,0,0,0,60,0,0,0,60,0,0,0,0,0,29,0,0,
+0,30,31,0,0,0,0,0,60,0,0,0,60,0,0,0,44,0,29,32,30,31,0,44,0,0,0,60,0,0,0,60,0,0,0,0,0,29,0,0,
+30,30,31,0,0,0,0,0,60,0,0,0,60,0,0,0,44,0,29,30,30,31,0,44,0,0,0,60,0,0,0,60,0,0,0,0,0,29,0,0,
+30,30,31,0,0,0,0,0,60,0,0,0,60,0,0,0,44,0,29,30,30,31,0,44,0,0,0,60,0,0,0,60,0,0,0,0,0,29,0,0,
+30,31,31,0,0,0,0,0,0,0,0,0,0,0,0,0,44,0,29,30,30,31,0,44,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,
+0,30,31,0,0,0,43,75,76,77,78,79,80,43,0,0,44,0,29,30,30,31,0,44,0,0,43,75,76,77,78,79,80,43,0,0,0,29,0,0,
+0,30,31,0,0,0,59,91,92,93,94,95,96,59,0,0,60,0,30,30,30,31,0,60,0,0,59,91,92,93,94,95,96,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,107,108,109,110,111,112,59,0,0,0,0,30,30,30,31,0,0,0,0,59,107,108,109,110,111,112,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,0,0,0,0,0,0,59,0,0,0,0,29,30,30,31,0,0,0,0,59,0,0,0,0,0,0,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,0,0,0,0,0,0,59,0,0,0,61,29,30,30,31,64,0,0,0,59,0,0,0,0,0,0,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,0,0,0,0,0,0,59,0,0,0,0,29,16,30,31,0,0,0,0,59,0,0,0,0,0,0,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,0,0,0,0,0,0,0,0,0,0,0,29,30,32,31,0,0,0,0,0,0,0,0,0,0,0,59,0,0,0,29,0,0,
+0,30,31,0,0,0,59,0,0,0,0,0,0,0,0,0,0,0,29,48,30,31,0,0,0,0,0,0,0,0,0,0,0,59,0,0,0,29,0,0,
+0,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,
+30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,
+30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,
+30,31,31,0,0,0,0,0,0,0,123,124,128,0,0,0,0,0,29,30,30,31,0,0,0,0,0,123,127,128,0,0,0,0,0,0,0,29,0,0,
+0,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,14,14,
+0,30,31,0,0,123,126,128,0,123,0,0,0,128,0,123,0,0,29,30,30,31,0,0,128,0,123,0,0,0,128,0,123,126,128,0,0,29,0,0,
+0,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <layer id="2" name="Solid" width="40" height="22">
+ <data encoding="csv">
+86,87,50,51,19,49,19,19,3,2,17,2,33,33,20,20,18,19,18,20,19,36,19,36,1,4,49,1,18,34,49,49,20,1,2,17,3,36,85,86,
+86,87,50,3,35,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,34,36,2,85,86,
+86,87,33,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,52,85,86,
+86,87,0,0,0,0,0,0,0,97,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,68,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,113,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83,84,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,53,54,54,54,54,54,54,55,0,0,0,0,0,0,0,0,0,0,0,0,53,54,54,54,54,54,54,55,0,0,0,0,85,86,
+86,87,54,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,99,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,115,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,69,70,70,70,70,70,70,70,70,71,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,101,102,102,102,102,102,102,102,102,103,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,54,55,56,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,53,54,85,86,
+86,87,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,57,0,0,0,0,0,0,0,0,0,0,0,0,57,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,53,54,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,55,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,36,52,121,122,34,34,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,6,6,6,6,6,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,5,6,7,0,0,0,21,22,22,22,22,22,8,23,0,0,0,5,6,7,0,0,0,0,0,0,0,0,85,86,
+86,87,0,0,0,0,0,0,0,0,21,24,23,0,0,0,21,40,22,22,40,22,22,23,0,0,0,21,22,23,0,0,0,0,0,0,0,0,85,86,
+86,86,70,71,0,5,6,7,0,5,9,22,10,7,0,5,9,22,22,8,22,22,24,10,7,0,5,9,8,10,7,0,5,6,7,0,69,70,86,86,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120
+</data>
+ </layer>
+ <layer id="3" name="Foreground" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="4" name="Objets">
+ <object id="4" name="Lava" type="Lava" x="0" y="160" width="320" height="8"/>
+ <object id="6" name="Player 1" type="Player" x="52" y="112">
+ <properties>
+ <property name="skin" value="scarlet"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="7" name="Player 2" type="Player" x="268" y="112">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="10" name="DiskSpawner" type="DiskSpawner" x="160" y="32">
+ <properties>
+ <property name="spawn_speed" type="float" value="0.1"/>
+ </properties>
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/hyperion.tsx b/stages/hyperion.tsx
new file mode 100644
index 0000000..8d60d7c
--- /dev/null
+++ b/stages/hyperion.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="hyperion" tilewidth="8" tileheight="8" tilecount="128" columns="16">
+ <image source="../assets/art/tileset/hyperion.png" width="128" height="64"/>
+</tileset>
diff --git a/stages/jungle.lua b/stages/jungle.lua
new file mode 100644
index 0000000..699e911
--- /dev/null
+++ b/stages/jungle.lua
@@ -0,0 +1,263 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 8,
+ nextobjectid = 26,
+ backgroundcolor = { 0, 0, 0 },
+ properties = {},
+ tilesets = {
+ {
+ name = "qujna",
+ firstgid = 1,
+ filename = "qujna.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 16,
+ image = "../assets/art/tileset/qujna.png",
+ imagewidth = 128,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 128,
+ tiles = {}
+ },
+ {
+ name = "objects",
+ firstgid = 129,
+ filename = "objects.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 2,
+ image = "../assets/art/tileset/objects.png",
+ imagewidth = 16,
+ imageheight = 8,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 2,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/qujna-bg.png",
+ id = 3,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 4,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 0, 30, 30, 30, 43, 43, 57, 30, 30, 30, 74, 75, 73, 30, 30, 30, 46, 46, 30, 46, 46, 30, 46, 46, 30, 46, 46, 73, 74, 75, 30, 30, 30, 57, 43, 43, 30, 30, 30, 30,
+ 30, 30, 30, 32, 74, 75, 30, 46, 46, 30, 46, 46, 30, 46, 0, 31, 0, 0, 29, 80, 80, 31, 0, 0, 29, 0, 46, 30, 46, 46, 30, 46, 0, 30, 74, 75, 96, 30, 30, 30,
+ 46, 46, 46, 46, 46, 46, 30, 46, 0, 31, 0, 0, 45, 46, 46, 47, 0, 0, 29, 80, 80, 31, 0, 0, 45, 46, 46, 47, 0, 0, 29, 0, 0, 30, 46, 46, 46, 46, 46, 46,
+ 0, 0, 9, 10, 11, 12, 45, 46, 46, 47, 0, 0, 0, 44, 44, 27, 0, 0, 45, 46, 46, 47, 0, 0, 0, 44, 44, 0, 0, 0, 45, 46, 46, 47, 0, 9, 10, 10, 11, 0,
+ 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 60, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 60, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0,
+ 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 60, 60, 0,
+ 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0,
+ 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0,
+ 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 0, 0, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0,
+ 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 42, 0, 0, 41, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 0,
+ 0, 0, 0, 0, 0, 0, 25, 26, 0, 25, 26, 0, 0, 0, 0, 0, 41, 42, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 29, 30, 112, 48, 111, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 26, 29, 30, 111, 48, 112, 30, 31, 0, 0, 0, 0, 0,
+ 0, 14, 14, 14, 14, 30, 30, 30, 30, 30, 30, 30, 14, 14, 14, 30, 30, 30, 0, 0, 0, 0, 0, 30, 30, 14, 14, 14, 30, 30, 30, 30, 30, 30, 30, 14, 14, 14, 14, 30,
+ 30, 30, 30, 30, 109, 30, 30, 30, 30, 30, 30, 30, 106, 30, 30, 30, 30, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 90, 30, 30, 30, 30, 30, 108, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 90, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Solid",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 22, 24, 22, 38, 38, 38, 38, 22, 22, 38, 38, 38, 38, 22, 22, 22, 38, 38, 38, 22, 22, 38, 38, 38, 38, 22, 22, 38, 38, 38, 38, 22, 22, 38, 38, 38, 38, 22, 22, 22,
+ 22, 22, 23, 34, 17, 20, 36, 21, 23, 2, 36, 35, 20, 21, 23, 36, 1, 2, 2, 21, 23, 4, 36, 35, 18, 21, 23, 2, 35, 35, 1, 21, 23, 20, 35, 34, 33, 21, 24, 22,
+ 8, 38, 39, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 37, 39, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 37, 38, 22,
+ 23, 87, 0, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 37, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 39, 0, 0, 0, 0, 21, 23, 0, 0, 0, 0, 0, 87, 21,
+ 23, 0, 0, 0, 0, 0, 0, 37, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 39, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 3, 1, 50, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 35, 20, 3, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 3, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 4, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 54, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 6, 6, 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 54, 21,
+ 23, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 40, 22, 38, 38, 22, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 21, 8, 23, 69, 70, 21, 22, 23, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 85, 86, 21, 22, 23, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 99, 100, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 50, 21, 22, 22, 6, 6, 22, 22, 23, 52, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 65, 66, 21,
+ 23, 115, 116, 0, 0, 0, 0, 21, 24, 23, 0, 0, 0, 0, 34, 33, 21, 40, 22, 22, 22, 22, 8, 23, 2, 35, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 81, 82, 21,
+ 23, 49, 34, 0, 0, 0, 4, 21, 22, 23, 51, 0, 0, 0, 36, 34, 21, 22, 22, 22, 22, 22, 22, 23, 2, 52, 0, 0, 0, 49, 21, 22, 23, 20, 0, 0, 0, 33, 2, 21,
+ 23, 50, 3, 101, 102, 51, 19, 21, 22, 23, 35, 20, 101, 102, 50, 20, 21, 22, 22, 22, 24, 22, 22, 23, 19, 20, 101, 102, 20, 51, 21, 24, 23, 33, 4, 101, 102, 49, 2, 21,
+ 22, 6, 7, 117, 118, 5, 6, 22, 8, 22, 6, 7, 117, 118, 5, 6, 22, 24, 22, 22, 22, 22, 22, 22, 6, 7, 117, 118, 5, 6, 22, 22, 22, 6, 7, 117, 118, 5, 6, 40
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 2,
+ name = "Foreground",
+ 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, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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",
+ draworder = "topdown",
+ id = 5,
+ name = "Objects",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 1,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 68,
+ y = 136,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 1,
+ ["skin"] = "saw-man"
+ }
+ },
+ {
+ id = 2,
+ name = "Player 2",
+ type = "Player",
+ shape = "point",
+ x = 252,
+ y = 136,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 4,
+ name = "Disk Spawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 84,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["disk_speed"] = 2,
+ ["spawn_speed"] = 0.1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/stages/jungle.tmx b/stages/jungle.tmx
new file mode 100644
index 0000000..8d88472
--- /dev/null
+++ b/stages/jungle.tmx
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" backgroundcolor="#000000" nextlayerid="8" nextobjectid="26">
+ <editorsettings>
+ <export target="jungle.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="qujna.tsx"/>
+ <tileset firstgid="129" source="objects.tsx"/>
+ <imagelayer id="3" name="Background">
+ <image source="../assets/art/tileset/qujna-bg.png" width="320" height="176"/>
+ </imagelayer>
+ <layer id="4" name="Background" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+0,30,30,30,43,43,57,30,30,30,74,75,73,30,30,30,46,46,30,46,46,30,46,46,30,46,46,73,74,75,30,30,30,57,43,43,30,30,30,30,
+30,30,30,32,74,75,30,46,46,30,46,46,30,46,0,31,0,0,29,80,80,31,0,0,29,0,46,30,46,46,30,46,0,30,74,75,96,30,30,30,
+46,46,46,46,46,46,30,46,0,31,0,0,45,46,46,47,0,0,29,80,80,31,0,0,45,46,46,47,0,0,29,0,0,30,46,46,46,46,46,46,
+0,0,9,10,11,12,45,46,46,47,0,0,0,44,44,27,0,0,45,46,46,47,0,0,0,44,44,0,0,0,45,46,46,47,0,9,10,10,11,0,
+0,0,0,0,0,12,0,0,0,0,0,0,0,60,44,0,0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,12,0,0,0,0,0,0,
+0,0,0,0,0,28,0,0,0,0,0,0,0,0,60,0,0,0,0,0,0,0,0,0,0,44,60,0,0,0,0,0,0,28,0,0,0,0,0,0,
+0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,0,0,0,0,0,0,0,28,0,0,0,60,60,0,
+0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,0,
+0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,0,
+0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,26,0,0,25,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,0,
+0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,25,26,42,0,0,41,25,26,0,0,0,0,0,0,0,0,0,0,0,0,0,60,60,0,
+0,0,0,0,0,0,25,26,0,25,26,0,0,0,0,0,41,42,0,44,44,0,0,0,0,0,0,0,0,0,0,0,25,26,0,0,0,0,0,0,
+0,0,0,0,0,13,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,14,14,14,14,14,15,0,0,0,0,0,
+0,0,0,0,0,29,30,112,48,111,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,26,29,30,111,48,112,30,31,0,0,0,0,0,
+0,14,14,14,14,30,30,30,30,30,30,30,14,14,14,30,30,30,0,0,0,0,0,30,30,14,14,14,30,30,30,30,30,30,30,14,14,14,14,30,
+30,30,30,30,109,30,30,30,30,30,30,30,106,30,30,30,30,0,0,30,30,30,30,30,30,30,30,30,90,30,30,30,30,30,108,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,90,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30
+</data>
+ </layer>
+ <layer id="1" name="Solid" width="40" height="22">
+ <data encoding="csv">
+22,24,22,38,38,38,38,22,22,38,38,38,38,22,22,22,38,38,38,22,22,38,38,38,38,22,22,38,38,38,38,22,22,38,38,38,38,22,22,22,
+22,22,23,34,17,20,36,21,23,2,36,35,20,21,23,36,1,2,2,21,23,4,36,35,18,21,23,2,35,35,1,21,23,20,35,34,33,21,24,22,
+8,38,39,0,0,0,0,21,23,0,0,0,0,21,23,0,0,0,0,37,39,0,0,0,0,21,23,0,0,0,0,21,23,0,0,0,0,37,38,22,
+23,87,0,0,0,0,0,21,23,0,0,0,0,37,39,0,0,0,0,0,0,0,0,0,0,37,39,0,0,0,0,21,23,0,0,0,0,0,87,21,
+23,0,0,0,0,0,0,37,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,39,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,54,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,54,54,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,3,1,50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,35,20,3,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,3,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,4,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,119,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,54,54,55,0,0,0,0,0,0,0,0,0,0,0,0,5,6,6,6,6,6,6,7,0,0,0,0,0,0,0,0,0,0,0,0,53,54,54,21,
+23,71,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,40,22,38,38,22,22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,21,8,23,69,70,21,22,23,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,21,22,23,85,86,21,22,23,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,99,100,0,0,0,0,5,6,7,0,0,0,0,0,50,21,22,22,6,6,22,22,23,52,0,0,0,0,0,5,6,7,0,0,0,0,65,66,21,
+23,115,116,0,0,0,0,21,24,23,0,0,0,0,34,33,21,40,22,22,22,22,8,23,2,35,0,0,0,0,21,22,23,0,0,0,0,81,82,21,
+23,49,34,0,0,0,4,21,22,23,51,0,0,0,36,34,21,22,22,22,22,22,22,23,2,52,0,0,0,49,21,22,23,20,0,0,0,33,2,21,
+23,50,3,101,102,51,19,21,22,23,35,20,101,102,50,20,21,22,22,22,24,22,22,23,19,20,101,102,20,51,21,24,23,33,4,101,102,49,2,21,
+22,6,7,117,118,5,6,22,8,22,6,7,117,118,5,6,22,24,22,22,22,22,22,22,6,7,117,118,5,6,22,22,22,6,7,117,118,5,6,40
+</data>
+ </layer>
+ <layer id="2" name="Foreground" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,60,60,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,60,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,60,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="5" name="Objects">
+ <object id="1" name="Player 1" type="Player" x="68" y="136">
+ <properties>
+ <property name="player_id" type="int" value="1"/>
+ <property name="skin" value="saw-man"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="2" name="Player 2" type="Player" x="252" y="136">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="4" name="Disk Spawner" type="DiskSpawner" x="160" y="84">
+ <properties>
+ <property name="disk_speed" type="float" value="2"/>
+ <property name="spawn_speed" type="float" value="0.1"/>
+ </properties>
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/mainmenu.lua b/stages/mainmenu.lua
new file mode 100644
index 0000000..a046c9b
--- /dev/null
+++ b/stages/mainmenu.lua
@@ -0,0 +1,171 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 6,
+ nextobjectid = 2,
+ properties = {},
+ tilesets = {},
+ layers = {
+ {
+ type = "imagelayer",
+ image = "",
+ id = 5,
+ name = "Calque d'Images 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Calque de Tuiles 1",
+ 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
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 2,
+ name = "Calque de Tuiles 2",
+ 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
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 3,
+ name = "Calque de Tuiles 3",
+ 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
+ }
+ },
+ {
+ type = "objectgroup",
+ draworder = "topdown",
+ id = 4,
+ name = "Calque d'Objets 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 1,
+ name = "MainMenu",
+ type = "MainMenu",
+ shape = "point",
+ x = 57.1908,
+ y = 71.312,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {}
+ }
+ }
+ }
+ }
+}
diff --git a/stages/mainmenu.tmx b/stages/mainmenu.tmx
new file mode 100644
index 0000000..9061a94
--- /dev/null
+++ b/stages/mainmenu.tmx
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="6" nextobjectid="2">
+ <imagelayer id="5" name="Calque d'Images 1"/>
+ <layer id="1" name="Calque de Tuiles 1" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <layer id="2" name="Calque de Tuiles 2" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <layer id="3" name="Calque de Tuiles 3" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="4" name="Calque d'Objets 1">
+ <object id="1" name="MainMenu" type="MainMenu" x="57.1908" y="71.312">
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/nothern.lua b/stages/nothern.lua
new file mode 100644
index 0000000..8a47fe6
--- /dev/null
+++ b/stages/nothern.lua
@@ -0,0 +1,372 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 7,
+ nextobjectid = 46,
+ properties = {},
+ tilesets = {
+ {
+ name = "nothern-fortress",
+ firstgid = 1,
+ filename = "nothern.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 16,
+ image = "../assets/art/tileset/nothern-fortress.png",
+ imagewidth = 128,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 128,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/nothern-fortress-bg.png",
+ id = 2,
+ name = "Calque d'Images 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 3,
+ name = "Calque de Tuiles 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 30, 123, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 13, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 30, 123, 30, 30, 30, 30, 30, 0, 30, 30, 30, 30, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 77, 16, 16, 16, 30, 30, 30, 31, 64, 0, 28, 10, 11, 0, 28, 0, 0, 12, 0, 12, 64, 29, 30, 30, 30, 30, 32, 32, 32, 78, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 93, 16, 16, 16, 30, 30, 30, 31, 0, 0, 9, 10, 0, 0, 12, 0, 0, 9, 10, 11, 0, 45, 30, 30, 30, 30, 32, 32, 32, 94, 30, 30, 30, 30, 30,
+ 30, 30, 30, 77, 16, 16, 16, 30, 30, 30, 30, 30, 30, 15, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 32, 32, 32, 78, 30, 30, 30,
+ 30, 30, 30, 93, 16, 16, 16, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 27, 12, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 32, 32, 32, 94, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 13, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 77, 16, 16, 16, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 32, 32, 32, 78, 30,
+ 30, 93, 16, 16, 16, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 32, 32, 32, 94, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 0, 28, 0, 0, 28, 0, 0, 0, 0, 45, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 109, 110, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 15, 0, 0, 0, 0, 28, 0, 0, 12, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 109, 110, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 0, 0, 12, 25, 26, 12, 0, 0, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 0, 0, 63, 0, 12, 41, 42, 12, 0, 63, 0, 0, 0, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 77, 16, 16, 16, 79, 80, 30, 30, 30, 30, 31, 0, 0, 0, 0, 28, 41, 42, 28, 0, 0, 0, 0, 0, 29, 30, 30, 30, 79, 80, 32, 32, 32, 78, 30, 30, 30,
+ 30, 30, 30, 93, 16, 16, 16, 95, 96, 79, 80, 30, 30, 47, 0, 0, 0, 0, 28, 41, 42, 28, 0, 0, 0, 0, 0, 29, 30, 79, 80, 95, 96, 32, 32, 32, 94, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 111, 112, 95, 96, 30, 31, 0, 0, 0, 25, 26, 28, 41, 42, 28, 25, 26, 0, 0, 13, 30, 30, 95, 96, 111, 112, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 24, 30, 30, 30, 111, 112, 111, 112, 30, 31, 0, 0, 0, 41, 42, 12, 41, 42, 28, 41, 42, 0, 0, 29, 30, 30, 111, 112, 111, 112, 30, 30, 30, 24, 30, 30, 30,
+ 30, 30, 30, 40, 30, 30, 30, 30, 30, 111, 112, 30, 31, 0, 123, 30, 30, 30, 12, 41, 42, 28, 0, 30, 30, 29, 30, 30, 30, 111, 112, 111, 112, 30, 30, 30, 40, 30, 30, 30,
+ 30, 30, 30, 30, 30, 24, 24, 24, 24, 111, 112, 22, 31, 0, 123, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 45, 30, 30, 30, 111, 112, 30, 30, 30, 30, 30, 30, 30, 30, 30
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 4,
+ name = "Calque de Tuiles 2",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 22, 22, 22, 22, 22, 22, 40, 22, 22, 22, 40, 22, 22, 22, 40, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 40, 22, 22, 22, 40, 22, 22, 22, 40, 22, 22, 22, 22, 22, 22,
+ 22, 69, 70, 24, 22, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 22, 22, 69, 70, 22, 22, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 22, 24, 69, 70, 22,
+ 22, 85, 86, 40, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 85, 86, 22, 23, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 40, 85, 86, 22,
+ 22, 22, 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 38, 38, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 22, 22, 22,
+ 22, 8, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 36, 34, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 8, 22,
+ 22, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 22,
+ 23, 52, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 20, 21,
+ 23, 52, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 34, 21,
+ 23, 4, 0, 0, 0, 0, 18, 35, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 33, 18, 0, 0, 0, 0, 3, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 53, 54, 55, 0, 0, 0, 0, 50, 4, 51, 52, 0, 0, 0, 0, 0, 53, 54, 54, 54, 54, 55, 0, 0, 0, 0, 0, 1, 18, 3, 51, 0, 0, 0, 0, 53, 54, 55, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,
+ 22, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 54, 54, 54, 54, 54, 54, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 22,
+ 22, 8, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 8, 22,
+ 22, 22, 22, 6, 7, 97, 98, 99, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 102, 67, 68, 5, 6, 22, 22, 22,
+ 22, 69, 70, 24, 23, 113, 114, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 118, 83, 84, 21, 24, 69, 70, 22,
+ 22, 85, 86, 40, 22, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 67, 68, 0, 0, 0, 0, 99, 100, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 22, 40, 85, 86, 22,
+ 22, 22, 22, 22, 22, 22, 24, 22, 22, 22, 24, 22, 22, 22, 24, 23, 83, 84, 5, 6, 6, 7, 115, 116, 21, 24, 22, 22, 22, 24, 22, 22, 22, 24, 22, 22, 22, 22, 22, 22
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 5,
+ name = "Calque de Tuiles 3",
+ 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
+ }
+ },
+ {
+ type = "objectgroup",
+ draworder = "topdown",
+ id = 6,
+ name = "Calque d'Objets 1",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 1,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 80,
+ y = 96,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 1,
+ ["skin"] = "neon"
+ }
+ },
+ {
+ id = 2,
+ name = "Player 2",
+ type = "Player",
+ shape = "point",
+ x = 240,
+ y = 96,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 5,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 24,
+ y = 32,
+ width = 56,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 6,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 40,
+ y = 16,
+ width = 56,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 7,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 8,
+ y = 80,
+ width = 32,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 8,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 24,
+ y = 128,
+ width = 32,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 9,
+ name = "< Force",
+ type = "Force",
+ shape = "rectangle",
+ x = 264,
+ y = 128,
+ width = 32,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 10,
+ name = "< Force",
+ type = "Force",
+ shape = "rectangle",
+ x = 224,
+ y = 16,
+ width = 56,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 11,
+ name = "< Force",
+ type = "Force",
+ shape = "rectangle",
+ x = 280,
+ y = 80,
+ width = 32,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 12,
+ name = "< Force",
+ type = "Force",
+ shape = "rectangle",
+ x = 240,
+ y = 32,
+ width = 56,
+ height = 16,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 17,
+ name = "Disk Spawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 152,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["disk_speed"] = 2,
+ ["spawn_speed"] = 0.1
+ }
+ },
+ {
+ id = 18,
+ name = "Disk Spawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 56,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["delay"] = 5,
+ ["disk_speed"] = 2,
+ ["spawn_speed"] = 0.1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/stages/nothern.tmx b/stages/nothern.tmx
new file mode 100644
index 0000000..b740b05
--- /dev/null
+++ b/stages/nothern.tmx
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="7" nextobjectid="46">
+ <editorsettings>
+ <export target="nothern.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="nothern.tsx"/>
+ <imagelayer id="2" name="Calque d'Images 1">
+ <image source="../assets/art/tileset/nothern-fortress-bg.png" width="320" height="176"/>
+ </imagelayer>
+ <layer id="3" name="Calque de Tuiles 1" width="40" height="22">
+ <data encoding="csv">
+30,30,30,30,30,30,30,30,30,30,30,30,31,30,123,30,30,30,30,30,30,30,30,30,30,13,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,31,30,123,30,30,30,30,30,0,30,30,30,30,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,77,16,16,16,30,30,30,31,64,0,28,10,11,0,28,0,0,12,0,12,64,29,30,30,30,30,32,32,32,78,30,30,30,30,30,
+30,30,30,30,30,93,16,16,16,30,30,30,31,0,0,9,10,0,0,12,0,0,9,10,11,0,45,30,30,30,30,32,32,32,94,30,30,30,30,30,
+30,30,30,77,16,16,16,30,30,30,30,30,30,15,0,0,0,0,0,28,0,0,0,0,0,0,0,29,30,30,30,30,30,32,32,32,78,30,30,30,
+30,30,30,93,16,16,16,30,30,30,30,30,30,31,0,0,0,0,0,27,12,0,0,0,0,0,0,29,30,30,30,30,30,32,32,32,94,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,0,0,0,0,28,0,0,0,0,0,0,29,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,0,0,0,0,27,0,0,0,0,0,0,29,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,47,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,0,0,0,0,0,61,0,0,0,0,0,13,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,77,16,16,16,30,30,30,30,30,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,30,30,30,30,30,30,32,32,32,78,30,
+30,93,16,16,16,30,30,30,30,30,30,30,31,0,0,0,0,0,61,0,0,0,0,0,0,0,29,30,30,30,30,30,30,30,30,32,32,32,94,30,
+30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,0,0,0,28,0,0,28,0,0,0,0,45,30,30,30,30,30,30,30,30,30,30,30,30,30,
+30,109,110,30,30,30,30,30,30,30,30,30,30,15,0,0,0,0,28,0,0,12,0,0,0,0,0,29,30,30,30,30,30,30,30,30,30,109,110,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,0,0,12,25,26,12,0,0,0,0,0,29,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,30,30,30,30,30,30,30,30,30,30,31,0,0,63,0,12,41,42,12,0,63,0,0,0,29,30,30,30,30,30,30,30,30,30,30,30,30,
+30,30,30,77,16,16,16,79,80,30,30,30,30,31,0,0,0,0,28,41,42,28,0,0,0,0,0,29,30,30,30,79,80,32,32,32,78,30,30,30,
+30,30,30,93,16,16,16,95,96,79,80,30,30,47,0,0,0,0,28,41,42,28,0,0,0,0,0,29,30,79,80,95,96,32,32,32,94,30,30,30,
+30,30,30,30,30,30,30,111,112,95,96,30,31,0,0,0,25,26,28,41,42,28,25,26,0,0,13,30,30,95,96,111,112,30,30,30,30,30,30,30,
+30,30,30,24,30,30,30,111,112,111,112,30,31,0,0,0,41,42,12,41,42,28,41,42,0,0,29,30,30,111,112,111,112,30,30,30,24,30,30,30,
+30,30,30,40,30,30,30,30,30,111,112,30,31,0,123,30,30,30,12,41,42,28,0,30,30,29,30,30,30,111,112,111,112,30,30,30,40,30,30,30,
+30,30,30,30,30,24,24,24,24,111,112,22,31,0,123,30,30,30,30,30,30,30,30,30,30,45,30,30,30,111,112,30,30,30,30,30,30,30,30,30
+</data>
+ </layer>
+ <layer id="4" name="Calque de Tuiles 2" width="40" height="22">
+ <data encoding="csv">
+22,22,22,22,22,22,40,22,22,22,40,22,22,22,40,22,22,22,22,22,22,22,22,22,22,40,22,22,22,40,22,22,22,40,22,22,22,22,22,22,
+22,69,70,24,22,38,38,38,38,38,38,38,38,38,38,38,38,22,22,69,70,22,22,38,38,38,38,38,38,38,38,38,38,38,38,22,24,69,70,22,
+22,85,86,40,23,0,0,0,0,0,0,0,0,0,0,0,20,21,22,85,86,22,23,1,0,0,0,0,0,0,0,0,0,0,0,21,40,85,86,22,
+22,22,22,38,39,0,0,0,0,0,0,0,0,0,0,0,0,37,38,38,38,38,39,0,0,0,0,0,0,0,0,0,0,0,0,37,38,22,22,22,
+22,8,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,2,36,34,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,8,22,
+22,38,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,37,38,22,
+23,52,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,20,21,
+23,52,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,34,21,
+23,4,0,0,0,0,18,35,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,33,18,0,0,0,0,3,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,53,54,55,0,0,0,0,50,4,51,52,0,0,0,0,0,53,54,54,54,54,55,0,0,0,0,0,1,18,3,51,0,0,0,0,53,54,55,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,
+22,6,7,0,0,0,0,0,0,0,0,0,0,0,0,53,54,54,54,54,54,54,54,54,55,0,0,0,0,0,0,0,0,0,0,0,0,5,6,22,
+22,8,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,8,22,
+22,22,22,6,7,97,98,99,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,102,67,68,5,6,22,22,22,
+22,69,70,24,23,113,114,115,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,118,83,84,21,24,69,70,22,
+22,85,86,40,22,6,6,6,6,6,6,6,6,6,6,7,67,68,0,0,0,0,99,100,5,6,6,6,6,6,6,6,6,6,6,22,40,85,86,22,
+22,22,22,22,22,22,24,22,22,22,24,22,22,22,24,23,83,84,5,6,6,7,115,116,21,24,22,22,22,24,22,22,22,24,22,22,22,22,22,22
+</data>
+ </layer>
+ <layer id="5" name="Calque de Tuiles 3" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="6" name="Calque d'Objets 1">
+ <object id="1" name="Player 1" type="Player" x="80" y="96">
+ <properties>
+ <property name="player_id" type="int" value="1"/>
+ <property name="skin" value="neon"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="2" name="Player 2" type="Player" x="240" y="96">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="5" name="Force &gt;" type="Force" x="24" y="32" width="56" height="16">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="6" name="Force &gt;" type="Force" x="40" y="16" width="56" height="16">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="7" name="Force &gt;" type="Force" x="8" y="80" width="32" height="16">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="8" name="Force &gt;" type="Force" x="24" y="128" width="32" height="16">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="9" name="&lt; Force" type="Force" x="264" y="128" width="32" height="16">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="10" name="&lt; Force" type="Force" x="224" y="16" width="56" height="16">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="11" name="&lt; Force" type="Force" x="280" y="80" width="32" height="16">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="12" name="&lt; Force" type="Force" x="240" y="32" width="56" height="16">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="17" name="Disk Spawner" type="DiskSpawner" x="160" y="152">
+ <properties>
+ <property name="disk_speed" type="float" value="2"/>
+ <property name="spawn_speed" type="float" value="0.1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="18" name="Disk Spawner" type="DiskSpawner" x="160" y="56">
+ <properties>
+ <property name="delay" type="float" value="5"/>
+ <property name="disk_speed" type="float" value="2"/>
+ <property name="spawn_speed" type="float" value="0.1"/>
+ </properties>
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/nothern.tsx b/stages/nothern.tsx
new file mode 100644
index 0000000..57a631f
--- /dev/null
+++ b/stages/nothern.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="nothern-fortress" tilewidth="8" tileheight="8" tilecount="128" columns="16">
+ <image source="../assets/art/tileset/nothern-fortress.png" width="128" height="64"/>
+</tileset>
diff --git a/stages/objects.tsx b/stages/objects.tsx
new file mode 100644
index 0000000..4e43843
--- /dev/null
+++ b/stages/objects.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="objects" tilewidth="8" tileheight="8" tilecount="2" columns="2">
+ <image source="../assets/art/tileset/objects.png" width="16" height="8"/>
+</tileset>
diff --git a/stages/objecttypes.xml b/stages/objecttypes.xml
new file mode 100644
index 0000000..7ec6d41
--- /dev/null
+++ b/stages/objecttypes.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<objecttypes>
+ <objecttype name="DiskSpawner" color="#a4181b">
+ <property name="delay" type="float" default="0"/>
+ <property name="disk_speed" type="float" default="1"/>
+ <property name="spawn_speed" type="float" default="0.1"/>
+ </objecttype>
+ <objecttype name="Force" color="#a420a2">
+ <property name="spdx" type="float" default="0"/>
+ <property name="spdy" type="float" default="0"/>
+ </objecttype>
+ <objecttype name="Lava" color="#a40003"/>
+ <objecttype name="MainMenu" color="#eaff00"/>
+ <objecttype name="Player" color="#25a438">
+ <property name="player_id" type="int" default="1"/>
+ <property name="skin" type="string"/>
+ <property name="xscale" type="int" default="1"/>
+ </objecttype>
+ <objecttype name="Slime" color="#00cf00"/>
+ <objecttype name="Water" color="#0000a4"/>
+</objecttypes>
diff --git a/stages/qujna.tsx b/stages/qujna.tsx
new file mode 100644
index 0000000..4b11589
--- /dev/null
+++ b/stages/qujna.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="qujna" tilewidth="8" tileheight="8" tilecount="128" columns="16">
+ <image source="../assets/art/tileset/qujna.png" width="128" height="64"/>
+</tileset>
diff --git a/stages/sky.lua b/stages/sky.lua
new file mode 100644
index 0000000..7f3c7fb
--- /dev/null
+++ b/stages/sky.lua
@@ -0,0 +1,293 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 6,
+ nextobjectid = 14,
+ properties = {},
+ tilesets = {
+ {
+ name = "hyperion",
+ firstgid = 1,
+ filename = "hyperion.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 16,
+ image = "../assets/art/tileset/hyperion.png",
+ imagewidth = 128,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 128,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/hyperion-bg.png",
+ id = 4,
+ name = "Background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 3,
+ name = "Background",
+ 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, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 29, 29, 30, 31, 31, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 28, 0, 9, 10, 11, 29, 30, 30, 31, 31, 0, 44, 27, 0, 60, 0, 29, 29, 30, 30, 31, 0, 12, 9, 10, 11, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 26, 0, 0, 0, 0, 29, 32, 32, 30, 31, 0, 44, 0, 0, 60, 0, 29, 30, 32, 32, 31, 0, 26, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 10, 11, 0, 0, 60, 25, 0, 0, 0, 0, 45, 46, 46, 46, 47, 0, 44, 0, 0, 60, 0, 45, 46, 46, 46, 47, 0, 42, 0, 0, 0, 44, 0, 0, 0, 9, 10, 0,
+ 0, 0, 0, 0, 0, 0, 60, 41, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 44, 0, 0, 60, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 44, 0, 0, 60, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 111, 110, 112, 0, 0, 0, 0, 0, 0, 0, 109, 106, 107, 107, 107, 108, 110, 110, 110, 110, 110, 110, 106, 107, 107, 123, 108, 0, 0, 0, 0, 0, 0, 0, 0, 109, 111, 0, 0,
+ 0, 0, 14, 14, 15, 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0, 13, 14, 14, 0, 0,
+ 0, 0, 32, 32, 31, 9, 10, 10, 10, 11, 29, 30, 30, 30, 30, 30, 30, 30, 93, 94, 95, 96, 30, 30, 30, 30, 30, 30, 30, 31, 9, 10, 10, 10, 11, 29, 32, 32, 0, 0,
+ 0, 0, 32, 32, 31, 0, 0, 0, 0, 0, 45, 46, 46, 46, 46, 46, 46, 30, 30, 30, 30, 30, 30, 46, 46, 46, 46, 46, 46, 47, 0, 0, 0, 0, 0, 29, 32, 32, 0, 0,
+ 0, 0, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 106, 107, 107, 107, 108, 29, 32, 32, 32, 32, 31, 106, 107, 107, 107, 108, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 0, 0,
+ 0, 0, 30, 30, 31, 110, 110, 110, 111, 110, 112, 0, 106, 107, 107, 107, 108, 29, 32, 32, 32, 32, 31, 106, 107, 107, 107, 108, 0, 109, 110, 110, 110, 110, 110, 29, 30, 30, 30, 0,
+ 0, 30, 30, 30, 30, 14, 14, 14, 14, 14, 14, 15, 106, 107, 107, 107, 108, 29, 30, 30, 30, 30, 31, 106, 107, 107, 107, 108, 13, 14, 14, 14, 14, 14, 14, 30, 30, 30, 14, 0,
+ 0, 30, 30, 30, 30, 64, 30, 30, 30, 30, 30, 31, 122, 123, 123, 123, 124, 29, 30, 30, 30, 30, 31, 122, 123, 123, 123, 124, 29, 30, 30, 30, 30, 30, 64, 30, 30, 30, 30, 0,
+ 0, 30, 30, 0, 0, 80, 30, 30, 30, 30, 30, 30, 14, 14, 14, 14, 14, 30, 14, 14, 30, 14, 30, 14, 14, 14, 14, 14, 30, 30, 30, 30, 30, 30, 80, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30, 30, 30, 64, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 64, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0,
+ 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Solid",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 22, 22, 22, 22, 22, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 22, 22, 22, 22, 22,
+ 22, 22, 38, 38, 39, 4, 0, 0, 0, 0, 0, 0, 53, 54, 54, 54, 55, 0, 0, 0, 0, 0, 0, 53, 54, 53, 54, 55, 0, 0, 0, 0, 0, 0, 2, 37, 38, 38, 22, 22,
+ 22, 23, 18, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 3, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 102, 101, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 50, 51, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 117, 118, 117, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 19, 3, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 17, 49, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 19, 18, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 54, 54, 54, 55, 0, 0, 0, 0, 0, 0, 53, 54, 54, 54, 54, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22,
+ 22, 23, 99, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, 21, 22,
+ 22, 23, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 82, 21, 22,
+ 22, 22, 6, 6, 6, 6, 6, 7, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 67, 68, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 5, 6, 6, 6, 6, 6, 22, 22,
+ 22, 8, 8, 8, 8, 8, 8, 23, 81, 82, 0, 0, 0, 0, 0, 0, 119, 120, 85, 86, 83, 84, 119, 120, 0, 0, 0, 0, 0, 0, 85, 86, 21, 8, 8, 8, 8, 8, 8, 22,
+ 22, 8, 8, 8, 8, 8, 8, 22, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 22, 8, 8, 8, 8, 8, 8, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 2,
+ name = "Foreground",
+ 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, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105, 0, 0,
+ 0, 0, 121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 110, 111, 0, 0, 89, 90, 0, 0, 111, 110, 0, 0, 110, 112, 0, 0, 0, 0, 0, 0, 0, 0, 121, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 105, 0, 75, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 76, 0, 105, 0, 0, 0, 0, 0,
+ 0, 0, 127, 128, 0, 121, 0, 91, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 92, 0, 121, 0, 127, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 125, 126, 0, 0, 0, 0, 0, 0, 0, 0, 127, 128, 127, 128, 0, 0, 0, 0, 0, 0, 0, 0, 125, 126, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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",
+ draworder = "topdown",
+ id = 5,
+ name = "Objects",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 1,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 48,
+ y = 56,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["skin"] = "theophile"
+ }
+ },
+ {
+ id = 2,
+ name = "Player2",
+ type = "Player",
+ shape = "point",
+ x = 272,
+ y = 56,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 3,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 16,
+ y = 24,
+ width = 16,
+ height = 104,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 5,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 288,
+ y = 24,
+ width = 16,
+ height = 104,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 9,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 144,
+ y = 64,
+ width = 32,
+ height = 80,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 12,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 104,
+ y = 16,
+ width = 16,
+ height = 64,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 13,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 200,
+ y = 16,
+ width = 16,
+ height = 64,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/stages/sky.tmx b/stages/sky.tmx
new file mode 100644
index 0000000..3a135a2
--- /dev/null
+++ b/stages/sky.tmx
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="6" nextobjectid="14">
+ <editorsettings>
+ <export target="sky.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="hyperion.tsx"/>
+ <imagelayer id="4" name="Background">
+ <image source="../assets/art/tileset/hyperion-bg.png" width="320" height="174"/>
+ </imagelayer>
+ <layer id="3" name="Background" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,31,0,0,0,0,0,0,0,29,29,30,31,31,0,0,0,0,0,44,0,0,0,0,0,0,
+0,0,0,0,0,0,60,28,0,9,10,11,29,30,30,31,31,0,44,27,0,60,0,29,29,30,30,31,0,12,9,10,11,44,0,0,0,0,0,0,
+0,0,0,0,0,0,60,26,0,0,0,0,29,32,32,30,31,0,44,0,0,60,0,29,30,32,32,31,0,26,0,0,0,44,0,0,0,0,0,0,
+0,0,10,11,0,0,60,25,0,0,0,0,45,46,46,46,47,0,44,0,0,60,0,45,46,46,46,47,0,42,0,0,0,44,0,0,0,9,10,0,
+0,0,0,0,0,0,60,41,0,0,0,0,106,107,107,107,108,0,44,0,0,60,0,106,107,107,107,108,0,0,0,0,0,44,0,0,0,0,0,0,
+0,0,0,0,0,0,60,0,0,0,0,0,106,107,107,107,108,0,44,0,0,60,0,106,107,107,107,108,0,0,0,0,0,44,0,0,0,0,0,0,
+0,0,0,0,0,0,60,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,44,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,106,107,107,107,108,0,0,0,0,0,0,0,0,0,0,0,0,
+0,111,110,112,0,0,0,0,0,0,0,109,106,107,107,107,108,110,110,110,110,110,110,106,107,107,123,108,0,0,0,0,0,0,0,0,109,111,0,0,
+0,0,14,14,15,0,0,0,0,0,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,13,14,14,0,0,
+0,0,32,32,31,9,10,10,10,11,29,30,30,30,30,30,30,30,93,94,95,96,30,30,30,30,30,30,30,31,9,10,10,10,11,29,32,32,0,0,
+0,0,32,32,31,0,0,0,0,0,45,46,46,46,46,46,46,30,30,30,30,30,30,46,46,46,46,46,46,47,0,0,0,0,0,29,32,32,0,0,
+0,0,30,30,31,0,0,0,0,0,0,0,106,107,107,107,108,29,32,32,32,32,31,106,107,107,107,108,0,0,0,0,0,0,0,29,30,30,0,0,
+0,0,30,30,31,110,110,110,111,110,112,0,106,107,107,107,108,29,32,32,32,32,31,106,107,107,107,108,0,109,110,110,110,110,110,29,30,30,30,0,
+0,30,30,30,30,14,14,14,14,14,14,15,106,107,107,107,108,29,30,30,30,30,31,106,107,107,107,108,13,14,14,14,14,14,14,30,30,30,14,0,
+0,30,30,30,30,64,30,30,30,30,30,31,122,123,123,123,124,29,30,30,30,30,31,122,123,123,123,124,29,30,30,30,30,30,64,30,30,30,30,0,
+0,30,30,0,0,80,30,30,30,30,30,30,14,14,14,14,14,30,14,14,30,14,30,14,14,14,14,14,30,30,30,30,30,30,80,0,0,0,0,0,
+0,0,0,0,0,0,30,30,30,30,30,30,30,64,30,30,30,30,30,30,30,30,30,30,30,30,64,30,30,30,30,30,30,0,0,0,0,0,0,0,
+30,30,30,30,30,30,0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,80,30,30,30,30,30,30,30,30,30,30,30,30,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <layer id="1" name="Solid" width="40" height="22">
+ <data encoding="csv">
+22,22,22,22,22,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,22,22,22,22,22,
+22,22,38,38,39,4,0,0,0,0,0,0,53,54,54,54,55,0,0,0,0,0,0,53,54,53,54,55,0,0,0,0,0,0,2,37,38,38,22,22,
+22,23,18,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,3,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,102,101,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,50,51,35,0,0,0,0,0,0,0,0,0,0,117,118,117,118,0,0,0,0,0,0,0,0,0,0,49,19,3,0,0,0,21,22,
+22,23,0,0,0,17,49,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,19,18,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,67,68,0,0,0,0,0,0,0,0,0,0,99,100,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,83,84,0,0,0,0,0,0,0,0,0,0,115,116,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,53,54,54,54,54,55,0,0,0,0,0,0,53,54,54,54,54,55,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,
+22,23,99,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,21,22,
+22,23,115,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,21,22,
+22,22,6,6,6,6,6,7,65,66,0,0,0,0,0,0,0,0,69,70,67,68,0,0,0,0,0,0,0,0,69,70,5,6,6,6,6,6,22,22,
+22,8,8,8,8,8,8,23,81,82,0,0,0,0,0,0,119,120,85,86,83,84,119,120,0,0,0,0,0,0,85,86,21,8,8,8,8,8,8,22,
+22,8,8,8,8,8,8,22,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,22,8,8,8,8,8,8,22,
+22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22
+</data>
+ </layer>
+ <layer id="2" name="Foreground" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,105,0,0,0,0,0,0,0,0,0,0,127,128,0,0,0,0,73,74,0,0,0,0,127,128,0,0,0,0,0,0,0,0,0,0,105,0,0,
+0,0,121,0,0,0,0,0,0,0,0,0,110,0,0,110,111,0,0,89,90,0,0,111,110,0,0,110,112,0,0,0,0,0,0,0,0,121,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,105,0,75,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,76,0,105,0,0,0,0,0,
+0,0,127,128,0,121,0,91,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,92,0,121,0,127,128,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,125,126,0,0,0,0,0,0,0,0,127,128,127,128,0,0,0,0,0,0,0,0,125,126,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="5" name="Objects">
+ <object id="1" name="Player 1" type="Player" x="48" y="56">
+ <properties>
+ <property name="skin" value="theophile"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="2" name="Player2" type="Player" x="272" y="56">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="3" name="Force ^" type="Force" x="16" y="24" width="16" height="104">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="5" name="Force ^" type="Force" x="288" y="24" width="16" height="104">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="9" name="Force ^" type="Force" x="144" y="64" width="32" height="80">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="12" name="Force ^" type="Force" x="104" y="16" width="16" height="64">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="13" name="Force ^" type="Force" x="200" y="16" width="16" height="64">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/thermopolis.tsx b/stages/thermopolis.tsx
new file mode 100644
index 0000000..2b1bf8b
--- /dev/null
+++ b/stages/thermopolis.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="thermopolis" tilewidth="8" tileheight="8" tilecount="128" columns="16">
+ <image source="../assets/art/tileset/thermopolis.png" width="128" height="64"/>
+</tileset>
diff --git a/stages/weirdo.lua b/stages/weirdo.lua
new file mode 100644
index 0000000..3232576
--- /dev/null
+++ b/stages/weirdo.lua
@@ -0,0 +1,351 @@
+return {
+ version = "1.4",
+ luaversion = "5.1",
+ tiledversion = "1.4.2",
+ orientation = "orthogonal",
+ renderorder = "right-down",
+ width = 40,
+ height = 22,
+ tilewidth = 8,
+ tileheight = 8,
+ nextlayerid = 7,
+ nextobjectid = 29,
+ properties = {},
+ tilesets = {
+ {
+ name = "weirdo",
+ firstgid = 1,
+ filename = "weirdo.tsx",
+ tilewidth = 8,
+ tileheight = 8,
+ spacing = 0,
+ margin = 0,
+ columns = 8,
+ image = "../assets/art/tileset/weirdo.png",
+ imagewidth = 64,
+ imageheight = 64,
+ objectalignment = "unspecified",
+ tileoffset = {
+ x = 0,
+ y = 0
+ },
+ grid = {
+ orientation = "orthogonal",
+ width = 8,
+ height = 8
+ },
+ properties = {},
+ terrains = {},
+ tilecount = 64,
+ tiles = {}
+ }
+ },
+ layers = {
+ {
+ type = "imagelayer",
+ image = "../assets/art/tileset/hyperion-bg.png",
+ id = 6,
+ name = "background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0.333333,
+ offsety = 0.333333,
+ properties = {}
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 5,
+ name = "background",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ encoding = "lua",
+ data = {
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 8, 14, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 55, 55, 55, 55, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 14, 8, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 14, 14, 14, 14, 14, 14, 14, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 18, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 16, 36, 36, 36, 36, 36, 36, 36, 36, 14, 14, 14, 14, 14, 36, 36, 36, 36, 36, 36, 36, 16, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 63, 63, 63, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 63, 63, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 20, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 20, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 20, 20, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36
+ }
+ },
+ {
+ type = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 1,
+ name = "Solid",
+ 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, 14, 14, 38, 22, 22, 22, 22, 22, 22, 39, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 38, 22, 22, 22, 22, 22, 22, 39, 14, 14, 0,
+ 0, 14, 14, 15, 58, 58, 58, 58, 58, 58, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 58, 58, 58, 58, 58, 58, 13, 14, 14, 0,
+ 0, 38, 22, 23, 0, 0, 0, 0, 0, 0, 9, 10, 10, 10, 10, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 26, 26, 26, 26, 27, 0, 0, 0, 0, 0, 0, 21, 22, 39, 0,
+ 0, 15, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 58, 58, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 15, 0, 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 13, 0,
+ 0, 46, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 47, 0,
+ 0, 20, 14, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 14, 20, 0,
+ 0, 20, 14, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 18, 18, 18, 18, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 14, 20, 0,
+ 0, 20, 14, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 14, 20, 0,
+ 0, 20, 14, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 14, 20, 0,
+ 0, 20, 14, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 14, 20, 20,
+ 0, 20, 20, 46, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 47, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 46, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 47, 20, 20, 20,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 = "tilelayer",
+ x = 0,
+ y = 0,
+ width = 40,
+ height = 22,
+ id = 4,
+ name = "foreground",
+ 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
+ }
+ },
+ {
+ type = "objectgroup",
+ draworder = "topdown",
+ id = 2,
+ name = "objects",
+ visible = true,
+ opacity = 1,
+ offsetx = 0,
+ offsety = 0,
+ properties = {},
+ objects = {
+ {
+ id = 2,
+ name = "Player 1",
+ type = "Player",
+ shape = "point",
+ x = 76,
+ y = 88,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["skin"] = "jean-luc"
+ }
+ },
+ {
+ id = 3,
+ name = "Player 2",
+ type = "Player",
+ shape = "point",
+ x = 244,
+ y = 88,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["player_id"] = 2,
+ ["skin"] = "jean-luc",
+ ["xscale"] = -1
+ }
+ },
+ {
+ id = 19,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 16,
+ y = 103,
+ width = 16,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 20,
+ name = "Force <",
+ type = "Force",
+ shape = "rectangle",
+ x = 288,
+ y = 103,
+ width = 16,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 21,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 160,
+ y = 119,
+ width = 48,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 22,
+ name = "Force >",
+ type = "Force",
+ shape = "rectangle",
+ x = 200,
+ y = 32,
+ width = 40,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = 1
+ }
+ },
+ {
+ id = 23,
+ name = "Force <",
+ type = "Force",
+ shape = "rectangle",
+ x = 112,
+ y = 119,
+ width = 48,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 24,
+ name = "Force <",
+ type = "Force",
+ shape = "rectangle",
+ x = 80,
+ y = 32,
+ width = 40,
+ height = 1,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdx"] = -1
+ }
+ },
+ {
+ id = 25,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 32,
+ y = 104,
+ width = 1,
+ height = 48,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 27,
+ name = "Force ^",
+ type = "Force",
+ shape = "rectangle",
+ x = 287,
+ y = 104,
+ width = 1,
+ height = 48,
+ rotation = 0,
+ visible = true,
+ properties = {
+ ["spdy"] = -1
+ }
+ },
+ {
+ id = 28,
+ name = "DiskSpawner",
+ type = "DiskSpawner",
+ shape = "point",
+ x = 160,
+ y = 56,
+ width = 0,
+ height = 0,
+ rotation = 0,
+ visible = true,
+ properties = {}
+ }
+ }
+ }
+ }
+}
diff --git a/stages/weirdo.tmx b/stages/weirdo.tmx
new file mode 100644
index 0000000..8859925
--- /dev/null
+++ b/stages/weirdo.tmx
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.4" tiledversion="1.4.2" orientation="orthogonal" renderorder="right-down" width="40" height="22" tilewidth="8" tileheight="8" infinite="0" nextlayerid="7" nextobjectid="29">
+ <editorsettings>
+ <export target="weirdo.lua" format="lua"/>
+ </editorsettings>
+ <tileset firstgid="1" source="weirdo.tsx"/>
+ <imagelayer id="6" name="background" offsetx="0.333333" offsety="0.333333">
+ <image source="../assets/art/tileset/hyperion-bg.png" width="320" height="174"/>
+ </imagelayer>
+ <layer id="5" name="background" width="40" height="22">
+ <data encoding="csv">
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,8,14,36,36,36,36,36,36,36,36,36,36,36,55,55,55,55,36,36,36,36,36,36,36,36,36,36,36,14,8,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,14,14,14,14,14,14,14,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,18,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,16,36,36,36,36,36,36,36,36,14,14,14,14,14,36,36,36,36,36,36,36,16,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,63,63,63,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,63,63,63,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,20,20,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,
+36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36
+</data>
+ </layer>
+ <layer id="1" name="Solid" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,14,14,38,22,22,22,22,22,22,39,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,38,22,22,22,22,22,22,39,14,14,0,
+0,14,14,15,58,58,58,58,58,58,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,58,58,58,58,58,58,13,14,14,0,
+0,38,22,23,0,0,0,0,0,0,9,10,10,10,10,22,22,22,22,22,22,22,22,22,22,26,26,26,26,27,0,0,0,0,0,0,21,22,39,0,
+0,15,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,30,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58,58,58,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,5,6,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,7,0,0,0,0,0,0,13,0,
+0,15,0,0,0,0,0,0,21,22,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,22,23,0,0,0,0,0,0,13,0,
+0,46,18,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,47,0,
+0,20,14,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,14,20,0,
+0,20,14,53,0,0,0,0,0,0,0,0,0,0,1,2,2,2,2,2,18,18,18,18,18,19,0,0,0,0,0,0,0,0,0,0,52,14,20,0,
+0,20,14,53,0,0,0,0,0,0,0,0,0,0,13,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,52,14,20,0,
+0,20,14,53,0,0,0,0,0,0,0,0,0,0,13,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,52,14,20,0,
+0,20,14,53,0,0,0,0,0,0,0,0,0,0,13,14,14,14,14,14,14,14,14,14,14,15,0,0,0,0,0,0,0,0,0,0,52,14,20,20,
+0,20,20,46,6,6,6,6,6,6,6,6,6,6,47,14,14,14,14,14,14,14,14,14,14,46,6,6,6,6,6,6,6,6,6,6,47,20,20,20,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <layer id="4" name="foreground" width="40" height="22">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+</data>
+ </layer>
+ <objectgroup id="2" name="objects">
+ <object id="2" name="Player 1" type="Player" x="76" y="88">
+ <properties>
+ <property name="skin" value="jean-luc"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="3" name="Player 2" type="Player" x="244" y="88">
+ <properties>
+ <property name="player_id" type="int" value="2"/>
+ <property name="skin" value="jean-luc"/>
+ <property name="xscale" type="int" value="-1"/>
+ </properties>
+ <point/>
+ </object>
+ <object id="19" name="Force &gt;" type="Force" x="16" y="103" width="16" height="1">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="20" name="Force &lt;" type="Force" x="288" y="103" width="16" height="1">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="21" name="Force &gt;" type="Force" x="160" y="119" width="48" height="1">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="22" name="Force &gt;" type="Force" x="200" y="32" width="40" height="1">
+ <properties>
+ <property name="spdx" type="int" value="1"/>
+ </properties>
+ </object>
+ <object id="23" name="Force &lt;" type="Force" x="112" y="119" width="48" height="1">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="24" name="Force &lt;" type="Force" x="80" y="32" width="40" height="1">
+ <properties>
+ <property name="spdx" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="25" name="Force ^" type="Force" x="32" y="104" width="1" height="48">
+ <properties>
+ <property name="spdy" type="int" value="-1"/>
+ </properties>
+ </object>
+ <object id="27" name="Force ^" type="Force" x="287" y="104" width="1" height="48">
+ <properties>
+ <property name="spdy" type="float" value="-1"/>
+ </properties>
+ </object>
+ <object id="28" name="DiskSpawner" type="DiskSpawner" x="160" y="56">
+ <point/>
+ </object>
+ </objectgroup>
+</map>
diff --git a/stages/weirdo.tsx b/stages/weirdo.tsx
new file mode 100644
index 0000000..1da64f9
--- /dev/null
+++ b/stages/weirdo.tsx
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<tileset version="1.4" tiledversion="1.4.2" name="weirdo" tilewidth="8" tileheight="8" tilecount="64" columns="8">
+ <image source="../assets/art/tileset/weirdo.png" width="64" height="64"/>
+</tileset>