diff options
98 files changed, 1689 insertions, 1006 deletions
diff --git a/assets/backgrounds/404.png b/assets/backgrounds/404.png Binary files differnew file mode 100644 index 0000000..d1d7231 --- /dev/null +++ b/assets/backgrounds/404.png diff --git a/assets/backgrounds/alpha-1.png b/assets/backgrounds/alpha.png Binary files differindex d897910..d897910 100644 --- a/assets/backgrounds/alpha-1.png +++ b/assets/backgrounds/alpha.png diff --git a/assets/decorations/205-exhaust-left.png b/assets/decorations/205-exhaust-left.png Binary files differnew file mode 100644 index 0000000..b631959 --- /dev/null +++ b/assets/decorations/205-exhaust-left.png diff --git a/assets/decorations/205-exhaust-right.png b/assets/decorations/205-exhaust-right.png Binary files differnew file mode 100644 index 0000000..95615dc --- /dev/null +++ b/assets/decorations/205-exhaust-right.png diff --git a/assets/decorations/205-exhaust-top.png b/assets/decorations/205-exhaust-top.png Binary files differnew file mode 100644 index 0000000..9ea95ca --- /dev/null +++ b/assets/decorations/205-exhaust-top.png diff --git a/assets/decorations/205-flames.png b/assets/decorations/205-flames.png Binary files differnew file mode 100644 index 0000000..d1a0cf4 --- /dev/null +++ b/assets/decorations/205-flames.png diff --git a/assets/decorations/sorona-bridge-left.png b/assets/decorations/sorona-bridge-left.png Binary files differnew file mode 100644 index 0000000..3543db0 --- /dev/null +++ b/assets/decorations/sorona-bridge-left.png diff --git a/assets/decorations/sorona-bridge-loop.png b/assets/decorations/sorona-bridge-loop.png Binary files differnew file mode 100644 index 0000000..40d237b --- /dev/null +++ b/assets/decorations/sorona-bridge-loop.png diff --git a/assets/decorations/sorona-bridge-right.png b/assets/decorations/sorona-bridge-right.png Binary files differnew file mode 100644 index 0000000..22fd8d5 --- /dev/null +++ b/assets/decorations/sorona-bridge-right.png diff --git a/assets/maps.png b/assets/maps.png Binary files differindex 261622c..f0e530d 100644 --- a/assets/maps.png +++ b/assets/maps.png diff --git a/assets/music/404.ogg b/assets/music/404.ogg Binary files differnew file mode 100644 index 0000000..e952135 --- /dev/null +++ b/assets/music/404.ogg diff --git a/assets/platforms/205-left.png b/assets/platforms/205-left.png Binary files differnew file mode 100644 index 0000000..9afd1c6 --- /dev/null +++ b/assets/platforms/205-left.png diff --git a/assets/platforms/205-right.png b/assets/platforms/205-right.png Binary files differnew file mode 100644 index 0000000..4e55642 --- /dev/null +++ b/assets/platforms/205-right.png diff --git a/assets/platforms/205-top.png b/assets/platforms/205-top.png Binary files differnew file mode 100644 index 0000000..e67eb66 --- /dev/null +++ b/assets/platforms/205-top.png diff --git a/assets/platforms/404-bottom.png b/assets/platforms/404-bottom.png Binary files differnew file mode 100644 index 0000000..b3e9831 --- /dev/null +++ b/assets/platforms/404-bottom.png diff --git a/assets/platforms/404-small.png b/assets/platforms/404-small.png Binary files differnew file mode 100644 index 0000000..787cd67 --- /dev/null +++ b/assets/platforms/404-small.png diff --git a/assets/platforms/404-top.png b/assets/platforms/404-top.png Binary files differnew file mode 100644 index 0000000..7452857 --- /dev/null +++ b/assets/platforms/404-top.png diff --git a/assets/platforms/sorona-center.png b/assets/platforms/sorona-button.png Binary files differindex 835526d..835526d 100644 --- a/assets/platforms/sorona-center.png +++ b/assets/platforms/sorona-button.png diff --git a/assets/platforms/sorona-left-bottom.png b/assets/platforms/sorona-left-bottom.png Binary files differdeleted file mode 100644 index 4c02b04..0000000 --- a/assets/platforms/sorona-left-bottom.png +++ /dev/null diff --git a/assets/platforms/sorona-medium.png b/assets/platforms/sorona-medium.png Binary files differnew file mode 100644 index 0000000..519f3c9 --- /dev/null +++ b/assets/platforms/sorona-medium.png diff --git a/assets/platforms/sorona-right-bottom.png b/assets/platforms/sorona-right-bottom.png Binary files differdeleted file mode 100644 index a023482..0000000 --- a/assets/platforms/sorona-right-bottom.png +++ /dev/null diff --git a/assets/platforms/sorona-right-top.png b/assets/platforms/sorona-right-top.png Binary files differdeleted file mode 100644 index 57ccb8d..0000000 --- a/assets/platforms/sorona-right-top.png +++ /dev/null diff --git a/assets/platforms/sorona-small.png b/assets/platforms/sorona-small.png Binary files differnew file mode 100644 index 0000000..da2fabe --- /dev/null +++ b/assets/platforms/sorona-small.png diff --git a/assets/platforms/sorona-left-top.png b/assets/platforms/sorona-spiked.png Binary files differindex e59bd99..e59bd99 100644 --- a/assets/platforms/sorona-left-top.png +++ b/assets/platforms/sorona-spiked.png diff --git a/assets/platforms/sorona-wide.png b/assets/platforms/sorona-wide.png Binary files differnew file mode 100644 index 0000000..4d595e3 --- /dev/null +++ b/assets/platforms/sorona-wide.png diff --git a/config/animations/clouds-default.lua b/config/animations/clouds-default.lua new file mode 100644 index 0000000..bbf8a28 --- /dev/null +++ b/config/animations/clouds-default.lua @@ -0,0 +1,18 @@ +return +{ + default = { + [1] = love.graphics.newQuad( 1, 1, 158,47, 478,49), + frames = 1, + repeated = true + }, + default2 = { + [1] = love.graphics.newQuad(160, 1, 158,47, 478,49), + frames = 1, + repeated = true + }, + default3 = { + [1] = love.graphics.newQuad(319, 1, 158,47, 478,49), + frames = 1, + repeated = true + } +} diff --git a/config/animations/flames.lua b/config/animations/flames.lua new file mode 100644 index 0000000..62ecbb1 --- /dev/null +++ b/config/animations/flames.lua @@ -0,0 +1,21 @@ +return +{ + default = { + [1] = love.graphics.newQuad(0, 0, 42, 19, 168, 19), + [2] = love.graphics.newQuad(42, 0, 42, 19, 168, 19), + frames = 2, + repeated = true + }, + fadein = { + [1] = love.graphics.newQuad(84, 0, 42, 19, 168, 19), + [2] = love.graphics.newQuad(126, 0, 42, 19, 168, 19), + frames = 2, + repeated = false + }, + fadeout = { + [1] = love.graphics.newQuad(126, 0, 42, 19, 168, 19), + [2] = love.graphics.newQuad(84, 0, 42, 19, 168, 19), + frames = 2, + repeated = false + } +} diff --git a/config/maps.lua b/config/maps.lua deleted file mode 100644 index 32e89a5..0000000 --- a/config/maps.lua +++ /dev/null @@ -1,9 +0,0 @@ -return { - "default", - "rill", - "ribbit", - "starstorm", - "aiguillon", - "sorona", - "alpha abyss" -} diff --git a/config/maps/205.lua b/config/maps/205.lua new file mode 100644 index 0000000..d0aa1f8 --- /dev/null +++ b/config/maps/205.lua @@ -0,0 +1,49 @@ +return +{ + name = "AI Station 205", + theme = "sorona.ogg", + portrait = 1, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 0}, + width = 360, + height = 240, + respawns = { + {x = -10, y = -55}, + {x = 0, y = -55}, + {x = 10, y = -55} + }, + create = { + { + flames = true + }, + { + x = -36, + y = -48, + platform = "205-top" + }, + { + x = -36+9, + y = -48+11, + decoration = "assets/decorations/205-exhaust-top.png" + }, + { + x = -122, + y = 10, + platform = "205-left" + }, + { + x = -122+49, + y = 10+2, + decoration = "assets/decorations/205-exhaust-left.png" + }, + { + x = 28, + y = 10, + platform = "205-right" + }, + { + x = 28+29, + y = 10+2, + decoration = "assets/decorations/205-exhaust-right.png" + } + } +} diff --git a/config/maps/404.lua b/config/maps/404.lua new file mode 100644 index 0000000..44b6c93 --- /dev/null +++ b/config/maps/404.lua @@ -0,0 +1,51 @@ +return +{ + name = "AI Station 404", + theme = "404.ogg", + portrait = 8, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 0}, + width = 360, + height = 240, + respawns = { + {x = -15, y = -80}, + {x = -5, y = -80}, + {x = 5, y = -80}, + {x = 15, y = -80} + }, + create = { + { + ratio = 0, + background = "assets/backgrounds/404.png", + }, + { + x = -105, + y = -75, + platform = "404-top" + }, + { + x = -123, + y = 25, + platform = "404-bottom" + }, + { + x = 138, + y = -25, + platform = "404-small" + }, + { + x = -180, + y = -25, + platform = "404-small" + }, + { + x = 138, + y = 65, + platform = "404-small" + }, + { + x = -180, + y = 65, + platform = "404-small" + } + } +}
\ No newline at end of file diff --git a/config/maps/aiguillon.lua b/config/maps/aiguillon.lua index 40d3928..c4f0ee3 100644 --- a/config/maps/aiguillon.lua +++ b/config/maps/aiguillon.lua @@ -1,58 +1,51 @@ -return { - -- CENTER AND SIZE - name = "aiguillon", +return +{ + name = "Aiguillon", theme = "aiguillon.ogg", - center_x = 0, - center_y = 10, + portrait = 5, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 10}, width = 370, height = 290, - -- RESPAWN POINTS respawns = { - {x = 0, y = -80}, - {x = 0, y = -80}, - {x = 0, y = -80}, - {x = 0, y = -80}, + {x = -15, y = -80}, + {x = -5, y = -80}, + {x = 5, y = -80}, + {x = 15, y = -80}, }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/aiguillon.png", - platforms = { + create = { + { + ratio = 0, + background = "assets/backgrounds/aiguillon.png" + }, { x = -108, y = 22, - shape = {1,0, 212,0, 212,12, 206,18, 14,18, 1,12}, - sprite = "assets/platforms/aiguillon-wide.png" + platform = "aiguillon-wide" }, { x = -46, y = -19, - shape = {1,0, 87,0, 87,18, 14,18, 1,12}, - sprite = "assets/platforms/aiguillon-middle.png" + platform = "aiguillon-middle" }, { x = -141, y = -57, - shape = {1,0, 50,0, 50,18, 5,18, 1,13}, - sprite = "assets/platforms/aiguillon-left-big.png" + platform = "aiguillon-left-big" }, { x = -132, y = 84, - shape = {1,0, 25,0, 25,18, 1,18}, - sprite = "assets/platforms/aiguillon-left-small.png" + platform = "aiguillon-left-small" }, { x = 77, y = -57, - shape = {1,0, 50,0, 50,12, 37,18, 1,18}, - sprite = "assets/platforms/aiguillon-right-big.png" + platform = "aiguillon-right-big" }, { x = 103, y = 84, - shape = {1,0, 25,0, 25,18, 1,18}, - sprite = "assets/platforms/aiguillon-right-small.png" + platform = "aiguillon-right-small" } }, - decorations = {} } diff --git a/config/maps/alpha abyss.lua b/config/maps/alpha abyss.lua deleted file mode 100644 index 0dd2c61..0000000 --- a/config/maps/alpha abyss.lua +++ /dev/null @@ -1,75 +0,0 @@ --- The abyss of the alpha. --- Animations -local animations_small = { - default = { - frames = 20, - repeated = true - } -} -local animations_big = { - default = { - frames = 20, - repeated = true - } -} -for i=1,10 do - local a = love.graphics.newQuad(i*118-118, 0, 118,51, 1180,51) - animations_big.default[i*2-1] = a - animations_big.default[i*2] = a - local a = love.graphics.newQuad(i*60-60, 0, 60,20, 600,20) - animations_small.default[i*2-1] = a - animations_small.default[i*2] = a -end --- Map data -return { - -- GENERAL - name = "alpha abyss", - theme = "alpha.ogg", - center_x = 0, - center_y = -80, - width = 360, - height = 240, - -- RESPAWN POINTS - respawns = { - {x = -30, y = 0}, - {x = 30, y = 0}, - {x = 0, y = 0}, - {x = -120, y = -50}, - {x = 120, y = -50}, - {x = 0, y = -75} - }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/alpha-1.png", - platforms = { - { - x = -60, - y = 0, - shape = {0,0, 117,0, 101,50, 16,50}, - sprite = "assets/platforms/alpha-big.png", - animations = animations_big - }, - { - x = -145, - y = -50, - shape = {0,0, 59,0, 59,19, 0,19}, - sprite = "assets/platforms/alpha-small.png", - animations = animations_small - }, - { - x = 85, - y = -50, - shape = {0,0, 59,0, 59,19, 0,19}, - sprite = "assets/platforms/alpha-small.png", - animations = animations_small - }, - { - x = -30, - y = -80, - shape = {0,0, 59,0, 59,19, 0,19}, - sprite = "assets/platforms/alpha-small.png", - animations = animations_small - } - }, - decorations = {} -} diff --git a/config/maps/alpha.lua b/config/maps/alpha.lua new file mode 100644 index 0000000..795b6cf --- /dev/null +++ b/config/maps/alpha.lua @@ -0,0 +1,43 @@ +return +{ + name = "Alpha Abyss", + theme = "alpha.ogg", + portrait = 7, -- TODO: See `maps/ribbit`. + center = {x = 0, y = -80}, + width = 360, + height = 240, + respawns = { + {x = -30, y = 0}, + {x = 30, y = 0}, + {x = 0, y = 0}, + {x = -120, y = -50}, + {x = 120, y = -50}, + {x = 0, y = -75} + }, + create = { + { + ratio = 0, + background = "assets/backgrounds/alpha.png", + }, + { + x = -60, + y = 0, + platform = "alpha-big", + }, + { + x = -145, + y = -50, + platform = "alpha-small", + }, + { + x = 85, + y = -50, + platform = "alpha-small", + }, + { + x = -30, + y = -80, + platform = "alpha-small", + } + }, +} diff --git a/config/maps/default.lua b/config/maps/default.lua index 05b8dc9..22c03f6 100644 --- a/config/maps/default.lua +++ b/config/maps/default.lua @@ -1,47 +1,46 @@ --- Default map from original roflnauts -return { - -- GENERAL +return +{ name = "default", theme = "default.ogg", - center_x = 0, - center_y = 0, + portrait = 1, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 0}, width = 360, height = 240, - -- RESPAWN POINTS respawns = { {x = -15, y = -80}, {x = -5, y = -80}, {x = 5, y = -80}, {x = 15, y = -80} }, - -- GRAPHICS - clouds = true, - background = "assets/backgrounds/default.png", - platforms = { + create = { + { + clouds = "assets/clouds.png", + animations = "clouds-default", + count = 8, + }, + { + ratio = 0, + background = "assets/backgrounds/default.png" + }, { x = -91, y = 0, - shape = {0,1, 180,1, 180,10, 95,76, 86,76, 0,10}, - sprite = "assets/platforms/default-big.png" + platform = "default-big" }, { x = 114, y = 50, - shape = {0,1, 51,1, 51,18, 0,18}, - sprite = "assets/platforms/default-side.png" + platform = "default-side" }, { x = -166, y = 50, - shape = {0,1, 51,1, 51,18, 0,18}, - sprite = "assets/platforms/default-side.png" + platform = "default-side" }, { x = -17, y = -50, - shape = {0,1, 33,1, 33,14, 0,14}, - sprite = "assets/platforms/default-top.png" + platform = "default-top" } - }, - decorations = {} + } } diff --git a/config/maps/ribbit.lua b/config/maps/ribbit.lua index c3f5c78..08683ac 100644 --- a/config/maps/ribbit.lua +++ b/config/maps/ribbit.lua @@ -1,46 +1,41 @@ -return { - -- GENERAL - name = "ribbit", +return +{ + name = "Ribbit IV", theme = "ribbit.ogg", - center_x = 0, - center_y = 50, + portrait = 3, -- TODO: Either separate portraits now or change `iconsList` and `menu/host`. See also both mentioned files. + center = {x = 0, y = 50}, width = 360, height = 240, - -- RESPAWN POINTS respawns = { {x = -15, y = -80}, {x = -5, y = -80}, {x = 5, y = -80}, {x = 15, y = -80} }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/ribbit.png", - platforms = { + create = { + { + ratio = 0, + background = "assets/backgrounds/ribbit.png" + }, { x = -154, y = 10, - shape = {1,12, 48,12, 48,32, 1,32}, - sprite = "assets/platforms/ribbit-left.png" + platform = "ribbit-left" }, { x = 67, y = 7, - shape = {36,14, 83,14, 83,29, 36,29}, - sprite = "assets/platforms/ribbit-right.png" + platform = "ribbit-right" }, { x = -70, y = -5, - shape = {0,3, 139,3, 134,24, 5,24}, - sprite = "assets/platforms/ribbit-top.png" + platform = "ribbit-top" }, { x = -54, y = 63, - shape = {0,3, 107,3, 75,44, 32,44}, - sprite = "assets/platforms/ribbit-bottom.png" + platform = "ribbit-bottom" } - }, - decorations = {} -}
\ No newline at end of file + } +} diff --git a/config/maps/rill.lua b/config/maps/rill.lua index 83c02f2..b027923 100644 --- a/config/maps/rill.lua +++ b/config/maps/rill.lua @@ -1,73 +1,66 @@ -return { - -- CENTER AND SIZE - name = "rill", +return +{ + name = "Rill", theme = "rill.ogg", - center_x = 0, - center_y = 75, + portrait = 2, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 75}, width = 400, height = 260, - -- RESPAWN POINTS respawns = { {x = -135, y = 10}, {x = -135, y = 10}, {x = 135, y = 10}, {x = 135, y = 10} }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/rill.png", - platforms = { + create = { + { + ratio = 0, + background = "assets/backgrounds/rill.png" + }, { x = -151, y = 25, - shape = {0,0, 55,0, 55,11, 0,11}, - sprite = "assets/platforms/rill-flat-left.png" + platform = "rill-flat-left" }, { x = 93, y = 25, - shape = {0,0, 55,0, 55,11, 0,11}, - sprite = "assets/platforms/rill-flat-right.png" + platform = "rill-flat-right" }, { x = -24, y = 55, - shape = {0,0, 48,0, 47,15, 1,15}, - sprite = "assets/platforms/rill-center.png" + platform = "rill-center" }, { x = -112, y = 80, - shape = {77,30, 17,0, 0,0, 0,7, 77,44}, - sprite = "assets/platforms/rill-slope-left.png" + platform = "rill-slope-left" }, { x = 35, y = 80, - shape = {0,30, 60,0, 77,0, 77,7, 0,44}, - sprite = "assets/platforms/rill-slope-right.png" - } - }, - decorations = { + platform = "rill-slope-right" + }, { x = 98, y = -20, - sprite = "assets/decorations/rill-lollipop-big-purple.png" + decoration = "assets/decorations/rill-lollipop-big-purple.png" }, { x = 127, y = 4, - sprite = "assets/decorations/rill-lollipop-small-green.png" + decoration = "assets/decorations/rill-lollipop-small-green.png" }, { x = -152, y = -20, - sprite = "assets/decorations/rill-lollipop-big-orange.png" + decoration = "assets/decorations/rill-lollipop-big-orange.png" }, { x = -121, y = 4, - sprite = "assets/decorations/rill-lollipop-small-blue.png" - }, + decoration = "assets/decorations/rill-lollipop-small-blue.png" + } } } diff --git a/config/maps/sorona.lua b/config/maps/sorona.lua index 8ec4727..4cc87cd 100644 --- a/config/maps/sorona.lua +++ b/config/maps/sorona.lua @@ -1,53 +1,50 @@ --- Sorona, but with the worms and such. -return { - -- GENERAL - name = "sorona", +return +{ + name = "Sorona", theme = "sorona.ogg", - center_x = 0, - center_y = 0, + portrait = 6, -- TODO: See `maps/ribbit`. + center = {x = 0, y = 0}, width = 360, height = 240, - -- RESPAWN POINTS respawns = { - {x = -98, y = -70}, - {x = 70, y = -70}, - {x = -30, y = -20}, - {x = -90, y = 40}, + {x = -10, y = -20}, + {x = 0, y = -20}, + {x = 10, y = -20} }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/sorona.png", - platforms = { + create = { { - x = -60, - y = 0, - shape = {0,1, 59,1, 59,17, 0,17}, - sprite = "assets/platforms/sorona-center.png" + ratio = 0, + background = "assets/backgrounds/sorona.png", }, { - x = -40, - y = 55, - shape = {3,0, 180,0, 180,20, 3,20}, - sprite = "assets/platforms/sorona-right-bottom.png" + x = -71, + y = 50, + platform = "sorona-wide" }, { - x = -120, - y = 55, - shape = {3,0, 62,0, 62,23, 3,23}, - sprite = "assets/platforms/sorona-left-bottom.png" + x = -84, + y = -5, + platform = "sorona-small" }, { - x = 0, - y = -50, - shape = {1,1, 140,1, 1,17, 140,17}, - sprite = "assets/platforms/sorona-right-top.png" + x = -50, + y = -4, + decoration = "assets/decorations/sorona-bridge-left.png" }, { - x = -150, - y = -55, - shape = {1,9, 106,9, 40,27, 1,27}, - sprite = "assets/platforms/sorona-left-top.png" + x = -14, + y = -4, + decoration = "assets/decorations/sorona-bridge-loop.png" + }, + { + x = 14, + y = -4, + decoration = "assets/decorations/sorona-bridge-right.png" + }, + { + x = 43, + y = -5, + platform = "sorona-small" } - }, - decorations = {} + } } diff --git a/config/maps/starstorm.lua b/config/maps/starstorm.lua index 7f00633..b4fabcd 100644 --- a/config/maps/starstorm.lua +++ b/config/maps/starstorm.lua @@ -1,12 +1,11 @@ -return { - -- CENTER AND SIZE - name = "starstorm", +return +{ + name = "Starstorm", theme = "starstorm.ogg", - center_x = 0, - center_y = -20, + portrait = 4, -- TODO: See `maps/ribbit`. + center = {x = 0, y = -20}, width = 400, height = 260, - -- RESPAWN POINTS respawns = { {x = 100, y = 45}, {x = -100, y = 45}, @@ -15,79 +14,65 @@ return { {x = -110, y = -70}, {x = 110, y = -70} }, - -- GRAPHICS - clouds = false, - background = "assets/backgrounds/starstorm.png", - platforms = { + create = { + { + ratio = 0, + background = "assets/backgrounds/starstorm.png" + }, { x = -170, y = -55, - shape = { - {0,1, 33,1, 39,6, 39,21, 31,21, 0,21}, - {40,6, 115,6, 115,14, 40,14} - }, - sprite = "assets/platforms/starstorm-left-top.png" + platform = "starstorm-left-top" }, { x = -156, y = -2, - shape = {0,0, 109,0, 109,20, 0,20}, - sprite = "assets/platforms/starstorm-left-middle.png" + platform = "starstorm-left-middle" }, { x = -160, y = 69, - shape = {0,4, 8,4, 13,1, 102,1, 102,16, 19,16, 0,11}, - sprite = "assets/platforms/starstorm-left-bottom.png" + platform = "starstorm-left-bottom" }, { x = 52, y = -55, - shape = { - {115,1, 82,1, 76,6, 76,21, 84,21, 115,21}, - {75,6, 0,6, 0,14, 75,14} - }, - sprite = "assets/platforms/starstorm-right-top.png" + platform = "starstorm-right-top" }, { x = 44, y = -2, - shape = {109,0, 0,0, 0,20, 109,20}, - sprite = "assets/platforms/starstorm-right-middle.png" + platform = "starstorm-right-middle" }, { x = 55, y = 69, - shape = {102,4, 94,4, 89,1, 0,1, 0,16, 83,16, 102,11}, - sprite = "assets/platforms/starstorm-right-bottom.png" + platform = "starstorm-right-bottom" }, { x = -27, y = 40, - shape = {0,6, 53,6, 53,14, 0,14}, - sprite = "assets/platforms/starstorm-center.png" - } - }, - decorations = { + platform = "starstorm-center" + }, { x = -166, y = -37, - sprite = "assets/decorations/starstorm-left-top.png" + decoration = "assets/decorations/starstorm-left-top.png" }, { x = -163, y = 19, - sprite = "assets/decorations/starstorm-left-bottom.png" + decoration = "assets/decorations/starstorm-left-bottom.png" }, { x = 119, y = -37, - sprite = "assets/decorations/starstorm-right-top.png" + decoration = "assets/decorations/starstorm-right-top.png" }, { - x = 52+77, + x = 129, y = 19, - sprite = "assets/decorations/starstorm-right-bottom.png" + decoration = "assets/decorations/starstorm-right-bottom.png" } } } diff --git a/config/menus/host.lua b/config/menus/host.lua index a180736..c8ef4d8 100644 --- a/config/menus/host.lua +++ b/config/menus/host.lua @@ -6,37 +6,49 @@ local Selector = require "not.Selector" local width, height = love.graphics.getWidth()/getScale(), love.graphics.getHeight()/getScale() local bx = width/2-29 -local map_Selector = Selector(menu) - -require "iconsList" -local icons, maps = getMapsIconsList() - if background == nil or not background:is(require "not.MenuBackground") then background = require "not.MenuBackground"(menu) end +-- TODO: This is temporary solution for generating available maps list and portraits for them to pass to Selector. See also: `iconsList`. +local icons, maps = {}, {} +do + local files = love.filesystem.getDirectoryItems("config/maps") + for _,filename in pairs(files) do + local path = string.format("config/maps/%s", filename) + if love.filesystem.isFile(path) and filename ~= "readme.md" then + local map = love.filesystem.load(path)() + local i, name = map.portrait, map.name + map.filename = path + if i then + table.insert(icons, love.graphics.newQuad((i-1)*76, 0, 76, 37, 608, 37)) + table.insert(maps, map) + end + end + end +end + +local mapSelector = Selector(maps, nil, menu) + return { background, - map_Selector - :setPosition(width/2, 40) - :setSize(80, 42) - :setMargin(0) - :set("global", true) - :set("first", true) - :set("list", maps) - :set("icons_i", love.graphics.newImage("assets/maps.png")) - :set("icons_q", icons) - :set("shape", "panorama") - :init() + mapSelector + :setPosition(width/2-40, 40) + :set("shape", Selector.SHAPE_PANORAMA) + :set("icons_quads", icons) + :set("icons_atlas", love.graphics.newImage("assets/maps.png")) + :set("getText", function (self) + return self:getSelected().name + end) , Button(menu) :setText("Next") :setPosition(bx,101) :set("isEnabled", function () - return map_Selector:isLocked() + return mapSelector:getLocked() end) :set("active", function (self) - MAP = map_Selector:getFullSelection(true)[1][1] -- please, don't kill me for this, kek + MAP = mapSelector:getSelected() self.parent:open("select") end) , diff --git a/config/menus/select.lua b/config/menus/select.lua index 23f9374..1e57960 100644 --- a/config/menus/select.lua +++ b/config/menus/select.lua @@ -3,46 +3,75 @@ local menu, background = ... local Button = require "not.Button" local Selector = require "not.Selector" local Element = require "not.Element" +local Group = require "not.Group" local width, height = love.graphics.getWidth()/getScale(), love.graphics.getHeight()/getScale() local bx = width/2-29 -local naut_Selector = Selector(menu) local start_Button = Button(menu) -require "iconsList" -local nautsIcons, nautsList = getNautsIconsList() - if background == nil or not background:is(require "not.MenuBackground") then background = require "not.MenuBackground"(menu) end +-- TODO: Temporary group for naut selectors. This isn't production code at any means! +local group, get +do + local atlas = love.graphics.newImage("assets/portraits.png") + local nauts = require("config.nauts") + local icons = {} + for i=0,#nauts-1 do + table.insert(icons, love.graphics.newQuad(i*28, 0, 28, 27, 1008, 27)) + end + + group = Group(menu) + + local + function attack (self) + if not self.lock then + if self.index == 1 then + return + end + if self.index == 2 then + self.index = self:rollRandom({1, 2}) + end + if self:isUnique() then + self.lock = true + end + end + end + + for i,_ in pairs(Controller.getSets()) do + group:addChild(Selector(nauts, group, menu)) + :set("icons_atlas", atlas) + :set("icons_quads", icons) + :set("attack", attack) + end + + group:set("margin", 16) + local gw, gh = group:getSize() + group:setPosition((width - gw)/2, 55) + + function get () + local selection = group:callEach("getLocked") + for i,naut in ipairs(selection) do + selection[i] = {naut, Controller.getSets()[i]} + end + return selection + end +end + return { background, - naut_Selector - :setPosition(width/2,60) - :setMargin(8) - :setSize(32, 32) - :set("list", nautsList) - :set("global", false) - :set("icons_i", love.graphics.newImage("assets/portraits.png")) - :set("icons_q", nautsIcons) - :init() - , + group, start_Button :setText("Force start") :setPosition(bx,134) :set("isEnabled", function () - if #naut_Selector:getFullSelection(false) > 1 then - return true - end - return false + return #get() > 1 end) :set("active", function (self) - local nauts = naut_Selector:getFullSelection(false) - if #nauts > 1 then - sceneManager:changeScene(World(MAP, nauts)) - end + sceneManager:changeScene(World(MAP, get())) end) , Button(menu) @@ -67,8 +96,7 @@ return { end end) :set("update", function (self, dt) - local total = #naut_Selector:getFullSelection(false) - if total > 1 then + if #get() > 1 then self.the_final_countdown = self.the_final_countdown - dt else self.the_final_countdown = 9 diff --git a/config/platforms/205-left.lua b/config/platforms/205-left.lua new file mode 100644 index 0000000..b04a17f --- /dev/null +++ b/config/platforms/205-left.lua @@ -0,0 +1,8 @@ +return +{ + sprite = "assets/platforms/205-left.png", + shape = { + {8,0, 54,0, 54,31, 8,27}, + {55,29, 94,29, 92,36, 55,36} + } +} diff --git a/config/platforms/205-right.lua b/config/platforms/205-right.lua new file mode 100644 index 0000000..c5bcca6 --- /dev/null +++ b/config/platforms/205-right.lua @@ -0,0 +1,8 @@ +return +{ + sprite = "assets/platforms/205-right.png", + shape = { + {86,0, 40,0, 40,31, 86,27}, + {39,29, 0,29, 2,36, 39,36} + } +} diff --git a/config/platforms/205-top.lua b/config/platforms/205-top.lua new file mode 100644 index 0000000..8470ed6 --- /dev/null +++ b/config/platforms/205-top.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/205-top.png", + shape = {0,1, 72,1, 70,8, 2,8} +} diff --git a/config/platforms/404-bottom.lua b/config/platforms/404-bottom.lua new file mode 100644 index 0000000..4e59a98 --- /dev/null +++ b/config/platforms/404-bottom.lua @@ -0,0 +1,10 @@ +return
+{
+ sprite = "assets/platforms/404-bottom.png",
+ shape = {
+ {0,0, 69,0, 87,17, 87,28, 0,28},
+ {161,17, 178,0, 247,0, 247,28, 161,28},
+ {33,28, 214,28, 214,57, 33,57},
+ {87,17, 161,17, 168,28, 87,28}
+ }
+}
diff --git a/config/platforms/404-small.lua b/config/platforms/404-small.lua new file mode 100644 index 0000000..36b8a1d --- /dev/null +++ b/config/platforms/404-small.lua @@ -0,0 +1,5 @@ +return
+{
+ sprite = "assets/platforms/404-small.png",
+ shape = {0,0, 43,0, 43,8, 0,8}
+}
diff --git a/config/platforms/404-top.lua b/config/platforms/404-top.lua new file mode 100644 index 0000000..3d3ba2b --- /dev/null +++ b/config/platforms/404-top.lua @@ -0,0 +1,9 @@ +return
+{
+ sprite = "assets/platforms/404-top.png",
+ shape = {
+ {45,0, 166,0, 166,13, 45,13},
+ {23,14, 188,14, 188,26, 23,26},
+ {0,27, 211,27, 211,45, 0,45}
+ }
+}
diff --git a/config/platforms/aiguillon-left-big.lua b/config/platforms/aiguillon-left-big.lua new file mode 100644 index 0000000..41ae46d --- /dev/null +++ b/config/platforms/aiguillon-left-big.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-left-big.png", + shape = {1,0, 50,0, 50,18, 5,18, 1,13} +} diff --git a/config/platforms/aiguillon-left-small.lua b/config/platforms/aiguillon-left-small.lua new file mode 100644 index 0000000..7495374 --- /dev/null +++ b/config/platforms/aiguillon-left-small.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-left-small.png", + shape = {1,0, 25,0, 25,18, 1,18} +} diff --git a/config/platforms/aiguillon-middle.lua b/config/platforms/aiguillon-middle.lua new file mode 100644 index 0000000..9107dcd --- /dev/null +++ b/config/platforms/aiguillon-middle.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-middle.png", + shape = {1,0, 87,0, 87,18, 14,18, 1,12} +} diff --git a/config/platforms/aiguillon-right-big.lua b/config/platforms/aiguillon-right-big.lua new file mode 100644 index 0000000..e5d525b --- /dev/null +++ b/config/platforms/aiguillon-right-big.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-right-big.png", + shape = {1,0, 50,0, 50,12, 37,18, 1,18} +} diff --git a/config/platforms/aiguillon-right-small.lua b/config/platforms/aiguillon-right-small.lua new file mode 100644 index 0000000..b0baf3d --- /dev/null +++ b/config/platforms/aiguillon-right-small.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-right-small.png", + shape = {1,0, 25,0, 25,18, 1,18} +} diff --git a/config/platforms/aiguillon-wide.lua b/config/platforms/aiguillon-wide.lua new file mode 100644 index 0000000..7b653a2 --- /dev/null +++ b/config/platforms/aiguillon-wide.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/aiguillon-wide.png", + shape = {1,0, 212,0, 212,12, 206,18, 14,18, 1,12} +} diff --git a/config/platforms/alpha-big.lua b/config/platforms/alpha-big.lua new file mode 100644 index 0000000..a0cfb32 --- /dev/null +++ b/config/platforms/alpha-big.lua @@ -0,0 +1,31 @@ +return +{ + sprite = "assets/platforms/alpha-big.png", + shape = {0,0, 117,0, 101,50, 16,50}, + animations = { + default = { + [1] = love.graphics.newQuad(0, 0, 118, 51, 1180, 51), + [2] = love.graphics.newQuad(0, 0, 118, 51, 1180, 51), + [3] = love.graphics.newQuad(118, 0, 118, 51, 1180, 51), + [4] = love.graphics.newQuad(118, 0, 118, 51, 1180, 51), + [5] = love.graphics.newQuad(236, 0, 118, 51, 1180, 51), + [6] = love.graphics.newQuad(236, 0, 118, 51, 1180, 51), + [7] = love.graphics.newQuad(354, 0, 118, 51, 1180, 51), + [8] = love.graphics.newQuad(354, 0, 118, 51, 1180, 51), + [9] = love.graphics.newQuad(472, 0, 118, 51, 1180, 51), + [10] = love.graphics.newQuad(472, 0, 118, 51, 1180, 51), + [11] = love.graphics.newQuad(590, 0, 118, 51, 1180, 51), + [12] = love.graphics.newQuad(590, 0, 118, 51, 1180, 51), + [13] = love.graphics.newQuad(708, 0, 118, 51, 1180, 51), + [14] = love.graphics.newQuad(708, 0, 118, 51, 1180, 51), + [15] = love.graphics.newQuad(826, 0, 118, 51, 1180, 51), + [16] = love.graphics.newQuad(826, 0, 118, 51, 1180, 51), + [17] = love.graphics.newQuad(944, 0, 118, 51, 1180, 51), + [18] = love.graphics.newQuad(944, 0, 118, 51, 1180, 51), + [19] = love.graphics.newQuad(1062, 0, 118, 51, 1180, 51), + [20] = love.graphics.newQuad(1062, 0, 118, 51, 1180, 51), + frames = 20, + repeated = true + } + } +} diff --git a/config/platforms/alpha-small.lua b/config/platforms/alpha-small.lua new file mode 100644 index 0000000..3c72af9 --- /dev/null +++ b/config/platforms/alpha-small.lua @@ -0,0 +1,31 @@ +return +{ + sprite = "assets/platforms/alpha-small.png", + shape = {0,0, 59,0, 59,19, 0,19}, + animations = { + default = { + [1] = love.graphics.newQuad(0, 0, 60, 20, 600, 20), + [2] = love.graphics.newQuad(0, 0, 60, 20, 600, 20), + [3] = love.graphics.newQuad(60, 0, 60, 20, 600, 20), + [4] = love.graphics.newQuad(60, 0, 60, 20, 600, 20), + [5] = love.graphics.newQuad(120, 0, 60, 20, 600, 20), + [6] = love.graphics.newQuad(120, 0, 60, 20, 600, 20), + [7] = love.graphics.newQuad(180, 0, 60, 20, 600, 20), + [8] = love.graphics.newQuad(180, 0, 60, 20, 600, 20), + [9] = love.graphics.newQuad(240, 0, 60, 20, 600, 20), + [10] = love.graphics.newQuad(240, 0, 60, 20, 600, 20), + [11] = love.graphics.newQuad(300, 0, 60, 20, 600, 20), + [12] = love.graphics.newQuad(300, 0, 60, 20, 600, 20), + [13] = love.graphics.newQuad(360, 0, 60, 20, 600, 20), + [14] = love.graphics.newQuad(360, 0, 60, 20, 600, 20), + [15] = love.graphics.newQuad(420, 0, 60, 20, 600, 20), + [16] = love.graphics.newQuad(420, 0, 60, 20, 600, 20), + [17] = love.graphics.newQuad(480, 0, 60, 20, 600, 20), + [18] = love.graphics.newQuad(480, 0, 60, 20, 600, 20), + [19] = love.graphics.newQuad(540, 0, 60, 20, 600, 20), + [20] = love.graphics.newQuad(540, 0, 60, 20, 600, 20), + frames = 20, + repeated = true + } + } +} diff --git a/config/platforms/default-big.lua b/config/platforms/default-big.lua new file mode 100644 index 0000000..85893b3 --- /dev/null +++ b/config/platforms/default-big.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/default-big.png", + shape = {0,1, 180,1, 180,10, 95,76, 86,76, 0,10} +} diff --git a/config/platforms/default-side.lua b/config/platforms/default-side.lua new file mode 100644 index 0000000..77b55bd --- /dev/null +++ b/config/platforms/default-side.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/default-side.png", + shape = {0,1, 51,1, 51,18, 0,18} +} diff --git a/config/platforms/default-top.lua b/config/platforms/default-top.lua new file mode 100644 index 0000000..dbe4cbe --- /dev/null +++ b/config/platforms/default-top.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/default-top.png", + shape = {0,1, 33,1, 33,14, 0,14} +} diff --git a/config/platforms/ribbit-bottom.lua b/config/platforms/ribbit-bottom.lua new file mode 100644 index 0000000..38e4d95 --- /dev/null +++ b/config/platforms/ribbit-bottom.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/ribbit-bottom.png", + shape = {0,3, 107,3, 75,44, 32,44}, +} diff --git a/config/platforms/ribbit-left.lua b/config/platforms/ribbit-left.lua new file mode 100644 index 0000000..69039dd --- /dev/null +++ b/config/platforms/ribbit-left.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/ribbit-left.png", + shape = {1,12, 48,12, 48,32, 1,32}, +} diff --git a/config/platforms/ribbit-right.lua b/config/platforms/ribbit-right.lua new file mode 100644 index 0000000..1aa6e9e --- /dev/null +++ b/config/platforms/ribbit-right.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/ribbit-right.png", + shape = {36,14, 83,14, 83,29, 36,29}, +} diff --git a/config/platforms/ribbit-top.lua b/config/platforms/ribbit-top.lua new file mode 100644 index 0000000..1493114 --- /dev/null +++ b/config/platforms/ribbit-top.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/ribbit-top.png", + shape = {0,3, 139,3, 134,24, 5,24}, +} diff --git a/config/platforms/rill-center.lua b/config/platforms/rill-center.lua new file mode 100644 index 0000000..72104b3 --- /dev/null +++ b/config/platforms/rill-center.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/rill-center.png", + shape = {0,0, 48,0, 47,15, 1,15} +} diff --git a/config/platforms/rill-flat-left.lua b/config/platforms/rill-flat-left.lua new file mode 100644 index 0000000..f1fdd5e --- /dev/null +++ b/config/platforms/rill-flat-left.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/rill-flat-left.png", + shape = {0,0, 55,0, 55,11, 0,11} +} diff --git a/config/platforms/rill-flat-right.lua b/config/platforms/rill-flat-right.lua new file mode 100644 index 0000000..8bf70a9 --- /dev/null +++ b/config/platforms/rill-flat-right.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/rill-flat-right.png", + shape = {0,0, 55,0, 55,11, 0,11} +} diff --git a/config/platforms/rill-slope-left.lua b/config/platforms/rill-slope-left.lua new file mode 100644 index 0000000..49052b4 --- /dev/null +++ b/config/platforms/rill-slope-left.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/rill-slope-left.png", + shape = {77,30, 17,0, 0,0, 0,7, 77,44} +} diff --git a/config/platforms/rill-slope-right.lua b/config/platforms/rill-slope-right.lua new file mode 100644 index 0000000..3eca829 --- /dev/null +++ b/config/platforms/rill-slope-right.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/rill-slope-right.png", + shape = {0,30, 60,0, 77,0, 77,7, 0,44} +} diff --git a/config/platforms/sorona-button.lua b/config/platforms/sorona-button.lua new file mode 100644 index 0000000..2ca3bae --- /dev/null +++ b/config/platforms/sorona-button.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/sorona-button.png", + shape = {0,1, 59,1, 59,17, 0,17} +} diff --git a/config/platforms/sorona-medium.lua b/config/platforms/sorona-medium.lua new file mode 100644 index 0000000..50eaeeb --- /dev/null +++ b/config/platforms/sorona-medium.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/sorona-medium.png", + shape = {3,1, 61,1, 61,23, 3,23} +} diff --git a/config/platforms/sorona-small.lua b/config/platforms/sorona-small.lua new file mode 100644 index 0000000..1a01c69 --- /dev/null +++ b/config/platforms/sorona-small.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/sorona-small.png", + shape = {3,1, 39,1, 39,18, 3,18} +} diff --git a/config/platforms/sorona-spiked.lua b/config/platforms/sorona-spiked.lua new file mode 100644 index 0000000..00d975b --- /dev/null +++ b/config/platforms/sorona-spiked.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/sorona-spiked.png", + shape = {1,9, 106,9, 40,27, 1,27} +} diff --git a/config/platforms/sorona-wide.lua b/config/platforms/sorona-wide.lua new file mode 100644 index 0000000..d0916c9 --- /dev/null +++ b/config/platforms/sorona-wide.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/sorona-wide.png", + shape = {1,1, 140,1, 1,17, 140,17} +} diff --git a/config/platforms/starstorm-center.lua b/config/platforms/starstorm-center.lua new file mode 100644 index 0000000..77af4f8 --- /dev/null +++ b/config/platforms/starstorm-center.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/starstorm-center.png", + shape = {0,6, 53,6, 53,14, 0,14} +} diff --git a/config/platforms/starstorm-left-bottom.lua b/config/platforms/starstorm-left-bottom.lua new file mode 100644 index 0000000..f40185b --- /dev/null +++ b/config/platforms/starstorm-left-bottom.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/starstorm-left-bottom.png", + shape = {0,4, 8,4, 13,1, 102,1, 102,16, 19,16, 0,11}, +} diff --git a/config/platforms/starstorm-left-middle.lua b/config/platforms/starstorm-left-middle.lua new file mode 100644 index 0000000..0804309 --- /dev/null +++ b/config/platforms/starstorm-left-middle.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/starstorm-left-middle.png", + shape = {0,0, 109,0, 109,20, 0,20} +} diff --git a/config/platforms/starstorm-left-top.lua b/config/platforms/starstorm-left-top.lua new file mode 100644 index 0000000..9cc1944 --- /dev/null +++ b/config/platforms/starstorm-left-top.lua @@ -0,0 +1,8 @@ +return +{ + sprite = "assets/platforms/starstorm-left-top.png", + shape = { + {0,1, 33,1, 39,6, 39,21, 31,21, 0,21}, + {40,6, 115,6, 115,14, 40,14} + } +} diff --git a/config/platforms/starstorm-right-bottom.lua b/config/platforms/starstorm-right-bottom.lua new file mode 100644 index 0000000..16462cb --- /dev/null +++ b/config/platforms/starstorm-right-bottom.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/starstorm-right-bottom.png", + shape = {102,4, 94,4, 89,1, 0,1, 0,16, 83,16, 102,11} +} diff --git a/config/platforms/starstorm-right-middle.lua b/config/platforms/starstorm-right-middle.lua new file mode 100644 index 0000000..af9b712 --- /dev/null +++ b/config/platforms/starstorm-right-middle.lua @@ -0,0 +1,5 @@ +return +{ + sprite = "assets/platforms/starstorm-right-middle.png", + shape = {109,0, 0,0, 0,20, 109,20} +} diff --git a/config/platforms/starstorm-right-top.lua b/config/platforms/starstorm-right-top.lua new file mode 100644 index 0000000..4470754 --- /dev/null +++ b/config/platforms/starstorm-right-top.lua @@ -0,0 +1,8 @@ +return +{ + sprite = "assets/platforms/starstorm-right-top.png", + shape = { + {115,1, 82,1, 76,6, 76,21, 84,21, 115,21}, + {75,6, 0,6, 0,14, 75,14} + } +} @@ -47,12 +47,18 @@ function love.draw () love.graphics.setFont(Font) love.graphics.setColor(255, 0, 0, 255) love.graphics.print("Debug ON", 10, 10, 0, scale, scale) - love.graphics.setColor(255, 255, 255, 255) - love.graphics.print("Current FPS: "..tostring(love.timer.getFPS()), 10, 10+9*scale, 0, scale, scale) + if dbg_msg then + love.graphics.setColor(255, 255, 255, 255) + love.graphics.print(dbg_msg, 10, 10+9*scale, 0, scale, scale) + end end end -function love.update (dt) sceneManager:update(dt) end +function love.update (dt) + dbg_msg = string.format("FPS: %d\n", love.timer.getFPS()) + sceneManager:update(dt) +end + function love.quit () Settings.save() end -- Pass input to Controller diff --git a/not/Button.lua b/not/Button.lua index a2f7a19..3493a84 100644 --- a/not/Button.lua +++ b/not/Button.lua @@ -15,6 +15,10 @@ function Button:new (parent) self.sprite, self.quads = parent:getSheet() end +function Button:getSize () + return 58, 15 +end + function Button:setText (text) self.text = text or "" return self diff --git a/not/Camera.lua b/not/Camera.lua index aa4df5b..65395cb 100644 --- a/not/Camera.lua +++ b/not/Camera.lua @@ -1,37 +1,46 @@ ---- `Camera` --- Used in drawing. -Camera = { - x = 0, - y = 0, - dest_x = 0, - dest_y = 0, - shake = 0, - timer = 0, - delay = 0, - origin_x = 0, - origin_y = 0, - shake_x = 0, - shake_y = 0, - world = --[[not.World]]nil, -} - --- Constructor of `Camera` -function Camera:new (world) - local o = {} - setmetatable(o, self) - self.__index = self - o.world = world - o:setPosition(o:follow()) - o:setDestination(o:follow()) - return o -end - --- Drawing offsets -function Camera:getOffsets () - return -self.x,-self.y -end - --- Position +--- Used in drawing other stuff in places. +-- TODO: Camera is missing documentation on every important method. +Camera = require "not.Object":extends() + +Camera.SHAKE_LENGTH = 0.6 +Camera.SHAKE_INTERVAL = 0.03 + +-- TODO: Camera would really make use of vec2s (other classes would use them too). +function Camera:new (x, y, world) + self.world = world + self:setPosition(x, y) + self:resetSum() + self:initShake() +end + +function Camera:initShake () + self.shakeTime = 0 + self.shakeInterval = 0 + self.shakeShift = { + theta = love.math.random() * 2, + radius = 0 + } +end + +function Camera:push () + love.graphics.push() +end + +function Camera:transform (scale, ratio, vw, vh) + local px, py = self:getPosition() + local sx, sy = self:getShake() + local dx, dy = (px + sx) * ratio, (py + sy) * ratio + + vw, vh = vw / scale / 2, vh / scale / 2 + + love.graphics.scale(scale, scale) + love.graphics.translate(vw - dx, vh - dy) +end + +function Camera:pop () + love.graphics.pop() +end + function Camera:setPosition (x, y) local x = x or 0 local y = y or 0 @@ -42,102 +51,86 @@ function Camera:getPosition () return self.x, self.y end -function Camera:getPositionScaled () - return self.x*getScale(), self.y*getScale() -end - --- Destination -function Camera:setDestination (x, y) - local x = x or 0 - local y = y or 0 - self.dest_x, self.dest_y = x, y +function Camera:getBoundaries (scale, vw, vh) + local x, y = self:getPosition() + local width, height = vw / scale / 2, vh / scale / 2 + return x - width, y - height, x + width, y + height end -function Camera:getDestination () - return self.dest_x, self.dest_y +function Camera:startShake () + self.shakeTime = Camera.SHAKE_LENGTH end --- Translate points -function Camera:translatePosition (x, y) - local x = x or 0 - local y = y or 0 - return (x-self.x)*getScale(), (y-self.y)*getScale() +local +function limit (theta) + if theta > 2 then + return limitAngle(theta - 2) + end + if theta < 0 then + return limitAngle(theta + 2) + end + return theta end -function Camera:translatePoints(...) - local a = {...} - local r = {} - local x,y = self:getOffsets() - for k,v in pairs(a) do - if k%2 == 1 then - table.insert(r, (v + x) * getScale()) +-- TODO: Magic numbers present in Camera's shake. +function Camera:shake (dt) + if self.shakeTime > 0 then + self.shakeTime = self.shakeTime - dt + if self.shakeInterval < 0 then + self.shakeShift.theta = self.shakeShift.theta - 1.3 + love.math.random() * 0.6 + self.shakeShift.radius = 50 * self.shakeTime + self.shakeInterval = Camera.SHAKE_INTERVAL else - table.insert(r, (v + y) * getScale()) + self.shakeShift.radius = self.shakeShift.radius * 0.66 + self.shakeInterval = self.shakeInterval - dt + end + if self.shakeTime < 0 then + self.shakeShift.radius = 0 end end - return r -end - --- Shake it --- Really bad script, but for now it works -function Camera:shake () - if self.shake_x == 0 then - self.shake_x = math.random(-10, 10) * 2 - elseif self.shake_x > 0 then - self.shake_x = math.random(-10, -1) * 2 - elseif self.shake_x < 0 then - self.shake_x = math.random(10, 1) * 2 - end - if self.shake_y == 0 then - self.shake_y = math.random(-10, 10) * 2 - elseif self.shake_y > 0 then - self.shake_y = math.random(-10, -1) * 2 - elseif self.shake_y < 0 then - self.shake_y = math.random(10, 1) * 2 - end - local x = self.origin_x + self.shake_x - local y = self.origin_y + self.shake_y - self:setDestination(x, y) end -function Camera:startShake () - self.timer = 0.3 - self.origin_x, self.origin_y = self:getPosition() +function Camera:getShake () + local radius = self.shakeShift.radius + local theta = self.shakeShift.theta * math.pi + return radius * math.cos(theta), radius * math.sin(theta) end --- Move follow -function Camera:follow () +function Camera:resetSum () + self.sumX = 0 + self.sumY = 0 + self.sumI = 0 +end + +function Camera:sum (x, y) local map = self.world.map - local sum_x,sum_y,i = map.center_x, map.center_y, 1 - for k,naut in pairs(self.world.Nauts) do - local naut_x,naut_y = naut:getPosition() - if math.abs(naut_x - map.center_x) < map.width/2 and - math.abs(naut_y - map.center_y) < map.height/2 then - i = i + 1 - sum_x = naut_x + sum_x - sum_y = naut_y + sum_y - end + if math.abs(x - map.center.x) < map.width/2 and + math.abs(y - map.center.y) < map.height/2 then + self.sumX = self.sumX + x + self.sumY = self.sumY + y + self.sumI = self.sumI + 1 end - local x = sum_x / i - love.graphics.getWidth()/getScale()/2 - local y = sum_y / i - love.graphics.getHeight()/getScale()/2 + 4*getScale() -- hotfix - return x,y end --- Update -function Camera:update (dt) - if self.timer > 0 then - self.timer = self.timer - dt - if self.delay <= 0 then - self:shake() - self.delay = 0.02 - else - self.delay = self.delay - dt - end - else - self:setDestination(self:follow()) +function Camera:getSumPostion () + if self.sumI > 0 then + return self.sumX / self.sumI, self.sumY / self.sumI end - local dx, dy = self:getDestination() - dx = (dx - self.x) * 6 * dt - dy = (dy - self.y) * 6 * dt - self:setPosition(self.x + dx, self.y + dy) + return 0, 0 +end + +function Camera:step (dt) + local x, y = self:getSumPostion() + local dx, dy = (x - self.x), (y - self.y) + if math.abs(dx) > 0.4 or math.abs(dy) > 0.4 then + x = self.x + (x - self.x) * dt * 6 + y = self.y + (y - self.y) * dt * 6 + end + self:setPosition(x, y) +end + +function Camera:update (dt) + self:step(dt) + self:shake(dt) + self:resetSum() end diff --git a/not/Cloud.lua b/not/Cloud.lua index 25169c0..4851042 100644 --- a/not/Cloud.lua +++ b/not/Cloud.lua @@ -1,61 +1,45 @@ -require "not.Decoration" - --- `Cloud` --- That white thing moving in the background. --- TODO: extends variables names to be readable. -Cloud = Decoration:extends() -Cloud.t = 1 -- type (sprite number) -Cloud.v = 13 -- velocity - --- TODO: allow maps to use other quads and sprites for clouds --- TODO: you know this isn't right, don't you? -local animations = { - default = { - [1] = love.graphics.newQuad( 1, 1, 158,47, 478,49), - frames = 1, - repeated = true - }, - default2 = { - [1] = love.graphics.newQuad(160, 1, 158,47, 478,49), - frames = 1, - repeated = true - }, - default3 = { - [1] = love.graphics.newQuad(319, 1, 158,47, 478,49), - frames = 1, - repeated = true - } -} - --- Constructor of `Cloud`. -function Cloud:new (x, y, t, v, world) - if self:getImage() == nil then - self:setImage(Sprite.newImage("assets/clouds.png")) - end - Cloud.__super.new(self, x, y, world, nil) - self:setAnimationsList(animations) - self:setVelocity(v) - self:setType(t) +-- Moving decorations with limited lifespan. +Cloud = require "not.Decoration":extends() + +function Cloud:new (x, y, world, imagePath) + Cloud.__super.new(self, x, y, world, imagePath) + self.velocity_x = 0 + self.velocity_y = 0 + self.boundary_x = 0 + self.boundary_y = 0 end --- Setters for cloud type and velocity. -function Cloud:setType (type) - local animation = "default" - if type > 1 then - animation = animation .. type - end - self:setAnimation(animation) - self.t = type +function Cloud:setVelocity (x, y) + self.velocity_x = x + self.velocity_y = y +end + +function Cloud:setBoundary (x, y) + self.boundary_x = x + self.boundary_y = y end -function Cloud:setVelocity (velocity) - self.v = velocity + +function Cloud:setStyle (style) + self:setAnimation(style) +end + +function Cloud:getStyle () + return self:getAnimation() +end + +function Cloud:testPosition () + if self.x > self.boundary_x or self.y > self.boundary_y then + return true + end end --- Update of `Cloud`, returns x for world to delete cloud after reaching right corner. +-- Cloud will get deleted if this function returns true. function Cloud:update (dt) Cloud.__super.update(self, dt) - self.x = self.x + self.v*dt - return self.x + self.x = self.x + self.velocity_x * dt + self.y = self.y + self.velocity_y * dt + return self:testPosition() end return Cloud diff --git a/not/CloudGenerator.lua b/not/CloudGenerator.lua new file mode 100644 index 0000000..e72514b --- /dev/null +++ b/not/CloudGenerator.lua @@ -0,0 +1,73 @@ +--- Generates clouds over time with randomized positions and styles. +-- Also used as factory for Clouds. +CloudGenerator = require "not.Object":extends() + +require "not.Cloud" + +function CloudGenerator:new (atlas, animations, count, world) + self.world = world + self.atlas = atlas + self.quads = animations + self.count = count + self.interval = 12 + self.timer = self.interval + self.layer = false +end + +-- TODO: This was a bad idea. Move Cloud creation back to World, pass created Cloud here for configuration. +function CloudGenerator:createCloud (x, y, style) + local cloud = Cloud(x, y, self.world, self.atlas) + cloud:setAnimationsList(self.quads) + cloud:setAnimation(style) + cloud:setVelocity(13, 0) + cloud:setBoundary(340, 320) + cloud.generator = self + cloud.layer = self.layer + return cloud +end + +-- TODO: CloudGen's randomization methods are too static (not configurable). +-- TODO: Random position for Clouds inside map shouldn't be random. Make them place them where no clouds are present. +function CloudGenerator:getRandomPosition (inside) + local x, y + local map = self.world.map + if not inside then + x = map.center.x - map.width*1.2 + love.math.random(-50, 20) + else + x = love.math.random(map.center.x - map.width / 2, map.center.x + map.width / 2) + end + y = love.math.random(map.center.y - map.height / 2, map.center.y + map.height / 2) + return x, y +end + +function CloudGenerator:getRandomStyle () + local num = love.math.random(1, 3) + local style = "default" + if num > 1 then + style = style .. tostring(num) + end + return style +end + +function CloudGenerator:run (count, inside) + count = count or 1 + for i=1,count do + local x, y = self:getRandomPosition(inside) + local style = self:getRandomStyle() + self.world:insertCloud(self:createCloud(x, y, style)) + end +end + +function CloudGenerator:update (dt) + local count = self.world:getCloudsCountFrom(self) + if self.timer < 0 then + if self.count > count then + self.timer = self.timer + self.interval + self:run() + end + else + self.timer = self.timer - dt + end +end + +return CloudGenerator diff --git a/not/Element.lua b/not/Element.lua index 24576e6..3b0d13a 100644 --- a/not/Element.lua +++ b/not/Element.lua @@ -1,22 +1,22 @@ -require "not.Object" - --- `Element` -- Empty element used inside `Menu`. -Element = Object:extends() - -Element.parent = --[[not.Menu]]nil -Element.x = 0 -Element.y = 0 +Element = require "not.Object":extends() function Element:new (parent) self.parent = parent + self.x = 0 + self.y = 0 end -function Element:delete () end -- deletes Element +-- TODO: Element's getSize is temporary. Create BoxElement and move it there. +function Element:getSize () + return 0, 0 +end function Element:getPosition () return self.x, self.y end + function Element:setPosition (x, y) self.x = x or 0 self.y = y or 0 @@ -30,12 +30,14 @@ function Element:set (name, func) return self end --- Called when menu tries to focus on this element. +--- Called when menu tries to focus on this element. -- If it will return false then menu will skip element and go to next in list. function Element:focus () return false -end -function Element:blur () end -- Called when Element loses focus. +end + +--- Called when Element loses focus. +function Element:blur () end -- LÖVE2D callbacks function Element:draw (scale) end diff --git a/not/Group.lua b/not/Group.lua new file mode 100644 index 0000000..970d3bc --- /dev/null +++ b/not/Group.lua @@ -0,0 +1,116 @@ +--- Element used for grouping elements and passing input to selected child based on controller set. +Group = require "not.Element":extends() + +function Group:new (parent) + Group.__super.new(self, parent) + self.children = {} + self.margin = 0 +end + +function Group:addChild (element) + table.insert(self.children, element) + return element +end + +-- TODO: Missing semi-important docs on Group's setPosition. +function Group:setPosition (x, y) + local dx = 0 + for _,child in ipairs(self.children) do + child:setPosition(x + dx, y) + dx = dx + child:getSize() + self.margin + end + return Group.__super.setPosition(self, x, y) +end + +function Group:getSize () + local twidth = -self.margin + local theight = 0 + for _,child in ipairs(self.children) do + local cwidth, cheight = child:getSize() + twidth = twidth + child:getSize() + self.margin + if theight < cheight then + theight = cheight + end + end + return twidth, theight +end + +--- Calls function with parameters for each child. +-- @param func key of function to call +-- @param ... parameters passed to function +-- @return table with calls' results +function Group:callEach (func, ...) + local results = {} + for _,child in ipairs(self.children) do + if type(child[func]) == "function" then + table.insert(results, child[func](child, ...) or nil) + end + end + return results +end + +--- Calls function with parameters for each but one child. +-- @param avoid child to avoid calling +-- @param func key of function to call +-- @param ... parameters passed to function +-- @return table with calls' results +function Group:callEachBut (avoid, func, ...) + local results = {} + for _,child in ipairs(self.children) do + if child ~= avoid then + if type(child[func]) == "function" then + table.insert(results, child[func](child, ...) or nil) + end + end + end + return results +end + +--- Calls function with parameters for one child based on controller set. +-- @param set controller set +-- @param func key of function to call +-- @param ... parameters passed to function +-- @return results of called function +function Group:callWithSet (set, func, ...) + for i,test in ipairs(Controller.getSets()) do + if test == set then + local child = self.children[i] + if child then + return child[func](child, ...) + end + end + end +end + +function Group:focus () + self:callEach("focus") + self.focused = true + return true +end + +function Group:blur () + self:callEach("blur") + self.focused = false +end + +function Group:draw (scale) + self:callEach("draw", scale) +end + +function Group:update (dt) + self:callEach("update", dt) +end + +function Group:controlpressed (set, action, key) + if self.focused then + self:callWithSet(set, "controlpressed", set, action, key) + end +end + +function Group:controlreleased (set, action, key) + if self.focused then + self:callWithSet(set, "controlreleased", set, action, key) + end +end + +return Group diff --git a/not/Hero.lua b/not/Hero.lua index 039aeb8..66bc511 100644 --- a/not/Hero.lua +++ b/not/Hero.lua @@ -27,7 +27,7 @@ function Hero:new (name, x, y, world) Hero.load() Hero.__super.new(self, x, y, world, imagePath) -- Physics - self.group = -1-#world.Nauts + self.group = -1-#world:getNautsAll() self:setBodyType("dynamic") self:setBodyFixedRotation(true) self:newFixture() @@ -87,8 +87,8 @@ function Hero:update (dt) -- TODO: World/Map function for testing if Point is inside playable area. local m = self.world.map local x, y = self:getPosition() - if (x < m.center_x - m.width*1.5 or x > m.center_x + m.width*1.5 or - y < m.center_y - m.height*1.5 or y > m.center_y + m.height*1.5) and + if (x < m.center.x - m.width*1.5 or x > m.center.x + m.width*1.5 or + y < m.center.y - m.height*1.5 or y > m.center.y + m.height*1.5) and self.isAlive then self:die() @@ -165,16 +165,17 @@ function Hero:getOffset () return 12,15 end --- Draw of `Hero` -function Hero:draw (offset_x, offset_y, scale, debug) +function Hero:draw (debug) if not self.isAlive then return end - Hero.__super.draw(self, offset_x, offset_y, scale, debug) + Hero.__super.draw(self, debug) end -function Hero:drawTag (offset_x, offset_y, scale) +-- TODO: Hero@drawTag's printf is not readable. +function Hero:drawTag () local x,y = self:getPosition() love.graphics.setFont(Font) - love.graphics.printf(string.format("Player %d", math.abs(self.group)), (math.floor(x)+offset_x)*scale, (math.floor(y)+offset_y-26)*scale,100,'center',0,scale,scale,50,0) + love.graphics.setColor(255, 255, 255) + love.graphics.printf(string.format("Player %d", math.abs(self.group)), math.floor(x), math.floor(y)-26 ,100,'center',0,1,1,50,0) end -- Draw HUD of `Hero` diff --git a/not/Layer.lua b/not/Layer.lua new file mode 100644 index 0000000..14dac32 --- /dev/null +++ b/not/Layer.lua @@ -0,0 +1,45 @@ +--- A little bit more than just a Canvas. +Layer = require "not.Object":extends() + +function Layer:new (width, height) + self.canvas = love.graphics.newCanvas(width, height) + self.transformScale = getScale() + self.transformRatio = 1 + self.drawScale = 1 +end + +function Layer:delete () + self.canvas = nil +end + +--- Sets this layer as current canvas for drawing with love.graphics functions. +-- @return old canvas used by love +function Layer:setAsCanvas () + local c = love.graphics.getCanvas() + love.graphics.setCanvas(self.canvas) + return c +end + +function Layer:renderTo (func, ...) + local c = self:setAsCanvas() + func(...) + love.graphics.setCanvas(c) +end + +function Layer:renderToWith (camera, func, ...) + camera:push() + camera:transform(self.transformScale, self.transformRatio, self.canvas:getDimensions()) + self:renderTo(func, ...) + camera:pop() +end + +function Layer:clear () + self:renderTo(love.graphics.clear) +end + +function Layer:draw () + love.graphics.setColor(255, 255, 255, 255) + love.graphics.draw(self.canvas, nil, nil, nil, self.drawScale, self.drawScale) +end + +return Layer diff --git a/not/MusicPlayer.lua b/not/MusicPlayer.lua index 4634ed9..17beda4 100644 --- a/not/MusicPlayer.lua +++ b/not/MusicPlayer.lua @@ -1,8 +1,5 @@ -require "not.Object" - ---- `MusicPlayer` --- Simple music player object that plays and loops selected track. -MusicPlayer = Object:extends() +--- Simple music player object that stores, playes and loops tracks.. +MusicPlayer = require "not.Object":extends() function MusicPlayer:new (trackName) self.tracks = {} @@ -13,8 +10,9 @@ function MusicPlayer:new (trackName) end function MusicPlayer:delete () - self.tracks = nil self:stop() + self.tracks = nil + self.source = nil end function MusicPlayer:setTrack (trackName) @@ -40,7 +38,10 @@ function MusicPlayer:getCurrentTrack () end end -function MusicPlayer:play () +function MusicPlayer:play (trackName) + if trackName then + self:setTrack(trackName) + end self.source:play() end diff --git a/not/Object.lua b/not/Object.lua index 30b91b5..352e9e3 100644 --- a/not/Object.lua +++ b/not/Object.lua @@ -1,3 +1,8 @@ --- Wrapping library to game's hierarchy in a shameless way. +--- Wrapping library to game's hierarchy in a shameless way. Object = require "lib.object.Object" + +--- Called before Object references are removed from parent. +-- This is not called when Object is garbage collected. +function Object:delete () end + return Object diff --git a/not/PhysicalBody.lua b/not/PhysicalBody.lua index 804c706..5081836 100644 --- a/not/PhysicalBody.lua +++ b/not/PhysicalBody.lua @@ -62,22 +62,30 @@ function PhysicalBody:update (dt) PhysicalBody.__super.update(self, dt) end --- Draw of `PhysicalBody`. -function PhysicalBody:draw (offset_x, offset_y, scale, debug) - PhysicalBody.__super.draw(self, offset_x, offset_y, scale) +function PhysicalBody:draw (debug) + PhysicalBody.__super.draw(self, debug) if debug then for _,fixture in pairs(self.body:getFixtureList()) do local category = fixture:getCategory() + -- TODO: Fixture drawing of PhysicalBodies could take activity into account in every case. if category == 1 then - love.graphics.setColor(255, 69, 0, 140) + love.graphics.setColor(255, 69, 0, 150) end if category == 2 then - love.graphics.setColor(137, 255, 0, 120) + love.graphics.setColor(137, 255, 0, 150) end if category == 3 then - love.graphics.setColor(137, 0, 255, 40) + love.graphics.setColor(137, 0, 255, 50) end - love.graphics.polygon("fill", self.world.camera:translatePoints(self.body:getWorldPoints(fixture:getShape():getPoints()))) + if category == 4 then + if self.body:isActive() then + love.graphics.setColor(255, 230, 0, 50) + else + love.graphics.setColor(255, 230, 0, 10) + end + end + local camera = self.world.camera + love.graphics.polygon("fill", self.body:getWorldPoints(fixture:getShape():getPoints())) end end end diff --git a/not/Ray.lua b/not/Ray.lua index 16a9bee..4ae640a 100644 --- a/not/Ray.lua +++ b/not/Ray.lua @@ -1,21 +1,10 @@ -require "not.Object" +--- That awesome effect that blinks when player dies! +Ray = require "not.Object":extends() ---- `Ray` --- That awesome effect that blinks when player dies! -Ray = Object:extends() - -Ray.naut =--[[not.Hero]]nil -Ray.world =--[[not.World]]nil -Ray.canvas =--[[love.graphics.newCanvas]]nil -Ray.delay = 0.3 - -function Ray:new (naut, world) - self.naut = naut +function Ray:new (source, world) + self.source = source self.world = world - -- Cavas, this is temporary, I believe. - local scale = getScale() - local w, h = love.graphics.getWidth(), love.graphics.getHeight() - self.canvas = love.graphics.newCanvas(w/scale, h/scale) + self.delay = 0.3 end function Ray:update (dt) @@ -26,25 +15,16 @@ function Ray:update (dt) return false end -function Ray:draw (offset_x, offset_y, scale) - love.graphics.setCanvas(self.canvas) - love.graphics.clear() +-- TODO: Ray should use Camera boundaries just-in-case. +-- TODO: Ray uses magic numbers. +function Ray:draw () love.graphics.setColor(255, 247, 228, 247) love.graphics.setLineStyle("rough") love.graphics.setLineWidth(self.delay*160) - local x, y = self.naut:getPosition() - local m = self.world.map - local dy = m.height - if y > m.center_y then - dy = -dy - end - love.graphics.line(-x+offset_x,-y+offset_y-dy*0.7,x+offset_x,y+dy*0.7+offset_y) - -- reset - love.graphics.setCanvas() - love.graphics.setLineWidth(1) - love.graphics.setColor(255,255,255,255) - -- draw on screen - love.graphics.draw(self.canvas, 0, 0, 0, scale, scale) + + local x, y = self.source:getPosition() + + love.graphics.line(x, y, -x, -y) end return Ray diff --git a/not/SceneManager.lua b/not/SceneManager.lua index c076448..4f9edfd 100644 --- a/not/SceneManager.lua +++ b/not/SceneManager.lua @@ -9,7 +9,10 @@ end -- This function should be removed when multiple scenes will be handled properly by SceneManager and other things. function SceneManager:changeScene (scene) - table.remove(self.scenes, #self.scenes) + local removed = table.remove(self.scenes, #self.scenes) + if removed then + removed:delete() + end return self:addScene(scene) end @@ -20,7 +23,8 @@ end -- Not nice, not nice. function SceneManager:removeTopScene () - table.remove(self.scenes, #self.scenes) + local scene = table.remove(self.scenes, #self.scenes) + scene:delete() end function SceneManager:getAllScenes () diff --git a/not/Selector.lua b/not/Selector.lua index ef78778..ee6f0e3 100644 --- a/not/Selector.lua +++ b/not/Selector.lua @@ -1,282 +1,195 @@ -require "not.Element" - --- `Selector` --- Used in Menu for selecting various things from list. Works for each Controller set or globally. ---[[ -How to use `Selector` in `Menu` config file? -selector:new(menu) - :setPosition(x, y) - :setMargin(8) -- each block has marigin on both sides; they do stack - :setSize(32, 32) -- size of single graphics frame - :set("list", require "nautslist") - :set("icons_i", love.graphics.newImage("assets/portraits.png")) - :set("icons_q", require "portraits") - :set("global", false) -- true: single selector; false: selector for each controller set present - :init() -]] -Selector = Element:extends() +-- Element for selecting variable from list. +Selector = require "not.Element":extends() -Selector.width = 0 -Selector.height = 0 -Selector.margin = 0 -Selector.focused = false -Selector.global = false -Selector.delay = 2 -Selector.first = false -Selector.list = --[[]]nil -Selector.sets = --[[]]nil -Selector.locks = --[[]]nil -Selector.selections = --[[]]nil -Selector.shape = "portrait" -Selector.sprite = --[[]]nil -Selector.quads = --[[]]nil -Selector.icons_i = --[[]]nil -Selector.icons_q = --[[]]nil +Selector.DEFAULT_DELAY = 2 +Selector.SHAPE_PORTRAIT = 1 +Selector.SHAPE_PANORAMA = 2 --- Constructor -function Selector:new (parent) +function Selector:new (list, group, parent) Selector.__super.new(self, parent) - self.sprite, self.quads = parent:getSheet() + self.atlas, self.quads = parent:getSheet() + self.group = group + self.list = list + self.delay = Selector.DEFAULT_DELAY + self.shape = Selector.SHAPE_PORTRAIT + self.focused = false + self.lock = false + self.index = 1 end --- Size of single block +-- TODO: See `not/Element@getSize`. function Selector:getSize () - return self.width, self.height -end -function Selector:setSize (width, height) - self.width, self.height = width, height - return self -end - --- Spacing between two blocks -function Selector:getMargin () - return self.margin -end -function Selector:setMargin (margin) - self.margin = margin - return self + if self.shape == Selector.SHAPE_PORTRAIT then + return 32, 32 + end + if self.shape == Selector.SHAPE_PANORAMA then + return 80, 42 + end end --- Initialize Selector with current settings. -function Selector:init () - -- Make sure that there is list present - if self.list == nil then - self.list = {} +--- Makes sure that n is in <1, total> range. +local +function limit (n, total) + if n > total then + return limit(n - total, total) end - -- Initialize global Selector - if self.global then - self.sets = {} - self.locks = {false} - self.selections = {1} - -- Initialize Selector for Controllers - else - self.sets = Controller.getSets() - self.locks = {} - self.selections = {} - for n=1,#self.sets do - self.locks[n] = false - self.selections[n] = 1 - end + if n < 1 then + return limit(n + total, total) end - return self + return n end --- Cycle through list on given number -function Selector:next (n) - local current = self.selections[n] - self:setSelection(n, current + 1) -end -function Selector:previous (n) - local current = self.selections[n] - self:setSelection(n, current - 1) +--- Chooses item with an index. +-- @param index selected item's index +-- @return old index +function Selector:setIndex (index) + local old = self.index + self.index = limit(index, #self.list) + return old end --- Get number associated with a given set -function Selector:checkNumber (set) - if self.global then return 1 end -- For global Selector - for n,check in pairs(self.sets) do - if check == set then return n end +function Selector:rollRandom (exclude) + local exclude = exclude or {} + local index = love.math.random(1, #self.list) + local elgible = true + for _,i in ipairs(exclude) do + if index == i then + elgible = false + break + end + end + if not elgible or not self:isUnique(self.list[index]) then + table.insert(exclude, index) + return self:rollRandom(exclude) end + return index end --- Check if given number is locked -function Selector:isLocked (n) - local n = n or 1 - return self.locks[n] +--- Returns selected item's value. +-- @return item selected from the list +function Selector:getSelected () + return self.list[self.index] end --- Sets value of selection of given number. Returns old. -function Selector:setSelection (n, new) - -- Functception. It sounds like fun but it isn't. - local function limit(new, total) - if new > total then - return limit(new - total, total) - elseif new < 1 then - return limit(total + new, total) - else - return new - end +--- Checks if selection is locked and returns item's value. +-- @return item selected from the list if Selector is locked, nil otherwise +function Selector:getLocked () + if self.lock then + return self:getSelected() end - local n = n or 1 - local old = self.selections[n] - self.selections[n] = limit(new, #self.list) - return old end --- Get value of selection of given number -function Selector:getSelection (n) - local n = n or 1 - return self.selections[n] +--- Checks if Selected value is unique in group's scope. +-- @param index optional parameter to fill in place of currently selected item +-- @return boolean answering question +function Selector:isUnique (item) + local item = item or self:getSelected() + if self.group then + local locked = self.group:callEachBut(self, "getLocked") + for _,value in pairs(locked) do + if value == item then + return false + end + end + end + return true end --- Get value from list by selection -function Selector:getListValue (i) - return self.list[i] +function Selector:getText () + return tostring(self:getSelected()) end --- Checks if selection of given number is unique within Selector scope. -function Selector:isUnique (n) - local selection = self:getSelection(n) - for fn,v in pairs(self.selections) do - if fn ~= n and self:isLocked(fn) and v == selection then - return false - end - end +function Selector:focus () + self.focused = true return true end --- Get list of selections, checks if not locked are allowed. -function Selector:getFullSelection (allowed) - local allowed = allowed - if allowed == nil then allowed = false end - local t = {} - for n,v in pairs(self.selections) do - local name = self:getListValue(self:getSelection(n)) - local locked = self:isLocked(n) - if locked or allowed then - local a = {name} - if self.sets[n] then table.insert(a, self.sets[n]) end - table.insert(t, a) - end - end - return t +function Selector:blur () + self.focused = false end --- Rolls and returns random selection from list that is not locked. -function Selector:rollRandom (avoids) - -- Me: You should make it simpler. - -- Inner me: Nah, it works. Leave it. - -- Me: Ok, let's leave it as it is. - local avoids = avoids or {} - local total = #self.list - local random = love.math.random(1, total) - local eligible = true - for _,avoid in ipairs(avoids) do - if random == avoid then - eligible = false - break - end +-- TODO: Temporary function to determine quad to use. Will be obsolete when BoxElement will be done. See also `not/Element@getSize`. +function Selector:getShapeString () + if self.shape == Selector.SHAPE_PORTRAIT then + return "portrait" end - if not eligible or self:isLocked(random) then - table.insert(avoids, random) - return self:rollRandom(avoid) - else - return random + if self.shape == Selector.SHAPE_PANORAMA then + return "panorama" end end --- Draw single block of Selector -function Selector:drawBlock (n, x, y, scale) - if self.quads == nil or self.sprite == nil then return end - local x, y = x or 0, y or 0 - local name = self:getListValue(self:getSelection(n)) - local locked = self:isLocked(n) - local sprite = self.sprite - local quad = self.quads - local icon = self.icons_i - local iconq = self.icons_q[name] - local w,h = self:getSize() - local unique = self:isUnique(n) - if unique then - love.graphics.setColor(255, 255, 255, 255) - else - love.graphics.setColor(140, 140, 140, 255) +function Selector:draw (scale) + local x, y = self:getPosition() + local w, h = self:getSize() + + local boxType = "normal" + if self:getLocked() then + boxType = "active" + end + + love.graphics.setColor(255, 255, 255, 255) + if not self:isUnique() then + love.graphics.setColor(120, 120, 120, 255) end - if not locked then - love.graphics.draw(sprite, quad[self.shape].normal, x*scale, y*scale, 0, scale, scale) - else - love.graphics.draw(sprite, quad[self.shape].active, x*scale, y*scale, 0, scale, scale) + love.graphics.draw(self.atlas, self.quads[self:getShapeString()][boxType], x*scale, y*scale, 0, scale, scale) + -- TODO: That is one way to draw icon for selected value. Find better one. See: `config/menus/host`. + if self.icons_atlas and self.icons_quads then + love.graphics.draw(self.icons_atlas, self.icons_quads[self.index], (x+2)*scale, (y+3)*scale, 0, scale, scale) end - love.graphics.draw(icon, iconq, (x+2)*scale, (y+3)*scale, 0, scale, scale) + + love.graphics.setColor(255, 255, 255, 255) + if self.focused then local dy = (h-6)/2 - if not locked then - love.graphics.draw(sprite, quad.arrow_l, (x+0-2-math.floor(self.delay))* scale, (y+dy)*scale, 0, scale, scale) - love.graphics.draw(sprite, quad.arrow_r, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale) - else - love.graphics.draw(sprite, quad.arrow_r, (x+0-2-math.floor(self.delay))* scale, (y+dy)*scale, 0, scale, scale) - love.graphics.draw(sprite, quad.arrow_l, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale) + local al, ar = self.quads.arrow_r, self.quads.arrow_l + if self.lock then + al, ar = ar, al end - end - if (self:getSelection(n) ~= 1 or self.first) then - love.graphics.setFont(Font) - love.graphics.setColor(255, 255, 255, 255) - love.graphics.printf(string.upper(name), (x-w)*scale, (y+h+1)*scale, w*3, "center", 0, scale, scale) - end -end --- Menu callbacks -function Selector:focus () -- Called when Element gains focus - self.focused = true - return true -end -function Selector:blur () -- Called when Element loses focus - self.focused = false -end - --- LÖVE2D callbacks -function Selector:draw (scale) - local x,y = self:getPosition() - local margin = self:getMargin() - local width = self:getSize() - x = x - #self.selections*0.5*(margin+margin+width) - for n=1,#self.selections do - self:drawBlock(n, x+(margin+width)*(n-1)+margin*n, y, scale) + love.graphics.draw(self.atlas, ar, (x+0-2-math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale) + love.graphics.draw(self.atlas, al, (x+w-4+math.floor(self.delay))*scale, (y+dy)*scale, 0, scale, scale) end + + love.graphics.setFont(Font) + love.graphics.printf(self:getText(), (x-w)*scale, (y+h+1)*scale, w*3, "center", 0, scale, scale) end + function Selector:update (dt) self.delay = self.delay + dt - if self.delay > Selector.delay then -- Selector.delay is initial - self.delay = self.delay - Selector.delay + if self.delay > Selector.DEFAULT_DELAY then + self.delay = self.delay - Selector.DEFAULT_DELAY end end --- Controller callbacks --- TODO: Add action to perform when key is pressed and selector is locked in e.g. to move into character selection from map selection. function Selector:controlpressed (set, action, key) if set and self.focused then - local n = self:checkNumber(set) - local locked = self:isLocked(n) - if action == "left" and not locked then self:previous(n) end - if action == "right" and not locked then self:next(n) end - if action == "attack" then - local name = self:getListValue(self:getSelection(n)) - if name == "random" then - self:setSelection(n, self:rollRandom({1,2})) -- avoid empty naut - self.locks[n] = true - else - -- If not empty or if first is allowed. Additionaly must be unique selection. - if (self:getSelection(n) ~= 1 or self.first) and self:isUnique(n) then - self.locks[n] = true - end - end - end - if action == "jump" then - if locked then - self.locks[n] = false - end + local handler = self[action] + if handler then + handler(self) end end end +function Selector:left () + if not self.lock then + self:setIndex(self.index - 1) + end +end + +function Selector:right () + if not self.lock then + self:setIndex(self.index + 1) + end +end + +function Selector:attack () + self.lock = true +end + +-- Selector doesn't actually jump, haha, I tricked you! +function Selector:jump () + self.lock = false +end + return Selector diff --git a/not/Sprite.lua b/not/Sprite.lua index 3951e6e..ec23eac 100644 --- a/not/Sprite.lua +++ b/not/Sprite.lua @@ -11,6 +11,7 @@ Sprite.frame = 1 Sprite.delay = .1 -- Constructor of `Sprite`. +-- TODO: Sprites' in general don't take actual Image in constructor. That is not only case of Decoration. function Sprite:new (imagePath) if type(imagePath) == "string" then self:setImage(Sprite.newImage(imagePath)) @@ -84,26 +85,24 @@ function Sprite:getOffset () return 0,0 end -- Drawing self to LOVE2D buffer. -- If there is no Quad, it will draw entire image. It won't draw anything if there is no image. +-- TODO: Sprite@draw requires a serious review! -- TODO: it doesn't follow same pattern as `not.Hero.draw`. It should implement so it can be called from `not.World`. -- TODO: change children if above changes are in effect: `not.Platform`, `not.Decoration`. -function Sprite:draw (offset_x, offset_y, scale) - local offset_x = offset_x or 0 - local offset_y = offset_y or 0 - +function Sprite:draw (debug) local i, q = self:getImage(), self:getQuad() local x, y = self:getPosition() local angle = self:getAngle() - local scaleX = self:getHorizontalMirror()*(scale or 1) - local scaleY = self:getVerticalMirror()*(scale or 1) + local scaleX = self:getHorizontalMirror() + local scaleY = self:getVerticalMirror() -- pixel grid ; `approx` selected to prevent floating characters on certain conditions local approx = math.floor if (y - math.floor(y)) > 0.5 then approx = math.ceil end - local draw_y = (approx(y) + offset_y) * scale - local draw_x = (math.floor(x) + offset_x) * scale + local draw_y = approx(y) + local draw_x = math.floor(x) - if i then + if i and not self.hidden then love.graphics.setColor(255,255,255,255) if q then love.graphics.draw(i, q, draw_x, draw_y, angle, scaleX, scaleY, self:getOffset()) diff --git a/not/Timer.lua b/not/Timer.lua new file mode 100644 index 0000000..9ae0de8 --- /dev/null +++ b/not/Timer.lua @@ -0,0 +1,30 @@ +Timer = require "not.Trigger":extends() + +function Timer:new (delay) + Timer.__super.new(self) + self.delay = delay + self.left = 0 + self.active = false + self.restart = false +end + +function Timer:start () + self.left = self.delay + self.active = true +end + +function Timer:update (dt) + if self.active then + if self.left < 0 then + self:emit() + self.active = false + if self.restart then + self:start() + end + else + self.left = self.left - dt + end + end +end + +return Timer diff --git a/not/Trap.lua b/not/Trap.lua new file mode 100644 index 0000000..0867a36 --- /dev/null +++ b/not/Trap.lua @@ -0,0 +1,51 @@ +Trap = require "not.PhysicalBody":extends() + +function Trap:new (direction, x, y, world, imagePath) + Trap.__super.new(self, x, y, world, imagePath) + self:setAnimationsList(require("config.animations.flames")) + self:setBodyType("static") + + local mirror = 1 + if direction == "left" then mirror = -1 end + local fixture = self:addFixture({0, 0, 41 * mirror, 0, 41 * mirror, 18, 0, 18}) + fixture:setCategory(4) + fixture:setMask(1,3,4) + fixture:setUserData({direction}) + fixture:setSensor(true) + + self.mirror = mirror +end + +function Trap:fadeIn () + self.hidden = false + self:setBodyActive(true) + if self.animations.fadein then + self:setAnimation("fadein") + end +end + +function Trap:fadeOut () + self:setBodyActive(false) + if self.animations.fadeout then + self:setAnimation("fadeout") + else + self.hidden = true + end +end + +function Trap:getHorizontalMirror () + return self.mirror +end + +function Trap:goToNextFrame () + if self.current.repeated or not (self.frame == self.current.frames) then + self.frame = (self.frame % self.current.frames) + 1 + elseif self.current == self.animations.fadeout then + self:setAnimation("default") + self.hidden = true + else + self:setAnimation("default") + end +end + +return Trap diff --git a/not/Trigger.lua b/not/Trigger.lua new file mode 100644 index 0000000..c6ef7c7 --- /dev/null +++ b/not/Trigger.lua @@ -0,0 +1,18 @@ +Trigger = require "not.Object":extends() + +function Trigger:new () + self.calls = {} +end + +function Trigger:register (func, ...) + local call = {func = func, params = {...}} + table.insert(self.calls, call) +end + +function Trigger:emit () + for _,call in pairs(self.calls) do + call.func(unpack(call.params)) + end +end + +return Trigger diff --git a/not/World.lua b/not/World.lua index c73a3da..4523efa 100644 --- a/not/World.lua +++ b/not/World.lua @@ -1,82 +1,183 @@ ---- `World` --- Used to manage physical world and everything inside it: clouds, platforms, nauts, background etc. +--- Used to manage physical world and everything inside it: clouds, platforms, nauts, background etc. -- TODO: Possibly move common parts of `World` and `Menu` to abstract class `Scene`. World = require "not.Scene":extends() -World.world =--[[love.physics.newWorld]]nil -World.Nauts =--[[{not.Hero}]]nil -World.Platforms =--[[{not.Platform}]]nil -World.Clouds =--[[{not.Cloud}]]nil -World.Decorations =--[[{not.Decoration}]]nil -World.Effects =--[[{not.Effect}]]nil -World.Rays =--[[{not.Ray}]]nil -World.camera =--[[not.Camera]]nil -World.music =--[[not.Music]]nil -World.clouds_delay = 5 -World.map =--[[config.maps.*]]nil -World.background =--[[image?]]nil -World.lastNaut = false - require "not.Platform" require "not.Player" -require "not.Cloud" require "not.Effect" require "not.Decoration" require "not.Ray" +require "not.Cloud" +require "not.CloudGenerator" +require "not.Layer" +require "not.Timer" +require "not.Trap" +require "not.Entity" --- Constructor of `World` ZA WARUDO! +--- ZA WARUDO! +-- TODO: Missing documentation on most of World's methods. function World:new (map, nauts) - -- Box2D physical world. love.physics.setMeter(64) self.world = love.physics.newWorld(0, 9.81*64, true) - self.world:setCallbacks(self.beginContact, self.endContact) - -- Tables for entities. TODO: It is still pretty bad! - self.Nauts = {} - self.Platforms = {} - self.Clouds = {} - self.Effects = {} - self.Decorations = {} - self.Rays = {} - -- Map and misc. - local map = map or "default" - self:loadMap(map) + self.world:setCallbacks(self:getContactCallbacks()) + + self.lastNaut = false + self.entities = {} + self.map = map + + self.camera = Camera(self.map.center.x, self.map.center.y, self) + + self:initLayers() + self:buildMap() self:spawnNauts(nauts) - self.camera = Camera:new(self) - musicPlayer:setTrack(self.map.theme) - musicPlayer:play() + + musicPlayer:play(self.map.theme) end -- The end of the world function World:delete () - for _,platform in pairs(self.Platforms) do - platform:delete() + for _,entity in pairs(self.entities) do + entity:delete() end - for _,naut in pairs(self.Nauts) do - naut:delete() + for layer in self.layers() do + layer:delete() end self.world:destroy() + collectgarbage() +end + +--- Custom iterator for layers table. +-- Iterates over elements in reversed order. Doesn't pay attention to any changes in table. +local +function layersIterator (layers) + local i = layers.n + 1 + return function () + i = i - 1 + return layers[i] + end +end + +--- Layers in World may exists as two references. Every reference is stored inside `instance.layers`. +-- First reference is indexed with number, it exists for every layer. +-- Second reference is indexed with string, it exists only for selected layers. +-- Mentioned special layers are initialized in this method. +-- Additionally layer count is stored inside `instance.layers.n`. +-- Layers are drawn in reverse order, meaning that `instance.layers[1]` will be on the top. +-- Calling `instance.layers` will return iterator. +function World:initLayers () + self.layers = setmetatable({}, {__call = layersIterator}) + self.layers.n = 0 + do + local width, height = love.graphics.getWidth() / getScale(), love.graphics.getHeight() / getScale() + local rays = self:addLayer(width, height) + rays.transformScale = 1 + rays.transformRatio = 0 + rays.drawScale = getScale() + self.layers.rays = rays + end + do + local width, height = love.graphics.getDimensions() + self.layers.tags = self:addLayer(width, height) + self.layers.platforms = self:addLayer(width, height) + self.layers.effects = self:addLayer(width, height) + self.layers.heroes = self:addLayer(width, height) + self.layers.decorations = self:addLayer(width, height) + self.layers.clouds = self:addLayer(width, height) + end +end + +-- TODO: Make collisions for category 3 more customizable or create new category for traps/area effects. +local +function createFlame (self, x, y, direction, timerIn, timerOut) + local trap = Trap(direction, x, y, self, "assets/decorations/205-flames.png") + + trap.layer = self.layers.platforms + + timerIn:register(trap.fadeIn, trap) + timerOut:register(trap.fadeOut, trap) + + self:insertEntity(trap) end --- Load map from file --- TODO: Change current map model to function-based one. -function World:loadMap (name) - local name = name or "default" - local map = love.filesystem.load(string.format("config/maps/%s.lua", name)) - self.map = map() - -- Platforms - for _,platform in pairs(self.map.platforms) do - self:createPlatform(platform.x, platform.y, platform.shape, platform.sprite, platform.animations) - end - -- Decorations - for _,decoration in pairs(self.map.decorations) do - self:createDecoration(decoration.x, decoration.y, decoration.sprite) - end - -- Background - self.background = love.graphics.newImage(self.map.background) - -- Clouds - if self.map.clouds then - for i=1,6 do - self:randomizeCloud(false) +local +function getAnimations (a) + if type(a) == "string" then + return require("config.animations." .. a) + end + if type(a) == "table" then + return a + end +end + +--- Builds map using one of tables frin config files located in `config/maps/` directory. +-- TODO: Clean World@buildMap. Possibly explode into more methods. +-- TODO: Move buildMap along with getAnimations to Factory. +function World:buildMap () + local width, height = love.graphics.getDimensions() + + for _,op in pairs(self.map.create) do + if op.platform then + -- TODO: Merge configs imported from other files to currently processed element. + local config = love.filesystem.load(string.format("config/platforms/%s.lua", op.platform))() + local platform = Platform(config.animations, config.shape, op.x, op.y, self, config.sprite) + platform.layer = self.layers.platforms + self:insertEntity(platform) + end + if op.decoration or op.background then + local imagePath = op.decoration or op.background + local entity = Decoration(0, 0, self, imagePath) + + local x, y = 0, 0 + if op.x and op.y then + x = op.x + y = op.y + elseif op.animations then + entity:setAnimationsList(getAnimations(op.animations)) + _,_,x,y = bg:getAnimation()[1]:getViewport() + bg:setPosition(x / -2, y / -2) + else + local image = love.graphics.newImage(imagePath) + x = image:getWidth() / -2 + y = image:getHeight() / -2 + end + entity:setPosition(x, y) + + local layer = self.layers.decorations + if op.ratio then + layer = self:addLayer(width, height) + layer.transformRatio = op.ratio + if op.background then + layer.transformScale = getRealScale() + end + end + entity.layer = layer + + self:insertEntity(entity) + end + if op.clouds then + local animations = getAnimations(op.animations) + local cg = CloudGenerator(op.clouds, animations, op.count, self) + if op.ratio then + cg.layer = self:addLayer(width, height) + cg.layer.transformRatio = op.ratio + end + self:insertEntity(cg) + cg:run(op.count, true) + end + -- TODO: Make flames and other traps more configurable through map config file. + if op.flames then + local timerIn = Timer(10) + local timerOut = Timer(5) + + timerIn:register(timerOut.start, timerOut) + timerOut:register(timerIn.start, timerIn) + + createFlame(self, -62, 16, "right", timerIn, timerOut) + createFlame(self, 63, 16, "left", timerIn, timerOut) + + self:insertEntity(timerIn) + self:insertEntity(timerOut) + timerOut:start() end end end @@ -96,89 +197,107 @@ function World:getSpawnPosition () return self.map.respawns[n].x, self.map.respawns[n].y end --- Add new platform to the world --- TODO: it would be nice if function parameters would be same as `not.Platform.new`. -function World:createPlatform (x, y, polygon, sprite, animations) - table.insert(self.Platforms, Platform(animations, polygon, x, y, self, sprite)) +function World:addLayer (width, height) + local layer = Layer(width, height) + local n = self.layers.n + 1 + self.layers[n] = layer + self.layers.n = n + return layer end --- Add new naut to the world --- TODO: separate two methods for `not.Hero` and `not.Player`. +-- TODO: Standardize `create*` methods with corresponding constructors. Pay attention to both params' order and names. function World:createNaut (x, y, name) - local naut = Player(name, x, y, self) - table.insert(self.Nauts, naut) - return naut -end - --- Add new decoration to the world --- TODO: `not.World.create*` functions often have different naming for parameters. It is not ground-breaking but it makes reading code harder for no good reason. -function World:createDecoration (x, y, sprite) - table.insert(self.Decorations, Decoration(x, y, self, sprite)) + local h = Player(name, x, y, self) + table.insert(self.entities, h) + h.layer = self.layers.heroes + return h end --- Add new cloud to the world --- TODO: extend variables names to provide better readability. --- TODO: follow new parameters in `not.Cloud.new` based on `not.Cloud.init`. -function World:createCloud (x, y, t, v) - table.insert(self.Clouds, Cloud(x, y, t, v, self)) +function World:createEffect (name, x, y) + local e = Effect(name, x, y, self) + table.insert(self.entities, e) + e.layer = self.layers.effects + return e end --- Randomize Cloud creation -function World:randomizeCloud (outside) - if outside == nil then - outside = true - else - outside = outside - end - local x,y,t,v - local m = self.map - if outside then - x = m.center_x-m.width*1.2+love.math.random(-50,20) - else - x = love.math.random(m.center_x-m.width/2,m.center_x+m.width/2) - end - y = love.math.random(m.center_y-m.height/2, m.center_y+m.height/2) - t = love.math.random(1,3) - v = love.math.random(8,18) - self:createCloud(x, y, t, v) +function World:createRay (naut) + local r = Ray(naut, self) + table.insert(self.entities, r) + r.layer = self.layers.rays + return r end --- Add an effect behind nauts --- TODO: follow new parameters in `not.Effect.new` based on `not.Effect.init`. --- TODO: along with `createRay` move this nearer reast of `create*` methods for readability. -function World:createEffect (name, x, y) - table.insert(self.Effects, Effect(name, x, y, self)) +function World:insertCloud (cloud) + table.insert(self.entities, cloud) + if not cloud.layer then + cloud.layer = self.layers.clouds + end + return cloud end --- Add a ray -function World:createRay (naut) - table.insert(self.Rays, Ray(naut, self)) +--- Verbose wrapper for inserting entities into entities table. +-- @param entity entity to insert +function World:insertEntity (entity) + if entity then + table.insert(self.entities, entity) + return entity + end end --- get Nauts functions --- more than -1 lives -function World:getNautsPlayable () - local nauts = {} - for _,naut in pairs(self.Nauts) do - if naut.lives > -1 then - table.insert(nauts, naut) +--- Searches entities for those which return true with filtering function. +-- @param filter function with entity as parameter +-- @return table containing results of search +function World:getEntities (filter) + local result = {} + for _,entity in pairs(self.entities) do + if filter(entity) then + table.insert(result, entity) end end - return nauts + return result end --- are alive -function World:getNautsAlive () - local nauts = {} - for _,naut in self.Nauts do - if naut.isAlive then - table.insert(nauts, naut) + +--- Counts entities returning true with filtering function. +-- @param filter function with entity as parameter +-- @return entity count +function World:countEntities (filter) + local count = 0 + for _,entity in pairs(self.entities) do + if filter(entity) then + count = count + 1 end end - return nauts + return count +end + +function World:getCloudsCount () + return self:countEntities(function (entity) + return entity:is(Cloud) + end) end --- all of them + +function World:getCloudsCountFrom (generator) + return self:countEntities(function (entity) + return entity:is(Cloud) and entity.generator == generator + end) +end + function World:getNautsAll () - return self.Nauts + return self:getEntities(function (entity) + return entity:is(require("not.Hero")) and not entity.body:isDestroyed() + end) +end + +function World:getNautsPlayable () + return self:getEntities(function (entity) + return entity:is(require("not.Hero")) and entity.lives > -1 + end) +end + +function World:getNautsAlive () + return self:getEntities(function (entity) + return entity:is(require("not.Hero")) and entity.isAlive + end) end -- get Map name @@ -206,121 +325,63 @@ end function World:update (dt) self.world:update(dt) self.camera:update(dt) - -- Engine world: Nauts, Grounds (kek) and Decorations - all Animateds (top kek) - for _,naut in pairs(self.Nauts) do - naut:update(dt) - end - for _,platform in pairs(self.Platforms) do - platform:update(dt) - end - for _,decoration in pairs(self.Decorations) do - decoration:update(dt) - end - -- Clouds - if self.map.clouds then - -- generator - local n = table.getn(self.Clouds) - self.clouds_delay = self.clouds_delay - dt - if self.clouds_delay < 0 and - n < 18 - then - self:randomizeCloud() - self.clouds_delay = self.clouds_delay + World.clouds_delay -- World.clouds_delay is initial - end - -- movement - for _,cloud in pairs(self.Clouds) do - if cloud:update(dt) > 340 then - table.remove(self.Clouds, _) - end - end - end - -- Effects - for _,effect in pairs(self.Effects) do - if effect:update(dt) then - table.remove(self.Effects, _) + + for key,entity in pairs(self.entities) do + if entity:update(dt) then + table.remove(self.entities, key):delete() end end - -- Rays - for _,ray in pairs(self.Rays) do - if ray:update(dt) then - table.remove(self.Rays, _) - end + + -- TODO: Possibly rename Camera@sum because this code part in World doesn't make sense without reading further. + self.camera:sum(self.map.center.x, self.map.center.y) + for _,hero in pairs(self:getNautsAll()) do + self.camera:sum(hero:getPosition()) end + + -- Some additional debug info. + local stats = love.graphics.getStats() + dbg_msg = string.format("%sMap: %s\nClouds: %d\nLoaded: %d\nMB: %.2f", dbg_msg, self.map.filename, self:getCloudsCount(), stats.images, stats.texturememory / 1024 / 1024) end --- Draw -function World:draw () - -- Camera stuff - local offset_x, offset_y = self.camera:getOffsets() - local scale = getScale() - local scaler = getRealScale() - - -- Background - love.graphics.draw(self.background, 0, 0, 0, scaler, scaler) - - -- TODO: this needs to be reworked! - -- Draw clouds - for _,cloud in pairs(self.Clouds) do - cloud:draw(offset_x, offset_y, scale) - end - -- Draw decorations - for _,decoration in pairs(self.Decorations) do - decoration:draw(offset_x, offset_y, scale) +function World:draw () + for _,entity in pairs(self.entities) do + if entity.draw and entity.layer then + entity.layer:renderToWith(self.camera, entity.draw, entity, debug) + end + if entity.drawTag then + self.layers.tags:renderToWith(self.camera, entity.drawTag, entity, debug) + end end - -- Draw effects - for _,effect in pairs(self.Effects) do - effect:draw(offset_x,offset_y, scale) + for layer in self.layers() do + layer:draw() + layer:clear() end - -- Draw player - for _,naut in pairs(self.Nauts) do - naut:draw(offset_x, offset_y, scale, debug) - end + -- TODO: Debug information could possibly get its own layer so it could follow flow of draw method. + if debug then + local center = self.map.center + local ax, ay, bx, by = self.camera:getBoundaries(getScale(), love.graphics.getDimensions()) - -- Draw ground - for _,platform in pairs(self.Platforms) do - platform:draw(offset_x, offset_y, scale, debug) - end + love.graphics.setLineWidth(1 / getScale()) + love.graphics.setLineStyle("rough") - -- Draw rays - for _,ray in pairs(self.Rays) do - ray:draw(offset_x, offset_y, scale) - end + self.camera:push() + self.camera:transform(getScale(), 1, love.graphics.getDimensions()) - -- draw center - if debug then - local c = self.camera - local w, h = love.graphics.getWidth(), love.graphics.getHeight() - -- draw map center love.graphics.setColor(130,130,130) - love.graphics.setLineWidth(1) - love.graphics.setLineStyle("rough") - local cx, cy = c:getPositionScaled() - local x1, y1 = c:translatePosition(self.map.center_x, cy) - local x2, y2 = c:translatePosition(self.map.center_x, cy+h) - love.graphics.line(x1,y1,x2,y2) - local x1, y1 = c:translatePosition(cx, self.map.center_y) - local x2, y2 = c:translatePosition(cx+w, self.map.center_y) - love.graphics.line(x1,y1,x2,y2) - -- draw ox, oy - love.graphics.setColor(200,200,200) - love.graphics.setLineStyle("rough") - local cx, cy = c:getPositionScaled() - local x1, y1 = c:translatePosition(0, cy) - local x2, y2 = c:translatePosition(0, cy+h) - love.graphics.line(x1,y1,x2,y2) - local x1, y1 = c:translatePosition(cx, 0) - local x2, y2 = c:translatePosition(cx+w, 0) - love.graphics.line(x1,y1,x2,y2) - end + love.graphics.line(ax,center.y,bx,center.y) + love.graphics.line(center.x,ay,center.x,by) - for _,naut in pairs(self.Nauts) do - naut:drawTag(offset_x, offset_y, scale) + love.graphics.setColor(200,200,200) + love.graphics.line(ax,0,bx,0) + love.graphics.line(0,ay,0,by) + self.camera:pop() end - - -- Draw HUDs - for _,naut in pairs(self.Nauts) do + + -- TODO: Draw method beyond this point is a very, very dark place (portraits drawing to review). + local scale = getScale() + for _,naut in pairs(self:getNautsAll()) do -- I have no idea where to place them T_T -- let's do: bottom-left, bottom-right, top-left, top-right local w, h = love.graphics.getWidth()/scale, love.graphics.getHeight()/scale @@ -330,15 +391,29 @@ function World:draw () end end --- Box2D callbacks --- TODO: Rather than here, these contacts should be in `Hero` (most likely). --- TODO: Explode these into more functions.\ --- TODO: Stop using magical numbers: --- [1] -> Platform --- [2] -> Hero --- [3] -> Punch sensor -function World.beginContact (a, b, coll) - if a:getCategory() == 1 then +--- Wraps World's beginContact and endContact to functions usable as callbacks for Box2D's world. +-- Only difference in new functions is absence of self as first argument. +-- @return wrapper for beginContact +-- @return wrapper for endContact +function World:getContactCallbacks () + local b = function (a, b, coll) + self:beginContact(a, b, coll) + end + local e = function (a, b, coll) + self:endContact(a, b, coll) + end + return b, e +end + +-- TODO: Move these constants to a proper place (I have no idea where proper place is). +local COLL_HERO = 2 +local COLL_PLATFORM = 1 +local COLL_PUNCH = 3 +local COLL_TRAP = 4 + +-- TODO: Review current state of both Box2D callbacks (again). +function World:beginContact (a, b, coll) + if a:getCategory() == COLL_PLATFORM then local x,y = coll:getNormal() if y < -0.6 then b:getUserData():land() @@ -348,37 +423,49 @@ function World.beginContact (a, b, coll) b:getUserData():playSound(3) end end - if a:getCategory() == 3 then - if b:getCategory() == 2 then + if a:getCategory() == COLL_PUNCH then + if b:getCategory() == COLL_HERO then b:getUserData():damage(a:getUserData()[2]) end - if b:getCategory() == 3 then + if b:getCategory() == COLL_PUNCH then a:getBody():getUserData():damage(b:getUserData()[2]) b:getBody():getUserData():damage(a:getUserData()[2]) local x1,y1 = b:getBody():getUserData():getPosition() local x2,y2 = a:getBody():getUserData():getPosition() local x = (x2 - x1) / 2 + x1 - 12 local y = (y2 - y1) / 2 + y1 - 15 - a:getBody():getUserData().world:createEffect("clash", x, y) + self:createEffect("clash", x, y) end end - if b:getCategory() == 3 then - if a:getCategory() == 2 then + if b:getCategory() == COLL_PUNCH then + if a:getCategory() == COLL_HERO then a:getUserData():damage(b:getUserData()[2]) end end + if a:getCategory() == COLL_TRAP then + if b:getCategory() == COLL_HERO then + b:getUserData():damage(a:getUserData()[1]) + end + end + if b:getCategory() == COLL_TRAP then + if a:getCategory() == COLL_HERO then + a:getUserData():damage(b:getUserData()[1]) + end + end end -function World.endContact (a, b, coll) - if a:getCategory() == 1 then + +function World:endContact (a, b, coll) + if a:getCategory() == COLL_PLATFORM then b:getUserData().inAir = true end end -- Controller callbacks --- TODO: names of this methods don't follow naming patterns in this project. See `Controller` and change it. function World:controlpressed (set, action, key) if key == "f6" and debug then - local map = self:getMapName() + local filename = self.map.filename + local map = love.filesystem.load(filename)() + map.filename = filename local nauts = {} for _,naut in pairs(self:getNautsAll()) do table.insert(nauts, {naut.name, naut:getControllerSet()}) |