diff --git a/assets/breakout/levels/angles.bin b/assets/breakout/levels/angles.bin new file mode 100644 index 000000000..62365f06b Binary files /dev/null and b/assets/breakout/levels/angles.bin differ diff --git a/assets/breakout/levels/b.bin b/assets/breakout/levels/b.bin new file mode 100644 index 000000000..6249ba254 Binary files /dev/null and b/assets/breakout/levels/b.bin differ diff --git a/assets/breakout/levels/bombrings.bin b/assets/breakout/levels/bombrings.bin new file mode 100644 index 000000000..9601e18e2 Binary files /dev/null and b/assets/breakout/levels/bombrings.bin differ diff --git a/assets/breakout/levels/brkLevel1.bin b/assets/breakout/levels/brkLevel1.bin deleted file mode 100644 index e89951e0e..000000000 Binary files a/assets/breakout/levels/brkLevel1.bin and /dev/null differ diff --git a/assets/breakout/levels/corner.bin b/assets/breakout/levels/corner.bin new file mode 100644 index 000000000..01746a0dd Binary files /dev/null and b/assets/breakout/levels/corner.bin differ diff --git a/assets/breakout/levels/devito.bin b/assets/breakout/levels/devito.bin new file mode 100644 index 000000000..92d888010 Binary files /dev/null and b/assets/breakout/levels/devito.bin differ diff --git a/assets/breakout/levels/firework.bin b/assets/breakout/levels/firework.bin new file mode 100644 index 000000000..74be0925f Binary files /dev/null and b/assets/breakout/levels/firework.bin differ diff --git a/assets/breakout/levels/flipflop.bin b/assets/breakout/levels/flipflop.bin new file mode 100644 index 000000000..4e71b63f1 Binary files /dev/null and b/assets/breakout/levels/flipflop.bin differ diff --git a/assets/breakout/levels/flower.bin b/assets/breakout/levels/flower.bin new file mode 100644 index 000000000..85c57c66e Binary files /dev/null and b/assets/breakout/levels/flower.bin differ diff --git a/assets/breakout/levels/foosball.bin b/assets/breakout/levels/foosball.bin new file mode 100644 index 000000000..1f9f9e9e8 Binary files /dev/null and b/assets/breakout/levels/foosball.bin differ diff --git a/assets/breakout/levels/gaylordlogo.bin b/assets/breakout/levels/gaylordlogo.bin new file mode 100644 index 000000000..164065cab Binary files /dev/null and b/assets/breakout/levels/gaylordlogo.bin differ diff --git a/assets/breakout/levels/getMorGet.bin b/assets/breakout/levels/getMorGet.bin new file mode 100644 index 000000000..e5bd433c5 Binary files /dev/null and b/assets/breakout/levels/getMorGet.bin differ diff --git a/assets/breakout/levels/halloween.bin b/assets/breakout/levels/halloween.bin new file mode 100644 index 000000000..690e50d74 Binary files /dev/null and b/assets/breakout/levels/halloween.bin differ diff --git a/assets/breakout/levels/intersection.bin b/assets/breakout/levels/intersection.bin new file mode 100644 index 000000000..4758e5c99 Binary files /dev/null and b/assets/breakout/levels/intersection.bin differ diff --git a/assets/breakout/levels/intro.bin b/assets/breakout/levels/intro.bin index 94b1d4743..8f99512e2 100644 Binary files a/assets/breakout/levels/intro.bin and b/assets/breakout/levels/intro.bin differ diff --git a/assets/breakout/levels/introenemy.bin b/assets/breakout/levels/introenemy.bin new file mode 100644 index 000000000..692e82e27 Binary files /dev/null and b/assets/breakout/levels/introenemy.bin differ diff --git a/assets/breakout/levels/jailbreak.bin b/assets/breakout/levels/jailbreak.bin new file mode 100644 index 000000000..50f2e4738 Binary files /dev/null and b/assets/breakout/levels/jailbreak.bin differ diff --git a/assets/breakout/levels/leftside.bin b/assets/breakout/levels/leftside.bin index b5e8ae296..268aa1292 100644 Binary files a/assets/breakout/levels/leftside.bin and b/assets/breakout/levels/leftside.bin differ diff --git a/assets/breakout/levels/lumberjacks.bin b/assets/breakout/levels/lumberjacks.bin new file mode 100644 index 000000000..a3f2f76e8 Binary files /dev/null and b/assets/breakout/levels/lumberjacks.bin differ diff --git a/assets/breakout/levels/m_attack.bin b/assets/breakout/levels/m_attack.bin new file mode 100644 index 000000000..806168f11 Binary files /dev/null and b/assets/breakout/levels/m_attack.bin differ diff --git a/assets/breakout/levels/mag03.bin b/assets/breakout/levels/mag03.bin new file mode 100644 index 000000000..b92891a7d Binary files /dev/null and b/assets/breakout/levels/mag03.bin differ diff --git a/assets/breakout/levels/outtaMyWay.bin b/assets/breakout/levels/outtaMyWay.bin new file mode 100644 index 000000000..b571fc228 Binary files /dev/null and b/assets/breakout/levels/outtaMyWay.bin differ diff --git a/assets/breakout/levels/paddles.bin b/assets/breakout/levels/paddles.bin new file mode 100644 index 000000000..628711d13 Binary files /dev/null and b/assets/breakout/levels/paddles.bin differ diff --git a/assets/breakout/levels/snake.bin b/assets/breakout/levels/snake.bin new file mode 100644 index 000000000..26572223b Binary files /dev/null and b/assets/breakout/levels/snake.bin differ diff --git a/assets/breakout/levels/starlite.bin b/assets/breakout/levels/starlite.bin index 06d9c30ba..efef50816 100644 Binary files a/assets/breakout/levels/starlite.bin and b/assets/breakout/levels/starlite.bin differ diff --git a/assets/breakout/levels/stormcastle.bin b/assets/breakout/levels/stormcastle.bin new file mode 100644 index 000000000..427daa64c Binary files /dev/null and b/assets/breakout/levels/stormcastle.bin differ diff --git a/assets/breakout/levels/superhard.bin b/assets/breakout/levels/superhard.bin new file mode 100644 index 000000000..33a01611f Binary files /dev/null and b/assets/breakout/levels/superhard.bin differ diff --git a/assets/breakout/levels/themaze.bin b/assets/breakout/levels/themaze.bin new file mode 100644 index 000000000..99400af0e Binary files /dev/null and b/assets/breakout/levels/themaze.bin differ diff --git a/assets/breakout/levels/tinyhuge.bin b/assets/breakout/levels/tinyhuge.bin new file mode 100644 index 000000000..04fbe4c6d Binary files /dev/null and b/assets/breakout/levels/tinyhuge.bin differ diff --git a/assets/breakout/levels/titlescreen.bin b/assets/breakout/levels/titlescreen.bin new file mode 100644 index 000000000..9c839fd36 Binary files /dev/null and b/assets/breakout/levels/titlescreen.bin differ diff --git a/assets/breakout/levels/trifecta.bin b/assets/breakout/levels/trifecta.bin new file mode 100644 index 000000000..c4f850dc1 Binary files /dev/null and b/assets/breakout/levels/trifecta.bin differ diff --git a/assets/breakout/levels/upsidedown.bin b/assets/breakout/levels/upsidedown.bin index 0e0a8380d..99b222f6c 100644 Binary files a/assets/breakout/levels/upsidedown.bin and b/assets/breakout/levels/upsidedown.bin differ diff --git a/assets/breakout/levels/wallball.bin b/assets/breakout/levels/wallball.bin new file mode 100644 index 000000000..9a0a740b2 Binary files /dev/null and b/assets/breakout/levels/wallball.bin differ diff --git a/assets/breakout/levels/wtf.bin b/assets/breakout/levels/wtf.bin new file mode 100644 index 000000000..0f100c5eb Binary files /dev/null and b/assets/breakout/levels/wtf.bin differ diff --git a/assets/breakout/levels/xmarks.bin b/assets/breakout/levels/xmarks.bin new file mode 100644 index 000000000..d1f0ccb6b Binary files /dev/null and b/assets/breakout/levels/xmarks.bin differ diff --git a/assets/breakout/levels/zip.bin b/assets/breakout/levels/zip.bin new file mode 100644 index 000000000..515fabaa6 Binary files /dev/null and b/assets/breakout/levels/zip.bin differ diff --git a/assets/breakout/sounds/sndBrk1up.mid b/assets/breakout/sounds/sndBrk1up.mid new file mode 100644 index 000000000..9757fa296 Binary files /dev/null and b/assets/breakout/sounds/sndBrk1up.mid differ diff --git a/assets/breakout/sprites/ball000.png b/assets/breakout/sprites/ball000.png index 759008622..e15b05228 100644 Binary files a/assets/breakout/sprites/ball000.png and b/assets/breakout/sprites/ball000.png differ diff --git a/assets/breakout/sprites/ball001.png b/assets/breakout/sprites/ball001.png index 436fb1580..50656244c 100644 Binary files a/assets/breakout/sprites/ball001.png and b/assets/breakout/sprites/ball001.png differ diff --git a/assets/breakout/sprites/ball002.png b/assets/breakout/sprites/ball002.png index a45ad4af2..f223c09cc 100644 Binary files a/assets/breakout/sprites/ball002.png and b/assets/breakout/sprites/ball002.png differ diff --git a/assets/breakout/sprites/ballTrail000.png b/assets/breakout/sprites/ballTrail000.png new file mode 100644 index 000000000..f043337a1 Binary files /dev/null and b/assets/breakout/sprites/ballTrail000.png differ diff --git a/assets/breakout/sprites/ballTrail001.png b/assets/breakout/sprites/ballTrail001.png new file mode 100644 index 000000000..2cde15587 Binary files /dev/null and b/assets/breakout/sprites/ballTrail001.png differ diff --git a/assets/breakout/sprites/ballTrail002.png b/assets/breakout/sprites/ballTrail002.png new file mode 100644 index 000000000..4fb095e57 Binary files /dev/null and b/assets/breakout/sprites/ballTrail002.png differ diff --git a/assets/breakout/sprites/ballTrail003.png b/assets/breakout/sprites/ballTrail003.png new file mode 100644 index 000000000..a48140bf5 Binary files /dev/null and b/assets/breakout/sprites/ballTrail003.png differ diff --git a/assets/breakout/sprites/cho000.png b/assets/breakout/sprites/cho000.png new file mode 100644 index 000000000..a16cf07b1 Binary files /dev/null and b/assets/breakout/sprites/cho000.png differ diff --git a/assets/breakout/sprites/cho001.png b/assets/breakout/sprites/cho001.png new file mode 100644 index 000000000..3a0a6cb18 Binary files /dev/null and b/assets/breakout/sprites/cho001.png differ diff --git a/assets/breakout/sprites/cho002.png b/assets/breakout/sprites/cho002.png new file mode 100644 index 000000000..db15ccfba Binary files /dev/null and b/assets/breakout/sprites/cho002.png differ diff --git a/assets/breakout/sprites/cho003.png b/assets/breakout/sprites/cho003.png new file mode 100644 index 000000000..480b087b1 Binary files /dev/null and b/assets/breakout/sprites/cho003.png differ diff --git a/assets/breakout/sprites/cho004.png b/assets/breakout/sprites/cho004.png new file mode 100644 index 000000000..d2c13e2e4 Binary files /dev/null and b/assets/breakout/sprites/cho004.png differ diff --git a/assets/breakout/sprites/rbmb000.png b/assets/breakout/sprites/rbmb000.png new file mode 100644 index 000000000..f7abcf52c Binary files /dev/null and b/assets/breakout/sprites/rbmb000.png differ diff --git a/assets/breakout/sprites/rbmb001.png b/assets/breakout/sprites/rbmb001.png new file mode 100644 index 000000000..7350db3ec Binary files /dev/null and b/assets/breakout/sprites/rbmb001.png differ diff --git a/assets/breakout/sprites/rbmb002.png b/assets/breakout/sprites/rbmb002.png new file mode 100644 index 000000000..448bb273b Binary files /dev/null and b/assets/breakout/sprites/rbmb002.png differ diff --git a/assets/breakout/tiles/brkTile004.png b/assets/breakout/tiles/brkTile004.png new file mode 100644 index 000000000..6728bdeb7 Binary files /dev/null and b/assets/breakout/tiles/brkTile004.png differ diff --git a/assets/breakout/tiles/brkTile005.png b/assets/breakout/tiles/brkTile005.png new file mode 100644 index 000000000..ba5ecffbe Binary files /dev/null and b/assets/breakout/tiles/brkTile005.png differ diff --git a/assets/breakout/tiles/brkTile006.png b/assets/breakout/tiles/brkTile006.png new file mode 100644 index 000000000..2aa9f925e Binary files /dev/null and b/assets/breakout/tiles/brkTile006.png differ diff --git a/assets/breakout/tiles/brkTile007.png b/assets/breakout/tiles/brkTile007.png new file mode 100644 index 000000000..0c37117c2 Binary files /dev/null and b/assets/breakout/tiles/brkTile007.png differ diff --git a/assets/breakout/tiles/brkTile028.png b/assets/breakout/tiles/brkTile028.png new file mode 100644 index 000000000..e27af4830 Binary files /dev/null and b/assets/breakout/tiles/brkTile028.png differ diff --git a/assets/breakout/tiles/brkTile056.png b/assets/breakout/tiles/brkTile056.png new file mode 100644 index 000000000..618f467e8 Binary files /dev/null and b/assets/breakout/tiles/brkTile056.png differ diff --git a/assets/breakout/tiles/brkTile057.png b/assets/breakout/tiles/brkTile057.png new file mode 100644 index 000000000..486b47f97 Binary files /dev/null and b/assets/breakout/tiles/brkTile057.png differ diff --git a/assets/breakout/tiles/brkTile104.png b/assets/breakout/tiles/brkTile104.png index 45ca8bdb2..486b47f97 100644 Binary files a/assets/breakout/tiles/brkTile104.png and b/assets/breakout/tiles/brkTile104.png differ diff --git a/assets/breakout/tiles/brkTile105.png b/assets/breakout/tiles/brkTile105.png index e2c70433b..a904e3cd8 100644 Binary files a/assets/breakout/tiles/brkTile105.png and b/assets/breakout/tiles/brkTile105.png differ diff --git a/assets/breakout/tiles/brkTile120.png b/assets/breakout/tiles/brkTile120.png index e7a62edce..3523c57c4 100644 Binary files a/assets/breakout/tiles/brkTile120.png and b/assets/breakout/tiles/brkTile120.png differ diff --git a/assets/breakout/tiles/brkTile121.png b/assets/breakout/tiles/brkTile121.png index 302434422..2a4cd7184 100644 Binary files a/assets/breakout/tiles/brkTile121.png and b/assets/breakout/tiles/brkTile121.png differ diff --git a/assets/credits.mid b/assets/credits.mid index 949583f2d..5dddb8d44 100644 Binary files a/assets/credits.mid and b/assets/credits.mid differ diff --git a/assets/menu/menu_bg.png b/assets/menu/menu_bg.png new file mode 100644 index 000000000..d0bfec0a8 Binary files /dev/null and b/assets/menu/menu_bg.png differ diff --git a/assets/menu/mnuArrow.png b/assets/menu/mnuArrow.png index ad5e4d7a9..7f20a3e0d 100644 Binary files a/assets/menu/mnuArrow.png and b/assets/menu/mnuArrow.png differ diff --git a/assets/menu/mnuArrowS.png b/assets/menu/mnuArrowS.png index b6735951f..6368f8a34 100644 Binary files a/assets/menu/mnuArrowS.png and b/assets/menu/mnuArrowS.png differ diff --git a/assets/menu/zip.png b/assets/menu/zip.png new file mode 100644 index 000000000..29063c956 Binary files /dev/null and b/assets/menu/zip.png differ diff --git a/assets/ray/doors/BG_DOOR.png b/assets/ray/doors/BG_DOOR.png index bfb6c033f..bc9d3512f 100644 Binary files a/assets/ray/doors/BG_DOOR.png and b/assets/ray/doors/BG_DOOR.png differ diff --git a/assets/ray/doors/BG_DOOR_ARTIFACT.png b/assets/ray/doors/BG_DOOR_ARTIFACT.png new file mode 100755 index 000000000..ca65f23a3 Binary files /dev/null and b/assets/ray/doors/BG_DOOR_ARTIFACT.png differ diff --git a/assets/ray/doors/BG_DOOR_CHARGE.png b/assets/ray/doors/BG_DOOR_CHARGE.png index e0742ef53..c0a68b08d 100644 Binary files a/assets/ray/doors/BG_DOOR_CHARGE.png and b/assets/ray/doors/BG_DOOR_CHARGE.png differ diff --git a/assets/ray/doors/BG_DOOR_ICE.png b/assets/ray/doors/BG_DOOR_ICE.png index 0bf576255..a2dac6653 100644 Binary files a/assets/ray/doors/BG_DOOR_ICE.png and b/assets/ray/doors/BG_DOOR_ICE.png differ diff --git a/assets/ray/doors/BG_DOOR_KEY_A.png b/assets/ray/doors/BG_DOOR_KEY_A.png index 0f670083f..66e6fb197 100644 Binary files a/assets/ray/doors/BG_DOOR_KEY_A.png and b/assets/ray/doors/BG_DOOR_KEY_A.png differ diff --git a/assets/ray/doors/BG_DOOR_KEY_B.png b/assets/ray/doors/BG_DOOR_KEY_B.png index 8afe14fcb..582433f5d 100644 Binary files a/assets/ray/doors/BG_DOOR_KEY_B.png and b/assets/ray/doors/BG_DOOR_KEY_B.png differ diff --git a/assets/ray/doors/BG_DOOR_KEY_C.png b/assets/ray/doors/BG_DOOR_KEY_C.png index 6328f75fa..b2baf58c6 100644 Binary files a/assets/ray/doors/BG_DOOR_KEY_C.png and b/assets/ray/doors/BG_DOOR_KEY_C.png differ diff --git a/assets/ray/doors/BG_DOOR_MISSILE.png b/assets/ray/doors/BG_DOOR_MISSILE.png index 8356a72f6..6af2d9eea 100644 Binary files a/assets/ray/doors/BG_DOOR_MISSILE.png and b/assets/ray/doors/BG_DOOR_MISSILE.png differ diff --git a/assets/ray/doors/BG_DOOR_SCRIPT.png b/assets/ray/doors/BG_DOOR_SCRIPT.png index ab5174adb..89547eda0 100644 Binary files a/assets/ray/doors/BG_DOOR_SCRIPT.png and b/assets/ray/doors/BG_DOOR_SCRIPT.png differ diff --git a/assets/ray/doors/BG_DOOR_XRAY.png b/assets/ray/doors/BG_DOOR_XRAY.png index 1ab397251..70f29c5fe 100644 Binary files a/assets/ray/doors/BG_DOOR_XRAY.png and b/assets/ray/doors/BG_DOOR_XRAY.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_0.png index 31e9a25c8..df4653bf5 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_0.png and b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_1.png index 977224659..5a9f1accf 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_1.png and b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_2.png index bf47d3285..15ef316dd 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_2.png and b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_3.png index f14690614..898e6c516 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_3.png and b/assets/ray/enemies/ARMORED/E_ARMORED_BLOCK_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_0.png index cfa766143..ff6b083ba 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_0.png and b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_1.png index ff9086353..5f0ee8947 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_1.png and b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_2.png index 7f00de898..7cdfed2c7 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_2.png and b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_3.png index c90c882f5..af2084c75 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_3.png and b/assets/ray/enemies/ARMORED/E_ARMORED_DEAD_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_0.png index 4b58b7171..aeb0b3789 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_0.png and b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_1.png index 5b011ff86..7d70d1c43 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_1.png and b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_2.png index 0108726f3..025d5d9a5 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_2.png and b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_3.png index 7d9270061..a83a32f57 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_HURT_3.png and b/assets/ray/enemies/ARMORED/E_ARMORED_HURT_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_0.png index 349a2d345..e490fa8ce 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_0.png and b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_1.png index 8c48ff2d8..cdbe4d27f 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_1.png and b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_2.png index dcad8c6a8..befc93b92 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_2.png and b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_3.png index 651c3a6db..778fa3d8a 100644 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_3.png and b/assets/ray/enemies/ARMORED/E_ARMORED_SHOOT_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0.png deleted file mode 100644 index 36fc87755..000000000 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_0.png new file mode 100644 index 000000000..5e07f3776 Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_1.png new file mode 100644 index 000000000..7acd0addc Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_2.png new file mode 100644 index 000000000..0baa4a50b Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_3.png new file mode 100644 index 000000000..26623fb49 Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1.png deleted file mode 100644 index b385ecf73..000000000 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_0.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_0.png new file mode 100644 index 000000000..2aa49d4f6 Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_0.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_1.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_1.png new file mode 100644 index 000000000..e518df84c Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_1.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_2.png new file mode 100644 index 000000000..60c8d4578 Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_2.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_3.png new file mode 100644 index 000000000..cea285ea8 Binary files /dev/null and b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_1_3.png differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_2.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_2.png deleted file mode 100644 index 9163ca4fe..000000000 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_3.png b/assets/ray/enemies/ARMORED/E_ARMORED_WALK_3.png deleted file mode 100644 index c5ddaeacd..000000000 Binary files a/assets/ray/enemies/ARMORED/E_ARMORED_WALK_3.png and /dev/null differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0.png index e3c330bb4..67694d410 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0.png and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_I.png new file mode 100755 index 000000000..0c48b037c Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_M.png new file mode 100755 index 000000000..26ca4e2c7 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_X.png new file mode 100755 index 000000000..583800b99 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1.png index 0478a3446..ef8ad20d5 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1.png and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_I.png new file mode 100755 index 000000000..f70f81cba Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_M.png new file mode 100755 index 000000000..e5ed0ca20 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_X.png new file mode 100755 index 000000000..ce0741ad6 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2.png index 28410823c..a50da1733 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2.png and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_I.png new file mode 100755 index 000000000..7eb55d9c5 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_M.png new file mode 100755 index 000000000..afd47ed8e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_X.png new file mode 100755 index 000000000..57f27d5cc Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3.png index 3e1b5d76c..cecdc79cb 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3.png and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_I.png new file mode 100755 index 000000000..c53fc62bc Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_M.png new file mode 100755 index 000000000..8703e5288 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_X.png new file mode 100755 index 000000000..1e2b816d0 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_BLOCK_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_0.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0.png index 61f9037a4..2a6cce59a 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_DEAD_0.png and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_I.png new file mode 100755 index 000000000..26c563c93 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_M.png new file mode 100755 index 000000000..03cba81fc Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_X.png new file mode 100755 index 000000000..60f51566d Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_1.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1.png index 2a3ae3a42..3138a3e56 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_DEAD_1.png and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_I.png new file mode 100755 index 000000000..4043a16af Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_M.png new file mode 100755 index 000000000..bc806450c Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_X.png new file mode 100755 index 000000000..cabf1d4a8 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_2.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2.png index b359450d0..b2badefdc 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_DEAD_2.png and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_I.png new file mode 100755 index 000000000..bb1009249 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_M.png new file mode 100755 index 000000000..845b46df7 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_X.png new file mode 100755 index 000000000..9f23eae8b Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_3.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3.png index 95ed72196..df108cb93 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_DEAD_3.png and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_I.png new file mode 100755 index 000000000..96d1d0d58 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_M.png new file mode 100755 index 000000000..5dd79f4ee Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_X.png new file mode 100755 index 000000000..f87cf1435 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_DEAD_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_0.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_0.png index 0b9f96448..f8571556b 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_HURT_0.png and b/assets/ray/enemies/BOSS/E_BOSS_HURT_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_I.png new file mode 100755 index 000000000..5cd6c6a30 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_M.png new file mode 100755 index 000000000..ab9d19801 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_X.png new file mode 100755 index 000000000..2db849398 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_1.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_1.png index 81fec7496..a24a0beb2 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_HURT_1.png and b/assets/ray/enemies/BOSS/E_BOSS_HURT_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_I.png new file mode 100755 index 000000000..a3221f59b Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_M.png new file mode 100755 index 000000000..bca713d62 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_X.png new file mode 100755 index 000000000..13f75e4e7 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_2.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_2.png index 4e319e7ec..094541853 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_HURT_2.png and b/assets/ray/enemies/BOSS/E_BOSS_HURT_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_I.png new file mode 100755 index 000000000..8239b8f22 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_M.png new file mode 100755 index 000000000..fa388d93c Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_X.png new file mode 100755 index 000000000..046a72c55 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_3.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_3.png index af711c58d..5437067a3 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_HURT_3.png and b/assets/ray/enemies/BOSS/E_BOSS_HURT_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_I.png new file mode 100755 index 000000000..9f6dc0f6d Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_M.png new file mode 100755 index 000000000..d00b6047f Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_HURT_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_X.png new file mode 100755 index 000000000..472f76cfe Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_HURT_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0.png index 618dfadd1..e5be1e18f 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0.png and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_I.png new file mode 100755 index 000000000..9090da647 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_M.png new file mode 100755 index 000000000..975d4052e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_X.png new file mode 100755 index 000000000..49417abda Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1.png index 780d23e56..c945e9690 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1.png and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_I.png new file mode 100755 index 000000000..333cacddc Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_M.png new file mode 100755 index 000000000..df6c72381 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_X.png new file mode 100755 index 000000000..384991bf6 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2.png index 27b8dba82..685a0a508 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2.png and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_I.png new file mode 100755 index 000000000..7523b4d19 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_M.png new file mode 100755 index 000000000..0eb43f6ef Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_X.png new file mode 100755 index 000000000..8f652847e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3.png index 7d7a8ec2a..26e894bb0 100644 Binary files a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3.png and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_I.png new file mode 100755 index 000000000..ab23a14a8 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_M.png new file mode 100755 index 000000000..806926c4a Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_X.png new file mode 100755 index 000000000..5581afa18 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_SHOOT_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0.png deleted file mode 100644 index 4b3e09d99..000000000 Binary files a/assets/ray/enemies/BOSS/E_BOSS_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0.png new file mode 100644 index 000000000..83b70032c Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_I.png new file mode 100644 index 000000000..5436f3e0e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_M.png new file mode 100644 index 000000000..dc58a6831 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_X.png new file mode 100644 index 000000000..ee04883ab Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1.png new file mode 100644 index 000000000..a25f78635 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_I.png new file mode 100644 index 000000000..fbd334555 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_M.png new file mode 100644 index 000000000..b2bc0c1db Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_X.png new file mode 100644 index 000000000..f94db774f Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2.png new file mode 100644 index 000000000..0297fc067 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_I.png new file mode 100644 index 000000000..37bafc1e2 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_M.png new file mode 100644 index 000000000..63a304c74 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_X.png new file mode 100644 index 000000000..f721604a5 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3.png new file mode 100644 index 000000000..633ee9111 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_I.png new file mode 100644 index 000000000..41e0b2ae9 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_M.png new file mode 100644 index 000000000..bad92abd2 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_X.png new file mode 100644 index 000000000..ef3db77ae Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_0_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1.png deleted file mode 100644 index aa03364d1..000000000 Binary files a/assets/ray/enemies/BOSS/E_BOSS_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0.png new file mode 100644 index 000000000..b8f68e9bf Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_I.png new file mode 100644 index 000000000..080a6c19e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_M.png new file mode 100644 index 000000000..56e965470 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_X.png new file mode 100644 index 000000000..b781d6b57 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_0_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1.png new file mode 100644 index 000000000..04bc91df0 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_I.png new file mode 100644 index 000000000..80cc27696 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_M.png new file mode 100644 index 000000000..00f4df819 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_X.png new file mode 100644 index 000000000..053b80254 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_1_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2.png new file mode 100644 index 000000000..f8049ad2e Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_I.png new file mode 100644 index 000000000..a4631eb40 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_M.png new file mode 100644 index 000000000..cae52ab06 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_X.png new file mode 100644 index 000000000..bae83f963 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_2_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3.png new file mode 100644 index 000000000..6ad852133 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_I.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_I.png new file mode 100644 index 000000000..124cb83d9 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_I.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_M.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_M.png new file mode 100644 index 000000000..573626de6 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_M.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_X.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_X.png new file mode 100644 index 000000000..762fd8ba4 Binary files /dev/null and b/assets/ray/enemies/BOSS/E_BOSS_WALK_1_3_X.png differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_2.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_2.png deleted file mode 100644 index e2c9be371..000000000 Binary files a/assets/ray/enemies/BOSS/E_BOSS_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/BOSS/E_BOSS_WALK_3.png b/assets/ray/enemies/BOSS/E_BOSS_WALK_3.png deleted file mode 100644 index fa44afc80..000000000 Binary files a/assets/ray/enemies/BOSS/E_BOSS_WALK_3.png and /dev/null differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_0.png index 8de1325ae..53f81e554 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_0.png and b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_1.png index a8f390545..ed86074ae 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_1.png and b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_2.png index bd20ae6df..a5176fb30 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_2.png and b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_3.png index 3d611137e..65855e391 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_3.png and b/assets/ray/enemies/FLAMING/E_FLAMING_BLOCK_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_0.png index 333cd3422..1af353704 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_0.png and b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_1.png index 3d55ddea2..938b96ee3 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_1.png and b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_2.png index 41e183ca9..97ec10789 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_2.png and b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_3.png index f38931f40..fa3915d44 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_3.png and b/assets/ray/enemies/FLAMING/E_FLAMING_DEAD_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_0.png index 1559f3a0d..ac5ca67fc 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_0.png and b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_1.png index 1b3281aa9..cb17a7b51 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_1.png and b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_2.png index c2ae48493..a09c9fb46 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_2.png and b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_3.png index 97d49a581..970439a9a 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_HURT_3.png and b/assets/ray/enemies/FLAMING/E_FLAMING_HURT_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_0.png index edfef4e46..b5696f8a3 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_0.png and b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_1.png index 13b7a15c1..42466ab44 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_1.png and b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_2.png index bd49410a5..748aae243 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_2.png and b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_3.png index 8f8a1f32b..97a40f509 100644 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_3.png and b/assets/ray/enemies/FLAMING/E_FLAMING_SHOOT_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0.png deleted file mode 100644 index 7e5f61880..000000000 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_0.png new file mode 100644 index 000000000..6098308de Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_1.png new file mode 100644 index 000000000..b86685e03 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_2.png new file mode 100644 index 000000000..a470d9fc4 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_3.png new file mode 100644 index 000000000..2bef874f9 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1.png deleted file mode 100644 index 04fe0c55f..000000000 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_0.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_0.png new file mode 100644 index 000000000..5befafef5 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_0.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_1.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_1.png new file mode 100644 index 000000000..3804abe47 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_1.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_2.png new file mode 100644 index 000000000..aa1e11c41 Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_2.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_3.png new file mode 100644 index 000000000..bf3e6db6a Binary files /dev/null and b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_1_3.png differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_2.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_2.png deleted file mode 100644 index dcb86551b..000000000 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_3.png b/assets/ray/enemies/FLAMING/E_FLAMING_WALK_3.png deleted file mode 100644 index f7289e579..000000000 Binary files a/assets/ray/enemies/FLAMING/E_FLAMING_WALK_3.png and /dev/null differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0.png index 886b99425..c0c8482c8 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0_X.png new file mode 100755 index 000000000..af036891a Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1.png index 08706c67d..5cc9e44ac 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1_X.png new file mode 100755 index 000000000..a6b160c18 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2.png index d1a1f7feb..7183dda69 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2_X.png new file mode 100755 index 000000000..26f10c716 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3.png index 7ff5baba9..a08edda23 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3_X.png new file mode 100755 index 000000000..11c595b4c Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_BLOCK_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0.png index 99608be29..82eebacbe 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0_X.png new file mode 100755 index 000000000..6202b1a12 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1.png index 90831eb9c..c2ad1498b 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1_X.png new file mode 100755 index 000000000..e54dec4b0 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2.png index 7cbb33ccc..4d7af620d 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2_X.png new file mode 100755 index 000000000..3f86154f5 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3.png index e8cb07597..f9d07ba54 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3_X.png new file mode 100755 index 000000000..561d2c375 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_DEAD_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0.png index 9ab462b87..d44102f17 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0_X.png new file mode 100755 index 000000000..c44cb4990 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1.png index 7e069171c..c322515f0 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1_X.png new file mode 100755 index 000000000..1a8201a7f Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2.png index 51e8ed4b3..0b5ab7dc7 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2_X.png new file mode 100755 index 000000000..cfd153815 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3.png index 43596a4a1..e493ffab5 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3_X.png new file mode 100755 index 000000000..b15442df5 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_HURT_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0.png index 1f717d044..9259fd8d1 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0_X.png new file mode 100755 index 000000000..fdb4c7407 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1.png index 8ea68ecdb..4953d3cee 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1_X.png new file mode 100755 index 000000000..72bf1eb03 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2.png index b61d233c7..40f3d982f 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2_X.png new file mode 100755 index 000000000..a5429dd4a Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3.png index 97df48cf8..e996a5ebc 100644 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3.png and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3_X.png new file mode 100755 index 000000000..e722b2ef9 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_SHOOT_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0.png deleted file mode 100644 index c88b9ca77..000000000 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0.png new file mode 100644 index 000000000..b3b5589f4 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0_X.png new file mode 100644 index 000000000..7407abbd4 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1.png new file mode 100644 index 000000000..cc84d325a Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1_X.png new file mode 100644 index 000000000..24f42bf0c Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2.png new file mode 100644 index 000000000..b757818b6 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2_X.png new file mode 100644 index 000000000..65eac1d83 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3.png new file mode 100644 index 000000000..db95df765 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3_X.png new file mode 100644 index 000000000..a12fe88dd Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1.png deleted file mode 100644 index 1f656adc0..000000000 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0.png new file mode 100644 index 000000000..e46d1253b Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0_X.png new file mode 100644 index 000000000..fed735883 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_0_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1.png new file mode 100644 index 000000000..564bc9454 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1_X.png new file mode 100644 index 000000000..2bafced08 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_1_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2.png new file mode 100644 index 000000000..1e801658a Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2_X.png new file mode 100644 index 000000000..8eccf4342 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_2_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3.png new file mode 100644 index 000000000..534e2f11a Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3_X.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3_X.png new file mode 100644 index 000000000..fd0558e35 Binary files /dev/null and b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_1_3_X.png differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_2.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_2.png deleted file mode 100644 index bf5d20505..000000000 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_3.png b/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_3.png deleted file mode 100644 index e9dd7a000..000000000 Binary files a/assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_3.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_0.png index aee9a6f10..db78581c8 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_0.png and b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_1.png index 3399aa717..957b0fb44 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_1.png and b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_2.png index 213c7e7f7..256b56bc6 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_2.png and b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_3.png index 502c59d12..b8fd44695 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_3.png and b/assets/ray/enemies/NORMAL/E_NORMAL_BLOCK_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_0.png index 11e88733e..7dd9afb31 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_0.png and b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_1.png index 8b24c4899..bd1ae61a6 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_1.png and b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_2.png index 81b297246..54ace82f5 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_2.png and b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_3.png index a2dfe2f71..7f339fd75 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_3.png and b/assets/ray/enemies/NORMAL/E_NORMAL_DEAD_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_0.png index 3d4a212d6..4592b3510 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_0.png and b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_1.png index fde21c533..520d0e891 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_1.png and b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_2.png index 692fd5a81..ad639e881 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_2.png and b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_3.png index 24ef231b2..f0a01a485 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_HURT_3.png and b/assets/ray/enemies/NORMAL/E_NORMAL_HURT_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_0.png index c36d04d30..3e6c0de67 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_0.png and b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_1.png index 5cd92e6a5..55f4aa3d6 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_1.png and b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_2.png index 722dcc5e2..1163c9bb9 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_2.png and b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_3.png index f05771f02..d523986d6 100644 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_3.png and b/assets/ray/enemies/NORMAL/E_NORMAL_SHOOT_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0.png deleted file mode 100644 index 34d911bac..000000000 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_0.png new file mode 100644 index 000000000..9e906d771 Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_1.png new file mode 100644 index 000000000..bafce486b Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_2.png new file mode 100644 index 000000000..0e8d4e12c Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_3.png new file mode 100644 index 000000000..14281d1a4 Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1.png deleted file mode 100644 index d37f3b608..000000000 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_0.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_0.png new file mode 100644 index 000000000..7ef2e4032 Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_0.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_1.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_1.png new file mode 100644 index 000000000..794f6ebfa Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_1.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_2.png new file mode 100644 index 000000000..0f9cc3ffa Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_2.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_3.png new file mode 100644 index 000000000..69c74f702 Binary files /dev/null and b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_1_3.png differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_2.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_2.png deleted file mode 100644 index 6e987250e..000000000 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_3.png b/assets/ray/enemies/NORMAL/E_NORMAL_WALK_3.png deleted file mode 100644 index a54e339fc..000000000 Binary files a/assets/ray/enemies/NORMAL/E_NORMAL_WALK_3.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/GUN_NORMAL.png b/assets/ray/enemies/NORMAL/GUN_NORMAL.png deleted file mode 100644 index 34d66e758..000000000 Binary files a/assets/ray/enemies/NORMAL/GUN_NORMAL.png and /dev/null differ diff --git a/assets/ray/enemies/NORMAL/OBJ_BULLET_NORMAL.png b/assets/ray/enemies/NORMAL/OBJ_BULLET_NORMAL.png deleted file mode 100644 index d4e807895..000000000 Binary files a/assets/ray/enemies/NORMAL/OBJ_BULLET_NORMAL.png and /dev/null differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_0.png b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_0.png index 16f44c708..99f708abb 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_0.png and b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_1.png b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_1.png index b14843012..74d2c07ae 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_1.png and b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_2.png b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_2.png index acb3d99c4..86b7ed48c 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_2.png and b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_3.png b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_3.png index 23def2ff2..ead3b6805 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_BLOCK_3.png and b/assets/ray/enemies/STRONG/E_STRONG_BLOCK_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_DEAD_0.png b/assets/ray/enemies/STRONG/E_STRONG_DEAD_0.png index fd9a40e0b..fccefcd6c 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_DEAD_0.png and b/assets/ray/enemies/STRONG/E_STRONG_DEAD_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_DEAD_1.png b/assets/ray/enemies/STRONG/E_STRONG_DEAD_1.png index 296c0fa6b..320f00e67 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_DEAD_1.png and b/assets/ray/enemies/STRONG/E_STRONG_DEAD_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_DEAD_2.png b/assets/ray/enemies/STRONG/E_STRONG_DEAD_2.png index 47443a094..1196d7e9c 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_DEAD_2.png and b/assets/ray/enemies/STRONG/E_STRONG_DEAD_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_DEAD_3.png b/assets/ray/enemies/STRONG/E_STRONG_DEAD_3.png index 75b85ea64..5415e5c0b 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_DEAD_3.png and b/assets/ray/enemies/STRONG/E_STRONG_DEAD_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_HURT_0.png b/assets/ray/enemies/STRONG/E_STRONG_HURT_0.png index 4592eb023..f947c6a22 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_HURT_0.png and b/assets/ray/enemies/STRONG/E_STRONG_HURT_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_HURT_1.png b/assets/ray/enemies/STRONG/E_STRONG_HURT_1.png index caac5220d..e27727da5 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_HURT_1.png and b/assets/ray/enemies/STRONG/E_STRONG_HURT_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_HURT_2.png b/assets/ray/enemies/STRONG/E_STRONG_HURT_2.png index 79de6e23b..39b93a9d2 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_HURT_2.png and b/assets/ray/enemies/STRONG/E_STRONG_HURT_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_HURT_3.png b/assets/ray/enemies/STRONG/E_STRONG_HURT_3.png index ac1118fc9..df6ef3607 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_HURT_3.png and b/assets/ray/enemies/STRONG/E_STRONG_HURT_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_0.png b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_0.png index e5cdd8ccf..b0cc5e65c 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_0.png and b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_1.png b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_1.png index 2da665636..ed87274b7 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_1.png and b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_2.png b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_2.png index 757a61f62..8c34aced6 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_2.png and b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_3.png b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_3.png index 39119f748..7b72d05ef 100644 Binary files a/assets/ray/enemies/STRONG/E_STRONG_SHOOT_3.png and b/assets/ray/enemies/STRONG/E_STRONG_SHOOT_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_0.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_0.png deleted file mode 100644 index 97c2f1e15..000000000 Binary files a/assets/ray/enemies/STRONG/E_STRONG_WALK_0.png and /dev/null differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_0_0.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_0.png new file mode 100644 index 000000000..f4e940d04 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_0_1.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_1.png new file mode 100644 index 000000000..cd42a0689 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_0_2.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_2.png new file mode 100644 index 000000000..e02e3ad72 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_0_3.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_3.png new file mode 100644 index 000000000..e260241b7 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_0_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_1.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_1.png deleted file mode 100644 index e0ec7c59e..000000000 Binary files a/assets/ray/enemies/STRONG/E_STRONG_WALK_1.png and /dev/null differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_1_0.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_0.png new file mode 100644 index 000000000..e3a2e2480 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_0.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_1_1.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_1.png new file mode 100644 index 000000000..258afb606 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_1.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_1_2.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_2.png new file mode 100644 index 000000000..8b5a59040 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_2.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_1_3.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_3.png new file mode 100644 index 000000000..1e120f5c8 Binary files /dev/null and b/assets/ray/enemies/STRONG/E_STRONG_WALK_1_3.png differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_2.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_2.png deleted file mode 100644 index 4ab172f71..000000000 Binary files a/assets/ray/enemies/STRONG/E_STRONG_WALK_2.png and /dev/null differ diff --git a/assets/ray/enemies/STRONG/E_STRONG_WALK_3.png b/assets/ray/enemies/STRONG/E_STRONG_WALK_3.png deleted file mode 100644 index a75a21545..000000000 Binary files a/assets/ray/enemies/STRONG/E_STRONG_WALK_3.png and /dev/null differ diff --git a/assets/ray/env/BASE/BG_BASE_CEILING.png b/assets/ray/env/BASE/BG_BASE_CEILING.png new file mode 100644 index 000000000..8ae3aee8b Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_CEILING.png differ diff --git a/assets/ray/env/BASE/BG_BASE_FLOOR.png b/assets/ray/env/BASE/BG_BASE_FLOOR.png new file mode 100644 index 000000000..e1de173c1 Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_FLOOR.png differ diff --git a/assets/ray/env/BASE/BG_BASE_WALL_1.png b/assets/ray/env/BASE/BG_BASE_WALL_1.png new file mode 100644 index 000000000..21c006ddd Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_WALL_1.png differ diff --git a/assets/ray/env/BASE/BG_BASE_WALL_2.png b/assets/ray/env/BASE/BG_BASE_WALL_2.png new file mode 100644 index 000000000..980bf09f9 Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_WALL_2.png differ diff --git a/assets/ray/env/BASE/BG_BASE_WALL_3.png b/assets/ray/env/BASE/BG_BASE_WALL_3.png new file mode 100644 index 000000000..221393628 Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_WALL_3.png differ diff --git a/assets/ray/env/BASE/BG_BASE_WALL_4.png b/assets/ray/env/BASE/BG_BASE_WALL_4.png new file mode 100644 index 000000000..3bbd2e2ae Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_WALL_4.png differ diff --git a/assets/ray/env/BASE/BG_BASE_WALL_5.png b/assets/ray/env/BASE/BG_BASE_WALL_5.png new file mode 100644 index 000000000..66ed76230 Binary files /dev/null and b/assets/ray/env/BASE/BG_BASE_WALL_5.png differ diff --git a/assets/ray/env/BG_CEILING.png b/assets/ray/env/BG_CEILING.png deleted file mode 100644 index 71d6bc1c4..000000000 Binary files a/assets/ray/env/BG_CEILING.png and /dev/null differ diff --git a/assets/ray/env/BG_FLOOR.png b/assets/ray/env/BG_FLOOR.png deleted file mode 100644 index 6e6ba3fb7..000000000 Binary files a/assets/ray/env/BG_FLOOR.png and /dev/null differ diff --git a/assets/ray/env/BG_FLOOR_HEAL.png b/assets/ray/env/BG_FLOOR_HEAL.png new file mode 100644 index 000000000..4e118c6c6 Binary files /dev/null and b/assets/ray/env/BG_FLOOR_HEAL.png differ diff --git a/assets/ray/env/BG_WALL_1.png b/assets/ray/env/BG_WALL_1.png deleted file mode 100644 index 7ea986ff8..000000000 Binary files a/assets/ray/env/BG_WALL_1.png and /dev/null differ diff --git a/assets/ray/env/BG_WALL_2.png b/assets/ray/env/BG_WALL_2.png deleted file mode 100644 index f27cec50e..000000000 Binary files a/assets/ray/env/BG_WALL_2.png and /dev/null differ diff --git a/assets/ray/env/BG_WALL_3.png b/assets/ray/env/BG_WALL_3.png deleted file mode 100644 index 26b520234..000000000 Binary files a/assets/ray/env/BG_WALL_3.png and /dev/null differ diff --git a/assets/ray/env/BG_WALL_4.png b/assets/ray/env/BG_WALL_4.png deleted file mode 100644 index a9678c2c9..000000000 Binary files a/assets/ray/env/BG_WALL_4.png and /dev/null differ diff --git a/assets/ray/env/BG_WALL_5.png b/assets/ray/env/BG_WALL_5.png deleted file mode 100644 index 48ddda7de..000000000 Binary files a/assets/ray/env/BG_WALL_5.png and /dev/null differ diff --git a/assets/ray/env/CAVE/BG_CAVE_CEILING.png b/assets/ray/env/CAVE/BG_CAVE_CEILING.png new file mode 100644 index 000000000..8683110c1 Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_CEILING.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_FLOOR.png b/assets/ray/env/CAVE/BG_CAVE_FLOOR.png new file mode 100644 index 000000000..065650128 Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_FLOOR.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_WALL_1.png b/assets/ray/env/CAVE/BG_CAVE_WALL_1.png new file mode 100644 index 000000000..599fe756e Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_WALL_1.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_WALL_2.png b/assets/ray/env/CAVE/BG_CAVE_WALL_2.png new file mode 100644 index 000000000..cbdfe0e9a Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_WALL_2.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_WALL_3.png b/assets/ray/env/CAVE/BG_CAVE_WALL_3.png new file mode 100644 index 000000000..cac7bce65 Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_WALL_3.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_WALL_4.png b/assets/ray/env/CAVE/BG_CAVE_WALL_4.png new file mode 100644 index 000000000..365f6677a Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_WALL_4.png differ diff --git a/assets/ray/env/CAVE/BG_CAVE_WALL_5.png b/assets/ray/env/CAVE/BG_CAVE_WALL_5.png new file mode 100644 index 000000000..db4dbfc21 Binary files /dev/null and b/assets/ray/env/CAVE/BG_CAVE_WALL_5.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_CEILING.png b/assets/ray/env/JUNGLE/BG_JUNGLE_CEILING.png new file mode 100644 index 000000000..4a1423ee7 Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_CEILING.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_FLOOR.png b/assets/ray/env/JUNGLE/BG_JUNGLE_FLOOR.png new file mode 100644 index 000000000..564e33fc9 Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_FLOOR.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_1.png b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_1.png new file mode 100644 index 000000000..24e62833a Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_1.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_2.png b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_2.png new file mode 100644 index 000000000..0480f6c43 Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_2.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_3.png b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_3.png new file mode 100644 index 000000000..2c73fbd17 Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_3.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_4.png b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_4.png new file mode 100644 index 000000000..41e61abdf Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_4.png differ diff --git a/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_5.png b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_5.png new file mode 100644 index 000000000..c21f277c7 Binary files /dev/null and b/assets/ray/env/JUNGLE/BG_JUNGLE_WALL_5.png differ diff --git a/assets/ray/env/test/ICE_FLOOR.png b/assets/ray/env/test/ICE_FLOOR.png deleted file mode 100644 index e69f619b9..000000000 Binary files a/assets/ray/env/test/ICE_FLOOR.png and /dev/null differ diff --git a/assets/ray/env/test/ICE_WALL.png b/assets/ray/env/test/ICE_WALL.png deleted file mode 100644 index aac2669ea..000000000 Binary files a/assets/ray/env/test/ICE_WALL.png and /dev/null differ diff --git a/assets/ray/env/test/JUN_FLOOR.png b/assets/ray/env/test/JUN_FLOOR.png deleted file mode 100644 index bbae33838..000000000 Binary files a/assets/ray/env/test/JUN_FLOOR.png and /dev/null differ diff --git a/assets/ray/env/test/JUN_WALL.png b/assets/ray/env/test/JUN_WALL.png deleted file mode 100644 index 902483786..000000000 Binary files a/assets/ray/env/test/JUN_WALL.png and /dev/null differ diff --git a/assets/ray/env/test/LAV_FLOOR.png b/assets/ray/env/test/LAV_FLOOR.png deleted file mode 100644 index 1e227ef4c..000000000 Binary files a/assets/ray/env/test/LAV_FLOOR.png and /dev/null differ diff --git a/assets/ray/env/test/LAV_WALL.png b/assets/ray/env/test/LAV_WALL.png deleted file mode 100644 index 2d0342f82..000000000 Binary files a/assets/ray/env/test/LAV_WALL.png and /dev/null differ diff --git a/assets/ray/env/test/SPA_FLOOR.png b/assets/ray/env/test/SPA_FLOOR.png deleted file mode 100644 index 7695feb82..000000000 Binary files a/assets/ray/env/test/SPA_FLOOR.png and /dev/null differ diff --git a/assets/ray/env/test/SPA_WALL.png b/assets/ray/env/test/SPA_WALL.png deleted file mode 100644 index 7d53f058c..000000000 Binary files a/assets/ray/env/test/SPA_WALL.png and /dev/null differ diff --git a/assets/ray/friends/OBJ_SCENERY_F1.png b/assets/ray/friends/OBJ_SCENERY_F1.png new file mode 100644 index 000000000..efb0262a5 Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F1.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F2.png b/assets/ray/friends/OBJ_SCENERY_F2.png new file mode 100644 index 000000000..a4f2478c5 Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F2.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F3.png b/assets/ray/friends/OBJ_SCENERY_F3.png new file mode 100644 index 000000000..44a81d3ec Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F3.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F4.png b/assets/ray/friends/OBJ_SCENERY_F4.png new file mode 100644 index 000000000..edb80d829 Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F4.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F5.png b/assets/ray/friends/OBJ_SCENERY_F5.png new file mode 100644 index 000000000..9cb5bf091 Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F5.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F6.png b/assets/ray/friends/OBJ_SCENERY_F6.png new file mode 100644 index 000000000..64ce5ab7e Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F6.png differ diff --git a/assets/ray/friends/OBJ_SCENERY_F7.png b/assets/ray/friends/OBJ_SCENERY_F7.png new file mode 100644 index 000000000..ac2b1625c Binary files /dev/null and b/assets/ray/friends/OBJ_SCENERY_F7.png differ diff --git a/assets/ray/guns/GUN_ICE.png b/assets/ray/guns/GUN_ICE.png index 76f98df1d..9767eb3c8 100644 Binary files a/assets/ray/guns/GUN_ICE.png and b/assets/ray/guns/GUN_ICE.png differ diff --git a/assets/ray/guns/GUN_MISSILE.png b/assets/ray/guns/GUN_MISSILE.png index 0048bb0f4..6c0ceecc5 100644 Binary files a/assets/ray/guns/GUN_MISSILE.png and b/assets/ray/guns/GUN_MISSILE.png differ diff --git a/assets/ray/guns/GUN_NORMAL.png b/assets/ray/guns/GUN_NORMAL.png new file mode 100644 index 000000000..11ff687e6 Binary files /dev/null and b/assets/ray/guns/GUN_NORMAL.png differ diff --git a/assets/ray/guns/GUN_XRAY.png b/assets/ray/guns/GUN_XRAY.png index 6cb5c6d33..4a1ccf78e 100644 Binary files a/assets/ray/guns/GUN_XRAY.png and b/assets/ray/guns/GUN_XRAY.png differ diff --git a/assets/ray/guns/HUD_MISSILE.png b/assets/ray/guns/HUD_MISSILE.png new file mode 100644 index 000000000..b7d4c6344 Binary files /dev/null and b/assets/ray/guns/HUD_MISSILE.png differ diff --git a/assets/ray/guns/OBJ_BULLET_CHARGE.png b/assets/ray/guns/OBJ_BULLET_CHARGE.png index ecfc9e712..f12af3b3b 100644 Binary files a/assets/ray/guns/OBJ_BULLET_CHARGE.png and b/assets/ray/guns/OBJ_BULLET_CHARGE.png differ diff --git a/assets/ray/guns/OBJ_BULLET_E_ARMOR.png b/assets/ray/guns/OBJ_BULLET_E_ARMOR.png new file mode 100644 index 000000000..36f8d7754 Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_E_ARMOR.png differ diff --git a/assets/ray/guns/OBJ_BULLET_E_FLAMING.png b/assets/ray/guns/OBJ_BULLET_E_FLAMING.png new file mode 100644 index 000000000..b1fcd04a6 Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_E_FLAMING.png differ diff --git a/assets/ray/guns/OBJ_BULLET_E_HIDDEN.png b/assets/ray/guns/OBJ_BULLET_E_HIDDEN.png new file mode 100644 index 000000000..79bec5d86 Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_E_HIDDEN.png differ diff --git a/assets/ray/guns/OBJ_BULLET_E_NORMAL.png b/assets/ray/guns/OBJ_BULLET_E_NORMAL.png new file mode 100644 index 000000000..39326749a Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_E_NORMAL.png differ diff --git a/assets/ray/guns/OBJ_BULLET_E_STRONG.png b/assets/ray/guns/OBJ_BULLET_E_STRONG.png new file mode 100644 index 000000000..e16bfecf7 Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_E_STRONG.png differ diff --git a/assets/ray/guns/OBJ_BULLET_ICE.png b/assets/ray/guns/OBJ_BULLET_ICE.png index 567cc0425..a7053e2ca 100644 Binary files a/assets/ray/guns/OBJ_BULLET_ICE.png and b/assets/ray/guns/OBJ_BULLET_ICE.png differ diff --git a/assets/ray/guns/OBJ_BULLET_MISSILE.png b/assets/ray/guns/OBJ_BULLET_MISSILE.png index 8115b6fba..56af51824 100644 Binary files a/assets/ray/guns/OBJ_BULLET_MISSILE.png and b/assets/ray/guns/OBJ_BULLET_MISSILE.png differ diff --git a/assets/ray/guns/OBJ_BULLET_NORMAL.png b/assets/ray/guns/OBJ_BULLET_NORMAL.png new file mode 100644 index 000000000..fbc56ef54 Binary files /dev/null and b/assets/ray/guns/OBJ_BULLET_NORMAL.png differ diff --git a/assets/ray/guns/OBJ_BULLET_XRAY.png b/assets/ray/guns/OBJ_BULLET_XRAY.png index c8b9294d0..c82ad5dc8 100644 Binary files a/assets/ray/guns/OBJ_BULLET_XRAY.png and b/assets/ray/guns/OBJ_BULLET_XRAY.png differ diff --git a/assets/ray/items/OBJ_ITEM_BEAM.png b/assets/ray/items/OBJ_ITEM_BEAM.png index 9f919f7a6..50fe13239 100644 Binary files a/assets/ray/items/OBJ_ITEM_BEAM.png and b/assets/ray/items/OBJ_ITEM_BEAM.png differ diff --git a/assets/ray/items/OBJ_ITEM_CHARGE_BEAM.png b/assets/ray/items/OBJ_ITEM_CHARGE_BEAM.png index 66b75495a..1e30d6bec 100644 Binary files a/assets/ray/items/OBJ_ITEM_CHARGE_BEAM.png and b/assets/ray/items/OBJ_ITEM_CHARGE_BEAM.png differ diff --git a/assets/ray/items/OBJ_ITEM_ENERGY_TANK.png b/assets/ray/items/OBJ_ITEM_ENERGY_TANK.png index a16e04dca..72ab02bd9 100644 Binary files a/assets/ray/items/OBJ_ITEM_ENERGY_TANK.png and b/assets/ray/items/OBJ_ITEM_ENERGY_TANK.png differ diff --git a/assets/ray/items/OBJ_ITEM_ICE.png b/assets/ray/items/OBJ_ITEM_ICE.png index 9d7977e8d..239c88cee 100644 Binary files a/assets/ray/items/OBJ_ITEM_ICE.png and b/assets/ray/items/OBJ_ITEM_ICE.png differ diff --git a/assets/ray/items/OBJ_ITEM_KEY_A.png b/assets/ray/items/OBJ_ITEM_KEY_A.png index 1faf1f2f6..55bb3caf5 100644 Binary files a/assets/ray/items/OBJ_ITEM_KEY_A.png and b/assets/ray/items/OBJ_ITEM_KEY_A.png differ diff --git a/assets/ray/items/OBJ_ITEM_KEY_B.png b/assets/ray/items/OBJ_ITEM_KEY_B.png index c5ec0546e..3c7c4df8a 100644 Binary files a/assets/ray/items/OBJ_ITEM_KEY_B.png and b/assets/ray/items/OBJ_ITEM_KEY_B.png differ diff --git a/assets/ray/items/OBJ_ITEM_KEY_C.png b/assets/ray/items/OBJ_ITEM_KEY_C.png index cb3383200..1006592be 100644 Binary files a/assets/ray/items/OBJ_ITEM_KEY_C.png and b/assets/ray/items/OBJ_ITEM_KEY_C.png differ diff --git a/assets/ray/items/OBJ_ITEM_MISSILE.png b/assets/ray/items/OBJ_ITEM_MISSILE.png index b04a0ab95..a22e0f238 100644 Binary files a/assets/ray/items/OBJ_ITEM_MISSILE.png and b/assets/ray/items/OBJ_ITEM_MISSILE.png differ diff --git a/assets/ray/items/OBJ_ITEM_PICKUP_ENERGY.png b/assets/ray/items/OBJ_ITEM_PICKUP_ENERGY.png index d733b5c9e..4b822b069 100644 Binary files a/assets/ray/items/OBJ_ITEM_PICKUP_ENERGY.png and b/assets/ray/items/OBJ_ITEM_PICKUP_ENERGY.png differ diff --git a/assets/ray/items/OBJ_ITEM_PICKUP_MISSILE.png b/assets/ray/items/OBJ_ITEM_PICKUP_MISSILE.png index 90fea127f..ccc04dfc2 100644 Binary files a/assets/ray/items/OBJ_ITEM_PICKUP_MISSILE.png and b/assets/ray/items/OBJ_ITEM_PICKUP_MISSILE.png differ diff --git a/assets/ray/items/OBJ_ITEM_SUIT_LAVA.png b/assets/ray/items/OBJ_ITEM_SUIT_LAVA.png index 40077e6c9..eaecf0a20 100644 Binary files a/assets/ray/items/OBJ_ITEM_SUIT_LAVA.png and b/assets/ray/items/OBJ_ITEM_SUIT_LAVA.png differ diff --git a/assets/ray/items/OBJ_ITEM_SUIT_WATER.png b/assets/ray/items/OBJ_ITEM_SUIT_WATER.png index 5c286df58..f180b7904 100644 Binary files a/assets/ray/items/OBJ_ITEM_SUIT_WATER.png and b/assets/ray/items/OBJ_ITEM_SUIT_WATER.png differ diff --git a/assets/ray/items/OBJ_ITEM_XRAY.png b/assets/ray/items/OBJ_ITEM_XRAY.png index 84efd8d7a..d28599ae2 100644 Binary files a/assets/ray/items/OBJ_ITEM_XRAY.png and b/assets/ray/items/OBJ_ITEM_XRAY.png differ diff --git a/assets/ray/maps/0.rmd b/assets/ray/maps/0.rmd index d453b50d0..a9917fb37 100755 Binary files a/assets/ray/maps/0.rmd and b/assets/ray/maps/0.rmd differ diff --git a/assets/ray/maps/1.rmd b/assets/ray/maps/1.rmd index fac6c6ba3..0f622e272 100755 Binary files a/assets/ray/maps/1.rmd and b/assets/ray/maps/1.rmd differ diff --git a/assets/ray/maps/2.rmd b/assets/ray/maps/2.rmd index 37a8175d2..fa5a0e452 100755 Binary files a/assets/ray/maps/2.rmd and b/assets/ray/maps/2.rmd differ diff --git a/assets/ray/maps/3.rmd b/assets/ray/maps/3.rmd index 03bd1a3e9..b82fca606 100755 Binary files a/assets/ray/maps/3.rmd and b/assets/ray/maps/3.rmd differ diff --git a/assets/ray/maps/4.rmd b/assets/ray/maps/4.rmd index 3529cb0f0..d15607155 100755 Binary files a/assets/ray/maps/4.rmd and b/assets/ray/maps/4.rmd differ diff --git a/assets/ray/maps/5.rmd b/assets/ray/maps/5.rmd index 446e1b9f5..57297f111 100755 Binary files a/assets/ray/maps/5.rmd and b/assets/ray/maps/5.rmd differ diff --git a/assets/ray/music/base_0.mid b/assets/ray/music/base_0.mid new file mode 100644 index 000000000..9800d9f14 Binary files /dev/null and b/assets/ray/music/base_0.mid differ diff --git a/assets/ray/music/base_1.mid b/assets/ray/music/base_1.mid new file mode 100644 index 000000000..a7f00d8e3 Binary files /dev/null and b/assets/ray/music/base_1.mid differ diff --git a/assets/ray/music/cave_0.mid b/assets/ray/music/cave_0.mid new file mode 100644 index 000000000..ab21a83b4 Binary files /dev/null and b/assets/ray/music/cave_0.mid differ diff --git a/assets/ray/music/cave_1.mid b/assets/ray/music/cave_1.mid new file mode 100644 index 000000000..f9ed84e6c Binary files /dev/null and b/assets/ray/music/cave_1.mid differ diff --git a/assets/ray/music/jungle_0.mid b/assets/ray/music/jungle_0.mid new file mode 100644 index 000000000..8951478dd Binary files /dev/null and b/assets/ray/music/jungle_0.mid differ diff --git a/assets/ray/music/jungle_1.mid b/assets/ray/music/jungle_1.mid new file mode 100644 index 000000000..8f184a2af Binary files /dev/null and b/assets/ray/music/jungle_1.mid differ diff --git a/assets/ray/music/ray_boss.mid b/assets/ray/music/ray_boss.mid new file mode 100644 index 000000000..3fdecccd3 Binary files /dev/null and b/assets/ray/music/ray_boss.mid differ diff --git a/assets/ray/scenery/OBJ_SCENERY_PORTAL.png b/assets/ray/scenery/OBJ_SCENERY_PORTAL.png index 5e2c723ad..2622ccb6d 100644 Binary files a/assets/ray/scenery/OBJ_SCENERY_PORTAL.png and b/assets/ray/scenery/OBJ_SCENERY_PORTAL.png differ diff --git a/assets/ray/scenery/OBJ_SCENERY_TERMINAL.png b/assets/ray/scenery/OBJ_SCENERY_TERMINAL.png index 3f1062c9a..8f4904c43 100644 Binary files a/assets/ray/scenery/OBJ_SCENERY_TERMINAL.png and b/assets/ray/scenery/OBJ_SCENERY_TERMINAL.png differ diff --git a/assets/ray/sfx/r_door_open.mid b/assets/ray/sfx/r_door_open.mid new file mode 100644 index 000000000..56addd5c5 Binary files /dev/null and b/assets/ray/sfx/r_door_open.mid differ diff --git a/assets/ray/sfx/r_e_block.mid b/assets/ray/sfx/r_e_block.mid new file mode 100644 index 000000000..6d85f5d0a Binary files /dev/null and b/assets/ray/sfx/r_e_block.mid differ diff --git a/assets/ray/sfx/r_e_damage.mid b/assets/ray/sfx/r_e_damage.mid new file mode 100644 index 000000000..5747761a9 Binary files /dev/null and b/assets/ray/sfx/r_e_damage.mid differ diff --git a/assets/ray/sfx/r_e_dead.mid b/assets/ray/sfx/r_e_dead.mid new file mode 100644 index 000000000..eda126739 Binary files /dev/null and b/assets/ray/sfx/r_e_dead.mid differ diff --git a/assets/ray/sfx/r_e_freeze.mid b/assets/ray/sfx/r_e_freeze.mid new file mode 100644 index 000000000..440e26203 Binary files /dev/null and b/assets/ray/sfx/r_e_freeze.mid differ diff --git a/assets/ray/sfx/r_game_over.mid b/assets/ray/sfx/r_game_over.mid new file mode 100644 index 000000000..ad35d401f Binary files /dev/null and b/assets/ray/sfx/r_game_over.mid differ diff --git a/assets/ray/sfx/r_health.mid b/assets/ray/sfx/r_health.mid new file mode 100644 index 000000000..907dab06f Binary files /dev/null and b/assets/ray/sfx/r_health.mid differ diff --git a/assets/ray/sfx/r_item_get.mid b/assets/ray/sfx/r_item_get.mid new file mode 100644 index 000000000..098401aa7 Binary files /dev/null and b/assets/ray/sfx/r_item_get.mid differ diff --git a/assets/ray/sfx/r_lava_dmg.mid b/assets/ray/sfx/r_lava_dmg.mid new file mode 100644 index 000000000..ad65f4024 Binary files /dev/null and b/assets/ray/sfx/r_lava_dmg.mid differ diff --git a/assets/ray/sfx/r_p_charge.mid b/assets/ray/sfx/r_p_charge.mid new file mode 100644 index 000000000..18e2d4702 Binary files /dev/null and b/assets/ray/sfx/r_p_charge.mid differ diff --git a/assets/ray/sfx/r_p_charge_start.mid b/assets/ray/sfx/r_p_charge_start.mid new file mode 100644 index 000000000..2ec7e6d9c Binary files /dev/null and b/assets/ray/sfx/r_p_charge_start.mid differ diff --git a/assets/ray/sfx/r_p_damage.mid b/assets/ray/sfx/r_p_damage.mid new file mode 100644 index 000000000..159956627 Binary files /dev/null and b/assets/ray/sfx/r_p_damage.mid differ diff --git a/assets/ray/sfx/r_p_ice.mid b/assets/ray/sfx/r_p_ice.mid new file mode 100644 index 000000000..e58400ee7 Binary files /dev/null and b/assets/ray/sfx/r_p_ice.mid differ diff --git a/assets/ray/sfx/r_p_missile.mid b/assets/ray/sfx/r_p_missile.mid new file mode 100644 index 000000000..2505e06ed Binary files /dev/null and b/assets/ray/sfx/r_p_missile.mid differ diff --git a/assets/ray/sfx/r_p_shoot.mid b/assets/ray/sfx/r_p_shoot.mid new file mode 100644 index 000000000..472f414cf Binary files /dev/null and b/assets/ray/sfx/r_p_shoot.mid differ diff --git a/assets/ray/sfx/r_p_xray.mid b/assets/ray/sfx/r_p_xray.mid new file mode 100644 index 000000000..da132fa72 Binary files /dev/null and b/assets/ray/sfx/r_p_xray.mid differ diff --git a/assets/ray/sfx/r_warp.mid b/assets/ray/sfx/r_warp.mid new file mode 100644 index 000000000..cf4be4148 Binary files /dev/null and b/assets/ray/sfx/r_warp.mid differ diff --git a/components/hdw-battmon/include/hdw-battmon.h b/components/hdw-battmon/include/hdw-battmon.h index 009b57842..09f24f3f5 100644 --- a/components/hdw-battmon/include/hdw-battmon.h +++ b/components/hdw-battmon/include/hdw-battmon.h @@ -1,3 +1,6 @@ +#ifndef _HDW_BATTMON_H_ +#define _HDW_BATTMON_H_ + /*! \file hdw-battmon.h * * \section battmon_design Design Philosophy @@ -31,3 +34,5 @@ void initBattmon(gpio_num_t gpio); void deinitBattmon(void); int readBattmon(void); + +#endif \ No newline at end of file diff --git a/components/hdw-bzr/hdw-bzr.c b/components/hdw-bzr/hdw-bzr.c index 2db7578ce..443bb2007 100644 --- a/components/hdw-bzr/hdw-bzr.c +++ b/components/hdw-bzr/hdw-bzr.c @@ -257,6 +257,9 @@ static void bzrPlayTrack(bzrTrack_t* trackL, bzrTrack_t* trackR, const song_t* s trackR->usAccum = 0; trackR->should_loop = song->shouldLoop; } + + // Un-pause if paused + bzrResume(); } /** @@ -268,12 +271,6 @@ static void bzrPlayTrack(bzrTrack_t* trackL, bzrTrack_t* trackR, const song_t* s */ void bzrPlayBgm(const song_t* song, buzzerPlayTrack_t track) { - // Don't play if muted - if (0 == bgmVolume) - { - return; - } - // Play this song on the BGM track bzrPlayTrack(&buzzers[0].bgm, &buzzers[1].bgm, song, track); @@ -295,12 +292,6 @@ void bzrPlayBgm(const song_t* song, buzzerPlayTrack_t track) */ void bzrPlaySfx(const song_t* song, buzzerPlayTrack_t track) { - // Don't play if muted - if (0 == sfxVolume) - { - return; - } - // Play this song on the SFX track bzrPlayTrack(&buzzers[0].sfx, &buzzers[1].sfx, song, track); @@ -421,8 +412,8 @@ static bool IRAM_ATTR buzzer_check_next_note_isr(gptimer_handle_t timer, const g int32_t tElapsedUs = tNowUs - tLastLoopUs; tLastLoopUs = tNowUs; - // Don't do much if muted or paused. Check here so that tElapsedUs stays sane - if (bzrPaused || ((0 == bgmVolume) && (0 == sfxVolume))) + // Don't do much if paused. Check here so that tElapsedUs stays sane + if (bzrPaused) { return false; } @@ -535,14 +526,18 @@ static bool IRAM_ATTR buzzer_track_check_next_note(bzrTrack_t* track, buzzerPlay /** * @brief Pause the buzzer but do not reset the song + * + * @return true if the buzzer was running and paused, false if it was not running to begin with */ -void bzrPause(void) +bool bzrPause(void) { if (!bzrPaused) { bzrPaused = true; bzrStop(false); + return true; } + return false; } /** @@ -550,14 +545,17 @@ void bzrPause(void) */ void bzrResume(void) { - if (bzrPaused) + if (bzrPaused || !bzrTimerActive) { // Mark it as not paused bzrPaused = false; - // Restart timer stopped by bzrStop() - gptimer_start(bzrTimer); - bzrTimerActive = true; + if (!bzrTimerActive) + { + // Restart timer stopped by bzrStop() + gptimer_start(bzrTimer); + bzrTimerActive = true; + } // For each buzzer, resume playing the tone before pausing for (uint16_t bIdx = 0; bIdx < NUM_BUZZERS; bIdx++) diff --git a/components/hdw-bzr/include/hdw-bzr.h b/components/hdw-bzr/include/hdw-bzr.h index e826c0496..512b029cf 100644 --- a/components/hdw-bzr/include/hdw-bzr.h +++ b/components/hdw-bzr/include/hdw-bzr.h @@ -268,7 +268,7 @@ void bzrPlaySfx(const song_t* song, buzzerPlayTrack_t track); void bzrStop(bool resetTracks); void bzrPlayNote(noteFrequency_t freq, buzzerPlayTrack_t track, uint16_t volume); void bzrStopNote(buzzerPlayTrack_t track); -void bzrPause(void); +bool bzrPause(void); void bzrResume(void); void* bzrSave(void); void bzrRestore(void* data); diff --git a/components/hdw-imu/include/hdw-imu.h b/components/hdw-imu/include/hdw-imu.h index 61732523b..4e346434c 100644 --- a/components/hdw-imu/include/hdw-imu.h +++ b/components/hdw-imu/include/hdw-imu.h @@ -12,15 +12,18 @@ * * \section imu_usage Usage * - * The core system will call initAccelerometer() and deInitAccelerometer() appropriately. And you can at any point + * The core system will call initAccelerometer() and deInitAccelerometer() appropriately. And you can at any point * call any of the proper IMU / accel functions. * - * The functions you can use are: - * esp_err_t accelGetAccelVec(int16_t* x, int16_t* y, int16_t* z); - * esp_err_t accelGetQuaternion( float * quaternion ); + * accelSetRegistersAndReset() \b must be called when entering a Swadge mode that uses the IMU. * - * You can, of course at any time call: - * esp_err_t accelIntegrate(); + * accelIntegrate() \b should be called periodically. This can be done either in the mode's main loop or in the + * background draw callback. If this is called from the background draw callback, make sure to only call it once per + * frame, since multiple callbacks are called per-frame. + * + * The functions you can use to get acceleration data are: + * - accelGetAccelVecRaw() + * - accelGetQuaternion() * * \section imu_example Example * diff --git a/components/hdw-led/hdw-led.c b/components/hdw-led/hdw-led.c index b26d2c83a..34ffd561f 100644 --- a/components/hdw-led/hdw-led.c +++ b/components/hdw-led/hdw-led.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "led_strip_encoder.h" #include "hdw-led.h" @@ -145,3 +146,26 @@ esp_err_t setLeds(led_t* leds, uint8_t numLeds) // Write RGB values to LEDs return rmt_transmit(led_chan, led_encoder, (uint8_t*)localLeds, numLeds * sizeof(led_t), &tx_config); } + +/** + * @brief Write the current LED state into the given array + * + * @param[out] leds The LED array to write the state into + * @param numLeds The maximum number of LEDs to write + * @return uint8_t The number of LEDs actually written to the array + */ +uint8_t getLedState(led_t* leds, uint8_t numLeds) +{ + if (NULL != leds && numLeds > 0) + { + if (numLeds > CONFIG_NUM_LEDS + 1) + { + numLeds = CONFIG_NUM_LEDS + 1; + } + + memcpy(leds, localLeds, sizeof(led_t) * numLeds); + return numLeds; + } + + return 0; +} \ No newline at end of file diff --git a/components/hdw-led/include/hdw-led.h b/components/hdw-led/include/hdw-led.h index 7e6314f39..4b07882ec 100644 --- a/components/hdw-led/include/hdw-led.h +++ b/components/hdw-led/include/hdw-led.h @@ -69,5 +69,6 @@ esp_err_t initLeds(gpio_num_t gpio, gpio_num_t gpioAlt, uint8_t brightness); esp_err_t deinitLeds(void); esp_err_t setLeds(led_t* leds, uint8_t numLeds); void setLedBrightness(uint8_t brightness); +uint8_t getLedState(led_t* leds, uint8_t numLeds); #endif \ No newline at end of file diff --git a/components/hdw-nvs/CMakeLists.txt b/components/hdw-nvs/CMakeLists.txt index 778a5a873..b88358ccb 100644 --- a/components/hdw-nvs/CMakeLists.txt +++ b/components/hdw-nvs/CMakeLists.txt @@ -1,3 +1,4 @@ idf_component_register(SRCS "hdw-nvs.c" INCLUDE_DIRS "include" - REQUIRES nvs_flash) + REQUIRES nvs_flash + PRIV_REQUIRES hdw-bzr) diff --git a/components/hdw-nvs/hdw-nvs.c b/components/hdw-nvs/hdw-nvs.c index 82173a5e9..ca42f53ce 100644 --- a/components/hdw-nvs/hdw-nvs.c +++ b/components/hdw-nvs/hdw-nvs.c @@ -8,6 +8,7 @@ #include #include "hdw-nvs.h" +#include "hdw-bzr.h" //============================================================================== // Functions @@ -89,20 +90,31 @@ bool deinitNvs(void) */ bool eraseNvs(void) { + bool bzrPaused = bzrPause(); + bool retVal = false; + switch (nvs_flash_erase()) { case ESP_OK: { // NVS erased successfully, need to re-initialize - return initNvs(true); + retVal = initNvs(true); + break; } default: case ESP_ERR_NOT_FOUND: { // Couldn't erase flash - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** @@ -139,14 +151,16 @@ bool writeNvs32(const char* key, int32_t val) */ bool readNamespaceNvs32(const char* namespace, const char* key, int32_t* outVal) { + // Pause the buzzer before NVS operations + bool bzrPaused = bzrPause(); + bool retVal = false; + nvs_handle_t handle; esp_err_t openErr = nvs_open(namespace, NVS_READONLY, &handle); switch (openErr) { case ESP_OK: { - // Assume the commit is bad - bool readOk = false; // Write the NVS esp_err_t readErr = nvs_get_i32(handle, key, outVal); // Check the write error @@ -154,7 +168,7 @@ bool readNamespaceNvs32(const char* namespace, const char* key, int32_t* outVal) { case ESP_OK: { - readOk = true; + retVal = true; break; } default: @@ -169,7 +183,7 @@ bool readNamespaceNvs32(const char* namespace, const char* key, int32_t* outVal) } // Close the handle nvs_close(handle); - return readOk; + break; } default: case ESP_ERR_NVS_NOT_INITIALIZED: @@ -179,9 +193,16 @@ bool readNamespaceNvs32(const char* namespace, const char* key, int32_t* outVal) case ESP_ERR_NO_MEM: { ESP_LOGE("NVS", "%s openErr %s", __func__, esp_err_to_name(openErr)); - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** @@ -194,14 +215,15 @@ bool readNamespaceNvs32(const char* namespace, const char* key, int32_t* outVal) */ bool writeNamespaceNvs32(const char* namespace, const char* key, int32_t val) { + bool bzrPaused = bzrPause(); + bool retVal = false; + nvs_handle_t handle; esp_err_t openErr = nvs_open(namespace, NVS_READWRITE, &handle); switch (openErr) { case ESP_OK: { - // Assume the commit is bad - bool commitOk = false; // Write the NVS esp_err_t writeErr = nvs_set_i32(handle, key, val); // Check the write error @@ -210,7 +232,7 @@ bool writeNamespaceNvs32(const char* namespace, const char* key, int32_t val) case ESP_OK: { // Commit NVS - commitOk = (ESP_OK == nvs_commit(handle)); + retVal = (ESP_OK == nvs_commit(handle)); break; } default: @@ -227,7 +249,7 @@ bool writeNamespaceNvs32(const char* namespace, const char* key, int32_t val) // Close the handle nvs_close(handle); - return commitOk; + break; } default: case ESP_ERR_NVS_NOT_INITIALIZED: @@ -237,9 +259,16 @@ bool writeNamespaceNvs32(const char* namespace, const char* key, int32_t val) case ESP_ERR_NO_MEM: { ESP_LOGE("NVS", "%s openErr %s", __func__, esp_err_to_name(openErr)); - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** @@ -285,14 +314,15 @@ bool writeNvsBlob(const char* key, const void* value, size_t length) */ bool readNamespaceNvsBlob(const char* namespace, const char* key, void* out_value, size_t* length) { + bool bzrPaused = bzrPause(); + bool retVal = false; + nvs_handle_t handle; esp_err_t openErr = nvs_open(namespace, NVS_READONLY, &handle); switch (openErr) { case ESP_OK: { - // Assume the commit is bad - bool readOk = false; // Write the NVS esp_err_t readErr = nvs_get_blob(handle, key, out_value, length); // Check the write error @@ -300,7 +330,7 @@ bool readNamespaceNvsBlob(const char* namespace, const char* key, void* out_valu { case ESP_OK: { - readOk = true; + retVal = true; break; } default: @@ -315,7 +345,7 @@ bool readNamespaceNvsBlob(const char* namespace, const char* key, void* out_valu } // Close the handle nvs_close(handle); - return readOk; + break; } default: case ESP_ERR_NVS_NOT_INITIALIZED: @@ -325,9 +355,16 @@ bool readNamespaceNvsBlob(const char* namespace, const char* key, void* out_valu case ESP_ERR_NO_MEM: { ESP_LOGE("NVS", "%s openErr %s", __func__, esp_err_to_name(openErr)); - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** @@ -341,14 +378,15 @@ bool readNamespaceNvsBlob(const char* namespace, const char* key, void* out_valu */ bool writeNamespaceNvsBlob(const char* namespace, const char* key, const void* value, size_t length) { + bool bzrPaused = bzrPause(); + bool retVal = false; + nvs_handle_t handle; esp_err_t openErr = nvs_open(namespace, NVS_READWRITE, &handle); switch (openErr) { case ESP_OK: { - // Assume the commit is bad - bool commitOk = false; // Write the NVS esp_err_t writeErr = nvs_set_blob(handle, key, value, length); // Check the write error @@ -357,7 +395,7 @@ bool writeNamespaceNvsBlob(const char* namespace, const char* key, const void* v case ESP_OK: { // Commit NVS - commitOk = (ESP_OK == nvs_commit(handle)); + retVal = (ESP_OK == nvs_commit(handle)); break; } default: @@ -374,7 +412,7 @@ bool writeNamespaceNvsBlob(const char* namespace, const char* key, const void* v // Close the handle nvs_close(handle); - return commitOk; + break; } default: case ESP_ERR_NVS_NOT_INITIALIZED: @@ -384,9 +422,16 @@ bool writeNamespaceNvsBlob(const char* namespace, const char* key, const void* v case ESP_ERR_NO_MEM: { ESP_LOGE("NVS", "%s openErr %s", __func__, esp_err_to_name(openErr)); - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** @@ -409,14 +454,15 @@ bool eraseNvsKey(const char* key) */ bool eraseNamespaceNvsKey(const char* namespace, const char* key) { + bool bzrPaused = bzrPause(); + bool retVal = false; + nvs_handle_t handle; esp_err_t openErr = nvs_open(namespace, NVS_READWRITE, &handle); switch (openErr) { case ESP_OK: { - // Assume the commit is bad - bool commitOk = false; // Write the NVS esp_err_t writeErr = nvs_erase_key(handle, key); // Check the write error @@ -425,7 +471,7 @@ bool eraseNamespaceNvsKey(const char* namespace, const char* key) case ESP_OK: { // Commit NVS - commitOk = (ESP_OK == nvs_commit(handle)); + retVal = (ESP_OK == nvs_commit(handle)); break; } default: @@ -442,7 +488,7 @@ bool eraseNamespaceNvsKey(const char* namespace, const char* key) // Close the handle nvs_close(handle); - return commitOk; + break; } default: case ESP_ERR_NVS_NOT_INITIALIZED: @@ -452,9 +498,16 @@ bool eraseNamespaceNvsKey(const char* namespace, const char* key) case ESP_ERR_NO_MEM: { ESP_LOGE("NVS", "%s openErr %s", __func__, esp_err_to_name(openErr)); - return false; + break; } } + + // Resume the buzzer if it was paused + if (bzrPaused) + { + bzrResume(); + } + return retVal; } /** diff --git a/components/hdw-spiffs/hdw-spiffs.c b/components/hdw-spiffs/hdw-spiffs.c index 1e12339ae..ef32c1b05 100644 --- a/components/hdw-spiffs/hdw-spiffs.c +++ b/components/hdw-spiffs/hdw-spiffs.c @@ -12,6 +12,7 @@ #include #include "hdw-spiffs.h" +#include "hdw-bzr.h" //============================================================================== // Variables @@ -74,6 +75,9 @@ bool deinitSpiffs(void) */ uint8_t* spiffsReadFile(const char* fname, size_t* outsize, bool readToSpiRam) { + // Pause the buzzer before SPIFFS reads + bool bzrPaused = bzrPause(); + uint8_t* output; // Read and display the contents of a small text file @@ -86,31 +90,38 @@ uint8_t* spiffsReadFile(const char* fname, size_t* outsize, bool readToSpiRam) if (f == NULL) { ESP_LOGE("SPIFFS", "Failed to open %s", fnameFull); - return NULL; + output = NULL; } - - // Get the file size - fseek(f, 0L, SEEK_END); - *outsize = ftell(f); - fseek(f, 0L, SEEK_SET); - - // Read the file into an array - if (readToSpiRam) + else { - output = (uint8_t*)heap_caps_calloc((*outsize + 1), sizeof(uint8_t), MALLOC_CAP_SPIRAM); + // Get the file size + fseek(f, 0L, SEEK_END); + *outsize = ftell(f); + fseek(f, 0L, SEEK_SET); + + // Read the file into an array + if (readToSpiRam) + { + output = (uint8_t*)heap_caps_calloc((*outsize + 1), sizeof(uint8_t), MALLOC_CAP_SPIRAM); + } + else + { + output = (uint8_t*)calloc((*outsize + 1), sizeof(uint8_t)); + } + fread(output, *outsize, 1, f); + // Add null terminator + (output)[*outsize] = 0; + + // Close the file + fclose(f); + + // Display the read contents from the file + ESP_LOGI("SPIFFS", "Read from %s: %u bytes", fname, *outsize); } - else + // Resume the buzzer if it was paused + if (bzrPaused) { - output = (uint8_t*)calloc((*outsize + 1), sizeof(uint8_t)); + bzrResume(); } - fread(output, *outsize, 1, f); - // Add null terminator - (output)[*outsize] = 0; - - // Close the file - fclose(f); - - // Display the read contents from the file - ESP_LOGI("SPIFFS", "Read from %s: %u bytes", fname, *outsize); return output; } diff --git a/emulator/src/components/hdw-bzr/hdw-bzr.c b/emulator/src/components/hdw-bzr/hdw-bzr.c index 69e036d68..f2b310e2b 100644 --- a/emulator/src/components/hdw-bzr/hdw-bzr.c +++ b/emulator/src/components/hdw-bzr/hdw-bzr.c @@ -207,6 +207,7 @@ static void bzrPlayTrack(bzrTrack_t* trackL, bzrTrack_t* trackR, const song_t* s void bzrPlayBgm(const song_t* song, buzzerPlayTrack_t track) { bzrPlayTrack(&buzzers[0].bgm, &buzzers[1].bgm, song, track); + bzrResume(); } /** @@ -219,6 +220,7 @@ void bzrPlayBgm(const song_t* song, buzzerPlayTrack_t track) void bzrPlaySfx(const song_t* song, buzzerPlayTrack_t track) { bzrPlayTrack(&buzzers[0].sfx, &buzzers[1].sfx, song, track); + bzrResume(); } /** @@ -461,14 +463,18 @@ void EmuSoundCb(struct SoundDriver* sd, short* in, short* out, int samples_R, in /** * @brief Pause the buzzer but do not reset the song + * + * @return true if the buzzer was running and paused, false if it was not running to begin with */ -void bzrPause(void) +bool bzrPause(void) { if (!bzrPaused) { bzrPaused = true; bzrStop(false); + return true; } + return false; } /** diff --git a/emulator/src/components/hdw-led/hdw-led.c b/emulator/src/components/hdw-led/hdw-led.c index bfec58796..c552ec0db 100644 --- a/emulator/src/components/hdw-led/hdw-led.c +++ b/emulator/src/components/hdw-led/hdw-led.c @@ -11,8 +11,8 @@ // Variables //============================================================================== -static led_t rdLeds[CONFIG_NUM_LEDS] = {0}; -static uint8_t ledBrightness = 0; +static led_t rdLeds[CONFIG_NUM_LEDS + 1] = {0}; +static uint8_t ledBrightness = 0; //============================================================================== // Functions @@ -78,6 +78,22 @@ esp_err_t setLeds(led_t* leds, uint8_t numLeds) return ESP_OK; } +uint8_t getLedState(led_t* leds, uint8_t numLeds) +{ + if (NULL != leds && numLeds > 0) + { + if (numLeds > CONFIG_NUM_LEDS + 1) + { + numLeds = CONFIG_NUM_LEDS + 1; + } + + memcpy(leds, rdLeds, sizeof(led_t) * numLeds); + return numLeds; + } + + return 0; +} + /** * @brief Get a pointer to the LED memory. * diff --git a/emulator/src/components/hdw-tft/hdw-tft.c b/emulator/src/components/hdw-tft/hdw-tft.c index 866d827de..1dc94577c 100644 --- a/emulator/src/components/hdw-tft/hdw-tft.c +++ b/emulator/src/components/hdw-tft/hdw-tft.c @@ -229,7 +229,13 @@ void drawDisplayTft(fnBackgroundDrawCallback_t fnBackgroundDrawCallback) int dstY = ((y * displayMult) + mY); int pxIdx = (dstY * (TFT_WIDTH * displayMult)) + dstX; - uint32_t color = paletteColorsEmu[frameBuffer[(y * TFT_WIDTH) + x]]; + int colorolor = frameBuffer[(y * TFT_WIDTH) + x]; + if (colorolor == 216) + { + colorolor = c500; + } + + uint32_t color = paletteColorsEmu[colorolor]; uint8_t a = (color) & 0xFF; uint8_t r = (color >> 8) & 0xFF; diff --git a/emulator/src/extensions/touch/ext_touch.c b/emulator/src/extensions/touch/ext_touch.c index 9ff8b5033..df4f4cc1f 100644 --- a/emulator/src/extensions/touch/ext_touch.c +++ b/emulator/src/extensions/touch/ext_touch.c @@ -229,11 +229,12 @@ static bool updateTouch(int32_t x, int32_t y, bool clicked) } /** - * @brief Initializes the touchpad extension. + * @brief Initializes the touchpad extension. If emulateTouch is enabled, the touchpad will display. + * + * Using keys 1-4 to control the touchpad 1-4 is always enabled. * * @param emuArgs - * @return true - * @return false + * @return true If touchpad emulation is enabled (it is) */ static bool touchInit(emuArgs_t* emuArgs) { @@ -248,17 +249,32 @@ static bool touchInit(emuArgs_t* emuArgs) if (emuArgs->emulateTouch) { requestPane(&touchEmuCallback, PANE_BOTTOM, PANE_MIN_SIZE, PANE_MIN_SIZE); - return true; - } - else - { - return false; } + + return true; } static int32_t touchKey(uint32_t key, bool down) { - const int32_t phiMap[] = {90, 0, 180, 270}; + // Map from state to touchpad rotation. Button bits are in URLD order + const int32_t phiMap[] = { + 0, // 0b0000 ____ (0 radius) + 270, // 0b0001 ___D + 180, // 0b0010 __L_ + 225, // 0b0011 __LD + 0, // 0b0100 _R__ + 315, // 0b0101 _R_D + 0, // 0b0110 _RL_ (0 radius) + 270, // 0b0111 _RLD + 90, // 0b1000 U___ + 0, // 0b1001 U__D (0 radius) + 135, // 0b1010 U_L_ + 180, // 0b1011 U_LD + 45, // 0b1100 UR__ + 0, // 0b1101 UR_D + 90, // 0b1110 URL_ + 0, // 0b1111 URLD (0 radius) + }; if (key < '1' || key > '4') { @@ -266,7 +282,7 @@ static int32_t touchKey(uint32_t key, bool down) return 0; } - int keyNum = (key - '1'); + int keyNum = (3 - (key - '1')); // Handle the key states separately so rolling over them works more or less how one might expect if (down && !(emuTouch.keyState & (1 << keyNum))) { @@ -277,22 +293,25 @@ static int32_t touchKey(uint32_t key, bool down) emuTouch.keyState &= ~(1 << keyNum); } - if (emuTouch.keyState) + int32_t radius = 1024; + int32_t intensity = emuTouch.lastTouchIntensity; + // Check for the canceled-out positions where + switch (emuTouch.keyState) { - for (int i = 0; i < 4; i++) - { - if (emuTouch.keyState & (1 << i)) - { - emulatorSetTouchJoystick(phiMap[i], 1024, emuTouch.lastTouchIntensity); - break; - } - } - } - else - { - emulatorSetTouchJoystick(0, 0, 0); + case 0: // All un-pressed + case 6: // LR pressed + case 9: // UD pressed + case 15: // All pressed + radius = 0; + intensity = 0; + break; + + default: + break; } + emulatorSetTouchJoystick(phiMap[emuTouch.keyState], radius, intensity); + // Consume event return -1; } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 68a8e581b..2a6073e28 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -26,6 +26,7 @@ idf_component_register(SRCS "swadge2024.c" "modes/breakout/starfield.c" "modes/breakout/tilemap.c" "modes/colorchord/colorchord.c" + "modes/credits/credits_utils.c" "modes/credits/mode_credits.c" "modes/dance/dance.c" "modes/dance/portableDance.c" @@ -61,6 +62,7 @@ idf_component_register(SRCS "swadge2024.c" "modes/quickSettings/quickSettings.c" "modes/ray/fp_math.c" "modes/ray/mode_ray.c" + "modes/ray/ray_credits.c" "modes/ray/ray_dialog.c" "modes/ray/ray_map.c" "modes/ray/ray_object.c" @@ -70,6 +72,7 @@ idf_component_register(SRCS "swadge2024.c" "modes/ray/ray_tex_manager.c" "modes/ray/ray_player.c" "modes/ray/ray_warp_screen.c" + "modes/ray/ray_death_screen.c" "modes/ray/enemies/ray_enemy.c" "modes/ray/enemies/ray_enemy.h" "modes/ray/enemies/ray_enemy_armored.c" diff --git a/main/asset_loaders/spiffs_song.c b/main/asset_loaders/spiffs_song.c index b5a80787d..294b50ce4 100644 --- a/main/asset_loaders/spiffs_song.c +++ b/main/asset_loaders/spiffs_song.c @@ -27,7 +27,7 @@ * @return true if the SNG was loaded successfully, * false if the SNG load failed and should not be used */ -bool loadSong(char* name, song_t* song, bool spiRam) +bool loadSong(const char* name, song_t* song, bool spiRam) { uint32_t caps = spiRam ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DEFAULT; diff --git a/main/asset_loaders/spiffs_song.h b/main/asset_loaders/spiffs_song.h index acf280dec..9732c25cf 100644 --- a/main/asset_loaders/spiffs_song.h +++ b/main/asset_loaders/spiffs_song.h @@ -39,7 +39,7 @@ #include "hdw-bzr.h" -bool loadSong(char* name, song_t* song, bool spiRam); +bool loadSong(const char* name, song_t* song, bool spiRam); void freeSong(song_t* song); #endif \ No newline at end of file diff --git a/main/display/font.c b/main/display/font.c index db71fe6dd..70e844698 100644 --- a/main/display/font.c +++ b/main/display/font.c @@ -22,6 +22,12 @@ */ void drawChar(paletteColor_t color, int h, const font_ch_t* ch, int16_t xOff, int16_t yOff) { + // Do not draw transparent chars + if (cTransparent == color) + { + return; + } + // This function has been micro optimized by cnlohr on 2022-09-07, using gcc version 8.4.0 (crosstool-NG // esp-2021r2-patch3) int bitIdx = 0; diff --git a/main/display/wsg.c b/main/display/wsg.c index 0ad191dae..b674571ea 100644 --- a/main/display/wsg.c +++ b/main/display/wsg.c @@ -149,7 +149,7 @@ void drawWsg(const wsg_t* wsg, int16_t xOff, int16_t yOff, bool flipLR, bool fli uint32_t advanceX = 1; if (flipLR) { - readX = wsgw; + readX = wsgw - 1; advanceX = -1; } @@ -323,6 +323,54 @@ void drawWsgSimple(const wsg_t* wsg, int16_t xOff, int16_t yOff) } } +/** + * @brief Draw a WSG to the display without flipping or rotation at half size + * + * @param wsg The WSG to draw to the display + * @param xOff The x offset to draw the WSG at + * @param yOff The y offset to draw the WSG at + */ +void drawWsgSimpleHalf(const wsg_t* wsg, int16_t xOff, int16_t yOff) +{ + // This function has been micro optimized by cnlohr on 2022-09-07, using gcc version 8.4.0 (crosstool-NG + // esp-2021r2-patch3) + + if (NULL == wsg->px) + { + return; + } + + // Only draw in bounds + int dWidth = TFT_WIDTH; + int wWidth = wsg->w; + int xMin = CLAMP(xOff, 0, dWidth); + int xMax = CLAMP(xOff + (wWidth / 2), 0, dWidth); + int yMin = CLAMP(yOff, 0, TFT_HEIGHT); + int yMax = CLAMP(yOff + (wsg->h / 2), 0, TFT_HEIGHT); + paletteColor_t* px = getPxTftFramebuffer(); + int numX = xMax - xMin; + int wsgY = (yMin - yOff); + int wsgX = (xMin - xOff); + paletteColor_t* lineout = &px[(yMin * dWidth) + xMin]; + const paletteColor_t* linein = &wsg->px[wsgY * wWidth + wsgX]; + + // Draw each pixel + for (int y = yMin; y < yMax; y++) + { + for (int x = 0; x < numX; x++) + { + int color = linein[x * 2]; + if (color != cTransparent) + { + lineout[x] = color; + } + } + lineout += dWidth; + linein += (2 * wWidth); + wsgY++; + } +} + /** * @brief Quickly copy a WSG to the display without flipping or rotation or transparency * diff --git a/main/display/wsg.h b/main/display/wsg.h index b332e4ba2..c3f2bbdf9 100644 --- a/main/display/wsg.h +++ b/main/display/wsg.h @@ -59,5 +59,6 @@ typedef struct void drawWsg(const wsg_t* wsg, int16_t xOff, int16_t yOff, bool flipLR, bool flipUD, int16_t rotateDeg); void drawWsgSimple(const wsg_t* wsg, int16_t xOff, int16_t yOff); void drawWsgTile(const wsg_t* wsg, int32_t xOff, int32_t yOff); +void drawWsgSimpleHalf(const wsg_t* wsg, int16_t xOff, int16_t yOff); #endif \ No newline at end of file diff --git a/main/menu/menu.c b/main/menu/menu.c index 56c19a20d..feb7d46fc 100644 --- a/main/menu/menu.c +++ b/main/menu/menu.c @@ -53,6 +53,7 @@ menu_t* initMenu(const char* title, menuCb cbFunc) menu->currentItem = NULL; menu->items = calloc(1, sizeof(list_t)); menu->parentMenu = NULL; + menu->showBattery = false; return menu; } @@ -794,3 +795,33 @@ menu_t* menuButton(menu_t* menu, buttonEvt_t evt) } return menu; } + +/** + * @brief Show or hide the battery on the menu. This should be called from the + * root menu after the menu is constructed + * + * @param menu The menu to show a battery indicator on + * @param showBattery true to show the battery, false to hide it + */ +void setShowBattery(menu_t* menu, bool showBattery) +{ + // Set this menu + menu->showBattery = showBattery; + + // For each item + node_t* itemNode = menu->items->first; + while (itemNode) + { + menuItem_t* item = (menuItem_t*)itemNode->val; + + // If this item has a submenu + if (NULL != item->subMenu) + { + // Set the battery there too (recursive) + setShowBattery(item->subMenu, showBattery); + } + + // Move to the next item + itemNode = itemNode->next; + } +} diff --git a/main/menu/menu.h b/main/menu/menu.h index 8ac1fae3e..2d0b9836d 100644 --- a/main/menu/menu.h +++ b/main/menu/menu.h @@ -179,6 +179,7 @@ typedef struct _menu_t list_t* items; ///< A list_t of menu items to display node_t* currentItem; ///< The currently selected menu item menu_t* parentMenu; ///< The parent menu, may be NULL if this is not a submenu + bool showBattery; ///< true if the battery measurement should be shown. false by default int32_t batteryReadTimer; ///< A timer to read the battery every 10s int batteryLevel; ///< The current battery measurement } menu_t; @@ -209,5 +210,6 @@ menu_t* menuNavigateToNextOption(menu_t* menu); menu_t* menuSelectCurrentItem(menu_t* menu); menu_t* menuButton(menu_t* menu, buttonEvt_t evt) __attribute__((warn_unused_result)); +void setShowBattery(menu_t* menu, bool showBattery); #endif \ No newline at end of file diff --git a/main/menu/menuLogbookRenderer.c b/main/menu/menuLogbookRenderer.c index ceee18414..5fbe7c169 100644 --- a/main/menu/menuLogbookRenderer.c +++ b/main/menu/menuLogbookRenderer.c @@ -10,6 +10,8 @@ #include "shapes.h" #include "fill.h" #include "color_utils.h" +#include "hdw-nvs.h" +#include "mode_ray.h" //============================================================================== // Defines @@ -64,6 +66,13 @@ menuLogbookRenderer_t* initMenuLogbookRenderer(font_t* menuFont) loadWsg("batt3.wsg", &renderer->batt[2], false); loadWsg("batt4.wsg", &renderer->batt[3], false); + // Load a background + loadWsg("menu_bg.wsg", &renderer->menu_bg, true); + + // Load Zip and check if it should be displayed + loadWsg("zip.wsg", &renderer->zip, false); + readNvs32(MAGTROID_UNLOCK_KEY, &renderer->magtroidUnlocked); + // Initialize LEDs for (uint16_t idx = 0; idx < CONFIG_NUM_LEDS; idx++) { @@ -89,6 +98,8 @@ void deinitMenuLogbookRenderer(menuLogbookRenderer_t* renderer) freeWsg(&renderer->batt[1]); freeWsg(&renderer->batt[2]); freeWsg(&renderer->batt[3]); + freeWsg(&renderer->menu_bg); + freeWsg(&renderer->zip); free(renderer); } @@ -109,12 +120,12 @@ static void drawMenuText(menuLogbookRenderer_t* renderer, const char* text, int1 { // Pick colors based on selection paletteColor_t cornerColor = c411; - paletteColor_t textColor = c511; + paletteColor_t textColor = c553; paletteColor_t topLineColor = c211; if (isSelected) { cornerColor = c532; - textColor = c554; + textColor = c555; topLineColor = c422; } @@ -218,12 +229,16 @@ static void drawMenuText(menuLogbookRenderer_t* renderer, const char* text, int1 */ void drawMenuLogbook(menu_t* menu, menuLogbookRenderer_t* renderer, int64_t elapsedUs) { - // Read battery every 10s - menu->batteryReadTimer -= elapsedUs; - if (0 >= menu->batteryReadTimer) + // Only poll the battery if requested + if (menu->showBattery) { - menu->batteryReadTimer += 10000000; - menu->batteryLevel = readBattmon(); + // Read battery every 10s + menu->batteryReadTimer -= elapsedUs; + if (0 >= menu->batteryReadTimer) + { + menu->batteryReadTimer += 10000000; + menu->batteryLevel = readBattmon(); + } } // For each LED @@ -268,8 +283,15 @@ void drawMenuLogbook(menu_t* menu, menuLogbookRenderer_t* renderer, int64_t elap // Light the LEDs setLeds(renderer->leds, CONFIG_NUM_LEDS); - // Clear the TFT - fillDisplayArea(0, 0, TFT_WIDTH, TFT_HEIGHT, c100); + // Clear the TFT with a background + drawWsgTile(&renderer->menu_bg, 0, 0); + + // If Zip was unlocked + if (renderer->magtroidUnlocked) + { + // Draw to the TFT + drawWsgSimple(&renderer->zip, TFT_WIDTH - renderer->zip.w, TFT_HEIGHT - renderer->zip.h); + } // Find the start of the 'page' node_t* pageStart = menu->items->first; @@ -348,25 +370,29 @@ void drawMenuLogbook(menu_t* menu, menuLogbookRenderer_t* renderer, int64_t elap drawWsg(&renderer->arrow, arrowX, arrowY, false, false, 90); } - // Draw the battery indicator depending on the last read value - wsg_t* toDraw = NULL; - // 872 is full - if (menu->batteryLevel == 0 || menu->batteryLevel > 741) - { - toDraw = &renderer->batt[3]; - } - else if (menu->batteryLevel > 695) + // Only draw the battery if requested + if (menu->showBattery) { - toDraw = &renderer->batt[2]; - } - else if (menu->batteryLevel > 652) - { - toDraw = &renderer->batt[1]; - } - else // 452 is dead - { - toDraw = &renderer->batt[0]; - } + // Draw the battery indicator depending on the last read value + wsg_t* toDraw = NULL; + // 872 is full + if (menu->batteryLevel == 0 || menu->batteryLevel > 741) + { + toDraw = &renderer->batt[3]; + } + else if (menu->batteryLevel > 695) + { + toDraw = &renderer->batt[2]; + } + else if (menu->batteryLevel > 652) + { + toDraw = &renderer->batt[1]; + } + else // 452 is dead + { + toDraw = &renderer->batt[0]; + } - drawWsg(toDraw, 212, 3, false, false, 0); + drawWsg(toDraw, 212, 3, false, false, 0); + } } diff --git a/main/menu/menuLogbookRenderer.h b/main/menu/menuLogbookRenderer.h index 382dfcb7e..280bd89eb 100644 --- a/main/menu/menuLogbookRenderer.h +++ b/main/menu/menuLogbookRenderer.h @@ -54,7 +54,10 @@ typedef struct font_t* font; ///< The font to render the menu with led_t leds[CONFIG_NUM_LEDS]; ///< An array with the RGB LED state to be output menuLed_t ledTimers[CONFIG_NUM_LEDS]; ///< An array with the LED timers for animation - wsg_t batt[4]; + wsg_t batt[4]; ///< Images for the battery levels + wsg_t menu_bg; ///< Background image for the menu + wsg_t zip; ///< Unlockable image of Zip + int32_t magtroidUnlocked; ///< Whether or not Zip should be drawn } menuLogbookRenderer_t; menuLogbookRenderer_t* initMenuLogbookRenderer(font_t* menuFont); diff --git a/main/modes/breakout/aabb_utils.c b/main/modes/breakout/aabb_utils.c index e7ea6f8df..78c3e7bda 100644 --- a/main/modes/breakout/aabb_utils.c +++ b/main/modes/breakout/aabb_utils.c @@ -3,7 +3,7 @@ //============================================================================== #include "aabb_utils.h" -//#include +// #include #include "fill.h" //============================================================================== @@ -21,13 +21,10 @@ */ void drawBox(box_t box, paletteColor_t color, bool isFilled, int32_t scalingFactor) { - if(isFilled) + if (isFilled) { - fillDisplayArea(box.x0 >> scalingFactor, - box.y0 >> scalingFactor, - box.x1 >> scalingFactor, - box.y1 >> scalingFactor, - color); + fillDisplayArea(box.x0 >> scalingFactor, box.y0 >> scalingFactor, box.x1 >> scalingFactor, + box.y1 >> scalingFactor, color); } else { @@ -49,8 +46,8 @@ void drawBox(box_t box, paletteColor_t color, bool isFilled, int32_t scalingFact */ bool boxesCollide(box_t box0, box_t box1, int32_t scalingFactor) { - return (box0.x0 >> scalingFactor) < (box1.x1 >> scalingFactor) && - (box0.x1 >> scalingFactor) > (box1.x0 >> scalingFactor) && - (box0.y0 >> scalingFactor) < (box1.y1 >> scalingFactor) && - (box0.y1 >> scalingFactor) > (box1.y0 >> scalingFactor); + return (box0.x0 >> scalingFactor) < (box1.x1 >> scalingFactor) + && (box0.x1 >> scalingFactor) > (box1.x0 >> scalingFactor) + && (box0.y0 >> scalingFactor) < (box1.y1 >> scalingFactor) + && (box0.y1 >> scalingFactor) > (box1.y0 >> scalingFactor); } diff --git a/main/modes/breakout/breakout.c b/main/modes/breakout/breakout.c index 8c0bec4c5..92d29c516 100644 --- a/main/modes/breakout/breakout.c +++ b/main/modes/breakout/breakout.c @@ -15,6 +15,7 @@ #include "gameData.h" #include "tilemap.h" +#include "hdw-nvs.h" #include "soundManager.h" #include "entityManager.h" @@ -37,16 +38,16 @@ //============================================================================== // Structs //============================================================================== -typedef void (*gameUpdateFunction_t)(breakout_t *self, int64_t elapsedUs); +typedef void (*gameUpdateFunction_t)(breakout_t* self, int64_t elapsedUs); struct breakout_t { - menu_t* menu; ///< The menu structure + menu_t* menu; ///< The menu structure menuLogbookRenderer_t* mRenderer; ///< The menu renderer - font_t logbook; ///< The font used in the menu and game + font_t logbook; ///< The font used in the menu and game font_t ibm_vga8; menuItem_t* levelSelectMenuItem; - + gameData_t gameData; tilemap_t tilemap; entityManager_t entityManager; @@ -60,6 +61,12 @@ struct breakout_t starfield_t starfield; gameUpdateFunction_t update; + + breakoutHighScores_t highScores; + uint8_t menuState; + uint8_t menuSelection; + + breakoutUnlockables_t unlockables; }; //============================================================================== @@ -71,91 +78,124 @@ static void breakoutEnterMode(void); static void breakoutExitMode(void); static void breakoutMenuCb(const char* label, bool selected, uint32_t settingVal); -static void breakoutGameLoop(breakout_t *self, int64_t elapsedUs); +static void breakoutGameLoop(breakout_t* self, int64_t elapsedUs); static void breakoutBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h, int16_t up, int16_t upNum); -static void drawBreakoutHud(font_t *font, gameData_t *gameData); -static void breakoutUpdateTitleScreen(breakout_t *self, int64_t elapsedUs); -static void drawBreakoutTitleScreen(font_t *font, gameData_t *gameData); -static void breakoutChangeStateReadyScreen(breakout_t *self); -static void breakoutUpdateReadyScreen(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawReadyScreen(font_t *logbook, font_t *ibm_vga8, gameData_t *gameData); -static void breakoutChangeStateGame(breakout_t *self); -static void breakoutDetectGameStateChange(breakout_t *self); -static void breakoutDetectBgmChange(breakout_t *self); -static void breakoutChangeStateDead(breakout_t *self); -static void breakoutUpdateDead(breakout_t *self, int64_t elapsedUs); -static void breakoutChangeStateGameOver(breakout_t *self); -static void breakoutUpdateGameOver(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawGameOver(font_t *logbook, font_t *ibm_vga8, gameData_t *gameData); -static void breakoutChangeStateTitleScreen(breakout_t *self); -static void breakoutChangeStateLevelClear(breakout_t *self); -static void breakoutUpdateLevelClear(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawLevelClear(font_t *font, gameData_t *gameData); -static void breakoutChangeStateGameClear(breakout_t *self); -static void breakoutUpdateGameClear(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawGameClear(font_t *ibm_vga8, font_t *logbook, gameData_t *gameData); -static void breakoutInitializeBreakoutHighScores(breakout_t* self); -static void breakoutLoadBreakoutHighScores(breakout_t* self); -static void breakoutSaveBreakoutHighScores(breakout_t* self); -static void breakoutInitializeBreakoutUnlockables(breakout_t* self); -static void breakoutLoadBreakoutUnlockables(breakout_t* self); -static void breakoutSaveBreakoutUnlockables(breakout_t* self); - -/* -static void drawBreakoutHighScores(font_t *font, breakoutHighScores_t *highScores, gameData_t *gameData); -uint8_t getHighScoreRank(breakoutHighScores_t *highScores, uint32_t newScore); -static void insertScoreIntoHighScores(breakoutHighScores_t *highScores, uint32_t newScore, char newInitials[], uint8_t rank); -*/ - -static void breakoutChangeStateNameEntry(breakout_t *self); -static void breakoutUpdateNameEntry(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawNameEntry(font_t *font, gameData_t *gameData, uint8_t currentInitial); -static void breakoutChangeStateShowHighScores(breakout_t *self); -static void breakoutUpdateShowHighScores(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawShowHighScores(font_t *font, uint8_t menuState); -static void breakoutChangeStatePause(breakout_t *self); -static void breakoutUpdatePause(breakout_t *self, int64_t elapsedUs); -static void breakoutDrawPause(font_t *font); +static void drawBreakoutHud(font_t* font, gameData_t* gameData); +static void breakoutUpdateMainMenu(breakout_t* self, int64_t elapsedUs); +static void breakoutChangeStateReadyScreen(breakout_t* self); +static void breakoutUpdateReadyScreen(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawReadyScreen(font_t* logbook, font_t* ibm_vga8, gameData_t* gameData); +static void breakoutChangeStateGame(breakout_t* self); +static void breakoutDetectGameStateChange(breakout_t* self); +static void breakoutDetectBgmChange(breakout_t* self); +static void breakoutChangeStateDead(breakout_t* self); +static void breakoutUpdateDead(breakout_t* self, int64_t elapsedUs); +static void breakoutChangeStateGameOver(breakout_t* self); +static void breakoutUpdateGameOver(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawGameOver(font_t* logbook, font_t* ibm_vga8, gameData_t* gameData); +static void breakoutChangeStateMainMenu(breakout_t* self); +static void breakoutChangeStateLevelClear(breakout_t* self); +static void breakoutUpdateLevelClear(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawLevelClear(font_t* font, gameData_t* gameData); +static void breakoutChangeStateGameClear(breakout_t* self); +static void breakoutUpdateGameClear(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawGameClear(font_t* ibm_vga8, font_t* logbook, gameData_t* gameData); +static void breakoutChangeStateTitleScreen(breakout_t* self); +static void breakoutUpdateTitleScreen(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawTitleScreen(font_t* font, gameData_t* gameData); + +static void breakoutInitializeHighScores(breakout_t* self); +static void breakoutLoadHighScores(breakout_t* self); +static void breakoutSaveHighScores(breakout_t* self); + +static void breakoutInitializeUnlockables(breakout_t* self); +static void breakoutLoadUnlockables(breakout_t* self); +static void breakoutSaveUnlockables(breakout_t* self); + +static void breakoutDrawHighScores(font_t* font, breakoutHighScores_t* highScores, gameData_t* gameData); +uint8_t breakoutGetHighScoreRank(breakoutHighScores_t* highScores, uint32_t newScore); +static void breakoutInsertScoreIntoHighScores(breakoutHighScores_t* highScores, uint32_t newScore, char newInitials[], + uint8_t rank); + +static void breakoutChangeStateNameEntry(breakout_t* self); +static void breakoutUpdateNameEntry(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawNameEntry(font_t* font, gameData_t* gameData, uint8_t currentInitial); +static void breakoutChangeStateShowHighScores(breakout_t* self); +static void breakoutUpdateShowHighScores(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawShowHighScores(font_t* font, uint8_t menuState); +static void breakoutChangeStatePause(breakout_t* self); +static void breakoutUpdatePause(breakout_t* self, int64_t elapsedUs); +static void breakoutDrawPause(font_t* font); uint16_t breakoutGetLevelIndex(uint8_t world, uint8_t level); +void breakoutBuildMainMenu(breakout_t* self); + //============================================================================== // Level Definitions //============================================================================== -#define NUM_LEVELS 11 - -static const leveldef_t leveldef[NUM_LEVELS] = { - {.filename = "intro.bin", - .timeLimit = 180}, - {.filename = "rightside.bin", - .timeLimit = 180}, - {.filename = "upsidedown.bin", - .timeLimit = 180}, - {.filename = "leftside.bin", - .timeLimit = 180}, - {.filename = "split.bin", - .timeLimit = 180}, - {.filename = "mag01.bin", - .timeLimit = 180}, - {.filename = "mag02.bin", - .timeLimit = 180}, - {.filename = "brkLvlChar1.bin", - .timeLimit = 180}, - {.filename = "bombtest.bin", - .timeLimit = 180}, - {.filename = "ponglike.bin", - .timeLimit = 180}, - {.filename = "starlite.bin", - .timeLimit = 180}, - }; - +#define NUM_LEVELS 41 + +// The index into leveldef[] where the actual game levels start +// As opposed to utility levels like titlescreen, debug, etc. +#define GAME_LEVEL_START_INDEX 1 + +static const leveldef_t leveldef[NUM_LEVELS] + = {{.filename = "titlescreen.bin", .timeLimit = 180}, + {.filename = "intro.bin", .timeLimit = 180}, + {.filename = "rightside.bin", .timeLimit = 180}, + {.filename = "upsidedown.bin", .timeLimit = 180}, + {.filename = "leftside.bin", .timeLimit = 180}, + {.filename = "split.bin", .timeLimit = 180}, + {.filename = "mag01.bin", .timeLimit = 180}, + {.filename = "mag02.bin", .timeLimit = 180}, + {.filename = "m_attack.bin", .timeLimit = 180}, + {.filename = "flower.bin", .timeLimit = 180}, + {.filename = "brkLvlChar1.bin", .timeLimit = 180}, + {.filename = "gaylordlogo.bin", .timeLimit = 180}, + {.filename = "trifecta.bin", .timeLimit = 180}, + {.filename = "xmarks.bin", .timeLimit = 180}, + {.filename = "bombtest.bin", .timeLimit = 180}, + {.filename = "devito.bin", .timeLimit = 180}, + {.filename = "lumberjacks.bin", .timeLimit = 180}, + {.filename = "halloween.bin", .timeLimit = 180}, + {.filename = "snake.bin", .timeLimit = 180}, + {.filename = "flipflop.bin", .timeLimit = 180}, + {.filename = "ponglike.bin", .timeLimit = 180}, + {.filename = "tinyhuge.bin", .timeLimit = 180}, + {.filename = "superhard.bin", .timeLimit = 180}, + {.filename = "firework.bin", .timeLimit = 180}, + {.filename = "starlite.bin", .timeLimit = 180}, + {.filename = "jailbreak.bin", /*Starting here, the levels are NOT in order!*/ + .timeLimit = 180}, + {.filename = "getMorGet.bin", .timeLimit = 180}, + {.filename = "outtaMyWay.bin", .timeLimit = 180}, + {.filename = "bombrings.bin", .timeLimit = 180}, + {.filename = "angles.bin", .timeLimit = 180}, + {.filename = "themaze.bin", .timeLimit = 180}, + {.filename = "intersection.bin", .timeLimit = 180}, + {.filename = "foosball.bin", .timeLimit = 180}, + {.filename = "paddles.bin", .timeLimit = 180}, + {.filename = "corner.bin", .timeLimit = 180}, + {.filename = "b.bin", .timeLimit = 180}, + {.filename = "wtf.bin", .timeLimit = 180}, + {.filename = "mag03.bin", .timeLimit = 180}, + {.filename = "wallball.bin", .timeLimit = 180}, + {.filename = "introenemy.bin", .timeLimit = 180}, + {.filename = "stormcastle.bin", .timeLimit = 180}}; + //============================================================================== // Look Up Tables //============================================================================== -static const paletteColor_t greenColors[4] = {c555, c051, c030, c051}; +static const paletteColor_t highScoreNewEntryColors[4] = {c050, c055, c005, c055}; +static const paletteColor_t redColors[4] = {c510, c440, c050, c440}; +static const paletteColor_t greenColors[4] = {c555, c051, c030, c051}; +static const paletteColor_t purpleColors[4] = {c405, c440, c055, c440}; + +static const int16_t cheatCode[9] = {PB_UP, PB_B, PB_DOWN, PB_B, PB_LEFT, PB_B, PB_RIGHT, PB_B, PB_START}; //============================================================================== // Strings @@ -166,17 +206,31 @@ static const paletteColor_t greenColors[4] = {c555, c051, c030, c051}; * Lengths are not explicitly given so the compiler can figure it out. */ -static const char breakoutName[] = "Galactic Brickdown"; +static const char breakoutName[] = "Galactic Brickdown"; +static const char breakoutTitleGalactic[] = "Galactic"; +static const char breakoutTitleBrickdown[] = "Brickdown"; +static const char breakoutPressStart[] = "Press Start"; -static const char breakoutNewGame[] = "New Game"; -static const char breakoutContinue[] = "Continue - Lv"; -static const char breakoutExit[] = "Exit"; +static const char breakoutNewGame[] = "New Game"; +static const char breakoutContinue[] = "Continue - Lv"; +static const char breakoutHighScores[] = "High Scores"; +static const char breakoutResetScores[] = "Reset Scores"; +static const char breakoutResetProgress[] = "Reset Progress"; +static const char breakoutExit[] = "Exit"; +static const char breakoutSaveAndExit[] = "Save & Exit"; -static const char breakoutReady[] = "Get Ready!"; +static const char breakoutReady[] = "Get Ready!"; static const char breakoutGameOver[] = "Game Over!"; static const char breakoutLevelClear[] = "Cleared!"; -static const char breakoutPause[] = "Paused"; +static const char breakoutPause[] = "Paused"; + +static const char breakoutHighScoreDisplayTitle[] = "Cosmic Scores"; +static const char breakoutNameEntryTitle[] = "Enter your initials!"; +static const char breakoutNameEnteredTitle[] = "Name registrated."; + +static const char breakoutNvsKey_scores[] = "brk_scores"; +static const char breakoutNvsKey_unlocks[] = "brk_unlocks"; //============================================================================== // Variables @@ -220,46 +274,29 @@ static void breakoutEnterMode(void) loadFont("logbook.font", &breakout->logbook, false); loadFont("ibm_vga8.font", &breakout->ibm_vga8, false); - // Initialize the menu - breakout->menu = initMenu(breakoutName, breakoutMenuCb); breakout->mRenderer = initMenuLogbookRenderer(&breakout->logbook); - initializeGameData(&(breakout->gameData)); + initializeGameData(&(breakout->gameData), &(breakout->soundManager)); initializeTileMap(&(breakout->tilemap)); initializeSoundManager(&(breakout->soundManager)); - initializeEntityManager(&(breakout->entityManager), &(breakout->tilemap), &(breakout->gameData), &(breakout->soundManager)); + initializeEntityManager(&(breakout->entityManager), &(breakout->tilemap), &(breakout->gameData), + &(breakout->soundManager)); initializeStarfield(&(breakout->starfield), false); - breakout->tilemap.entityManager = &(breakout->entityManager); + breakout->tilemap.entityManager = &(breakout->entityManager); breakout->tilemap.executeTileSpawnAll = true; - breakout->tilemap.mapOffsetX = -4; - - loadMapFromFile(&(breakout->tilemap), leveldef[0].filename); + breakout->tilemap.mapOffsetX = 0; - addSingleItemToMenu(breakout->menu, breakoutNewGame); - - /* - Manually allocate and build "level select" menu item - because the max setting will have to change as levels are unlocked - */ + // loadMapFromFile(&(breakout->tilemap), leveldef[0].filename); - breakout->levelSelectMenuItem = calloc(1,sizeof(menuItem_t)); - breakout->levelSelectMenuItem->label = breakoutContinue; - breakout->levelSelectMenuItem->minSetting = 1; - breakout->levelSelectMenuItem->maxSetting = NUM_LEVELS; - breakout->levelSelectMenuItem->currentSetting = 1; - breakout->levelSelectMenuItem->options = NULL; - breakout->levelSelectMenuItem->subMenu = NULL; + breakoutLoadHighScores(breakout); + breakoutLoadUnlockables(breakout); - push(breakout->menu->items, breakout->levelSelectMenuItem); - - addSingleItemToMenu(breakout->menu, breakoutExit); - - //Set frame rate to 60 FPS + // Set frame rate to 60 FPS setFrameRateUs(16666); - // Set the mode to menu mode - breakout->update = &breakoutUpdateTitleScreen; + breakout->menu = NULL; + breakoutChangeStateTitleScreen(breakout); } /** @@ -267,9 +304,14 @@ static void breakoutEnterMode(void) */ static void breakoutExitMode(void) { - // Deinitialize the menu. - // This will also free the "level select" menu item. - deinitMenu(breakout->menu); + // deinitMenu can't set menu pointer to NULL, + // so this is the only way to know that the menu has not been previously freed. + if (breakout->update == &breakoutUpdateMainMenu) + { + // Deinitialize the menu. + // This will also free the "level select" menu item. + deinitMenu(breakout->menu); + } deinitMenuLogbookRenderer(breakout->mRenderer); // Free the fonts @@ -298,23 +340,54 @@ static void breakoutMenuCb(const char* label, bool selected, uint32_t settingVal if (label == breakoutNewGame) { initializeGameDataFromTitleScreen(&(breakout->gameData)); + deactivateAllEntities(&(breakout->entityManager), false, false, false); breakout->gameData.level = 1; - loadMapFromFile(&(breakout->tilemap), leveldef[0].filename); - breakout->gameData.countdown = leveldef[0].timeLimit; - breakoutChangeStateReadyScreen(breakout); - } else if (label == breakoutContinue) + loadMapFromFile(&(breakout->tilemap), leveldef[GAME_LEVEL_START_INDEX].filename); + breakout->gameData.countdown = leveldef[GAME_LEVEL_START_INDEX].timeLimit; + breakoutChangeStateReadyScreen(breakout); + deinitMenu(breakout->menu); + } + else if (label == breakoutContinue) { initializeGameDataFromTitleScreen(&(breakout->gameData)); + deactivateAllEntities(&(breakout->entityManager), false, false, false); breakout->gameData.level = settingVal; - loadMapFromFile(&(breakout->tilemap), leveldef[breakout->gameData.level - 1].filename); - breakout->gameData.countdown = leveldef[breakout->gameData.level -1].timeLimit; - breakoutChangeStateReadyScreen(breakout); + loadMapFromFile(&(breakout->tilemap), leveldef[breakout->gameData.level].filename); + breakout->gameData.countdown = leveldef[breakout->gameData.level].timeLimit; + breakoutChangeStateReadyScreen(breakout); + deinitMenu(breakout->menu); + } + else if (label == breakoutHighScores) + { + breakoutChangeStateShowHighScores(breakout); + breakout->gameData.btnState = 0; + deinitMenu(breakout->menu); + } + else if (label == breakoutResetScores) + { + breakoutInitializeHighScores(breakout); + bzrPlaySfx(&(breakout->soundManager.detonate), BZR_STEREO); + } + else if (label == breakoutResetProgress) + { + breakoutInitializeHighScores(breakout); + bzrPlaySfx(&(breakout->soundManager.die), BZR_STEREO); + } + else if (label == breakoutSaveAndExit) + { + breakoutSaveHighScores(breakout); + breakoutSaveUnlockables(breakout); + switchToSwadgeMode(&mainMenuMode); } else if (label == breakoutExit) { switchToSwadgeMode(&mainMenuMode); } } + else + { + bzrPlaySfx(&(breakout->soundManager.hit3), BZR_STEREO); + } } /** @@ -325,54 +398,109 @@ static void breakoutMenuCb(const char* label, bool selected, uint32_t settingVal */ static void breakoutMainLoop(int64_t elapsedUs) { - breakout->update(breakout, elapsedUs); -} - -void breakoutChangeStateTitleScreen(breakout_t *self){ - self->gameData.frameCount = 0; - self->update=&breakoutUpdateTitleScreen; -} - -static void breakoutUpdateTitleScreen(breakout_t *self, int64_t elapsedUs){ // Process button events buttonEvt_t evt = {0}; while (checkButtonQueueWrapper(&evt)) { - // Pass button events to the menu - breakout->menu = menuButton(breakout->menu, evt); + // Save the button state + breakout->btnState = evt.state; + breakout->gameData.btnState = evt.state; + + if (breakout->update == &breakoutUpdateMainMenu) + { + // Pass button events to the menu + breakout->menu = menuButton(breakout->menu, evt); + } } + breakout->update(breakout, elapsedUs); + + breakout->prevBtnState = breakout->btnState; + breakout->gameData.prevBtnState = breakout->prevBtnState; +} + +void breakoutChangeStateMainMenu(breakout_t* self) +{ + self->gameData.frameCount = 0; + self->update = &breakoutUpdateMainMenu; + breakoutBuildMainMenu(breakout); +} + +static void breakoutUpdateMainMenu(breakout_t* self, int64_t elapsedUs) +{ // Draw the menu drawMenuLogbook(breakout->menu, breakout->mRenderer, elapsedUs); } -static void breakoutChangeStateReadyScreen(breakout_t *self){ +static void breakoutChangeStateReadyScreen(breakout_t* self) +{ self->gameData.frameCount = 0; + + // Set up Cho Intro + deactivateAllEntities(&(self->entityManager), false, true, true); + self->gameData.ballsInPlay = 0; + forceTileSpawnEntitiesWithinView(&(self->tilemap)); + + self->entityManager.playerEntity = NULL; + self->entityManager.playerEntity = createEntity(&(self->entityManager), ENTITY_CHO_INTRO, 0, 0); + self->update = &breakoutUpdateReadyScreen; } -static void breakoutUpdateReadyScreen(breakout_t *self, int64_t elapsedUs){ +static void breakoutUpdateReadyScreen(breakout_t* self, int64_t elapsedUs) +{ self->gameData.frameCount++; - if(self->gameData.frameCount > 179){ - breakoutChangeStateGame(self); - } updateLedsInGame(&(self->gameData)); + drawStarfield(&(self->starfield)); + + if (self->entityManager.playerEntity != NULL && self->entityManager.playerEntity->active) + { + self->entityManager.playerEntity->updateFunction(self->entityManager.playerEntity); + + if (self->gameData.targetBlocksBroken > 0) + { + drawTileMap(&(self->tilemap)); + updateStarfield(&(self->starfield), 1); + } + } + else + { + if (!(self->gameData.frameCount % 60)) + { + breakoutChangeStateGame(self); + } + + if (self->gameData.targetBlocksBroken > 0 || !(self->gameData.frameCount % 2)) + { + drawTileMap(&(self->tilemap)); + } + + updateStarfield(&(self->starfield), 1); + } + + drawEntities(&(self->entityManager)); breakoutDrawReadyScreen(&(self->logbook), &(self->ibm_vga8), &(self->gameData)); } -static void breakoutDrawReadyScreen(font_t *logbook, font_t *ibm_vga8, gameData_t *gameData){ +static void breakoutDrawReadyScreen(font_t* logbook, font_t* ibm_vga8, gameData_t* gameData) +{ drawBreakoutHud(ibm_vga8, gameData); drawText(logbook, c555, breakoutReady, (TFT_WIDTH - textWidth(logbook, breakoutReady)) >> 1, 128); } -static void breakoutChangeStateGame(breakout_t *self){ - self->gameData.frameCount = 0; - self->gameData.playerTimeBombsCount = 0; +static void breakoutChangeStateGame(breakout_t* self) +{ + self->gameData.frameCount = 0; + self->gameData.playerTimeBombsCount = 0; self->gameData.playerRemoteBombPlaced = false; - deactivateAllEntities(&(self->entityManager), false, true); - self->tilemap.executeTileSpawnAll = true; - self->update = &breakoutGameLoop; + // deactivateAllEntities(&(self->entityManager), false, true); + // self->tilemap.executeTileSpawnAll = true; + + // TODO: State change functions should probably always reset this. + self->gameData.changeState = 0; + self->gameData.gameState = ST_GAME; + self->update = &breakoutGameLoop; } /** @@ -381,15 +509,14 @@ static void breakoutChangeStateGame(breakout_t *self){ * * @param elapsedUs The time that has elapsed since the last call to this function, in microseconds */ -static void breakoutGameLoop(breakout_t *self, int64_t elapsedUs) +static void breakoutGameLoop(breakout_t* self, int64_t elapsedUs) { - buttonEvt_t evt = {0}; - while (checkButtonQueueWrapper(&evt)) + updateTouchInput(&(self->gameData)); + + if (((breakout->gameData.btnState & PB_START) && !(breakout->gameData.prevBtnState & PB_START))) { - // Save the button state - self->gameData.btnState = evt.state; + breakout->gameData.changeState = ST_PAUSE; } - updateTouchInput(&(self->gameData)); updateLedsInGame(&(self->gameData)); breakoutDetectGameStateChange(self); @@ -404,17 +531,17 @@ static void breakoutGameLoop(breakout_t *self, int64_t elapsedUs) drawBreakoutHud(&(self->ibm_vga8), &(breakout->gameData)); self->gameData.frameCount++; - if(self->gameData.frameCount > 59){ + if (self->gameData.frameCount > 59) + { self->gameData.frameCount = 0; - if(self->gameData.countdown > 0){ + if (self->gameData.countdown > 0) + { self->gameData.countdown--; } - + self->gameData.inGameTimer++; } - - self->gameData.prevBtnState = self->gameData.btnState; } /** @@ -434,13 +561,19 @@ static void breakoutBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int1 fillDisplayArea(x, y, x + w, y + h, c000); } -void breakoutDetectGameStateChange(breakout_t *self){ - if(!self->gameData.changeState){ +void breakoutDetectGameStateChange(breakout_t* self) +{ + if (!self->gameData.changeState) + { return; } switch (self->gameData.changeState) { + case ST_GAME: + breakoutChangeStateGame(self); + return; + case ST_DEAD: breakoutChangeStateDead(self); break; @@ -448,7 +581,7 @@ void breakoutDetectGameStateChange(breakout_t *self){ case ST_READY_SCREEN: breakoutChangeStateReadyScreen(self); break; - + case ST_LEVEL_CLEAR: breakoutChangeStateLevelClear(self); break; @@ -464,28 +597,35 @@ void breakoutDetectGameStateChange(breakout_t *self){ self->gameData.changeState = 0; } -void breakoutChangeStateDead(breakout_t *self){ +void breakoutChangeStateDead(breakout_t* self) +{ self->gameData.frameCount = 0; self->gameData.lives--; - //self->gameData.levelDeaths++; + // self->gameData.levelDeaths++; self->gameData.combo = 0; - //self->gameData.initialHp = 1; + // self->gameData.initialHp = 1; - //buzzer_stop(); - //buzzer_play_bgm(&sndDie); + // buzzer_stop(); + // buzzer_play_bgm(&sndDie); - self->update=&breakoutUpdateDead; + self->update = &breakoutUpdateDead; } - -void breakoutUpdateDead(breakout_t *self, int64_t elapsedUs){ +void breakoutUpdateDead(breakout_t* self, int64_t elapsedUs) +{ self->gameData.frameCount++; - if(self->gameData.frameCount > 179){ + if (self->gameData.frameCount > 179) + { resetGameDataLeds(&(self->gameData)); - if(self->gameData.lives > 0){ + if (self->gameData.lives > 0) + { breakoutChangeStateReadyScreen(self); - } else { + return; + } + else + { breakoutChangeStateGameOver(self); + return; } } @@ -494,26 +634,30 @@ void breakoutUpdateDead(breakout_t *self, int64_t elapsedUs){ updateStarfield(&(self->starfield), 5); drawStarfield(&(self->starfield)); - + drawTileMap(&(self->tilemap)); drawEntities(&(self->entityManager)); drawBreakoutHud(&(self->ibm_vga8), &(self->gameData)); /*if(self->gameData.countdown < 0){ - drawText(self->disp, &(self->radiostars), c555, str_time_up, (self->disp->w - textWidth(&(self->radiostars), str_time_up)) / 2, 128); + drawText(self->disp, &(self->radiostars), c555, str_time_up, (self->disp->w - textWidth(&(self->radiostars), + str_time_up)) / 2, 128); }*/ } -void breakoutChangeStateGameOver(breakout_t *self){ +void breakoutChangeStateGameOver(breakout_t* self) +{ self->gameData.frameCount = 0; - resetGameDataLeds(&(self->gameData)); - //buzzer_play_bgm(&bgmGameOver); - self->update=&breakoutUpdateGameOver; + resetGameDataLeds(&(self->gameData)); + // buzzer_play_bgm(&bgmGameOver); + self->update = &breakoutUpdateGameOver; } -void breakoutUpdateGameOver(breakout_t *self, int64_t elapsedUs){ +void breakoutUpdateGameOver(breakout_t* self, int64_t elapsedUs) +{ self->gameData.frameCount++; - if(self->gameData.frameCount > 179){ + if (self->gameData.frameCount > 179) + { /*//Handle unlockables if(self->gameData.score >= BIG_SCORE) { @@ -527,22 +671,23 @@ void breakoutUpdateGameOver(breakout_t *self, int64_t elapsedUs){ if(!self->gameData.debugMode){ savePlatformerUnlockables(self); } - - changeStateNameEntry(self);*/ - deactivateAllEntities(&(self->entityManager), false, false); - breakoutChangeStateTitleScreen(self); + */ + deactivateAllEntities(&(self->entityManager), false, false, false); + breakoutChangeStateNameEntry(self); } breakoutDrawGameOver(&(self->logbook), &(self->ibm_vga8), &(self->gameData)); - //updateLedsGameOver(&(self->gameData)); + // updateLedsGameOver(&(self->gameData)); } -void breakoutDrawGameOver(font_t *logbook, font_t *ibm_vga8, gameData_t *gameData){ +void breakoutDrawGameOver(font_t* logbook, font_t* ibm_vga8, gameData_t* gameData) +{ drawBreakoutHud(ibm_vga8, gameData); drawText(logbook, c555, breakoutGameOver, (TFT_WIDTH - textWidth(logbook, breakoutGameOver)) / 2, 128); } -static void drawBreakoutHud(font_t *font, gameData_t *gameData){ +static void drawBreakoutHud(font_t* font, gameData_t* gameData) +{ char scoreStr[32]; snprintf(scoreStr, sizeof(scoreStr) - 1, "%06" PRIu32, gameData->score); @@ -552,146 +697,170 @@ static void drawBreakoutHud(font_t *font, gameData_t *gameData){ char livesStr[8]; snprintf(livesStr, sizeof(livesStr) - 1, "x%d", gameData->lives); - //char timeStr[10]; - //snprintf(timeStr, sizeof(timeStr) - 1, "T:%03d", gameData->countdown); + // char timeStr[10]; + // snprintf(timeStr, sizeof(timeStr) - 1, "T:%03d", gameData->countdown); - if(gameData->frameCount > 29) { + if (gameData->frameCount > 29) + { drawText(font, c500, "1UP", 24, 2); } - + drawText(font, c555, livesStr, 48, 2); - //drawText(font, c555, coinStr, 160, 16); + // drawText(font, c555, coinStr, 160, 16); drawText(font, c555, scoreStr, 80, 2); drawText(font, c555, levelStr, 184, 2); - //drawText(d, font, (gameData->countdown > 30) ? c555 : redColors[(gameData->frameCount >> 3) % 4], timeStr, 220, 16); + // drawText(d, font, (gameData->countdown > 30) ? c555 : redColors[(gameData->frameCount >> 3) % 4], timeStr, 220, + // 16); drawText(font, c555, "B", 271, 32); drawText(font, c555, "O", 271, 44); drawText(font, c555, "N", 271, 56); drawText(font, c555, "U", 271, 68); drawText(font, c555, "S", 271, 80); - drawRect(271,96,279,96+(gameData->countdown >> 1), c555); + drawRect(271, 96, 279, 96 + (gameData->countdown >> 1), c555); - //if(gameData->comboTimer == 0){ - // return; - //} + // if(gameData->comboTimer == 0){ + // return; + // } - //snprintf(scoreStr, sizeof(scoreStr) - 1, "+%" PRIu32 " (x%d)", gameData->comboScore, gameData->combo); + // snprintf(scoreStr, sizeof(scoreStr) - 1, "+%" PRIu32 " (x%d)", gameData->comboScore, gameData->combo); snprintf(scoreStr, sizeof(scoreStr) - 1, "x%d", gameData->combo); - drawText(font, /*(gameData->comboTimer < 60) ? c030:*/ greenColors[(breakout->gameData.frameCount >> 3) % 4], scoreStr, 144, 2); + drawText(font, /*(gameData->comboTimer < 60) ? c030:*/ greenColors[(breakout->gameData.frameCount >> 3) % 4], + scoreStr, 144, 2); + + // Draw centering lines, for paddle control debug + // drawLine(TFT_WIDTH >> 1, 0, TFT_WIDTH >> 1, TFT_HEIGHT, c500, 0); + // drawLine(0, (TFT_HEIGHT >> 1)+8, TFT_WIDTH, (TFT_HEIGHT >> 1)+8, c005, 0); } -void breakoutChangeStateLevelClear(breakout_t *self){ +void breakoutChangeStateLevelClear(breakout_t* self) +{ self->gameData.frameCount = 0; resetGameDataLeds(&(self->gameData)); - self->update=&breakoutUpdateLevelClear; + self->update = &breakoutUpdateLevelClear; } -void breakoutUpdateLevelClear(breakout_t *self, int64_t elapsedUs){ +void breakoutUpdateLevelClear(breakout_t* self, int64_t elapsedUs) +{ self->gameData.frameCount++; self->gameData.targetBlocksBroken = 0; - if(self->gameData.frameCount > 60){ - if(self->gameData.countdown > 0){ + if (self->gameData.frameCount > 60) + { + if (self->gameData.countdown > 0) + { self->gameData.countdown--; - - if(self->gameData.countdown % 2){ + + if (self->gameData.countdown % 2) + { bzrPlayBgm(&(self->soundManager.tally), BZR_STEREO); } - uint16_t comboPoints = 20 * self->gameData.combo; + scorePoints(&(self->gameData), 80, -1); + } + else if (self->gameData.frameCount % 60 == 0) + { + // Hey look, it's a frame rule! + deactivateAllEntities(&(self->entityManager), false, false, false); + + uint16_t levelIndex = self->gameData.level; - self->gameData.score += comboPoints; - self->gameData.comboScore = comboPoints; + if (levelIndex >= NUM_LEVELS - 1) + { + // Game Cleared! - if(self->gameData.combo > 1){ - self->gameData.combo--; - } - } else if(self->gameData.frameCount % 60 == 0) { - //Hey look, it's a frame rule! - deactivateAllEntities(&(self->entityManager), false, false); - - uint16_t levelIndex = self->gameData.level - 1; - - if(levelIndex >= NUM_LEVELS - 1){ - //Game Cleared! - - //if(!self->gameData.debugMode){ - //Determine achievements - /*self->unlockables.gameCleared = true; - - if(!self->gameData.continuesUsed){ - self->unlockables.oneCreditCleared = true; - - if(self->gameData.inGameTimer < FAST_TIME) { - self->unlockables.fastTime = true; - } - } + // if(!self->gameData.debugMode){ + // Determine achievements + /*self->unlockables.gameCleared = true; - if(self->gameData.score >= BIG_SCORE) { - self->unlockables.bigScore = true; - } + if(!self->gameData.continuesUsed){ + self->unlockables.oneCreditCleared = true; - if(self->gameData.score >= BIGGER_SCORE) { - self->unlockables.biggerScore = true; + if(self->gameData.inGameTimer < FAST_TIME) { + self->unlockables.fastTime = true; } - }*/ + } + + if(self->gameData.score >= BIG_SCORE) { + self->unlockables.bigScore = true; + } + + if(self->gameData.score >= BIGGER_SCORE) { + self->unlockables.biggerScore = true; + } + }*/ breakoutChangeStateGameClear(self); return; - } else { - //Advance to the next level + } + else + { + // Advance to the next level self->gameData.level++; - //Unlock the next level + // Unlock the next level levelIndex++; - /*if(levelIndex > self->unlockables.maxLevelIndexUnlocked){ + if (levelIndex > self->unlockables.maxLevelIndexUnlocked) + { self->unlockables.maxLevelIndexUnlocked = levelIndex; - }*/ + } loadMapFromFile(&(breakout->tilemap), leveldef[levelIndex].filename); breakout->gameData.countdown = leveldef[levelIndex].timeLimit; breakoutChangeStateReadyScreen(self); + if (!self->gameData.debugMode) + { + breakoutSaveUnlockables(self); + } + return; } - - /*if(!self->gameData.debugMode){ - savePlatformerUnlockables(self); - }*/ } } + else if (self->gameData.frameCount < 30 || !(self->gameData.frameCount % 2)) + { + drawTileMap(&(self->tilemap)); + } - //updateEntities(&(self->entityManager)); + updateEntities(&(self->entityManager)); drawStarfield(&(self->starfield)); - drawTileMap(&(self->tilemap)); + // drawTileMap(&(self->tilemap)); drawEntities(&(self->entityManager)); drawBreakoutHud(&(self->ibm_vga8), &(self->gameData)); - breakoutDrawLevelClear( &(self->logbook), &(self->gameData)); + breakoutDrawLevelClear(&(self->logbook), &(self->gameData)); updateLedsLevelClear(&(self->gameData)); } -void breakoutDrawLevelClear(font_t *font, gameData_t *gameData){ +void breakoutDrawLevelClear(font_t* font, gameData_t* gameData) +{ drawText(font, c555, breakoutLevelClear, (TFT_WIDTH - textWidth(font, breakoutLevelClear)) / 2, 128); } -void breakoutChangeStateGameClear(breakout_t *self){ +void breakoutChangeStateGameClear(breakout_t* self) +{ self->gameData.frameCount = 0; - self->update=&breakoutUpdateGameClear; + self->update = &breakoutUpdateGameClear; resetGameDataLeds(&(self->gameData)); - //buzzer_play_bgm(&bgmSmooth); + // buzzer_play_bgm(&bgmSmooth); } -void breakoutUpdateGameClear(breakout_t *self, int64_t elapsedUs){ +void breakoutUpdateGameClear(breakout_t* self, int64_t elapsedUs) +{ self->gameData.frameCount++; - if(self->gameData.frameCount > 450){ - if(self->gameData.lives > 0){ - if(self->gameData.frameCount % 60 == 0){ + if (self->gameData.frameCount > 450) + { + if (self->gameData.lives > 0) + { + if (self->gameData.frameCount % 60 == 0) + { self->gameData.lives--; self->gameData.score += 200000; - //buzzer_play_sfx(&snd1up); + // buzzer_play_sfx(&snd1up); } - } else if(self->gameData.frameCount % 960 == 0) { + } + else if (self->gameData.frameCount % 960 == 0) + { breakoutChangeStateGameOver(self); } } @@ -701,42 +870,35 @@ void breakoutUpdateGameClear(breakout_t *self, int64_t elapsedUs){ updateLedsGameClear(&(self->gameData)); } -void breakoutDrawGameClear(font_t *ibm_vga8, font_t *logbook, gameData_t *gameData){ +void breakoutDrawGameClear(font_t* ibm_vga8, font_t* logbook, gameData_t* gameData) +{ drawBreakoutHud(ibm_vga8, gameData); drawText(logbook, c555, "Thanks for playing!", 16, 48); - - if(gameData->frameCount > 300){ + + if (gameData->frameCount > 300) + { drawText(logbook, c555, "See you next", 8, 112); drawText(logbook, c555, "debug mission!", 8, 160); } - } -void breakoutChangeStatePause(breakout_t *self){ - //buzzer_play_bgm(&sndPause); +void breakoutChangeStatePause(breakout_t* self) +{ + // buzzer_play_bgm(&sndPause); self->gameData.btnState = 0; - self->update=&breakoutUpdatePause; + self->update = &breakoutUpdatePause; } -void breakoutUpdatePause(breakout_t *self, int64_t elapsedUs){ - buttonEvt_t evt = {0}; - while (checkButtonQueueWrapper(&evt)) +void breakoutUpdatePause(breakout_t* self, int64_t elapsedUs) +{ + if (((self->gameData.btnState & PB_START) && !(self->gameData.prevBtnState & PB_START))) { - // Save the button state - breakout->gameData.btnState = evt.state; - } - - if(( - (self->gameData.btnState & PB_START) - && - !(self->gameData.prevBtnState & PB_START) - )){ - //buzzer_play_sfx(&sndPause); - //self->gameData.changeBgm = self->gameData.currentBgm; - //self->gameData.currentBgm = BGM_NULL; + // buzzer_play_sfx(&sndPause); + // self->gameData.changeBgm = self->gameData.currentBgm; + // self->gameData.currentBgm = BGM_NULL; self->gameData.btnState = 0; - self->update=&breakoutGameLoop; + self->update = &breakoutGameLoop; } drawStarfield(&(self->starfield)); @@ -744,14 +906,408 @@ void breakoutUpdatePause(breakout_t *self, int64_t elapsedUs){ drawEntities(&(self->entityManager)); drawBreakoutHud(&(self->ibm_vga8), &(self->gameData)); breakoutDrawPause(&(self->logbook)); - - self->gameData.prevBtnState = self->prevBtnState; } -void breakoutDrawPause(font_t *font){ +void breakoutDrawPause(font_t* font) +{ drawText(font, c555, breakoutPause, (TFT_WIDTH - textWidth(font, breakoutPause)) / 2, 128); } -uint16_t breakoutGetLevelIndex(uint8_t world, uint8_t level){ - return (world-1) * 4 + (level-1); +uint16_t breakoutGetLevelIndex(uint8_t world, uint8_t level) +{ + return (world - 1) * 4 + (level - 1); +} + +static void breakoutChangeStateTitleScreen(breakout_t* self) +{ + self->gameData.frameCount = 0; + + self->update = &breakoutUpdateTitleScreen; + + if (self->gameData.gameState != ST_TITLE_SCREEN) + { + deactivateAllEntities(&(self->entityManager), false, false, false); + loadMapFromFile(&(breakout->tilemap), leveldef[0].filename); + createEntity(&(self->entityManager), ENTITY_CAPTIVE_BALL, 24 + esp_random() % 232, 24 + esp_random() % 216); + createEntity(&(self->entityManager), ENTITY_CAPTIVE_BALL, 24 + esp_random() % 232, 24 + esp_random() % 216); + createEntity(&(self->entityManager), ENTITY_CAPTIVE_BALL, 24 + esp_random() % 232, 24 + esp_random() % 216); + } + + self->gameData.gameState = ST_TITLE_SCREEN; +} + +static void breakoutUpdateTitleScreen(breakout_t* self, int64_t elapsedUs) +{ + self->gameData.frameCount++; + + if (self->gameData.frameCount > 600) + { + // resetGameDataLeds(&(self->gameData)); + breakout->menuSelection = 0; + breakoutChangeStateShowHighScores(self); + + return; + } + + if ((self->gameData.btnState & cheatCode[breakout->menuSelection]) + && !(self->gameData.prevBtnState & cheatCode[breakout->menuSelection])) + { + breakout->menuSelection++; + + if (breakout->menuSelection > 8) + { + breakout->menuSelection = 0; + breakout->menuState = 1; + breakout->gameData.debugMode = true; + bzrPlaySfx(&(breakout->soundManager.snd1up), BZR_STEREO); + } + else + { + bzrPlaySfx(&(breakout->soundManager.hit3), BZR_STEREO); + } + } + + if (((self->gameData.btnState & PB_START) && !(self->gameData.prevBtnState & PB_START))) + { + self->gameData.btnState = 0; + breakout->menuSelection = 0; + + if (!breakout->gameData.debugMode) + { + bzrPlaySfx(&(breakout->soundManager.launch), BZR_STEREO); + } + + breakoutChangeStateMainMenu(self); + return; + } + + /* + if(!(self->gameData.frameCount % 180)) { + createEntity(&(self->entityManager), ENTITY_CAPTIVE_BALL, 24 + esp_random() % 232, 24 + esp_random() % 216); + } + */ + + updateStarfield(&(self->starfield), 8); + updateEntities(&(self->entityManager)); + drawStarfield(&(self->starfield)); + drawTileMap(&(self->tilemap)); + drawEntities(&(self->entityManager)); + breakoutDrawTitleScreen(&(self->logbook), &(self->gameData)); + updateLedsTitleScreen(&(self->gameData)); +} + +static void breakoutDrawTitleScreen(font_t* font, gameData_t* gameData) +{ + drawText(font, c000, breakoutTitleGalactic, 52, 100); + drawText(font, c000, breakoutTitleBrickdown, 100, 124); + drawText(font, purpleColors[(breakout->gameData.frameCount >> 3) % 4], breakoutTitleGalactic, 48, 96); + drawText(font, redColors[(breakout->gameData.frameCount >> 3) % 4], breakoutTitleBrickdown, 96, 120); + + if ((gameData->frameCount % 60) < 30) + { + drawText(font, c555, breakoutPressStart, (TFT_WIDTH - textWidth(font, breakoutPressStart)) >> 1, 192); + } +} + +void breakoutInitializeHighScores(breakout_t* self) +{ + self->highScores.scores[0] = 100000; + self->highScores.scores[1] = 80000; + self->highScores.scores[2] = 40000; + self->highScores.scores[3] = 20000; + self->highScores.scores[4] = 10000; + + for (uint8_t i = 0; i < NUM_BREAKOUT_HIGH_SCORES; i++) + { + self->highScores.initials[i][0] = 'J' + i; + self->highScores.initials[i][1] = 'P' - i; + self->highScores.initials[i][2] = 'V' + i; + } +} + +void breakoutLoadHighScores(breakout_t* self) +{ + size_t size = sizeof(breakoutHighScores_t); + // Try reading the value + if (false == readNvsBlob(breakoutNvsKey_scores, &(self->highScores), &(size))) + { + // Value didn't exist, so write the default + breakoutInitializeHighScores(self); + } +} + +void breakoutSaveHighScores(breakout_t* self) +{ + size_t size = sizeof(breakoutHighScores_t); + writeNvsBlob(breakoutNvsKey_scores, &(self->highScores), size); +} + +void breakoutDrawHighScores(font_t* font, breakoutHighScores_t* highScores, gameData_t* gameData) +{ + drawText(font, redColors[(gameData->frameCount >> 3) % 4], "Rank Score Name", 10, 88); + for (uint8_t i = 0; i < NUM_BREAKOUT_HIGH_SCORES; i++) + { + char rowStr[32]; + snprintf(rowStr, sizeof(rowStr) - 1, " %d %06" PRIu32 " %c%c%c", i + 1, highScores->scores[i], + highScores->initials[i][0], highScores->initials[i][1], highScores->initials[i][2]); + drawText(font, (gameData->rank == i) ? highScoreNewEntryColors[(gameData->frameCount >> 3) % 4] : c555, rowStr, + 16, 120 + i * 22); + } +} + +uint8_t breakoutGetHighScoreRank(breakoutHighScores_t* highScores, uint32_t newScore) +{ + uint8_t i; + for (i = 0; i < NUM_BREAKOUT_HIGH_SCORES; i++) + { + if (highScores->scores[i] < newScore) + { + break; + } + } + + return i; +} + +void breakoutInsertScoreIntoHighScores(breakoutHighScores_t* highScores, uint32_t newScore, char newInitials[], + uint8_t rank) +{ + if (rank >= NUM_BREAKOUT_HIGH_SCORES) + { + return; + } + + for (uint8_t i = NUM_BREAKOUT_HIGH_SCORES - 1; i > rank; i--) + { + highScores->scores[i] = highScores->scores[i - 1]; + highScores->initials[i][0] = highScores->initials[i - 1][0]; + highScores->initials[i][1] = highScores->initials[i - 1][1]; + highScores->initials[i][2] = highScores->initials[i - 1][2]; + } + + highScores->scores[rank] = newScore; + highScores->initials[rank][0] = newInitials[0]; + highScores->initials[rank][1] = newInitials[1]; + highScores->initials[rank][2] = newInitials[2]; +} + +//-------------- + +void breakoutChangeStateShowHighScores(breakout_t* self) +{ + self->gameData.frameCount = 0; + self->update = &breakoutUpdateShowHighScores; +} + +void breakoutUpdateShowHighScores(breakout_t* self, int64_t elapsedUs) +{ + self->gameData.frameCount++; + + if ((self->gameData.frameCount > 300) + || (((self->gameData.btnState & PB_START) && !(self->gameData.prevBtnState & PB_START)) + || ((self->gameData.btnState & PB_A) && !(self->gameData.prevBtnState & PB_A)))) + { + self->menuState = 0; + self->menuSelection = 0; + bzrStop(true); + breakoutChangeStateTitleScreen(self); + } + + updateStarfield(&(self->starfield), 8); + drawStarfield(&(self->starfield)); + + breakoutDrawShowHighScores(&(self->logbook), self->menuState); + breakoutDrawHighScores(&(self->logbook), &(self->highScores), &(self->gameData)); + + updateLedsTitleScreen(&(self->gameData)); + // updateLedsShowHighScores(&(self->gameData)); +} + +void breakoutDrawShowHighScores(font_t* font, uint8_t menuState) +{ + /*if(platformer->easterEgg){ + drawText(font, highScoreNewEntryColors[(platformer->gameData.frameCount >> 3) % 4], str_hbd, (TFT_WIDTH - + textWidth(font, str_hbd)) / 2, 32); } else*/ + if (menuState == 3) + { + drawText(font, redColors[(breakout->gameData.frameCount >> 3) % 4], breakoutNameEnteredTitle, + (TFT_WIDTH - textWidth(font, breakoutNameEnteredTitle)) / 2, 32); + } + else + { + drawText(font, purpleColors[(breakout->gameData.frameCount >> 3) % 4], breakoutHighScoreDisplayTitle, + (TFT_WIDTH - textWidth(font, breakoutHighScoreDisplayTitle)) / 2, 32); + } +} + +void breakoutChangeStateNameEntry(breakout_t* self) +{ + self->gameData.frameCount = 0; + uint8_t rank = breakoutGetHighScoreRank(&(self->highScores), self->gameData.score); + self->gameData.rank = rank; + self->menuState = 0; + + resetGameDataLeds(&(self->gameData)); + + if (rank >= NUM_BREAKOUT_HIGH_SCORES || self->gameData.debugMode) + { + self->menuSelection = 0; + self->gameData.rank = NUM_BREAKOUT_HIGH_SCORES; + breakoutChangeStateShowHighScores(self); + return; + } + + // bzrPlayBgm(&(self->soundManager.bgmNameEntry), BZR_STEREO); + self->menuSelection = self->gameData.initials[0]; + self->update = &breakoutUpdateNameEntry; +} + +void breakoutUpdateNameEntry(breakout_t* self, int64_t elapsedUs) +{ + self->gameData.frameCount++; + + if (self->gameData.btnState & PB_LEFT && !(self->gameData.prevBtnState & PB_LEFT)) + { + self->menuSelection--; + + if (self->menuSelection < 32) + { + self->menuSelection = 90; + } + + self->gameData.initials[self->menuState] = self->menuSelection; + bzrPlaySfx(&(self->soundManager.hit3), BZR_STEREO); + } + else if (self->gameData.btnState & PB_RIGHT && !(self->gameData.prevBtnState & PB_RIGHT)) + { + self->menuSelection++; + + if (self->menuSelection > 90) + { + self->menuSelection = 32; + } + + self->gameData.initials[self->menuState] = self->menuSelection; + bzrPlaySfx(&(self->soundManager.hit3), BZR_STEREO); + } + else if (self->gameData.btnState & PB_B && !(self->gameData.prevBtnState & PB_B)) + { + if (self->menuState > 0) + { + self->menuState--; + self->menuSelection = self->gameData.initials[self->menuState]; + bzrPlaySfx(&(self->soundManager.hit3), BZR_STEREO); + } + else + { + bzrPlaySfx(&(self->soundManager.hit2), BZR_STEREO); + } + } + else if (self->gameData.btnState & PB_A && !(self->gameData.prevBtnState & PB_A)) + { + self->menuState++; + + if (self->menuState > 2) + { + breakoutInsertScoreIntoHighScores(&(self->highScores), self->gameData.score, self->gameData.initials, + self->gameData.rank); + breakoutSaveHighScores(self); + breakoutChangeStateShowHighScores(self); + bzrPlaySfx(&(self->soundManager.snd1up), BZR_STEREO); + return; + } + else + { + self->menuSelection = self->gameData.initials[self->menuState]; + bzrPlaySfx(&(self->soundManager.hit3), BZR_STEREO); + } + } + + updateStarfield(&(self->starfield), 8); + drawStarfield(&(self->starfield)); + breakoutDrawNameEntry(&(self->logbook), &(self->gameData), self->menuState); + updateLedsShowHighScores(&(self->gameData)); +} + +void breakoutDrawNameEntry(font_t* font, gameData_t* gameData, uint8_t currentInitial) +{ + drawText(font, greenColors[(breakout->gameData.frameCount >> 3) % 4], breakoutNameEntryTitle, + (TFT_WIDTH - textWidth(font, breakoutNameEntryTitle)) / 2, 64); + + char rowStr[32]; + snprintf(rowStr, sizeof(rowStr) - 1, "%d %06" PRIu32, gameData->rank + 1, gameData->score); + drawText(font, c555, rowStr, 16, 128); + + for (uint8_t i = 0; i < 3; i++) + { + snprintf(rowStr, sizeof(rowStr) - 1, "%c", gameData->initials[i]); + drawText(font, (currentInitial == i) ? highScoreNewEntryColors[(gameData->frameCount >> 3) % 4] : c555, rowStr, + 200 + 16 * i, 128); + } +} + +void breakoutInitializeUnlockables(breakout_t* self) +{ + self->unlockables.maxLevelIndexUnlocked = 1; + self->unlockables.gameCleared = false; + /*self->unlockables.oneCreditCleared = false; + self->unlockables.bigScore = false; + self->unlockables.fastTime = false; + self->unlockables.biggerScore = false;*/ +} + +void breakoutLoadUnlockables(breakout_t* self) +{ + size_t size = sizeof(breakoutUnlockables_t); + // Try reading the value + if (false == readNvsBlob(breakoutNvsKey_unlocks, &(self->unlockables), &(size))) + { + // Value didn't exist, so write the default + breakoutInitializeUnlockables(self); + } +} + +void breakoutSaveUnlockables(breakout_t* self) +{ + size_t size = sizeof(breakoutUnlockables_t); + writeNvsBlob(breakoutNvsKey_unlocks, &(self->unlockables), size); +} + +void breakoutBuildMainMenu(breakout_t* self) +{ + // Initialize the menu + breakout->menu = initMenu(breakoutName, breakoutMenuCb); + addSingleItemToMenu(breakout->menu, breakoutNewGame); + + /* + Manually allocate and build "level select" menu item + because the max setting will have to change as levels are unlocked + */ + if (breakout->unlockables.maxLevelIndexUnlocked > 0 || breakout->gameData.debugMode) + { + breakout->levelSelectMenuItem = calloc(1, sizeof(menuItem_t)); + breakout->levelSelectMenuItem->label = breakoutContinue; + breakout->levelSelectMenuItem->minSetting = 1; + breakout->levelSelectMenuItem->maxSetting + = (breakout->gameData.debugMode) ? NUM_LEVELS - 1 : breakout->unlockables.maxLevelIndexUnlocked; + breakout->levelSelectMenuItem->currentSetting + = (breakout->gameData.level == 0) ? breakout->levelSelectMenuItem->maxSetting : breakout->gameData.level; + breakout->levelSelectMenuItem->options = NULL; + breakout->levelSelectMenuItem->subMenu = NULL; + + push(breakout->menu->items, breakout->levelSelectMenuItem); + } + + addSingleItemToMenu(breakout->menu, breakoutHighScores); + + if (breakout->gameData.debugMode) + { + addSingleItemToMenu(breakout->menu, breakoutResetScores); + addSingleItemToMenu(breakout->menu, breakoutResetProgress); + addSingleItemToMenu(breakout->menu, breakoutSaveAndExit); + } + else + { + addSingleItemToMenu(breakout->menu, breakoutExit); + } } \ No newline at end of file diff --git a/main/modes/breakout/breakout.h b/main/modes/breakout/breakout.h index abd9137b2..bb2e7569c 100644 --- a/main/modes/breakout/breakout.h +++ b/main/modes/breakout/breakout.h @@ -5,4 +5,30 @@ extern swadgeMode_t breakoutMode; +/*============================================================================== + * Defines + *============================================================================*/ + +#define NUM_BREAKOUT_HIGH_SCORES 5 + +//============================================================================== +// Structs +//============================================================================== + +typedef struct +{ + uint32_t scores[NUM_BREAKOUT_HIGH_SCORES]; + char initials[NUM_BREAKOUT_HIGH_SCORES][3]; +} breakoutHighScores_t; + +typedef struct +{ + uint8_t maxLevelIndexUnlocked; + bool gameCleared; + /*bool oneCreditCleared; + bool bigScore; + bool fastTime; + bool biggerScore;*/ +} breakoutUnlockables_t; + #endif \ No newline at end of file diff --git a/main/modes/breakout/breakout_typedef.h b/main/modes/breakout/breakout_typedef.h index 9897abaed..3e3d61668 100644 --- a/main/modes/breakout/breakout_typedef.h +++ b/main/modes/breakout/breakout_typedef.h @@ -6,7 +6,8 @@ typedef struct entityManager_t entityManager_t; typedef struct tilemap_t tilemap_t; typedef struct entity_t entity_t; -typedef enum { +typedef enum +{ ST_NULL, ST_TITLE_SCREEN, ST_READY_SCREEN, @@ -20,7 +21,8 @@ typedef enum { ST_PAUSE } gameStateEnum_t; -typedef enum { +typedef enum +{ BGM_NO_CHANGE, BGM_MAIN, BGM_ATHLETIC, @@ -29,13 +31,15 @@ typedef enum { BGM_NULL } bgmEnum_t; -typedef enum { +typedef enum +{ SP_PADDLE_0, SP_PADDLE_1, SP_PADDLE_2, SP_PADDLE_VERTICAL_0, SP_PADDLE_VERTICAL_1, SP_PADDLE_VERTICAL_2, + SP_BALL, SP_BALL_0, SP_BALL_1, SP_BALL_2, @@ -45,7 +49,23 @@ typedef enum { SP_EXPLOSION_0, SP_EXPLOSION_1, SP_EXPLOSION_2, - SP_EXPLOSION_3 + SP_EXPLOSION_3, + SP_BALL_TRAIL_0, + SP_BALL_TRAIL_1, + SP_BALL_TRAIL_2, + SP_BALL_TRAIL_3, + SP_CHO_WALK_0, + SP_CHO_WALK_1, + SP_CHO_WALK_2, + SP_CHO_WIN_0, + SP_CHO_WIN_1, + SP_CRAWLER_TOP, + SP_CRAWLER_RIGHT, + SP_CRAWLER_BOTTOM, + SP_CRAWLER_LEFT, + SP_RBOMB_0, + SP_RBOMB_1, + SP_RBOMB_2 } spriteDef_t; #endif \ No newline at end of file diff --git a/main/modes/breakout/entity.c b/main/modes/breakout/entity.c index 091835db3..f260bdfa4 100644 --- a/main/modes/breakout/entity.c +++ b/main/modes/breakout/entity.c @@ -17,13 +17,13 @@ //============================================================================== // Constants //============================================================================== -#define SUBPIXEL_RESOLUTION 4 +#define SUBPIXEL_RESOLUTION 4 #define TILE_SIZE_IN_POWERS_OF_2 3 -#define TILE_SIZE 8 -#define HALF_TILE_SIZE 4 -#define DESPAWN_THRESHOLD 64 +#define TILE_SIZE 8 +#define HALF_TILE_SIZE 4 +#define DESPAWN_THRESHOLD 64 -#define SIGNOF(x) ((x > 0) - (x < 0)) +#define SIGNOF(x) ((x > 0) - (x < 0)) #define TO_TILE_COORDS(x) ((x) >> TILE_SIZE_IN_POWERS_OF_2) // #define TO_PIXEL_COORDS(x) ((x) >> SUBPIXEL_RESOLUTION) // #define TO_SUBPIXEL_COORDS(x) ((x) << SUBPIXEL_RESOLUTION) @@ -34,63 +34,47 @@ #define BOMB_EXPLOSION_TILE_CHECK_OFFSET_LENGTH 74 static const int16_t bombExplosionTileCheckOffsets[74] = { -// X, Y - -1, -3, - 0, -3, - 1, -3, - -2, -2, - -1, -2, - 0, -2, - 1, -2, - 2, -2, - -3, -1, - -2, -1, - -1, -1, - 0, -1, - 1, -1, - 2, -1, - 3, -1, - -3, 0, - -2, 0, - -1, 0, - 0, 0, - 1, 0, - 2, 0, - 3, 0, - -3, 1, - -2, 1, - -1, 1, - 0, 1, - 1, 1, - 2, 1, - 3, 1, - -2, 2, - -1, 2, - 0, 2, - 1, 2, - 2, 2, - -1, 3, - 0, 3, - 1, 3 -}; + // X, Y + -1, -3, 0, -3, 1, -3, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, -3, -1, -2, -1, -1, -1, 0, -1, 1, + -1, 2, -1, 3, -1, -3, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 3, 0, -3, 1, -2, 1, -1, 1, + 0, 1, 1, 1, 2, 1, 3, 1, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, -1, 3, 0, 3, 1, 3}; + +#define BALL_SPEED_UP_TABLE_LENGTH 12 +#define BALL_SPEED_UP_TABLE_ROW_LENGTH 2 + +#define BOUNCE_THRESHOLD_LOOKUP_OFFSET 0 +#define NEW_SPEED_LOOKUP_OFFSET 1 + +static const int16_t ballSpeedUps[BALL_SPEED_UP_TABLE_LENGTH * BALL_SPEED_UP_TABLE_ROW_LENGTH] = { + // bounce new + // threshold speed + 0, 39, 5, 43, 4, 47, 4, 51, 3, 55, 3, 59, 3, 63, 2, 67, 20, 71, 30, 75, 40, 79, 50, 80}; //============================================================================== // Functions //============================================================================== -void initializeEntity(entity_t *self, entityManager_t *entityManager, tilemap_t *tilemap, gameData_t *gameData, soundManager_t *soundManager) +void initializeEntity(entity_t* self, entityManager_t* entityManager, tilemap_t* tilemap, gameData_t* gameData, + soundManager_t* soundManager) { - self->active = false; - self->tilemap = tilemap; - self->gameData = gameData; - self->soundManager = soundManager; - self->homeTileX = 0; - self->homeTileY = 0; - self->entityManager = entityManager; - self->spriteFlipHorizontal = false; - self->spriteFlipVertical = false; - self->spriteRotateAngle = 0; - self->attachedToEntity = NULL; - self->shouldAdvanceMultiplier = false; + self->active = false; + self->persistent = false; + self->tilemap = tilemap; + self->gameData = gameData; + self->soundManager = soundManager; + self->homeTileX = 0; + self->homeTileY = 0; + self->entityManager = entityManager; + self->spriteFlipHorizontal = false; + self->spriteFlipVertical = false; + self->spriteRotateAngle = 0; + self->attachedToEntity = NULL; + self->shouldAdvanceMultiplier = false; + self->baseSpeed = 0; + self->bouncesToNextSpeedUp = 5; + self->speedUpLookupIndex = 0; + self->maxSpeed = 63; + self->bouncesOffUnbreakableBlocks = 0; + self->breakInfiniteLoopBounceThreshold = -1; // Fields not explicitly initialized // self->type = 0; @@ -114,165 +98,151 @@ void initializeEntity(entity_t *self, entityManager_t *entityManager, tilemap_t // self->collisionHandler = NULL; // self->tileCollisionHandler = NULL; // self->overlapTileHandler = NULL; -}; +} -void updatePlayer(entity_t *self) +void updatePlayer(entity_t* self) { - if(self->gameData->isTouched) + if (self->gameData->isTouched) { int32_t xdiff; - //TODO: tune these values some more!!! + // TODO: tune these values some more!!! - int32_t touchIntoLevel = (self->gameData->touchX << 2) + 128; // play with this value until center touch moves paddle to center + int32_t touchIntoLevel + = (self->gameData->touchX << 2) + 192; // play with this value until center touch moves paddle to center - // the leftmost coordinate that the originX point of the paddle sprite can occupy - // | the rightmost coordinate that the originX point of the paddle sprite can occupy - touchIntoLevel = CLAMP(touchIntoLevel,608,3872); - xdiff = self->x - touchIntoLevel; - xdiff = CLAMP(xdiff, -1024, 1024); + // the leftmost coordinate that the originX point of the paddle sprite can + // occupy | the rightmost coordinate that the originX point of the paddle + // sprite can occupy + touchIntoLevel = CLAMP(touchIntoLevel, 608, 3872); + xdiff = self->x - touchIntoLevel; + xdiff = CLAMP(xdiff, -1024, 1024); if (self->x != touchIntoLevel) { self->xspeed = -xdiff; - } else { + } + else + { self->xspeed = 0; } - } else { + } + else + { self->xspeed = 0; } self->x += self->xspeed; - if(self->gameData->frameCount % 10 == 0 && self->spriteIndex < SP_PADDLE_2){ + if (self->gameData->frameCount % 10 == 0 && self->spriteIndex < SP_PADDLE_2) + { self->spriteIndex++; } +} - /* - TODO: - Move this. Doesn't need to be repeated across every paddle. - */ - if( - ( - (self->gameData->btnState & PB_START) - && - !(self->gameData->prevBtnState & PB_START) - ) - ){ - self->gameData->changeState = ST_PAUSE; - } - -}; - -void updatePlayerVertical(entity_t *self) -{ - if(self->gameData->isTouched) +void updatePlayerVertical(entity_t* self) +{ + if (self->gameData->isTouched) { int32_t ydiff; - int32_t touchIntoLevel = ((984 - self->gameData->touchY)<< 2) + 128; // play with this value until center touch moves paddle to center + int32_t touchIntoLevel = ((984 - self->gameData->touchY) << 2) + + 128; // play with this value until center touch moves paddle to center - // the leftmost coordinate that the originX point of the paddle sprite can occupy - // | the rightmost coordinate that the originX point of the paddle sprite can occupy - touchIntoLevel = CLAMP(touchIntoLevel,608,3488); - ydiff = self->y - touchIntoLevel; - ydiff = CLAMP(ydiff, -1024, 1024); + // the leftmost coordinate that the originX point of the paddle sprite can + // occupy | the rightmost coordinate that the originX point of the paddle + // sprite can occupy + touchIntoLevel = CLAMP(touchIntoLevel, 608, 3488); + ydiff = self->y - touchIntoLevel; + ydiff = CLAMP(ydiff, -1024, 1024); if (self->y != touchIntoLevel) { self->yspeed = -ydiff; - } else { + } + else + { self->yspeed = 0; } - } else { + } + else + { self->yspeed = 0; } self->y += self->yspeed; - if(self->gameData->frameCount % 10 == 0 && self->spriteIndex < SP_PADDLE_VERTICAL_2){ + if (self->gameData->frameCount % 10 == 0 && self->spriteIndex < SP_PADDLE_VERTICAL_2) + { self->spriteIndex++; } +} - /* - TODO: - Move this. Doesn't need to be repeated across every paddle. - */ - if( - ( - (self->gameData->btnState & PB_START) - && - !(self->gameData->prevBtnState & PB_START) - ) - ){ - self->gameData->changeState = ST_PAUSE; - } - -}; - -void updateBall(entity_t *self) -{ - if(self->attachedToEntity != NULL){ - //Ball is caught - switch(self->attachedToEntity->type){ - case(ENTITY_PLAYER_PADDLE_BOTTOM): +void updateBall(entity_t* self) +{ + if (self->attachedToEntity != NULL) + { + // Ball is caught + switch (self->attachedToEntity->type) + { + case (ENTITY_PLAYER_PADDLE_BOTTOM): self->x = self->attachedToEntity->x; - self->y = self->attachedToEntity->y-((self->entityManager->sprites[self->spriteIndex].originY + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originY) << SUBPIXEL_RESOLUTION); + self->y = self->attachedToEntity->y + - ((self->entityManager->sprites[self->spriteIndex].originY + + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originY) + << SUBPIXEL_RESOLUTION); - if( - self->gameData->btnState & PB_UP - && - !(self->gameData->prevBtnState & PB_UP) - ) + if (self->gameData->btnState & PB_UP && !(self->gameData->prevBtnState & PB_UP)) { - //Launch ball - setVelocity(self, 90 - CLAMP((self->attachedToEntity->xspeed)/SUBPIXEL_RESOLUTION,-60,60), 63); + // Launch ball + setVelocity(self, 90 - CLAMP((self->attachedToEntity->xspeed) / SUBPIXEL_RESOLUTION, -60, 60), + self->baseSpeed); self->attachedToEntity = NULL; bzrPlaySfx(&(self->soundManager->launch), BZR_STEREO); } break; - case(ENTITY_PLAYER_PADDLE_TOP): + case (ENTITY_PLAYER_PADDLE_TOP): self->x = self->attachedToEntity->x; - self->y = self->attachedToEntity->y+((self->entityManager->sprites[self->spriteIndex].originY + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originY) << SUBPIXEL_RESOLUTION); + self->y = self->attachedToEntity->y + + ((self->entityManager->sprites[self->spriteIndex].originY + + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originY) + << SUBPIXEL_RESOLUTION); - if( - self->gameData->btnState & PB_UP - && - !(self->gameData->prevBtnState & PB_UP) - ) + if (self->gameData->btnState & PB_UP && !(self->gameData->prevBtnState & PB_UP)) { - //Launch ball - setVelocity(self, 270 + CLAMP((self->attachedToEntity->xspeed)/SUBPIXEL_RESOLUTION,-60,60), 63); + // Launch ball + setVelocity(self, 270 + CLAMP((self->attachedToEntity->xspeed) / SUBPIXEL_RESOLUTION, -60, 60), + self->baseSpeed); self->attachedToEntity = NULL; bzrPlaySfx(&(self->soundManager->launch), BZR_STEREO); } break; - case(ENTITY_PLAYER_PADDLE_LEFT): - self->x = self->attachedToEntity->x+((self->entityManager->sprites[self->spriteIndex].originX + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originX) << SUBPIXEL_RESOLUTION); + case (ENTITY_PLAYER_PADDLE_LEFT): + self->x = self->attachedToEntity->x + + ((self->entityManager->sprites[self->spriteIndex].originX + + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originX) + << SUBPIXEL_RESOLUTION); self->y = self->attachedToEntity->y; - if( - self->gameData->btnState & PB_UP - && - !(self->gameData->prevBtnState & PB_UP) - ) + if (self->gameData->btnState & PB_UP && !(self->gameData->prevBtnState & PB_UP)) { - //Launch ball - setVelocity(self, 0 - CLAMP((self->attachedToEntity->yspeed)/SUBPIXEL_RESOLUTION,-60,60), 63); + // Launch ball + setVelocity(self, 0 - CLAMP((self->attachedToEntity->yspeed) / SUBPIXEL_RESOLUTION, -60, 60), + self->baseSpeed); self->attachedToEntity = NULL; bzrPlaySfx(&(self->soundManager->launch), BZR_STEREO); } break; - case(ENTITY_PLAYER_PADDLE_RIGHT): - self->x = self->attachedToEntity->x-((self->entityManager->sprites[self->spriteIndex].originX + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originX) << SUBPIXEL_RESOLUTION); + case (ENTITY_PLAYER_PADDLE_RIGHT): + self->x = self->attachedToEntity->x + - ((self->entityManager->sprites[self->spriteIndex].originX + + self->entityManager->sprites[self->attachedToEntity->spriteIndex].originX) + << SUBPIXEL_RESOLUTION); self->y = self->attachedToEntity->y; - if( - self->gameData->btnState & PB_UP - && - !(self->gameData->prevBtnState & PB_UP) - ) + if (self->gameData->btnState & PB_UP && !(self->gameData->prevBtnState & PB_UP)) { - //Launch ball - setVelocity(self, 180 - CLAMP(-(self->attachedToEntity->yspeed)/SUBPIXEL_RESOLUTION,-60,60), 63); + // Launch ball + setVelocity(self, 180 - CLAMP(-(self->attachedToEntity->yspeed) / SUBPIXEL_RESOLUTION, -60, 60), + self->baseSpeed); self->attachedToEntity = NULL; bzrPlaySfx(&(self->soundManager->launch), BZR_STEREO); } @@ -280,156 +250,674 @@ void updateBall(entity_t *self) default: break; } - } else { - //Ball is in play + } + else + { + // Ball is in play moveEntityWithTileCollisions(self); detectEntityCollisions(self); - if( - self->gameData->btnState & PB_DOWN - && - !(self->gameData->prevBtnState & PB_DOWN) - ) + if (self->gameData->btnState & PB_DOWN && !(self->gameData->prevBtnState & PB_DOWN)) { - if(self->gameData->playerTimeBombsCount < 3){ - //Drop time bomb - entity_t* createdBomb = createEntity(self->entityManager, ENTITY_PLAYER_TIME_BOMB, self->x >> SUBPIXEL_RESOLUTION, self->y >> SUBPIXEL_RESOLUTION); - if(createdBomb != NULL){ + if (self->gameData->playerTimeBombsCount < 3) + { + // Drop time bomb + entity_t* createdBomb = createEntity(self->entityManager, ENTITY_PLAYER_TIME_BOMB, + self->x >> SUBPIXEL_RESOLUTION, self->y >> SUBPIXEL_RESOLUTION); + if (createdBomb != NULL) + { self->gameData->playerTimeBombsCount++; bzrPlaySfx(&(self->soundManager->dropBomb), BZR_LEFT); } } } - if( - self->gameData->btnState & PB_RIGHT - && - !(self->gameData->prevBtnState & PB_RIGHT) - ) + if (self->gameData->btnState & PB_RIGHT && !(self->gameData->prevBtnState & PB_RIGHT)) { - if(!self->gameData->playerRemoteBombPlaced){ - //Drop remote bomb - entity_t* createdBomb = createEntity(self->entityManager, ENTITY_PLAYER_REMOTE_BOMB, self->x >> SUBPIXEL_RESOLUTION, self->y >> SUBPIXEL_RESOLUTION); - if(createdBomb != NULL){ + if (!self->gameData->playerRemoteBombPlaced) + { + // Drop remote bomb + entity_t* createdBomb = createEntity(self->entityManager, ENTITY_PLAYER_REMOTE_BOMB, + self->x >> SUBPIXEL_RESOLUTION, self->y >> SUBPIXEL_RESOLUTION); + if (createdBomb != NULL) + { self->gameData->playerRemoteBombPlaced = true; bzrPlaySfx(&(self->soundManager->dropBomb), BZR_LEFT); } } } - if(self->gameData->frameCount % 5 == 0) { + if (self->gameData->frameCount % 5 == 0) + { self->spriteIndex = SP_BALL_0 + ((self->spriteIndex + 1) % 3); } self->spriteFlipHorizontal = (self->xspeed >= 0) ? false : true; - } - if(self->y > 3840 || self->x > 4480) { - self->gameData->changeState = ST_DEAD; - destroyEntity(self, true); - bzrPlaySfx(&(self->soundManager->die), BZR_STEREO); + if (self->gameData->frameCount % 2 == 0) + { + createEntity(self->entityManager, ENTITY_BALL_TRAIL, self->x >> SUBPIXEL_RESOLUTION, + self->y >> SUBPIXEL_RESOLUTION); + } } -}; -void updateBallAtStart(entity_t *self){ - //Find a nearby paddle and attach ball to it + detectLostBall(self, true); +} + +void updateBallAtStart(entity_t* self) +{ + // Find a nearby paddle and attach ball to it for (uint8_t i = 0; i < MAX_ENTITIES; i++) { - entity_t *checkEntity = &(self->entityManager->entities[i]); - if (checkEntity->active && checkEntity != self && (checkEntity->type == ENTITY_PLAYER_PADDLE_BOTTOM || checkEntity->type == ENTITY_PLAYER_PADDLE_TOP || checkEntity->type == ENTITY_PLAYER_PADDLE_LEFT || checkEntity->type == ENTITY_PLAYER_PADDLE_RIGHT) ) + entity_t* checkEntity = &(self->entityManager->entities[i]); + if (checkEntity->active && checkEntity != self + && (checkEntity->type == ENTITY_PLAYER_PADDLE_BOTTOM || checkEntity->type == ENTITY_PLAYER_PADDLE_TOP + || checkEntity->type == ENTITY_PLAYER_PADDLE_LEFT || checkEntity->type == ENTITY_PLAYER_PADDLE_RIGHT)) { - uint32_t dist = abs(self->x - checkEntity->x) + abs(self->y - checkEntity->y); - - if (dist < 400) + if (getTaxiCabDistanceBetweenEntities(self, checkEntity) < 400) { self->attachedToEntity = checkEntity; - self->updateFunction = &updateBall; + self->updateFunction = &updateBall; self->collisionHandler = &ballCollisionHandler; } } } } -void updateTimeBomb(entity_t * self){ - if(self->gameData->frameCount % 5 == 0) { +bool isOutsidePlayfield(entity_t* self) +{ + return (self->y > 3840 || self->x > 4480); +} + +void detectLostBall(entity_t* self, bool respawn) +{ + if (isOutsidePlayfield(self)) + { + destroyEntity(self, respawn); + self->gameData->ballsInPlay--; + + if (self->gameData->ballsInPlay <= 0) + { + self->gameData->changeState = ST_DEAD; + bzrPlaySfx(&(self->soundManager->die), BZR_STEREO); + } + } +} + +void updateCaptiveBallNotInPlay(entity_t* self) +{ + moveEntityWithTileCollisions(self); + detectEntityCollisions(self); + + if (isOutsidePlayfield(self)) + { + destroyEntity(self, false); + } +} + +void updateCaptiveBallInPlay(entity_t* self) +{ + moveEntityWithTileCollisions(self); + detectEntityCollisions(self); + detectLostBall(self, false); + + if (self->gameData->frameCount % 2 == 0) + { + createEntity(self->entityManager, ENTITY_BALL_TRAIL, self->x >> SUBPIXEL_RESOLUTION, + self->y >> SUBPIXEL_RESOLUTION); + } +} + +uint32_t getTaxiCabDistanceBetweenEntities(entity_t* self, entity_t* other) +{ + return abs(self->x - other->x) + abs(self->y - other->y); +} + +void updateTimeBomb(entity_t* self) +{ + if (self->gameData->frameCount % 5 == 0) + { self->spriteIndex = SP_BOMB_0 + ((self->spriteIndex + 1) % 3); } self->animationTimer--; - - if(self->animationTimer == 0){ + + if (self->animationTimer == 0) + { explodeBomb(self); self->gameData->playerTimeBombsCount--; } } -void updateRemoteBomb(entity_t * self){ - if(self->animationTimer > 0){ +void updateRemoteBomb(entity_t* self) +{ + if (self->animationTimer > 0) + { self->animationTimer--; return; } - if(self->gameData->frameCount % 5 == 0) { - self->spriteIndex = SP_BOMB_0 + ((self->spriteIndex + 1) % 3); + if (self->gameData->frameCount % 5 == 0) + { + self->spriteIndex = SP_RBOMB_0 + ((self->spriteIndex + 1) % 3); } - if( - self->gameData->btnState & PB_RIGHT - && - !(self->gameData->prevBtnState & PB_RIGHT) - ){ + if (self->gameData->btnState & PB_RIGHT && !(self->gameData->prevBtnState & PB_RIGHT)) + { explodeBomb(self); self->gameData->playerRemoteBombPlaced = false; } } -void explodeBomb(entity_t* self){ +void explodeBomb(entity_t* self) +{ uint8_t tx = TO_TILE_COORDS(self->x >> SUBPIXEL_RESOLUTION); - uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); - uint8_t ctx, cty; - - for(uint16_t i = 0; i < BOMB_EXPLOSION_TILE_CHECK_OFFSET_LENGTH; i+=2){ - ctx = tx + bombExplosionTileCheckOffsets[i]; - cty = ty + bombExplosionTileCheckOffsets[i+1]; - uint8_t tileId = getTile(self->tilemap, ctx, cty); - - switch(tileId){ - case TILE_BLOCK_1x1_RED ... TILE_UNUSED_127: { - breakBlockTile(self->tilemap, self->gameData, tileId, ctx, cty); - scorePoints(self->gameData, 10, 0); - break; - } - case TILE_BOUNDARY_1 ... TILE_BOUNDARY_3:{ - break; - } - default: { - break; - } + uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); + uint8_t ctx, cty; + + for (uint16_t i = 0; i < BOMB_EXPLOSION_TILE_CHECK_OFFSET_LENGTH; i += 2) + { + ctx = tx + bombExplosionTileCheckOffsets[i]; + cty = ty + bombExplosionTileCheckOffsets[i + 1]; + uint8_t tileId = getTile(self->tilemap, ctx, cty); + + switch (tileId) + { + case TILE_BLOCK_1x1_RED ... TILE_UNUSED_127: + { + scorePoints(self->gameData, 10 * breakBlockTile(self->tilemap, self->gameData, tileId, ctx, cty), 0); + break; + } + case TILE_BOUNDARY_1 ... TILE_UNUSED_F: + { + break; + } + default: + { + break; } } + } + destroyEntity(self, false); + createEntity(self->entityManager, ENTITY_PLAYER_BOMB_EXPLOSION, self->x >> SUBPIXEL_RESOLUTION, + self->y >> SUBPIXEL_RESOLUTION); + bzrPlaySfx(&(self->soundManager->detonate), BZR_LEFT); +} + +void updateExplosion(entity_t* self) +{ + if (self->gameData->frameCount % 5 == 0) + { + self->spriteIndex++; + } + + if (self->spriteIndex > SP_EXPLOSION_3) + { destroyEntity(self, false); - createEntity(self->entityManager, ENTITY_PLAYER_BOMB_EXPLOSION, self->x >> SUBPIXEL_RESOLUTION, self->y >> SUBPIXEL_RESOLUTION); - bzrPlaySfx(&(self->soundManager->detonate), BZR_LEFT); + } +} + +void updateBallTrail(entity_t* self) +{ + self->animationTimer--; + if (self->animationTimer < 1) + { + if (self->visible) + { + self->spriteIndex++; + if (self->spriteIndex > SP_BALL_TRAIL_3) + { + destroyEntity(self, false); + } + } + else + { + self->visible = true; + } + self->animationTimer = 2; + } } -void updateExplosion(entity_t * self){ - if(self->gameData->frameCount % 5 == 0) { +void updateChoIntro(entity_t* self) +{ + // This entity's state is determined by whether or not it found the ball. + if (self->attachedToEntity == NULL) + { + // Find the first ball and "attach" self to it + self->attachedToEntity = findFirstEntityOfType(self->entityManager, ENTITY_PLAYER_BALL); + if (self->attachedToEntity != NULL) + { + self->attachedToEntity->visible = false; + + // If we found the ball, walk towards it from the far side of the screen + self->y = self->attachedToEntity->y; + self->x = ((self->attachedToEntity->x >> SUBPIXEL_RESOLUTION) > (TFT_WIDTH >> 1)) + ? 0 + : TFT_WIDTH << SUBPIXEL_RESOLUTION; + self->xspeed = (self->attachedToEntity->x > self->x) ? 32 : -32; + self->spriteFlipHorizontal = (self->xspeed > 0) ? false : true; + return; + } + + // Couldn't find ball? Destroy self. + destroyEntity(self, false); + return; + } + + self->x += self->xspeed; + + if (self->gameData->frameCount % 5 == 0) + { self->spriteIndex++; + if (self->spriteIndex > SP_CHO_WALK_2) + { + self->spriteIndex = SP_CHO_WALK_0; + } + } + + // Very close to ball? "Become" the ball + if (getTaxiCabDistanceBetweenEntities(self, self->attachedToEntity) < 32) + { + self->attachedToEntity->visible = true; + + destroyEntity(self, false); + return; + } +} + +entity_t* findFirstEntityOfType(entityManager_t* entityManager, uint8_t type) +{ + for (uint8_t i = 0; i < MAX_ENTITIES; i++) + { + entity_t* checkEntity = &(entityManager->entities[i]); + if (checkEntity->active && (checkEntity->type == type)) + { + return checkEntity; + } + } + + return NULL; +} + +void updateChoLevelClear(entity_t* self) +{ + if (self->gameData->countdown > 20) + { + if (self->gameData->frameCount % 9 == 0) + { + self->spriteIndex = SP_CHO_WIN_0 + (self->gameData->frameCount & 1); + } + } + else + { + self->spriteIndex = SP_EXPLOSION_0; + self->updateFunction = &updateExplosion; + } +} + +void updateCrawler(entity_t* self) +{ + if (self->gameData->frameCount % 10 == 0) + { + self->spriteFlipHorizontal = !self->spriteFlipHorizontal; + } + + if (self->breakInfiniteLoopBounceThreshold > 0) + { + self->breakInfiniteLoopBounceThreshold--; + } + + detectEntityCollisions(self); + + uint8_t tx = TO_TILE_COORDS(self->x >> SUBPIXEL_RESOLUTION); + uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); + uint8_t t; + + switch (self->animationTimer) + { + // CLOCKWISE + case CRAWLER_TOP_TO_RIGHT: // On top of a block, going right + if (((self->x % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx, ty + 1); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_RIGHT_TO_BOTTOM); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + + t = getTile(self->tilemap, tx + 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_LEFT_TO_TOP); + } + + break; + + case CRAWLER_RIGHT_TO_BOTTOM: // On the right side of a block, going down + if (((self->y % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx - 1, ty); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_BOTTOM_TO_LEFT); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + t = getTile(self->tilemap, tx, ty + 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_TOP_TO_RIGHT); + } + + break; + + case CRAWLER_BOTTOM_TO_LEFT: // On the bottom of a block, going left + if (((self->x % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx, ty - 1); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_LEFT_TO_TOP); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + t = getTile(self->tilemap, tx - 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_RIGHT_TO_BOTTOM); + } + + break; + + case CRAWLER_LEFT_TO_TOP: // On the left side of a block, going up + if (((self->y % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx + 1, ty); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_TOP_TO_RIGHT); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + t = getTile(self->tilemap, tx, ty - 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_BOTTOM_TO_LEFT); + } + + break; + + // COUNTER-CLOCKWISE + case CRAWLER_TOP_TO_LEFT: // On top of a block, going left + if (((self->x % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx, ty + 1); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_LEFT_TO_BOTTOM); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + t = getTile(self->tilemap, tx - 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_RIGHT_TO_TOP); + } + + break; + + case CRAWLER_LEFT_TO_BOTTOM: // On the left side of a block, going down + if (((self->y % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx + 1, ty); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_BOTTOM_TO_RIGHT); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + t = getTile(self->tilemap, tx, ty + 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_TOP_TO_LEFT); + } + + break; + + case CRAWLER_BOTTOM_TO_RIGHT: // On the bottom of a block, going right + if (((self->x % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx, ty - 1); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_RIGHT_TO_TOP); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + + t = getTile(self->tilemap, tx + 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_LEFT_TO_BOTTOM); + } + + break; + + case CRAWLER_RIGHT_TO_TOP: // On the right side of a block, going up + if (((self->y % (TILE_SIZE << SUBPIXEL_RESOLUTION)) - (HALF_TILE_SIZE << SUBPIXEL_RESOLUTION))) + { + break; + } + + t = getTile(self->tilemap, tx - 1, ty); + if (!isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_TOP_TO_LEFT); + self->bouncesOffUnbreakableBlocks++; + } + else + { + self->bouncesOffUnbreakableBlocks = 0; + } + + t = getTile(self->tilemap, tx, ty - 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, CRAWLER_BOTTOM_TO_RIGHT); + } + break; + + default: + break; + } + + if (self->bouncesOffUnbreakableBlocks > 4) + { + scorePoints(self->gameData, 100, 1); + destroyEntity(self, false); + createEntity(self->entityManager, ENTITY_PLAYER_BOMB_EXPLOSION, self->x >> SUBPIXEL_RESOLUTION, + self->y >> SUBPIXEL_RESOLUTION); + bzrPlaySfx(&(self->soundManager->detonate), BZR_LEFT); } - if(self->spriteIndex > SP_EXPLOSION_3){ + if (isOutsidePlayfield(self)) + { destroyEntity(self, false); } + + self->x += self->xspeed; + self->y += self->yspeed; +} + +void crawlerSetMoveState(entity_t* self, uint8_t state) +{ + uint16_t blocksLeft = self->tilemap->totalTargetBlocks - self->gameData->targetBlocksBroken; + if (blocksLeft < 100) + { + self->baseSpeed = 16; + } + else if (blocksLeft < 80) + { + self->baseSpeed = 24; + } + else if (blocksLeft < 60) + { + self->baseSpeed = 32; + } + else if (blocksLeft < 20) + { + self->baseSpeed = 48; + } + else if (blocksLeft < 10) + { + self->baseSpeed = 64; + } + + switch (state) + { + // CLOCKWISE + case CRAWLER_TOP_TO_RIGHT: // On top of a block, going right + self->xspeed = self->baseSpeed; + self->yspeed = 0; + self->spriteRotateAngle = 0; + self->spriteIndex = SP_CRAWLER_TOP; + break; + case CRAWLER_RIGHT_TO_BOTTOM: // On the right side of a block, going down + self->yspeed = self->baseSpeed; + self->xspeed = 0; + self->spriteRotateAngle = 90; + self->spriteIndex = SP_CRAWLER_RIGHT; + break; + case CRAWLER_BOTTOM_TO_LEFT: // On the bottom of a block, going left + self->xspeed = -self->baseSpeed; + self->yspeed = 0; + self->spriteRotateAngle = 180; + self->spriteIndex = SP_CRAWLER_BOTTOM; + break; + case CRAWLER_LEFT_TO_TOP: // On the left side of a block, going up + self->yspeed = -self->baseSpeed; + self->xspeed = 0; + self->spriteRotateAngle = 270; + self->spriteIndex = SP_CRAWLER_LEFT; + break; + // COUNTER-CLOCKWISE + case CRAWLER_TOP_TO_LEFT: // On top of a block, going left + self->xspeed = -self->baseSpeed; + self->yspeed = 0; + self->spriteRotateAngle = 0; + self->spriteIndex = SP_CRAWLER_TOP; + break; + case CRAWLER_LEFT_TO_BOTTOM: // On the left side of a block, going down + self->yspeed = self->baseSpeed; + self->xspeed = 0; + self->spriteRotateAngle = 270; + self->spriteIndex = SP_CRAWLER_LEFT; + break; + case CRAWLER_BOTTOM_TO_RIGHT: // On the bottom of a block, going right + self->xspeed = self->baseSpeed; + self->yspeed = 0; + self->spriteRotateAngle = 180; + self->spriteIndex = SP_CRAWLER_BOTTOM; + break; + case CRAWLER_RIGHT_TO_TOP: // On the right side of a block, going up + self->yspeed = -self->baseSpeed; + self->xspeed = 0; + self->spriteRotateAngle = 90; + self->spriteIndex = SP_CRAWLER_RIGHT; + break; + default: + break; + } + + self->animationTimer = state; +} + +void crawlerInitMoveState(entity_t* self) +{ + uint8_t tx = TO_TILE_COORDS(self->x >> SUBPIXEL_RESOLUTION); + uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); + uint8_t t; + + t = getTile(self->tilemap, tx, ty + 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, ((tx + ty) % 2) ? CRAWLER_TOP_TO_RIGHT : CRAWLER_TOP_TO_LEFT); + return; + } + + t = getTile(self->tilemap, tx - 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, ((tx + ty) % 2) ? CRAWLER_RIGHT_TO_BOTTOM : CRAWLER_RIGHT_TO_TOP); + return; + } + + t = getTile(self->tilemap, tx, ty - 1); + if (isSolid(t)) + { + crawlerSetMoveState(self, ((tx + ty) % 2) ? CRAWLER_BOTTOM_TO_LEFT : CRAWLER_BOTTOM_TO_RIGHT); + return; + } + + t = getTile(self->tilemap, tx + 1, ty); + if (isSolid(t)) + { + crawlerSetMoveState(self, ((tx + ty) % 2) ? CRAWLER_LEFT_TO_TOP : CRAWLER_LEFT_TO_BOTTOM); + return; + } } -void moveEntityWithTileCollisions(entity_t *self) +void moveEntityWithTileCollisions(entity_t* self) { - uint16_t newX = self->x; uint16_t newY = self->y; - uint8_t tx = TO_TILE_COORDS(self->x >> SUBPIXEL_RESOLUTION); - uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); + uint8_t tx = TO_TILE_COORDS(self->x >> SUBPIXEL_RESOLUTION); + uint8_t ty = TO_TILE_COORDS(self->y >> SUBPIXEL_RESOLUTION); // bool collision = false; // Are we inside a block? Push self out of block @@ -438,7 +926,6 @@ void moveEntityWithTileCollisions(entity_t *self) if (isSolid(t)) { - if (self->xspeed == 0 && self->yspeed == 0) { newX += (self->spriteFlipHorizontal) ? 16 : -16; @@ -457,7 +944,6 @@ void moveEntityWithTileCollisions(entity_t *self) } else { - if (self->yspeed != 0) { int16_t hcof = (((self->x >> SUBPIXEL_RESOLUTION) % TILE_SIZE) - HALF_TILE_SIZE); @@ -471,13 +957,14 @@ void moveEntityWithTileCollisions(entity_t *self) newX = ((tx + 1) * TILE_SIZE - HALF_TILE_SIZE) << SUBPIXEL_RESOLUTION; } - uint8_t newTy = TO_TILE_COORDS(((self->y + self->yspeed) >> SUBPIXEL_RESOLUTION) + SIGNOF(self->yspeed) * HALF_TILE_SIZE); + uint8_t newTy = TO_TILE_COORDS(((self->y + self->yspeed) >> SUBPIXEL_RESOLUTION) + + SIGNOF(self->yspeed) * HALF_TILE_SIZE); if (newTy != ty) { uint8_t newVerticalTile = getTile(self->tilemap, tx, newTy); - //if (newVerticalTile > TILE_UNUSED_29 && newVerticalTile < TILE_BG_GOAL_ZONE) + // if (newVerticalTile > TILE_UNUSED_29 && newVerticalTile < TILE_BG_GOAL_ZONE) { if (self->tileCollisionHandler(self, newVerticalTile, tx, newTy, 2 << (self->yspeed > 0))) { @@ -501,13 +988,14 @@ void moveEntityWithTileCollisions(entity_t *self) } // Handle outside of tile - uint8_t newTx = TO_TILE_COORDS(((self->x + self->xspeed) >> SUBPIXEL_RESOLUTION) + SIGNOF(self->xspeed) * HALF_TILE_SIZE); + uint8_t newTx = TO_TILE_COORDS(((self->x + self->xspeed) >> SUBPIXEL_RESOLUTION) + + SIGNOF(self->xspeed) * HALF_TILE_SIZE); if (newTx != tx) { uint8_t newHorizontalTile = getTile(self->tilemap, newTx, ty); - //if (newHorizontalTile > TILE_UNUSED_29 && newHorizontalTile < TILE_BG_GOAL_ZONE) + // if (newHorizontalTile > TILE_UNUSED_29 && newHorizontalTile < TILE_BG_GOAL_ZONE) { if (self->tileCollisionHandler(self, newHorizontalTile, newTx, ty, (self->xspeed > 0))) { @@ -532,31 +1020,32 @@ void moveEntityWithTileCollisions(entity_t *self) self->y = newY + self->yspeed; } -void destroyEntity(entity_t *self, bool respawn) +void destroyEntity(entity_t* self, bool respawn) { if (respawn && !(self->homeTileX == 0 && self->homeTileY == 0)) { self->tilemap->map[self->homeTileY * self->tilemap->mapWidth + self->homeTileX] = self->type + 128; } + self->attachedToEntity = NULL; self->entityManager->activeEntities--; self->active = false; } -void detectEntityCollisions(entity_t *self) +void detectEntityCollisions(entity_t* self) { sprite_t* selfSprite = &(self->entityManager->sprites[self->spriteIndex]); box_t* selfSpriteBox = &(selfSprite->collisionBox); - + box_t selfBox; selfBox.x0 = (self->x >> SUBPIXEL_RESOLUTION) - selfSprite->originX + selfSpriteBox->x0; selfBox.y0 = (self->y >> SUBPIXEL_RESOLUTION) - selfSprite->originY + selfSpriteBox->y0; selfBox.x1 = (self->x >> SUBPIXEL_RESOLUTION) - selfSprite->originX + selfSpriteBox->x1; selfBox.y1 = (self->y >> SUBPIXEL_RESOLUTION) - selfSprite->originY + selfSpriteBox->y1; - entity_t *checkEntity; + entity_t* checkEntity; sprite_t* checkEntitySprite; - box_t* checkEntitySpriteBox; + box_t* checkEntitySpriteBox; box_t checkEntityBox; for (uint8_t i = 0; i < MAX_ENTITIES; i++) @@ -564,13 +1053,17 @@ void detectEntityCollisions(entity_t *self) checkEntity = &(self->entityManager->entities[i]); if (checkEntity->active && checkEntity != self) { - checkEntitySprite = &(self->entityManager->sprites[checkEntity->spriteIndex]); + checkEntitySprite = &(self->entityManager->sprites[checkEntity->spriteIndex]); checkEntitySpriteBox = &(checkEntitySprite->collisionBox); - - checkEntityBox.x0 = (checkEntity->x >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originX + checkEntitySpriteBox->x0; - checkEntityBox.y0 = (checkEntity->y >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originY + checkEntitySpriteBox->y0; - checkEntityBox.x1 = (checkEntity->x >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originX + checkEntitySpriteBox->x1; - checkEntityBox.y1 = (checkEntity->y >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originY + checkEntitySpriteBox->y1; + + checkEntityBox.x0 + = (checkEntity->x >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originX + checkEntitySpriteBox->x0; + checkEntityBox.y0 + = (checkEntity->y >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originY + checkEntitySpriteBox->y0; + checkEntityBox.x1 + = (checkEntity->x >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originX + checkEntitySpriteBox->x1; + checkEntityBox.y1 + = (checkEntity->y >> SUBPIXEL_RESOLUTION) - checkEntitySprite->originY + checkEntitySpriteBox->y1; if (boxesCollide(selfBox, checkEntityBox, 0)) { @@ -580,114 +1073,129 @@ void detectEntityCollisions(entity_t *self) } } -void playerCollisionHandler(entity_t *self, entity_t *other) +void playerCollisionHandler(entity_t* self, entity_t* other) { - } -/* -void enemyCollisionHandler(entity_t *self, entity_t *other) +void crawlerCollisionHandler(entity_t* self, entity_t* other) { switch (other->type) { - case ENTITY_TEST: - case ENTITY_DUST_BUNNY: - case ENTITY_WASP: - case ENTITY_BUSH_2: - case ENTITY_BUSH_3: - case ENTITY_DUST_BUNNY_2: - case ENTITY_DUST_BUNNY_3: - case ENTITY_WASP_2: - case ENTITY_WASP_3: - case ENTITY_POWERUP: - case ENTITY_1UP: - if((self->xspeed > 0 && self->x < other->x) || (self->xspeed < 0 && self->x > other->x)){ - self->xspeed = -self->xspeed; - self->spriteFlipHorizontal = -self->spriteFlipHorizontal; + case ENTITY_CRAWLER: + { + if (self->breakInfiniteLoopBounceThreshold) + { + break; } - break; - case ENTITY_HIT_BLOCK: - self->xspeed = other->xspeed*2; - self->yspeed = other->yspeed*2; - scorePoints(self->gameData, self->scoreValue); - //buzzer_play_sfx(&sndSquish); - killEnemy(self); - break; - case ENTITY_WAVE_BALL: - self->xspeed = other->xspeed >> 1; - self->yspeed = -abs(other->xspeed >> 1); - scorePoints(self->gameData, self->scoreValue); - //buzzer_play_sfx(&sndBreak); - killEnemy(self); - destroyEntity(other, false); - break; + + crawlerSetMoveState(self, (self->animationTimer + 4) % 8); + self->breakInfiniteLoopBounceThreshold = 30; + } default: { break; } } } -*/ -void dummyCollisionHandler(entity_t *self, entity_t *other) +void dummyCollisionHandler(entity_t* self, entity_t* other) { return; } -void ballCollisionHandler(entity_t *self, entity_t *other) +void ballCollisionHandler(entity_t* self, entity_t* other) { switch (other->type) { case ENTITY_PLAYER_PADDLE_BOTTOM: - if(self->yspeed > 0){ - setVelocity(self, 90 + (other->x - self->x)/SUBPIXEL_RESOLUTION, 63); + if (self->yspeed > 0) + { + advanceBallSpeed(self, 1); + setVelocity(self, 90 + (other->x - self->x) / SUBPIXEL_RESOLUTION, self->baseSpeed); bzrPlaySfx(&(self->soundManager->hit2), BZR_LEFT); - if(self->shouldAdvanceMultiplier){ - scorePoints(self->gameData, 0, 2 ); + if (self->shouldAdvanceMultiplier) + { + scorePoints(self->gameData, 0, self->gameData->ballsInPlay); self->shouldAdvanceMultiplier = false; - other->spriteIndex = SP_PADDLE_0; + other->spriteIndex = SP_PADDLE_0; } + + self->bouncesOffUnbreakableBlocks = 0; } break; case ENTITY_PLAYER_PADDLE_TOP: - if(self->yspeed < 0){ - setVelocity(self, 270 + (self->x - other->x)/SUBPIXEL_RESOLUTION, 63); + if (self->yspeed < 0) + { + advanceBallSpeed(self, 1); + setVelocity(self, 270 + (self->x - other->x) / SUBPIXEL_RESOLUTION, self->baseSpeed); bzrPlaySfx(&(self->soundManager->hit2), BZR_LEFT); - if(self->shouldAdvanceMultiplier){ - scorePoints(self->gameData, 0, 2 ); + if (self->shouldAdvanceMultiplier) + { + scorePoints(self->gameData, 0, self->gameData->ballsInPlay); self->shouldAdvanceMultiplier = false; - other->spriteIndex = SP_PADDLE_0; + other->spriteIndex = SP_PADDLE_0; } + + self->bouncesOffUnbreakableBlocks = 0; } break; case ENTITY_PLAYER_PADDLE_LEFT: - if(self->xspeed < 0){ - setVelocity(self, 0 + (other->y - self->y)/SUBPIXEL_RESOLUTION, 63); + if (self->xspeed < 0) + { + advanceBallSpeed(self, 1); + setVelocity(self, 0 + (other->y - self->y) / SUBPIXEL_RESOLUTION, self->baseSpeed); bzrPlaySfx(&(self->soundManager->hit2), BZR_LEFT); - if(self->shouldAdvanceMultiplier){ - scorePoints(self->gameData, 0, 2 ); + if (self->shouldAdvanceMultiplier) + { + scorePoints(self->gameData, 0, self->gameData->ballsInPlay); self->shouldAdvanceMultiplier = false; - other->spriteIndex = SP_PADDLE_VERTICAL_0; + other->spriteIndex = SP_PADDLE_VERTICAL_0; } + + self->bouncesOffUnbreakableBlocks = 0; } break; case ENTITY_PLAYER_PADDLE_RIGHT: - if(self->xspeed > 0){ - setVelocity(self, 180 + (self->y - other->y)/SUBPIXEL_RESOLUTION, 63); + if (self->xspeed > 0) + { + advanceBallSpeed(self, 1); + setVelocity(self, 180 + (self->y - other->y) / SUBPIXEL_RESOLUTION, self->baseSpeed); bzrPlaySfx(&(self->soundManager->hit2), BZR_LEFT); - if(self->shouldAdvanceMultiplier){ - scorePoints(self->gameData, 0, 2 ); + if (self->shouldAdvanceMultiplier) + { + scorePoints(self->gameData, 0, self->gameData->ballsInPlay); self->shouldAdvanceMultiplier = false; - other->spriteIndex = SP_PADDLE_VERTICAL_0; + other->spriteIndex = SP_PADDLE_VERTICAL_0; } + + self->bouncesOffUnbreakableBlocks = 0; } break; case ENTITY_PLAYER_BOMB_EXPLOSION: - setVelocity(self, getAtan2(other->y - self->y, self->x - other->x), 63); + if (!other->spriteRotateAngle) + { + advanceBallSpeed(self, 3); + } + + setVelocity(self, getAtan2(other->y - self->y, self->x - other->x), self->baseSpeed); + other->spriteRotateAngle = 1 + (self->x % 359); + + if (self->shouldAdvanceMultiplier) + { + scorePoints(self->gameData, 0, self->gameData->ballsInPlay); + self->shouldAdvanceMultiplier = false; + } + + self->bouncesOffUnbreakableBlocks = 0; + break; + case ENTITY_CRAWLER: + setVelocity(self, getAtan2(other->y - self->y, self->x - other->x), self->baseSpeed); + advanceBallSpeed(self, 1); + bzrPlaySfx(&(self->soundManager->hit3), BZR_LEFT); break; default: { @@ -696,26 +1204,91 @@ void ballCollisionHandler(entity_t *self, entity_t *other) } } -bool playerTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) +void captiveBallCollisionHandler(entity_t* self, entity_t* other) { - if (isSolid(tileId)) + bool shouldChangeState = false; + switch (other->type) { - switch (direction) - { - case 0: // PB_LEFT - self->xspeed = 0; - break; - case 1: // PB_RIGHT - self->xspeed = 0; + case ENTITY_PLAYER_PADDLE_BOTTOM: + case ENTITY_PLAYER_PADDLE_TOP: + case ENTITY_PLAYER_PADDLE_LEFT: + case ENTITY_PLAYER_PADDLE_RIGHT: + shouldChangeState = true; break; - case 2: // PB_UP - self->yspeed = 0; + case ENTITY_PLAYER_BOMB_EXPLOSION: + if (!other->spriteRotateAngle) + { + shouldChangeState = true; + } break; - case 4: // PB_DOWN - self->yspeed = 0; + case ENTITY_CRAWLER: + setVelocity(self, getAtan2(other->y - self->y, self->x - other->x), self->baseSpeed); break; - default: // Should never hit - return false; + default: + { + return; + } + } + + if (shouldChangeState) + { + self->collisionHandler = &ballCollisionHandler; + self->tileCollisionHandler = &ballTileCollisionHandler; + self->overlapTileHandler = &ballOverlapTileHandler; + self->updateFunction = &updateCaptiveBallInPlay; + self->gameData->ballsInPlay++; + bzrPlaySfx(&(self->soundManager->launch), BZR_RIGHT); + } +} + +void advanceBallSpeed(entity_t* self, uint16_t factor) +{ + if (self->speedUpLookupIndex >= BALL_SPEED_UP_TABLE_LENGTH) + { + return; + } + + self->bouncesToNextSpeedUp -= factor; + if (self->bouncesToNextSpeedUp < 0) + { + self->speedUpLookupIndex += BALL_SPEED_UP_TABLE_ROW_LENGTH; + if (self->speedUpLookupIndex >= BALL_SPEED_UP_TABLE_LENGTH) + { + return; + } + + self->bouncesToNextSpeedUp = ballSpeedUps[(self->speedUpLookupIndex * BALL_SPEED_UP_TABLE_ROW_LENGTH) + + BOUNCE_THRESHOLD_LOOKUP_OFFSET]; + + self->baseSpeed + = ballSpeedUps[(self->speedUpLookupIndex * BALL_SPEED_UP_TABLE_ROW_LENGTH) + NEW_SPEED_LOOKUP_OFFSET]; + if (self->baseSpeed > self->maxSpeed) + { + self->baseSpeed = self->maxSpeed; + } + } +} + +bool playerTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) +{ + if (isSolid(tileId)) + { + switch (direction) + { + case 0: // PB_LEFT + self->xspeed = 0; + break; + case 1: // PB_RIGHT + self->xspeed = 0; + break; + case 2: // PB_UP + self->yspeed = 0; + break; + case 4: // PB_DOWN + self->yspeed = 0; + break; + default: // Should never hit + return false; } // trigger tile collision resolution return true; @@ -794,26 +1367,36 @@ bool enemyTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8 } */ -bool dummyTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) +bool dummyTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) { return false; } -bool ballTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) +bool ballTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) { - switch(tileId){ - case TILE_BLOCK_1x1_RED ... TILE_UNUSED_127: { - breakBlockTile(self->tilemap, self->gameData, tileId, tx, ty); + switch (tileId) + { + case TILE_BLOCK_1x1_RED ... TILE_BLOCK_1x1_BLACK: + case TILE_BLOCK_2x1_RED_L ... TILE_BLOCK_2x1_BLACK_R: + case TILE_BLOCK_2x2_RED_UL ... TILE_BLOCK_2x2_BLACK_UR: + case TILE_BLOCK_2x2_WHITE_DL ... TILE_BLOCK_2x2_BLACK_DR: + { + // breakBlockTile(self->tilemap, self->gameData, tileId, tx, ty); bzrPlaySfx(&(self->soundManager->hit1), BZR_LEFT); - scorePoints(self->gameData, 10, -1); - self->shouldAdvanceMultiplier = true; + scorePoints(self->gameData, 10 * breakBlockTile(self->tilemap, self->gameData, tileId, tx, ty), + (self->shouldAdvanceMultiplier) ? -1 : 0); + self->shouldAdvanceMultiplier = true; + self->bouncesOffUnbreakableBlocks = 0; break; } - case TILE_BOUNDARY_1 ... TILE_BOUNDARY_3:{ + case TILE_BOUNDARY_1 ... TILE_UNUSED_F: + { bzrPlaySfx(&(self->soundManager->hit3), BZR_LEFT); + self->bouncesOffUnbreakableBlocks++; break; } - default: { + default: + { break; } } @@ -822,20 +1405,28 @@ bool ballTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_ { switch (direction) { - case 0: // PB_LEFT - self->xspeed = -self->xspeed; - break; - case 1: // PB_RIGHT - self->xspeed = -self->xspeed; - break; - case 2: // PB_UP - self->yspeed = -self->yspeed; - break; - case 4: // PB_DOWN - self->yspeed = -self->yspeed; - break; - default: // Should never hit - return false; + case 0: // LEFT + case 1: // RIGHT + if (self->bouncesOffUnbreakableBlocks > self->breakInfiniteLoopBounceThreshold) + { + // Subtly change ball bounce angle if the ball has bounced off many unbreakable blocks in a row + self->xspeed += (1 << SUBPIXEL_RESOLUTION) * SIGNOF(self->xspeed); + self->bouncesOffUnbreakableBlocks = 0; + } + self->xspeed = -self->xspeed; + break; + case 2: // UP + case 4: // DOWN + if (self->bouncesOffUnbreakableBlocks > self->breakInfiniteLoopBounceThreshold) + { + // Subtly change ball bounce angle if the ball has bounced off many unbreakable blocks in a row + self->yspeed += (1 << SUBPIXEL_RESOLUTION) * SIGNOF(self->yspeed); + self->bouncesOffUnbreakableBlocks = 0; + } + self->yspeed = -self->yspeed; + break; + default: // Should never hit + return false; } // trigger tile collision resolution return true; @@ -844,30 +1435,73 @@ bool ballTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_ return false; } -void ballOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty){ - switch(tileId){ - case TILE_BLOCK_1x1_RED ... TILE_UNUSED_127: { - breakBlockTile(self->tilemap, self->gameData, tileId, tx, ty); +bool captiveBallTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction) +{ + if (isSolid(tileId)) + { + switch (direction) + { + case 0: // PB_LEFT + self->xspeed = -self->xspeed; + break; + case 1: // PB_RIGHT + self->xspeed = -self->xspeed; + break; + case 2: // PB_UP + self->yspeed = -self->yspeed; + break; + case 4: // PB_DOWN + self->yspeed = -self->yspeed; + break; + default: // Should never hit + return false; + } + // trigger tile collision resolution + return true; + } + + return false; +} + +void ballOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty) +{ + switch (tileId) + { + case TILE_BLOCK_1x1_RED ... TILE_BLOCK_1x1_BLACK: + case TILE_BLOCK_2x1_RED_L ... TILE_BLOCK_2x1_BLACK_R: + case TILE_BLOCK_2x2_RED_UL ... TILE_BLOCK_2x2_BLACK_UR: + case TILE_BLOCK_2x2_WHITE_DL ... TILE_BLOCK_2x2_BLACK_DR: + { bzrPlaySfx(&(self->soundManager->hit1), BZR_LEFT); - scorePoints(self->gameData, 1, -1); + scorePoints(self->gameData, 10 * breakBlockTile(self->tilemap, self->gameData, tileId, tx, ty), + (self->shouldAdvanceMultiplier) ? -1 : 0); + self->shouldAdvanceMultiplier = true; + self->bouncesOffUnbreakableBlocks = 0; break; } - case TILE_BOUNDARY_1 ... TILE_BOUNDARY_3:{ + case TILE_BOUNDARY_1 ... TILE_UNUSED_F: + { bzrPlaySfx(&(self->soundManager->hit3), BZR_LEFT); break; } - default: { + default: + { break; } } } -void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, uint8_t tx, uint8_t ty){ - switch(tileId){ - case TILE_BLOCK_1x1_RED ... TILE_BLOCK_1x1_BLACK: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - break; +int16_t breakBlockTile(tilemap_t* tilemap, gameData_t* gameData, uint8_t tileId, uint8_t tx, uint8_t ty) +{ + int16_t blockBreakCount = 0; + + switch (tileId) + { + case TILE_BLOCK_1x1_RED ... TILE_BLOCK_1x1_STONE: + { + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; + break; } case TILE_BLOCK_2x1_RED_L: case TILE_BLOCK_2x1_ORANGE_L: @@ -881,16 +1515,18 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x1_TAN_L: case TILE_BLOCK_2x1_BROWN_L: case TILE_BLOCK_2x1_BLACK_L: + case TILE_BLOCK_2x1_STONE_L: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - - if(isBlock(getTile(tilemap, tx+1, ty))){ - setTile(tilemap, tx+1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; - break; + if (isBlock(getTile(tilemap, tx + 1, ty))) + { + setTile(tilemap, tx + 1, ty, TILE_EMPTY); + blockBreakCount++; + } + + break; } case TILE_BLOCK_2x1_RED_R: case TILE_BLOCK_2x1_ORANGE_R: @@ -904,16 +1540,18 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x1_TAN_R: case TILE_BLOCK_2x1_BROWN_R: case TILE_BLOCK_2x1_BLACK_R: + case TILE_BLOCK_2x1_STONE_R: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; - if(isBlock(getTile(tilemap, tx-1, ty))){ - setTile(tilemap, tx-1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } + if (isBlock(getTile(tilemap, tx - 1, ty))) + { + setTile(tilemap, tx - 1, ty, TILE_EMPTY); + blockBreakCount++; + } - break; + break; } case TILE_BLOCK_2x2_RED_UL: case TILE_BLOCK_2x2_ORANGE_UL: @@ -927,26 +1565,30 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x2_TAN_UL: case TILE_BLOCK_2x2_BROWN_UL: case TILE_BLOCK_2x2_BLACK_UL: + case TILE_BLOCK_2x2_STONE_UL: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - - if(isBlock(getTile(tilemap, tx+1, ty))){ - setTile(tilemap, tx+1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx,ty+1))){ - setTile(tilemap, tx, ty+1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx+1,ty+1))){ - setTile(tilemap, tx+1, ty+1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - break; + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; + + if (isBlock(getTile(tilemap, tx + 1, ty))) + { + setTile(tilemap, tx + 1, ty, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx, ty + 1))) + { + setTile(tilemap, tx, ty + 1, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx + 1, ty + 1))) + { + setTile(tilemap, tx + 1, ty + 1, TILE_EMPTY); + blockBreakCount++; + } + + break; } case TILE_BLOCK_2x2_RED_UR: case TILE_BLOCK_2x2_ORANGE_UR: @@ -960,26 +1602,30 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x2_TAN_UR: case TILE_BLOCK_2x2_BROWN_UR: case TILE_BLOCK_2x2_BLACK_UR: + case TILE_BLOCK_2x2_STONE_UR: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - - if(isBlock(getTile(tilemap, tx-1, ty))){ - setTile(tilemap, tx-1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx,ty+1))){ - setTile(tilemap, tx, ty+1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx-1,ty+1))){ - setTile(tilemap, tx-1, ty+1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - break; + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; + + if (isBlock(getTile(tilemap, tx - 1, ty))) + { + setTile(tilemap, tx - 1, ty, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx, ty + 1))) + { + setTile(tilemap, tx, ty + 1, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx - 1, ty + 1))) + { + setTile(tilemap, tx - 1, ty + 1, TILE_EMPTY); + blockBreakCount++; + } + + break; } case TILE_BLOCK_2x2_RED_DL: case TILE_BLOCK_2x2_ORANGE_DL: @@ -993,26 +1639,30 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x2_TAN_DL: case TILE_BLOCK_2x2_BROWN_DL: case TILE_BLOCK_2x2_BLACK_DL: + case TILE_BLOCK_2x2_STONE_DL: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - - if(isBlock(getTile(tilemap, tx+1, ty))){ - setTile(tilemap, tx+1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx,ty-1))){ - setTile(tilemap, tx, ty-1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx+1,ty-1))){ - setTile(tilemap, tx+1, ty-1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - break; + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; + + if (isBlock(getTile(tilemap, tx + 1, ty))) + { + setTile(tilemap, tx + 1, ty, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx, ty - 1))) + { + setTile(tilemap, tx, ty - 1, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx + 1, ty - 1))) + { + setTile(tilemap, tx + 1, ty - 1, TILE_EMPTY); + blockBreakCount++; + } + + break; } case TILE_BLOCK_2x2_RED_DR: case TILE_BLOCK_2x2_ORANGE_DR: @@ -1026,54 +1676,74 @@ void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, ui case TILE_BLOCK_2x2_TAN_DR: case TILE_BLOCK_2x2_BROWN_DR: case TILE_BLOCK_2x2_BLACK_DR: + case TILE_BLOCK_2x2_STONE_DR: + { + setTile(tilemap, tx, ty, TILE_EMPTY); + blockBreakCount++; + + if (isBlock(getTile(tilemap, tx - 1, ty))) + { + setTile(tilemap, tx - 1, ty, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx, ty - 1))) + { + setTile(tilemap, tx, ty - 1, TILE_EMPTY); + blockBreakCount++; + } + + if (isBlock(getTile(tilemap, tx - 1, ty - 1))) + { + setTile(tilemap, tx - 1, ty - 1, TILE_EMPTY); + blockBreakCount++; + } + + break; + } + + default: { - setTile(tilemap, tx, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - - if(isBlock(getTile(tilemap, tx-1, ty))){ - setTile(tilemap, tx-1, ty, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx,ty-1))){ - setTile(tilemap, tx, ty-1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - if(isBlock(getTile(tilemap, tx-1,ty-1))){ - setTile(tilemap, tx-1, ty-1, TILE_EMPTY); - gameData->targetBlocksBroken++; - } - - break; - } - - default: { break; } } setLedBreakBlock(gameData, tileId); + gameData->targetBlocksBroken += blockBreakCount; + + if (gameData->targetBlocksBroken >= tilemap->totalTargetBlocks) + { + entity_t* playerBall = findFirstEntityOfType(tilemap->entityManager, ENTITY_PLAYER_BALL); + if (playerBall != NULL) + { + playerBall->updateFunction = &updateChoLevelClear; + playerBall->entityManager->playerEntity = playerBall; + deactivateAllEntities(playerBall->entityManager, true, false, false); + } - if(gameData->targetBlocksBroken >= tilemap->totalTargetBlocks){ gameData->changeState = ST_LEVEL_CLEAR; } -}; -void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ + return blockBreakCount; +} + +void setLedBreakBlock(gameData_t* gameData, uint8_t tileId) +{ uint8_t ledIndex = esp_random() % CONFIG_NUM_LEDS; - uint16_t nr = 0; - uint16_t ng = 0; - uint16_t nb = 0; + int16_t nr = 0; + int16_t ng = 0; + int16_t nb = 0; - switch(tileId){ + switch (tileId) + { case TILE_BLOCK_1x1_RED: case TILE_BLOCK_2x1_RED_L: case TILE_BLOCK_2x1_RED_R: case TILE_BLOCK_2x2_RED_UL: case TILE_BLOCK_2x2_RED_UR: case TILE_BLOCK_2x2_RED_DL: - case TILE_BLOCK_2x2_RED_DR: { + case TILE_BLOCK_2x2_RED_DR: + { nr = 255; break; } @@ -1083,7 +1753,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_ORANGE_UL: case TILE_BLOCK_2x2_ORANGE_UR: case TILE_BLOCK_2x2_ORANGE_DL: - case TILE_BLOCK_2x2_ORANGE_DR: { + case TILE_BLOCK_2x2_ORANGE_DR: + { nr = 255; ng = 127; break; @@ -1094,7 +1765,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_YELLOW_UL: case TILE_BLOCK_2x2_YELLOW_UR: case TILE_BLOCK_2x2_YELLOW_DL: - case TILE_BLOCK_2x2_YELLOW_DR: { + case TILE_BLOCK_2x2_YELLOW_DR: + { nr = 255; ng = 255; break; @@ -1105,7 +1777,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_GREEN_UL: case TILE_BLOCK_2x2_GREEN_UR: case TILE_BLOCK_2x2_GREEN_DL: - case TILE_BLOCK_2x2_GREEN_DR: { + case TILE_BLOCK_2x2_GREEN_DR: + { ng = 255; break; } @@ -1115,7 +1788,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_CYAN_UL: case TILE_BLOCK_2x2_CYAN_UR: case TILE_BLOCK_2x2_CYAN_DL: - case TILE_BLOCK_2x2_CYAN_DR: { + case TILE_BLOCK_2x2_CYAN_DR: + { ng = 255; nb = 255; break; @@ -1126,7 +1800,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_BLUE_UL: case TILE_BLOCK_2x2_BLUE_UR: case TILE_BLOCK_2x2_BLUE_DL: - case TILE_BLOCK_2x2_BLUE_DR: { + case TILE_BLOCK_2x2_BLUE_DR: + { nb = 255; break; } @@ -1136,7 +1811,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_PURPLE_UL: case TILE_BLOCK_2x2_PURPLE_UR: case TILE_BLOCK_2x2_PURPLE_DL: - case TILE_BLOCK_2x2_PURPLE_DR: { + case TILE_BLOCK_2x2_PURPLE_DR: + { nr = 255; nb = 127; break; @@ -1147,7 +1823,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_MAGENTA_UL: case TILE_BLOCK_2x2_MAGENTA_UR: case TILE_BLOCK_2x2_MAGENTA_DL: - case TILE_BLOCK_2x2_MAGENTA_DR: { + case TILE_BLOCK_2x2_MAGENTA_DR: + { nr = 255; nb = 255; break; @@ -1158,7 +1835,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_WHITE_UL: case TILE_BLOCK_2x2_WHITE_UR: case TILE_BLOCK_2x2_WHITE_DL: - case TILE_BLOCK_2x2_WHITE_DR: { + case TILE_BLOCK_2x2_WHITE_DR: + { nr = 255; ng = 255; nb = 255; @@ -1170,7 +1848,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_TAN_UL: case TILE_BLOCK_2x2_TAN_UR: case TILE_BLOCK_2x2_TAN_DL: - case TILE_BLOCK_2x2_TAN_DR: { + case TILE_BLOCK_2x2_TAN_DR: + { nr = 255; ng = 204; nb = 103; @@ -1182,7 +1861,8 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_BROWN_UL: case TILE_BLOCK_2x2_BROWN_UR: case TILE_BLOCK_2x2_BROWN_DL: - case TILE_BLOCK_2x2_BROWN_DR: { + case TILE_BLOCK_2x2_BROWN_DR: + { nr = 153; ng = 102; nb = 102; @@ -1194,17 +1874,17 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ case TILE_BLOCK_2x2_BLACK_UL: case TILE_BLOCK_2x2_BLACK_UR: case TILE_BLOCK_2x2_BLACK_DL: - case TILE_BLOCK_2x2_BLACK_DR: { + case TILE_BLOCK_2x2_BLACK_DR: + { nr = 64; ng = 64; nb = 64; break; } - default: { + default: + { break; } - - } nr += gameData->leds[ledIndex].r; @@ -1218,12 +1898,13 @@ void setLedBreakBlock(gameData_t *gameData, uint8_t tileId){ setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateDummy(entity_t *self) +void updateDummy(entity_t* self) { // Do nothing, because that's what dummies do! } -void setVelocity(entity_t *self, int16_t direction, int16_t magnitude){ +void setVelocity(entity_t* self, int16_t direction, int16_t magnitude) +{ while (direction < 0) { direction += 360; @@ -1233,14 +1914,15 @@ void setVelocity(entity_t *self, int16_t direction, int16_t magnitude){ direction -= 360; } - int16_t sin = getSin1024(direction); - int16_t cos = getCos1024(direction); + int16_t sin = getSin1024(direction); + int16_t cos = getCos1024(direction); self->xspeed = (magnitude * cos) / 1024; self->yspeed = -(magnitude * sin) / 1024; } -void playerOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty){ +void playerOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty) +{ /*switch(tileId){ case TILE_COIN_1...TILE_COIN_3:{ setTile(self->tilemap, tx, ty, TILE_EMPTY); @@ -1269,6 +1951,7 @@ void playerOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_ }*/ } -void defaultOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty){ - //Nothing to do. +void defaultOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty) +{ + // Nothing to do. } diff --git a/main/modes/breakout/entity.h b/main/modes/breakout/entity.h index 743b2ba45..b6ffa0f7d 100644 --- a/main/modes/breakout/entity.h +++ b/main/modes/breakout/entity.h @@ -16,17 +16,18 @@ // Enums //============================================================================== -typedef enum { +typedef enum +{ ENTITY_PLAYER_PADDLE_BOTTOM, ENTITY_PLAYER_PADDLE_TOP, ENTITY_PLAYER_PADDLE_LEFT, ENTITY_PLAYER_PADDLE_RIGHT, - ENTITY_UNUSED_4, - ENTITY_UNUSED_5, - ENTITY_UNUSED_6, - ENTITY_UNUSED_7, - ENTITY_UNUSED_8, - ENTITY_UNUSED_9, + ENTITY_PLAYER_TIME_BOMB, + ENTITY_PLAYER_REMOTE_BOMB, + ENTITY_PLAYER_BOMB_EXPLOSION, + ENTITY_BALL_TRAIL, + ENTITY_CHO_INTRO, + ENTITY_CRAWLER, ENTITY_UNUSED_10, ENTITY_UNUSED_11, ENTITY_UNUSED_12, @@ -34,31 +35,47 @@ typedef enum { ENTITY_UNUSED_14, ENTITY_UNUSED_15, ENTITY_PLAYER_BALL, - ENTITY_PLAYER_TIME_BOMB, - ENTITY_PLAYER_BOMB_EXPLOSION, - ENTITY_PLAYER_REMOTE_BOMB + ENTITY_CAPTIVE_BALL, + ENTITY_UNUSED_18, + ENTITY_UNUSED_19, + ENTITY_UNUSED_20, + ENTITY_UNUSED_21 } entityIndex_t; +typedef enum +{ + CRAWLER_TOP_TO_RIGHT, + CRAWLER_RIGHT_TO_BOTTOM, + CRAWLER_BOTTOM_TO_LEFT, + CRAWLER_LEFT_TO_TOP, + CRAWLER_TOP_TO_LEFT, + CRAWLER_RIGHT_TO_TOP, + CRAWLER_BOTTOM_TO_RIGHT, + CRAWLER_LEFT_TO_BOTTOM +} crawlerMoveState_t; + //============================================================================== // Structs //============================================================================== -typedef void(*updateFunction_t)(struct entity_t *self); -typedef void(*collisionHandler_t)(struct entity_t *self, struct entity_t *other); -typedef bool(*tileCollisionHandler_t)(struct entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); -typedef void(*fallOffTileHandler_t)(struct entity_t *self); -typedef void(*overlapTileHandler_t)(struct entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty); +typedef void (*updateFunction_t)(struct entity_t* self); +typedef void (*collisionHandler_t)(struct entity_t* self, struct entity_t* other); +typedef bool (*tileCollisionHandler_t)(struct entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, + uint8_t direction); +typedef void (*fallOffTileHandler_t)(struct entity_t* self); +typedef void (*overlapTileHandler_t)(struct entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty); struct entity_t { bool active; + bool persistent; uint8_t type; updateFunction_t updateFunction; uint16_t x; uint16_t y; - + int16_t xspeed; int16_t yspeed; @@ -69,24 +86,27 @@ struct entity_t uint8_t animationTimer; - tilemap_t * tilemap; - gameData_t * gameData; - soundManager_t * soundManager; + tilemap_t* tilemap; + gameData_t* gameData; + soundManager_t* soundManager; uint8_t homeTileX; uint8_t homeTileY; - int16_t jumpPower; - bool visible; - uint8_t hp; - int8_t invincibilityFrames; - uint16_t scoreValue; - entity_t *attachedToEntity; + entity_t* attachedToEntity; + bool shouldAdvanceMultiplier; - - entityManager_t *entityManager; + int16_t bouncesOffUnbreakableBlocks; + int16_t breakInfiniteLoopBounceThreshold; + + int16_t baseSpeed; + int16_t maxSpeed; + int16_t bouncesToNextSpeedUp; + uint8_t speedUpLookupIndex; + + entityManager_t* entityManager; collisionHandler_t collisionHandler; tileCollisionHandler_t tileCollisionHandler; @@ -96,42 +116,59 @@ struct entity_t //============================================================================== // Prototypes //============================================================================== -void initializeEntity(entity_t * self, entityManager_t * entityManager, tilemap_t * tilemap, gameData_t * gameData, soundManager_t * soundManager); - -void updatePlayer(entity_t * self); -void updatePlayerVertical(entity_t * self); - -void updateBall(entity_t * self); -void updateBallAtStart(entity_t *self); -void updateTimeBomb(entity_t * self); -void updateRemoteBomb(entity_t * self); +void initializeEntity(entity_t* self, entityManager_t* entityManager, tilemap_t* tilemap, gameData_t* gameData, + soundManager_t* soundManager); + +void updatePlayer(entity_t* self); +void updatePlayerVertical(entity_t* self); + +void updateBall(entity_t* self); +void updateBallAtStart(entity_t* self); +bool isOutsidePlayfield(entity_t* self); +void detectLostBall(entity_t* self, bool respawn); +void updateCaptiveBallNotInPlay(entity_t* self); +void updateCaptiveBallInPlay(entity_t* self); +uint32_t getTaxiCabDistanceBetweenEntities(entity_t* self, entity_t* other); +void updateTimeBomb(entity_t* self); +void updateRemoteBomb(entity_t* self); void explodeBomb(entity_t* self); -void updateExplosion(entity_t * self); +void updateExplosion(entity_t* self); +void updateBallTrail(entity_t* self); +void updateChoIntro(entity_t* self); +void updateCrawler(entity_t* self); +void crawlerSetMoveState(entity_t* self, uint8_t state); +void crawlerInitMoveState(entity_t* self); + +entity_t* findFirstEntityOfType(entityManager_t* entityManager, uint8_t type); +void updateChoLevelClear(entity_t* self); -void moveEntityWithTileCollisions(entity_t * self); +void moveEntityWithTileCollisions(entity_t* self); -void destroyEntity(entity_t *self, bool respawn); +void destroyEntity(entity_t* self, bool respawn); -void detectEntityCollisions(entity_t *self); +void detectEntityCollisions(entity_t* self); -void playerCollisionHandler(entity_t *self, entity_t* other); -void enemyCollisionHandler(entity_t *self, entity_t *other); -void dummyCollisionHandler(entity_t *self, entity_t *other); -void ballCollisionHandler(entity_t *self, entity_t *other); +void playerCollisionHandler(entity_t* self, entity_t* other); +void crawlerCollisionHandler(entity_t* self, entity_t* other); +void dummyCollisionHandler(entity_t* self, entity_t* other); +void ballCollisionHandler(entity_t* self, entity_t* other); +void captiveBallCollisionHandler(entity_t* self, entity_t* other); +void advanceBallSpeed(entity_t* self, uint16_t factor); -bool playerTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); -bool enemyTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); -bool dummyTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); -bool ballTileCollisionHandler(entity_t *self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); +bool playerTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); +bool enemyTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); +bool dummyTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); +bool ballTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); +bool captiveBallTileCollisionHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty, uint8_t direction); void defaultOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty); void playerOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty); void ballOverlapTileHandler(entity_t* self, uint8_t tileId, uint8_t tx, uint8_t ty); -void breakBlockTile(tilemap_t *tilemap, gameData_t *gameData, uint8_t tileId, uint8_t tx, uint8_t ty); -void setLedBreakBlock(gameData_t *gameData, uint8_t tileId); +int16_t breakBlockTile(tilemap_t* tilemap, gameData_t* gameData, uint8_t tileId, uint8_t tx, uint8_t ty); +void setLedBreakBlock(gameData_t* gameData, uint8_t tileId); void updateDummy(entity_t* self); -void setVelocity(entity_t *self, int16_t direction, int16_t magnitude); +void setVelocity(entity_t* self, int16_t direction, int16_t magnitude); #endif diff --git a/main/modes/breakout/entityManager.c b/main/modes/breakout/entityManager.c index d3c8a709b..9b8af5e8e 100644 --- a/main/modes/breakout/entityManager.c +++ b/main/modes/breakout/entityManager.c @@ -21,213 +21,361 @@ //============================================================================== // Functions //============================================================================== -void initializeEntityManager(entityManager_t * entityManager, tilemap_t * tilemap, gameData_t * gameData, soundManager_t * soundManager) +void initializeEntityManager(entityManager_t* entityManager, tilemap_t* tilemap, gameData_t* gameData, + soundManager_t* soundManager) { loadSprites(entityManager); entityManager->entities = calloc(MAX_ENTITIES, sizeof(entity_t)); - - for(uint8_t i=0; i < MAX_ENTITIES; i++) + + for (uint8_t i = 0; i < MAX_ENTITIES; i++) { initializeEntity(&(entityManager->entities[i]), entityManager, tilemap, gameData, soundManager); } entityManager->activeEntities = 0; - entityManager->tilemap = tilemap; + entityManager->tilemap = tilemap; - - //entityManager->viewEntity = createPlayer(entityManager, entityManager->tilemap->warps[0].x * 16, entityManager->tilemap->warps[0].y * 16); - //entityManager->playerEntity = entityManager->viewEntity; -}; + // entityManager->viewEntity = createPlayer(entityManager, entityManager->tilemap->warps[0].x * 16, + // entityManager->tilemap->warps[0].y * 16); entityManager->playerEntity = entityManager->viewEntity; +} -void loadSprites(entityManager_t * entityManager) +void loadSprites(entityManager_t* entityManager) { loadWsg("paddle000.wsg", &(entityManager->sprites[SP_PADDLE_0].wsg), false); - entityManager->sprites[SP_PADDLE_0].originX=14; - entityManager->sprites[SP_PADDLE_0].originY=4; + entityManager->sprites[SP_PADDLE_0].originX = 14; + entityManager->sprites[SP_PADDLE_0].originY = 4; entityManager->sprites[SP_PADDLE_0].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_0].collisionBox.x1 = 27; entityManager->sprites[SP_PADDLE_0].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_0].collisionBox.y1 = 7; loadWsg("paddle001.wsg", &entityManager->sprites[SP_PADDLE_1].wsg, false); - entityManager->sprites[SP_PADDLE_1].originX=14; - entityManager->sprites[SP_PADDLE_1].originY=4; + entityManager->sprites[SP_PADDLE_1].originX = 14; + entityManager->sprites[SP_PADDLE_1].originY = 4; entityManager->sprites[SP_PADDLE_1].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_1].collisionBox.x1 = 27; entityManager->sprites[SP_PADDLE_1].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_1].collisionBox.y1 = 7; loadWsg("paddle002.wsg", &entityManager->sprites[SP_PADDLE_2].wsg, false); - entityManager->sprites[SP_PADDLE_2].originX=14; - entityManager->sprites[SP_PADDLE_2].originY=4; + entityManager->sprites[SP_PADDLE_2].originX = 14; + entityManager->sprites[SP_PADDLE_2].originY = 4; entityManager->sprites[SP_PADDLE_2].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_2].collisionBox.x1 = 27; entityManager->sprites[SP_PADDLE_2].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_2].collisionBox.y1 = 7; loadWsg("paddleVertical000.wsg", &entityManager->sprites[SP_PADDLE_VERTICAL_0].wsg, false); - entityManager->sprites[SP_PADDLE_VERTICAL_0].originX=4; - entityManager->sprites[SP_PADDLE_VERTICAL_0].originY=14; + entityManager->sprites[SP_PADDLE_VERTICAL_0].originX = 4; + entityManager->sprites[SP_PADDLE_VERTICAL_0].originY = 14; entityManager->sprites[SP_PADDLE_VERTICAL_0].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_0].collisionBox.x1 = 7; entityManager->sprites[SP_PADDLE_VERTICAL_0].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_0].collisionBox.y1 = 27; loadWsg("paddleVertical001.wsg", &entityManager->sprites[SP_PADDLE_VERTICAL_1].wsg, false); - entityManager->sprites[SP_PADDLE_VERTICAL_1].originX=4; - entityManager->sprites[SP_PADDLE_VERTICAL_1].originY=14; + entityManager->sprites[SP_PADDLE_VERTICAL_1].originX = 4; + entityManager->sprites[SP_PADDLE_VERTICAL_1].originY = 14; entityManager->sprites[SP_PADDLE_VERTICAL_1].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_1].collisionBox.x1 = 7; entityManager->sprites[SP_PADDLE_VERTICAL_1].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_1].collisionBox.y1 = 27; loadWsg("paddleVertical002.wsg", &entityManager->sprites[SP_PADDLE_VERTICAL_2].wsg, false); - entityManager->sprites[SP_PADDLE_VERTICAL_2].originX=4; - entityManager->sprites[SP_PADDLE_VERTICAL_2].originY=14; + entityManager->sprites[SP_PADDLE_VERTICAL_2].originX = 4; + entityManager->sprites[SP_PADDLE_VERTICAL_2].originY = 14; entityManager->sprites[SP_PADDLE_VERTICAL_2].collisionBox.x0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_2].collisionBox.x1 = 7; entityManager->sprites[SP_PADDLE_VERTICAL_2].collisionBox.y0 = 0; entityManager->sprites[SP_PADDLE_VERTICAL_2].collisionBox.y1 = 27; + loadWsg("ball.wsg", &entityManager->sprites[SP_BALL].wsg, false); + entityManager->sprites[SP_BALL].originX = 4; + entityManager->sprites[SP_BALL].originY = 4; + entityManager->sprites[SP_BALL].collisionBox.x0 = 0; + entityManager->sprites[SP_BALL].collisionBox.x1 = 7; + entityManager->sprites[SP_BALL].collisionBox.y0 = 0; + entityManager->sprites[SP_BALL].collisionBox.y1 = 7; + loadWsg("ball000.wsg", &entityManager->sprites[SP_BALL_0].wsg, false); - entityManager->sprites[SP_BALL_0].originX=4; - entityManager->sprites[SP_BALL_0].originY=4; + entityManager->sprites[SP_BALL_0].originX = 4; + entityManager->sprites[SP_BALL_0].originY = 4; entityManager->sprites[SP_BALL_0].collisionBox.x0 = 0; entityManager->sprites[SP_BALL_0].collisionBox.x1 = 7; entityManager->sprites[SP_BALL_0].collisionBox.y0 = 0; entityManager->sprites[SP_BALL_0].collisionBox.y1 = 7; loadWsg("ball001.wsg", &entityManager->sprites[SP_BALL_1].wsg, false); - entityManager->sprites[SP_BALL_1].originX=4; - entityManager->sprites[SP_BALL_1].originY=4; + entityManager->sprites[SP_BALL_1].originX = 4; + entityManager->sprites[SP_BALL_1].originY = 4; entityManager->sprites[SP_BALL_1].collisionBox.x0 = 0; entityManager->sprites[SP_BALL_1].collisionBox.x1 = 7; entityManager->sprites[SP_BALL_1].collisionBox.y0 = 0; entityManager->sprites[SP_BALL_1].collisionBox.y1 = 7; loadWsg("ball002.wsg", &entityManager->sprites[SP_BALL_2].wsg, false); - entityManager->sprites[SP_BALL_2].originX=4; - entityManager->sprites[SP_BALL_2].originY=4; + entityManager->sprites[SP_BALL_2].originX = 4; + entityManager->sprites[SP_BALL_2].originY = 4; entityManager->sprites[SP_BALL_2].collisionBox.x0 = 0; entityManager->sprites[SP_BALL_2].collisionBox.x1 = 7; entityManager->sprites[SP_BALL_2].collisionBox.y0 = 0; entityManager->sprites[SP_BALL_2].collisionBox.y1 = 7; loadWsg("dbmb000.wsg", &entityManager->sprites[SP_BOMB_0].wsg, false); - entityManager->sprites[SP_BOMB_0].originX=4; - entityManager->sprites[SP_BOMB_0].originY=4; + entityManager->sprites[SP_BOMB_0].originX = 4; + entityManager->sprites[SP_BOMB_0].originY = 4; entityManager->sprites[SP_BOMB_0].collisionBox.x0 = 0; entityManager->sprites[SP_BOMB_0].collisionBox.x1 = 7; entityManager->sprites[SP_BOMB_0].collisionBox.y0 = 0; entityManager->sprites[SP_BOMB_0].collisionBox.y1 = 7; loadWsg("dbmb001.wsg", &entityManager->sprites[SP_BOMB_1].wsg, false); - entityManager->sprites[SP_BOMB_1].originX=4; - entityManager->sprites[SP_BOMB_1].originY=4; + entityManager->sprites[SP_BOMB_1].originX = 4; + entityManager->sprites[SP_BOMB_1].originY = 4; entityManager->sprites[SP_BOMB_1].collisionBox.x0 = 0; entityManager->sprites[SP_BOMB_1].collisionBox.x1 = 7; entityManager->sprites[SP_BOMB_1].collisionBox.y0 = 0; entityManager->sprites[SP_BOMB_1].collisionBox.y1 = 7; loadWsg("dbmb002.wsg", &entityManager->sprites[SP_BOMB_2].wsg, false); - entityManager->sprites[SP_BOMB_2].originX=4; - entityManager->sprites[SP_BOMB_2].originY=4; + entityManager->sprites[SP_BOMB_2].originX = 4; + entityManager->sprites[SP_BOMB_2].originY = 4; entityManager->sprites[SP_BOMB_2].collisionBox.x0 = 0; entityManager->sprites[SP_BOMB_2].collisionBox.x1 = 7; entityManager->sprites[SP_BOMB_2].collisionBox.y0 = 0; entityManager->sprites[SP_BOMB_2].collisionBox.y1 = 7; loadWsg("boom000.wsg", &entityManager->sprites[SP_EXPLOSION_0].wsg, false); - entityManager->sprites[SP_EXPLOSION_0].originX=20; - entityManager->sprites[SP_EXPLOSION_0].originY=20; + entityManager->sprites[SP_EXPLOSION_0].originX = 20; + entityManager->sprites[SP_EXPLOSION_0].originY = 20; entityManager->sprites[SP_EXPLOSION_0].collisionBox.x0 = 0; entityManager->sprites[SP_EXPLOSION_0].collisionBox.x1 = 39; entityManager->sprites[SP_EXPLOSION_0].collisionBox.y0 = 0; entityManager->sprites[SP_EXPLOSION_0].collisionBox.y1 = 39; loadWsg("boom001.wsg", &entityManager->sprites[SP_EXPLOSION_1].wsg, false); - entityManager->sprites[SP_EXPLOSION_1].originX=20; - entityManager->sprites[SP_EXPLOSION_1].originY=20; + entityManager->sprites[SP_EXPLOSION_1].originX = 20; + entityManager->sprites[SP_EXPLOSION_1].originY = 20; entityManager->sprites[SP_EXPLOSION_1].collisionBox.x0 = 0; entityManager->sprites[SP_EXPLOSION_1].collisionBox.x1 = 39; entityManager->sprites[SP_EXPLOSION_1].collisionBox.y0 = 0; entityManager->sprites[SP_EXPLOSION_1].collisionBox.y1 = 39; loadWsg("boom002.wsg", &entityManager->sprites[SP_EXPLOSION_2].wsg, false); - entityManager->sprites[SP_EXPLOSION_2].originX=20; - entityManager->sprites[SP_EXPLOSION_2].originY=20; + entityManager->sprites[SP_EXPLOSION_2].originX = 20; + entityManager->sprites[SP_EXPLOSION_2].originY = 20; entityManager->sprites[SP_EXPLOSION_2].collisionBox.x0 = 0; entityManager->sprites[SP_EXPLOSION_2].collisionBox.x1 = 39; entityManager->sprites[SP_EXPLOSION_2].collisionBox.y0 = 0; entityManager->sprites[SP_EXPLOSION_2].collisionBox.y1 = 39; loadWsg("boom003.wsg", &entityManager->sprites[SP_EXPLOSION_3].wsg, false); - entityManager->sprites[SP_EXPLOSION_3].originX=20; - entityManager->sprites[SP_EXPLOSION_3].originY=20; + entityManager->sprites[SP_EXPLOSION_3].originX = 20; + entityManager->sprites[SP_EXPLOSION_3].originY = 20; entityManager->sprites[SP_EXPLOSION_3].collisionBox.x0 = 0; entityManager->sprites[SP_EXPLOSION_3].collisionBox.x1 = 39; entityManager->sprites[SP_EXPLOSION_3].collisionBox.y0 = 0; entityManager->sprites[SP_EXPLOSION_3].collisionBox.y1 = 39; -}; -void updateEntities(entityManager_t * entityManager) + loadWsg("ballTrail000.wsg", &entityManager->sprites[SP_BALL_TRAIL_0].wsg, false); + entityManager->sprites[SP_BALL_TRAIL_0].originX = 4; + entityManager->sprites[SP_BALL_TRAIL_0].originY = 4; + entityManager->sprites[SP_BALL_TRAIL_0].collisionBox.x0 = 0; + entityManager->sprites[SP_BALL_TRAIL_0].collisionBox.x1 = 7; + entityManager->sprites[SP_BALL_TRAIL_0].collisionBox.y0 = 0; + entityManager->sprites[SP_BALL_TRAIL_0].collisionBox.y1 = 7; + + loadWsg("ballTrail001.wsg", &entityManager->sprites[SP_BALL_TRAIL_1].wsg, false); + entityManager->sprites[SP_BALL_TRAIL_1].originX = 4; + entityManager->sprites[SP_BALL_TRAIL_1].originY = 4; + entityManager->sprites[SP_BALL_TRAIL_1].collisionBox.x0 = 0; + entityManager->sprites[SP_BALL_TRAIL_1].collisionBox.x1 = 7; + entityManager->sprites[SP_BALL_TRAIL_1].collisionBox.y0 = 0; + entityManager->sprites[SP_BALL_TRAIL_1].collisionBox.y1 = 7; + + loadWsg("ballTrail002.wsg", &entityManager->sprites[SP_BALL_TRAIL_2].wsg, false); + entityManager->sprites[SP_BALL_TRAIL_2].originX = 4; + entityManager->sprites[SP_BALL_TRAIL_2].originY = 4; + entityManager->sprites[SP_BALL_TRAIL_2].collisionBox.x0 = 0; + entityManager->sprites[SP_BALL_TRAIL_2].collisionBox.x1 = 7; + entityManager->sprites[SP_BALL_TRAIL_2].collisionBox.y0 = 0; + entityManager->sprites[SP_BALL_TRAIL_2].collisionBox.y1 = 7; + + loadWsg("ballTrail003.wsg", &entityManager->sprites[SP_BALL_TRAIL_3].wsg, false); + entityManager->sprites[SP_BALL_TRAIL_3].originX = 4; + entityManager->sprites[SP_BALL_TRAIL_3].originY = 4; + entityManager->sprites[SP_BALL_TRAIL_3].collisionBox.x0 = 0; + entityManager->sprites[SP_BALL_TRAIL_3].collisionBox.x1 = 7; + entityManager->sprites[SP_BALL_TRAIL_3].collisionBox.y0 = 0; + entityManager->sprites[SP_BALL_TRAIL_3].collisionBox.y1 = 7; + + loadWsg("cho000.wsg", &entityManager->sprites[SP_CHO_WALK_0].wsg, false); + entityManager->sprites[SP_CHO_WALK_0].originX = 7; + entityManager->sprites[SP_CHO_WALK_0].originY = 11; + entityManager->sprites[SP_CHO_WALK_0].collisionBox.x0 = 0; + entityManager->sprites[SP_CHO_WALK_0].collisionBox.x1 = 15; + entityManager->sprites[SP_CHO_WALK_0].collisionBox.y0 = 0; + entityManager->sprites[SP_CHO_WALK_0].collisionBox.y1 = 15; + + loadWsg("cho001.wsg", &entityManager->sprites[SP_CHO_WALK_1].wsg, false); + entityManager->sprites[SP_CHO_WALK_1].originX = 7; + entityManager->sprites[SP_CHO_WALK_1].originY = 11; + entityManager->sprites[SP_CHO_WALK_1].collisionBox.x0 = 0; + entityManager->sprites[SP_CHO_WALK_1].collisionBox.x1 = 15; + entityManager->sprites[SP_CHO_WALK_1].collisionBox.y0 = 0; + entityManager->sprites[SP_CHO_WALK_1].collisionBox.y1 = 15; + + loadWsg("cho002.wsg", &entityManager->sprites[SP_CHO_WALK_2].wsg, false); + entityManager->sprites[SP_CHO_WALK_2].originX = 7; + entityManager->sprites[SP_CHO_WALK_2].originY = 11; + entityManager->sprites[SP_CHO_WALK_2].collisionBox.x0 = 0; + entityManager->sprites[SP_CHO_WALK_2].collisionBox.x1 = 15; + entityManager->sprites[SP_CHO_WALK_2].collisionBox.y0 = 0; + entityManager->sprites[SP_CHO_WALK_2].collisionBox.y1 = 15; + + loadWsg("cho003.wsg", &entityManager->sprites[SP_CHO_WIN_0].wsg, false); + entityManager->sprites[SP_CHO_WIN_0].originX = 7; + entityManager->sprites[SP_CHO_WIN_0].originY = 7; + entityManager->sprites[SP_CHO_WIN_0].collisionBox.x0 = 0; + entityManager->sprites[SP_CHO_WIN_0].collisionBox.x1 = 15; + entityManager->sprites[SP_CHO_WIN_0].collisionBox.y0 = 0; + entityManager->sprites[SP_CHO_WIN_0].collisionBox.y1 = 15; + + loadWsg("cho004.wsg", &entityManager->sprites[SP_CHO_WIN_1].wsg, false); + entityManager->sprites[SP_CHO_WIN_1].originX = 7; + entityManager->sprites[SP_CHO_WIN_1].originY = 7; + entityManager->sprites[SP_CHO_WIN_1].collisionBox.x0 = 0; + entityManager->sprites[SP_CHO_WIN_1].collisionBox.x1 = 15; + entityManager->sprites[SP_CHO_WIN_1].collisionBox.y0 = 0; + entityManager->sprites[SP_CHO_WIN_1].collisionBox.y1 = 15; + + loadWsg("sprite009.wsg", &entityManager->sprites[SP_CRAWLER_TOP].wsg, false); + entityManager->sprites[SP_CRAWLER_TOP].originX = 7; + entityManager->sprites[SP_CRAWLER_TOP].originY = 12; + entityManager->sprites[SP_CRAWLER_TOP].collisionBox.x0 = 0; + entityManager->sprites[SP_CRAWLER_TOP].collisionBox.x1 = 15; + entityManager->sprites[SP_CRAWLER_TOP].collisionBox.y0 = 0; + entityManager->sprites[SP_CRAWLER_TOP].collisionBox.y1 = 15; + + // TODO: don't need to allocate this same sprite 3 more times... + loadWsg("sprite009.wsg", &entityManager->sprites[SP_CRAWLER_RIGHT].wsg, false); + entityManager->sprites[SP_CRAWLER_RIGHT].originX = 4; + entityManager->sprites[SP_CRAWLER_RIGHT].originY = 7; + entityManager->sprites[SP_CRAWLER_RIGHT].collisionBox.x0 = 0; + entityManager->sprites[SP_CRAWLER_RIGHT].collisionBox.x1 = 15; + entityManager->sprites[SP_CRAWLER_RIGHT].collisionBox.y0 = 0; + entityManager->sprites[SP_CRAWLER_RIGHT].collisionBox.y1 = 15; + + loadWsg("sprite009.wsg", &entityManager->sprites[SP_CRAWLER_BOTTOM].wsg, false); + entityManager->sprites[SP_CRAWLER_BOTTOM].originX = 7; + entityManager->sprites[SP_CRAWLER_BOTTOM].originY = 4; + entityManager->sprites[SP_CRAWLER_BOTTOM].collisionBox.x0 = 0; + entityManager->sprites[SP_CRAWLER_BOTTOM].collisionBox.x1 = 15; + entityManager->sprites[SP_CRAWLER_BOTTOM].collisionBox.y0 = 0; + entityManager->sprites[SP_CRAWLER_BOTTOM].collisionBox.y1 = 15; + + loadWsg("sprite009.wsg", &entityManager->sprites[SP_CRAWLER_LEFT].wsg, false); + entityManager->sprites[SP_CRAWLER_LEFT].originX = 12; + entityManager->sprites[SP_CRAWLER_LEFT].originY = 7; + entityManager->sprites[SP_CRAWLER_LEFT].collisionBox.x0 = 0; + entityManager->sprites[SP_CRAWLER_LEFT].collisionBox.x1 = 15; + entityManager->sprites[SP_CRAWLER_LEFT].collisionBox.y0 = 0; + entityManager->sprites[SP_CRAWLER_LEFT].collisionBox.y1 = 15; + + loadWsg("rbmb000.wsg", &entityManager->sprites[SP_RBOMB_0].wsg, false); + entityManager->sprites[SP_RBOMB_0].originX = 4; + entityManager->sprites[SP_RBOMB_0].originY = 4; + entityManager->sprites[SP_RBOMB_0].collisionBox.x0 = 0; + entityManager->sprites[SP_RBOMB_0].collisionBox.x1 = 7; + entityManager->sprites[SP_RBOMB_0].collisionBox.y0 = 0; + entityManager->sprites[SP_RBOMB_0].collisionBox.y1 = 7; + + loadWsg("rbmb001.wsg", &entityManager->sprites[SP_RBOMB_1].wsg, false); + entityManager->sprites[SP_RBOMB_1].originX = 4; + entityManager->sprites[SP_RBOMB_1].originY = 4; + entityManager->sprites[SP_RBOMB_1].collisionBox.x0 = 0; + entityManager->sprites[SP_RBOMB_1].collisionBox.x1 = 7; + entityManager->sprites[SP_RBOMB_1].collisionBox.y0 = 0; + entityManager->sprites[SP_RBOMB_1].collisionBox.y1 = 7; + + loadWsg("rbmb002.wsg", &entityManager->sprites[SP_RBOMB_2].wsg, false); + entityManager->sprites[SP_RBOMB_2].originX = 4; + entityManager->sprites[SP_RBOMB_2].originY = 4; + entityManager->sprites[SP_RBOMB_2].collisionBox.x0 = 0; + entityManager->sprites[SP_RBOMB_2].collisionBox.x1 = 7; + entityManager->sprites[SP_RBOMB_2].collisionBox.y0 = 0; + entityManager->sprites[SP_RBOMB_2].collisionBox.y1 = 7; +} + +void updateEntities(entityManager_t* entityManager) { - for(uint8_t i=0; i < MAX_ENTITIES; i++) + for (uint8_t i = 0; i < MAX_ENTITIES; i++) { - if(entityManager->entities[i].active) + if (entityManager->entities[i].active) { entityManager->entities[i].updateFunction(&(entityManager->entities[i])); - if(&(entityManager->entities[i]) == entityManager->viewEntity){ + if (&(entityManager->entities[i]) == entityManager->viewEntity) + { viewFollowEntity(entityManager->tilemap, &(entityManager->entities[i])); } } } -}; +} -void deactivateAllEntities(entityManager_t * entityManager, bool excludePlayer, bool respawn){ - for(uint8_t i=0; i < MAX_ENTITIES; i++) +void deactivateAllEntities(entityManager_t* entityManager, bool excludePlayer, bool excludePersistent, bool respawn) +{ + for (uint8_t i = 0; i < MAX_ENTITIES; i++) { entity_t* currentEntity = &(entityManager->entities[i]); - if(!currentEntity->active){ + if (!currentEntity->active || (excludePersistent && currentEntity->persistent)) + { continue; } - + destroyEntity(currentEntity, respawn); - - if(excludePlayer && currentEntity == entityManager->playerEntity){ + + if (excludePlayer && currentEntity == entityManager->playerEntity) + { currentEntity->active = true; } } } -void drawEntities(entityManager_t * entityManager) +void drawEntities(entityManager_t* entityManager) { - for(uint8_t i=0; i < MAX_ENTITIES; i++) + for (uint8_t i = 0; i < MAX_ENTITIES; i++) { entity_t currentEntity = entityManager->entities[i]; - if(currentEntity.active && currentEntity.visible) + if (currentEntity.active && currentEntity.visible) { - drawWsg(&(entityManager->sprites[currentEntity.spriteIndex].wsg), (currentEntity.x >> SUBPIXEL_RESOLUTION) - entityManager->sprites[currentEntity.spriteIndex].originX - entityManager->tilemap->mapOffsetX, (currentEntity.y >> SUBPIXEL_RESOLUTION) - entityManager->tilemap->mapOffsetY - entityManager->sprites[currentEntity.spriteIndex].originY, currentEntity.spriteFlipHorizontal, currentEntity.spriteFlipVertical, currentEntity.spriteRotateAngle); + drawWsg(&(entityManager->sprites[currentEntity.spriteIndex].wsg), + (currentEntity.x >> SUBPIXEL_RESOLUTION) - entityManager->sprites[currentEntity.spriteIndex].originX + - entityManager->tilemap->mapOffsetX, + (currentEntity.y >> SUBPIXEL_RESOLUTION) - entityManager->tilemap->mapOffsetY + - entityManager->sprites[currentEntity.spriteIndex].originY, + currentEntity.spriteFlipHorizontal, currentEntity.spriteFlipVertical, + currentEntity.spriteRotateAngle); } } -}; +} -entity_t * findInactiveEntity(entityManager_t * entityManager) +entity_t* findInactiveEntity(entityManager_t* entityManager) { - if(entityManager->activeEntities == MAX_ENTITIES) + if (entityManager->activeEntities == MAX_ENTITIES) { return NULL; }; - + uint8_t entityIndex = 0; - while(entityManager->entities[entityIndex].active){ + while (entityManager->entities[entityIndex].active) + { entityIndex++; - //Extra safeguard to make sure we don't get stuck here - if(entityIndex >= MAX_ENTITIES) + // Extra safeguard to make sure we don't get stuck here + if (entityIndex >= MAX_ENTITIES) { return NULL; } @@ -236,34 +384,38 @@ entity_t * findInactiveEntity(entityManager_t * entityManager) return &(entityManager->entities[entityIndex]); } -void viewFollowEntity(tilemap_t * tilemap, entity_t * entity){ +void viewFollowEntity(tilemap_t* tilemap, entity_t* entity) +{ int16_t moveViewByX = (entity->x) >> SUBPIXEL_RESOLUTION; - int16_t moveViewByY = (entity->y > 63616) ? 0: (entity->y) >> SUBPIXEL_RESOLUTION; + int16_t moveViewByY = (entity->y > 63616) ? 0 : (entity->y) >> SUBPIXEL_RESOLUTION; int16_t centerOfViewX = tilemap->mapOffsetX + 140; int16_t centerOfViewY = tilemap->mapOffsetY + 120; - //if(centerOfViewX != moveViewByX) { - moveViewByX -= centerOfViewX; + // if(centerOfViewX != moveViewByX) { + moveViewByX -= centerOfViewX; //} - //if(centerOfViewY != moveViewByY) { - moveViewByY -= centerOfViewY; + // if(centerOfViewY != moveViewByY) { + moveViewByY -= centerOfViewY; //} - //if(moveViewByX && moveViewByY){ - scrollTileMap(tilemap, moveViewByX, moveViewByY); + // if(moveViewByX && moveViewByY){ + scrollTileMap(tilemap, moveViewByX, moveViewByY); //} } -entity_t* createEntity(entityManager_t *entityManager, uint8_t objectIndex, uint16_t x, uint16_t y){ - if(entityManager->activeEntities == MAX_ENTITIES){ +entity_t* createEntity(entityManager_t* entityManager, uint8_t objectIndex, uint16_t x, uint16_t y) +{ + if (entityManager->activeEntities == MAX_ENTITIES) + { return NULL; } - entity_t *createdEntity; + entity_t* createdEntity; - switch(objectIndex){ + switch (objectIndex) + { case ENTITY_PLAYER_PADDLE_BOTTOM: createdEntity = createPlayer(entityManager, x, y); break; @@ -279,6 +431,9 @@ entity_t* createEntity(entityManager_t *entityManager, uint8_t objectIndex, uint case ENTITY_PLAYER_BALL: createdEntity = createBall(entityManager, x, y); break; + case ENTITY_CAPTIVE_BALL: + createdEntity = createCaptiveBall(entityManager, x, y); + break; case ENTITY_PLAYER_TIME_BOMB: createdEntity = createTimeBomb(entityManager, x, y); break; @@ -288,277 +443,462 @@ entity_t* createEntity(entityManager_t *entityManager, uint8_t objectIndex, uint case ENTITY_PLAYER_REMOTE_BOMB: createdEntity = createRemoteBomb(entityManager, x, y); break; + case ENTITY_BALL_TRAIL: + createdEntity = createBallTrail(entityManager, x, y); + break; + case ENTITY_CHO_INTRO: + createdEntity = createChoIntro(entityManager, x, y); + break; + case ENTITY_CRAWLER: + createdEntity = createCrawler(entityManager, x, y); + break; default: createdEntity = NULL; } - if(createdEntity != NULL) { + if (createdEntity != NULL) + { entityManager->activeEntities++; } return createdEntity; } -entity_t* createPlayer(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createPlayer(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; - entity->xspeed = 0; - entity->yspeed = 0; - entity->jumpPower = 0; + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->hp = 1; - entity->animationTimer = 0; - - entity->type = ENTITY_PLAYER_PADDLE_BOTTOM; - entity->spriteIndex = SP_PADDLE_0; - entity->updateFunction = &updatePlayer; - entity->collisionHandler = &playerCollisionHandler; + entity->spriteRotateAngle = 0; + entity->animationTimer = 0; + + entity->type = ENTITY_PLAYER_PADDLE_BOTTOM; + entity->spriteIndex = SP_PADDLE_0; + entity->updateFunction = &updatePlayer; + entity->collisionHandler = &playerCollisionHandler; entity->tileCollisionHandler = &playerTileCollisionHandler; - entity->overlapTileHandler = &playerOverlapTileHandler; + entity->overlapTileHandler = &playerOverlapTileHandler; return entity; } -entity_t* createPlayerPaddleTop(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createPlayerPaddleTop(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; - entity->xspeed = 0; - entity->yspeed = 0; - entity->jumpPower = 0; + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipVertical = true; - entity->spriteRotateAngle = 0; - entity->hp = 1; - entity->animationTimer = 0; //Used as a cooldown for shooting square wave balls - - entity->type = ENTITY_PLAYER_PADDLE_TOP; - entity->spriteIndex = SP_PADDLE_0; - entity->updateFunction = &updatePlayer; - entity->collisionHandler = &playerCollisionHandler; + entity->spriteRotateAngle = 0; + entity->animationTimer = 0; // Used as a cooldown for shooting square wave balls + + entity->type = ENTITY_PLAYER_PADDLE_TOP; + entity->spriteIndex = SP_PADDLE_0; + entity->updateFunction = &updatePlayer; + entity->collisionHandler = &playerCollisionHandler; entity->tileCollisionHandler = &playerTileCollisionHandler; - entity->overlapTileHandler = &playerOverlapTileHandler; + entity->overlapTileHandler = &playerOverlapTileHandler; return entity; } -entity_t* createPlayerPaddleLeft(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createPlayerPaddleLeft(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; - entity->xspeed = 0; - entity->yspeed = 0; - entity->jumpPower = 0; + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipHorizontal = true; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->hp = 1; - entity->animationTimer = 0; //Used as a cooldown for shooting square wave balls - - entity->type = ENTITY_PLAYER_PADDLE_LEFT; - entity->spriteIndex = SP_PADDLE_VERTICAL_0; - entity->updateFunction = &updatePlayerVertical; - entity->collisionHandler = &playerCollisionHandler; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 0; // Used as a cooldown for shooting square wave balls + + entity->type = ENTITY_PLAYER_PADDLE_LEFT; + entity->spriteIndex = SP_PADDLE_VERTICAL_0; + entity->updateFunction = &updatePlayerVertical; + entity->collisionHandler = &playerCollisionHandler; entity->tileCollisionHandler = &playerTileCollisionHandler; - entity->overlapTileHandler = &playerOverlapTileHandler; + entity->overlapTileHandler = &playerOverlapTileHandler; return entity; } -entity_t* createPlayerPaddleRight(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createPlayerPaddleRight(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; - entity->xspeed = 0; - entity->yspeed = 0; - entity->jumpPower = 0; + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipHorizontal = false; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->hp = 1; - entity->animationTimer = 0; //Used as a cooldown for shooting square wave balls - - entity->type = ENTITY_PLAYER_PADDLE_RIGHT; - entity->spriteIndex = SP_PADDLE_VERTICAL_0; - entity->updateFunction = &updatePlayerVertical; - entity->collisionHandler = &playerCollisionHandler; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 0; // Used as a cooldown for shooting square wave balls + + entity->type = ENTITY_PLAYER_PADDLE_RIGHT; + entity->spriteIndex = SP_PADDLE_VERTICAL_0; + entity->updateFunction = &updatePlayerVertical; + entity->collisionHandler = &playerCollisionHandler; entity->tileCollisionHandler = &playerTileCollisionHandler; - entity->overlapTileHandler = &playerOverlapTileHandler; + entity->overlapTileHandler = &playerOverlapTileHandler; return entity; } -entity_t* createBall(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createBall(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; - - entity->xspeed = 0; - entity->yspeed = 0; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipHorizontal = false; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->scoreValue = 100; - entity->shouldAdvanceMultiplier = false; - - entity->type = ENTITY_PLAYER_BALL; - entity->spriteIndex = SP_BALL_0; - entity->updateFunction = &updateBallAtStart; - entity->collisionHandler = &dummyCollisionHandler; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + + entity->shouldAdvanceMultiplier = false; + entity->baseSpeed = 39; + entity->bouncesToNextSpeedUp = 5; + entity->speedUpLookupIndex = 0; + entity->maxSpeed = 127; + entity->bouncesOffUnbreakableBlocks = 0; + entity->breakInfiniteLoopBounceThreshold = 32; + + entity->type = ENTITY_PLAYER_BALL; + entity->spriteIndex = SP_BALL_0; + entity->updateFunction = &updateBallAtStart; + entity->collisionHandler = &dummyCollisionHandler; entity->tileCollisionHandler = &ballTileCollisionHandler; - entity->overlapTileHandler = &ballOverlapTileHandler; + entity->overlapTileHandler = &ballOverlapTileHandler; + entity->gameData->ballsInPlay++; return entity; } -entity_t* createTimeBomb(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createCaptiveBall(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; - - entity->xspeed = 0; - entity->yspeed = 0; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + entity->spriteFlipHorizontal = false; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->scoreValue = 100; - entity->animationTimer = 48; - - entity->type = ENTITY_PLAYER_TIME_BOMB; - entity->spriteIndex = SP_BOMB_0; - entity->updateFunction = &updateTimeBomb; - entity->collisionHandler = &dummyCollisionHandler; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + + entity->shouldAdvanceMultiplier = false; + entity->baseSpeed = 39; + entity->bouncesToNextSpeedUp = 5; + entity->speedUpLookupIndex = 0; + entity->maxSpeed = 127; + entity->bouncesOffUnbreakableBlocks = 0; + entity->breakInfiniteLoopBounceThreshold = 16; + + setVelocity(entity, (x + y) % 360, 39); + + if (entity->yspeed == 0) + { + entity->yspeed = -16; + } + + entity->type = ENTITY_CAPTIVE_BALL; + entity->spriteIndex = SP_BALL; + entity->updateFunction = &updateCaptiveBallNotInPlay; + entity->collisionHandler = &captiveBallCollisionHandler; + entity->tileCollisionHandler = &captiveBallTileCollisionHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; + + return entity; +} + +entity_t* createTimeBomb(entityManager_t* entityManager, uint16_t x, uint16_t y) +{ + entity_t* entity = findInactiveEntity(entityManager); + + if (entity == NULL) + { + return NULL; + } + + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; + entity->spriteFlipHorizontal = false; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 48; + + entity->type = ENTITY_PLAYER_TIME_BOMB; + entity->spriteIndex = SP_BOMB_0; + entity->updateFunction = &updateTimeBomb; + entity->collisionHandler = &dummyCollisionHandler; entity->tileCollisionHandler = &dummyTileCollisionHandler; - entity->overlapTileHandler = &defaultOverlapTileHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; - //Entity cannot be respawned from the tilemap + // Entity cannot be respawned from the tilemap entity->homeTileX = 0; entity->homeTileY = 0; return entity; } -entity_t* createExplosion(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createExplosion(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; - - entity->xspeed = 0; - entity->yspeed = 0; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipHorizontal = false; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->scoreValue = 100; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; - entity->type = ENTITY_PLAYER_BOMB_EXPLOSION; - entity->spriteIndex = SP_EXPLOSION_0; - entity->updateFunction = &updateExplosion; - entity->collisionHandler = &dummyCollisionHandler; + entity->type = ENTITY_PLAYER_BOMB_EXPLOSION; + entity->spriteIndex = SP_EXPLOSION_0; + entity->updateFunction = &updateExplosion; + entity->collisionHandler = &dummyCollisionHandler; entity->tileCollisionHandler = &dummyTileCollisionHandler; - entity->overlapTileHandler = &defaultOverlapTileHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; - //Entity cannot be respawned from the tilemap + // Entity cannot be respawned from the tilemap entity->homeTileX = 0; entity->homeTileY = 0; return entity; } -entity_t* createRemoteBomb(entityManager_t * entityManager, uint16_t x, uint16_t y) +entity_t* createRemoteBomb(entityManager_t* entityManager, uint16_t x, uint16_t y) { - entity_t * entity = findInactiveEntity(entityManager); + entity_t* entity = findInactiveEntity(entityManager); - if(entity == NULL) { + if (entity == NULL) + { return NULL; } - entity->active = true; - entity->visible = true; - entity->x = x << SUBPIXEL_RESOLUTION; - entity->y = y << SUBPIXEL_RESOLUTION; - - entity->xspeed = 0; - entity->yspeed = 0; + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; entity->spriteFlipHorizontal = false; - entity->spriteFlipVertical = false; - entity->spriteRotateAngle = 0; - entity->scoreValue = 100; - entity->animationTimer = 48; - - entity->type = ENTITY_PLAYER_REMOTE_BOMB; - entity->spriteIndex = SP_BOMB_0; - entity->updateFunction = &updateRemoteBomb; - entity->collisionHandler = &dummyCollisionHandler; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 48; + + entity->type = ENTITY_PLAYER_REMOTE_BOMB; + entity->spriteIndex = SP_RBOMB_0; + entity->updateFunction = &updateRemoteBomb; + entity->collisionHandler = &dummyCollisionHandler; entity->tileCollisionHandler = &dummyTileCollisionHandler; - entity->overlapTileHandler = &defaultOverlapTileHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; - //Entity cannot be respawned from the tilemap + // Entity cannot be respawned from the tilemap entity->homeTileX = 0; entity->homeTileY = 0; return entity; } -void freeEntityManager(entityManager_t * self){ +entity_t* createBallTrail(entityManager_t* entityManager, uint16_t x, uint16_t y) +{ + entity_t* entity = findInactiveEntity(entityManager); + + if (entity == NULL) + { + return NULL; + } + + entity->active = true; + entity->visible = false; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; + entity->spriteFlipHorizontal = false; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 4; + + entity->type = ENTITY_BALL_TRAIL; + entity->spriteIndex = SP_BALL_TRAIL_0; + entity->updateFunction = &updateBallTrail; + entity->collisionHandler = &dummyCollisionHandler; + entity->tileCollisionHandler = &dummyTileCollisionHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; + + // Entity cannot be respawned from the tilemap + entity->homeTileX = 0; + entity->homeTileY = 0; + + return entity; +} + +entity_t* createChoIntro(entityManager_t* entityManager, uint16_t x, uint16_t y) +{ + entity_t* entity = findInactiveEntity(entityManager); + + if (entity == NULL) + { + return NULL; + } + + entity->active = true; + entity->visible = true; + entity->persistent = false; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->xspeed = 0; + entity->yspeed = 0; + entity->spriteFlipHorizontal = false; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + entity->animationTimer = 0; + + entity->type = ENTITY_CHO_INTRO; + entity->spriteIndex = SP_CHO_WALK_0; + entity->updateFunction = &updateChoIntro; + entity->collisionHandler = &dummyCollisionHandler; + entity->tileCollisionHandler = &dummyTileCollisionHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; + + // Entity cannot be respawned from the tilemap + entity->homeTileX = 0; + entity->homeTileY = 0; + + return entity; +} + +entity_t* createCrawler(entityManager_t* entityManager, uint16_t x, uint16_t y) +{ + entity_t* entity = findInactiveEntity(entityManager); + + if (entity == NULL) + { + return NULL; + } + + entity->active = true; + entity->visible = true; + entity->persistent = true; + entity->x = x << SUBPIXEL_RESOLUTION; + entity->y = y << SUBPIXEL_RESOLUTION; + + entity->baseSpeed = 8; + entity->maxSpeed = 8; + entity->xspeed = 0; + entity->yspeed = 0; + entity->spriteFlipHorizontal = false; + entity->spriteFlipVertical = false; + entity->spriteRotateAngle = 0; + + entity->type = ENTITY_CRAWLER; + entity->spriteIndex = SP_CRAWLER_TOP; + entity->updateFunction = &updateCrawler; + entity->collisionHandler = &crawlerCollisionHandler; + entity->tileCollisionHandler = &dummyTileCollisionHandler; + entity->overlapTileHandler = &defaultOverlapTileHandler; + + // Entity cannot be respawned from the tilemap + entity->homeTileX = 0; + entity->homeTileY = 0; + + crawlerInitMoveState(entity); + + // This will be reused to track defeat condition + entity->bouncesOffUnbreakableBlocks = 0; + + // This will be reused as a cooldown for collisions with other crawlers. + entity->breakInfiniteLoopBounceThreshold = 0; + + return entity; +} + +void freeEntityManager(entityManager_t* self) +{ free(self->entities); - for(uint8_t i=0; isprites[i].wsg)); } } diff --git a/main/modes/breakout/entityManager.h b/main/modes/breakout/entityManager.h index e92bc1360..b76834f28 100644 --- a/main/modes/breakout/entityManager.h +++ b/main/modes/breakout/entityManager.h @@ -18,8 +18,8 @@ //============================================================================== // Constants //============================================================================== -#define MAX_ENTITIES 32 -#define SPRITESET_SIZE 16 +#define MAX_ENTITIES 32 +#define SPRITESET_SIZE 33 //============================================================================== // Structs @@ -28,37 +28,43 @@ struct entityManager_t { sprite_t sprites[SPRITESET_SIZE]; - entity_t * entities; + entity_t* entities; uint8_t activeEntities; - entity_t * viewEntity; - entity_t * playerEntity; + entity_t* viewEntity; + entity_t* playerEntity; - tilemap_t * tilemap; + tilemap_t* tilemap; }; //============================================================================== // Prototypes //============================================================================== -void initializeEntityManager(entityManager_t * entityManager, tilemap_t * tilemap, gameData_t * gameData, soundManager_t * soundManager); -void loadSprites(entityManager_t * entityManager); -void updateEntities(entityManager_t * entityManager); -void deactivateAllEntities(entityManager_t * entityManager, bool excludePlayer, bool respawn); -void drawEntities(entityManager_t * entityManager); -entity_t * findInactiveEntity(entityManager_t * entityManager); +void initializeEntityManager(entityManager_t* entityManager, tilemap_t* tilemap, gameData_t* gameData, + soundManager_t* soundManager); +void loadSprites(entityManager_t* entityManager); +void updateEntities(entityManager_t* entityManager); +void deactivateAllEntities(entityManager_t* entityManager, bool excludePlayer, bool excludePersistent, bool respawn); +void drawEntities(entityManager_t* entityManager); +entity_t* findInactiveEntity(entityManager_t* entityManager); -void viewFollowEntity(tilemap_t * tilemap, entity_t * entity); -entity_t* createEntity(entityManager_t *entityManager, uint8_t objectIndex, uint16_t x, uint16_t y); -entity_t* createPlayer(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createPlayerPaddleTop(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createPlayerPaddleLeft(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createPlayerPaddleRight(entityManager_t * entityManager, uint16_t x, uint16_t y); +void viewFollowEntity(tilemap_t* tilemap, entity_t* entity); +entity_t* createEntity(entityManager_t* entityManager, uint8_t objectIndex, uint16_t x, uint16_t y); +entity_t* createPlayer(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createPlayerPaddleTop(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createPlayerPaddleLeft(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createPlayerPaddleRight(entityManager_t* entityManager, uint16_t x, uint16_t y); -entity_t* createBall(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createTimeBomb(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createExplosion(entityManager_t * entityManager, uint16_t x, uint16_t y); -entity_t* createRemoteBomb(entityManager_t * entityManager, uint16_t x, uint16_t y); +entity_t* createBall(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createCaptiveBall(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createTimeBomb(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createExplosion(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createRemoteBomb(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createBallTrail(entityManager_t* entityManager, uint16_t x, uint16_t y); -void freeEntityManager(entityManager_t * entityManager); +entity_t* createChoIntro(entityManager_t* entityManager, uint16_t x, uint16_t y); +entity_t* createCrawler(entityManager_t* entityManager, uint16_t x, uint16_t y); + +void freeEntityManager(entityManager_t* entityManager); #endif diff --git a/main/modes/breakout/gameData.c b/main/modes/breakout/gameData.c index 9db558599..e9175afab 100644 --- a/main/modes/breakout/gameData.c +++ b/main/modes/breakout/gameData.c @@ -5,7 +5,7 @@ #include #include "gameData.h" #include "entityManager.h" -//#include "platformer_sounds.h" +// #include "platformer_sounds.h" #include "esp_random.h" #include "hdw-btn.h" #include "touchUtils.h" @@ -13,82 +13,94 @@ //============================================================================== // Functions //============================================================================== - void initializeGameData(gameData_t * gameData){ - gameData->gameState = 0; - gameData->btnState = 0; - gameData->score = 0; - gameData->lives = 3; - gameData->countdown = 000; - - gameData->level = 1; +void initializeGameData(gameData_t* gameData, soundManager_t* soundManager) +{ + gameData->gameState = 0; + gameData->btnState = 0; + gameData->score = 0; + gameData->lives = 3; + gameData->ballsInPlay = 0; + gameData->countdown = 000; + + gameData->extraLifeScore = 8000; + + gameData->level = 1; gameData->frameCount = 0; gameData->combo = 0; - //gameData->comboTimer = 0; - gameData->bgColor = c335; + // gameData->comboTimer = 0; + gameData->bgColor = c335; gameData->initials[0] = 'A'; gameData->initials[1] = 'A'; gameData->initials[2] = 'A'; - gameData->rank = 5; + gameData->rank = 5; /*gameData->extraLifeCollected = false; gameData->checkpoint = 0; gameData->levelDeaths = 0; gameData->initialHp = 1;*/ - gameData->debugMode = false; + gameData->debugMode = false; gameData->continuesUsed = false; - gameData->inGameTimer = 0; + gameData->inGameTimer = 0; gameData->playerBombs[0] = NULL; gameData->playerBombs[1] = NULL; gameData->playerBombs[2] = NULL; - gameData->playerTimeBombsCount = 0; - gameData->playerRemoteBombPlaced = false; + gameData->playerTimeBombsCount = 0; + gameData->playerRemoteBombPlaced = false; /*gameData->nextBombToDetonate = 0; gameData->nextBombSlot = 0; gameData->bombDetonateCooldown = 0;*/ + gameData->soundManager = soundManager; } - void initializeGameDataFromTitleScreen(gameData_t * gameData){ - gameData->gameState = 0; - gameData->btnState = 0; - gameData->score = 0; - gameData->lives = 3; - gameData->countdown = 000; - gameData->frameCount = 0; +void initializeGameDataFromTitleScreen(gameData_t* gameData) +{ + gameData->gameState = 0; + gameData->btnState = 0; + gameData->score = 0; + gameData->lives = 3; + gameData->ballsInPlay = 0; + gameData->countdown = 000; + gameData->frameCount = 0; + + gameData->extraLifeScore = 8000; gameData->combo = 0; - //gameData->comboTimer = 0; - gameData->bgColor = c000; - gameData->currentBgm = 0; - gameData->changeBgm = 0; - gameData->continuesUsed = (gameData->level == 1) ? false : true; - gameData->inGameTimer = 0; + // gameData->comboTimer = 0; + gameData->bgColor = c000; + gameData->currentBgm = 0; + gameData->changeBgm = 0; + gameData->continuesUsed = (gameData->level == 1) ? false : true; + gameData->inGameTimer = 0; gameData->targetBlocksBroken = 0; resetGameDataLeds(gameData); - gameData->playerTimeBombsCount = 0; + gameData->playerTimeBombsCount = 0; gameData->playerRemoteBombPlaced = false; - //gameData->nextBombToDetonate = 0; - //gameData->nextBombSlot = 0; - //gameData->bombDetonateCooldown = 0; + // gameData->nextBombToDetonate = 0; + // gameData->nextBombSlot = 0; + // gameData->bombDetonateCooldown = 0; } -void updateLedsHpMeter(entityManager_t *entityManager, gameData_t *gameData){ - if(entityManager->playerEntity == NULL){ +void updateLedsHpMeter(entityManager_t* entityManager, gameData_t* gameData) +{ + if (entityManager->playerEntity == NULL) + { return; } - uint8_t hp = entityManager->playerEntity->hp; - if(hp > 3){ + uint8_t hp = 0; // entityManager->playerEntity->hp; + if (hp > 3) + { hp = 3; } - //HP meter led pairs: - //3 4 - //2 5 - //1 6 + // HP meter led pairs: + // 3 4 + // 2 5 + // 1 6 for (int32_t i = 1; i < 7; i++) { gameData->leds[i].r = 0x80; @@ -96,35 +108,45 @@ void updateLedsHpMeter(entityManager_t *entityManager, gameData_t *gameData){ gameData->leds[i].b = 0x00; } - for (int32_t i = 1; i < 1+hp; i++) + for (int32_t i = 1; i < 1 + hp; i++) { gameData->leds[i].r = 0x00; gameData->leds[i].g = 0x80; - gameData->leds[7-i].r = 0x00; - gameData->leds[7-i].g = 0x80; + gameData->leds[7 - i].r = 0x00; + gameData->leds[7 - i].g = 0x80; } setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void scorePoints(gameData_t * gameData, uint16_t points, int16_t incCombo){ +void scorePoints(gameData_t* gameData, uint16_t points, int16_t incCombo) +{ gameData->combo += incCombo; - if(gameData->combo < 1){ + if (gameData->combo < 1) + { gameData->combo = 1; } - + uint32_t comboPoints = points * gameData->combo; gameData->score += comboPoints; gameData->comboScore = comboPoints; - - //gameData->comboTimer = (gameData->levelDeaths < 3) ? 240: 1; + + if (gameData->score >= gameData->extraLifeScore) + { + gameData->lives++; + gameData->extraLifeScore += (gameData->extraLifeScore + 1000); + bzrPlaySfx(&(gameData->soundManager->snd1up), BZR_STEREO); + } + + // gameData->comboTimer = (gameData->levelDeaths < 3) ? 240: 1; } -void resetGameDataLeds(gameData_t * gameData) +void resetGameDataLeds(gameData_t* gameData) { - for(uint8_t i=0;ileds[i].r = 0; gameData->leds[i].g = 0; gameData->leds[i].b = 0; @@ -133,41 +155,46 @@ void resetGameDataLeds(gameData_t * gameData) setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateLedsShowHighScores(gameData_t * gameData){ - if(( (gameData->frameCount) % 10) == 0){ +void updateLedsShowHighScores(gameData_t* gameData) +{ + if (((gameData->frameCount) % 10) == 0) + { for (int32_t i = 0; i < 8; i++) { - - if(( (gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) { - gameData->leds[i].r = 0xF0; + if (((gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) + { + gameData->leds[i].r = 0xF0; gameData->leds[i].g = 0xF0; - gameData->leds[i].b = 0x00; } - if(gameData->leds[i].r > 0){ + if (gameData->leds[i].r > 0) + { gameData->leds[i].r -= 0x05; } - - if(gameData->leds[i].g > 0){ + + if (gameData->leds[i].g > 0) + { gameData->leds[i].g -= 0x10; } - if(gameData->leds[i].b > 0){ - gameData->leds[i].b = 0x00; + if (gameData->leds[i].b > 0) + { + gameData->leds[i].b = gameData->leds[i].b >> 1; } - } } setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateLedsGameOver(gameData_t * gameData){ - if(( (gameData->frameCount) % 10) == 0){ +void updateLedsGameOver(gameData_t* gameData) +{ + if (((gameData->frameCount) % 10) == 0) + { for (int32_t i = 0; i < 8; i++) { - - if(( (gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) { - gameData->leds[i].r = 0xF0; + if (((gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) + { + gameData->leds[i].r = 0xF0; gameData->leds[i].g = 0x00; gameData->leds[i].b = 0x00; } @@ -180,25 +207,30 @@ void updateLedsGameOver(gameData_t * gameData){ setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateLedsLevelClear(gameData_t * gameData){ - if(( (gameData->frameCount) % 10) == 0){ +void updateLedsLevelClear(gameData_t* gameData) +{ + if (((gameData->frameCount) % 10) == 0) + { for (int32_t i = 0; i < 8; i++) { - - if(( (gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) { + if (((gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) + { gameData->leds[i].g = (esp_random() % 24) * (10); gameData->leds[i].b = (esp_random() % 24) * (10); } - if(gameData->leds[i].r > 0){ + if (gameData->leds[i].r > 0) + { gameData->leds[i].r -= 0x10; } - - if(gameData->leds[i].g > 0){ + + if (gameData->leds[i].g > 0) + { gameData->leds[i].g -= 0x10; } - if(gameData->leds[i].b > 0){ + if (gameData->leds[i].b > 0) + { gameData->leds[i].b -= 0x10; } } @@ -206,26 +238,31 @@ void updateLedsLevelClear(gameData_t * gameData){ setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateLedsGameClear(gameData_t * gameData){ - if(( (gameData->frameCount) % 10) == 0){ +void updateLedsGameClear(gameData_t* gameData) +{ + if (((gameData->frameCount) % 10) == 0) + { for (int32_t i = 0; i < 8; i++) { - - if(( (gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) { + if (((gameData->frameCount >> 4) % CONFIG_NUM_LEDS) == i) + { gameData->leds[i].r = (esp_random() % 24) * (10); gameData->leds[i].g = (esp_random() % 24) * (10); gameData->leds[i].b = (esp_random() % 24) * (10); } - if(gameData->leds[i].r > 0){ + if (gameData->leds[i].r > 0) + { gameData->leds[i].r -= 0x10; } - - if(gameData->leds[i].g > 0){ + + if (gameData->leds[i].g > 0) + { gameData->leds[i].g -= 0x10; } - if(gameData->leds[i].b > 0){ + if (gameData->leds[i].b > 0) + { gameData->leds[i].b -= 0x10; } } @@ -233,38 +270,72 @@ void updateLedsGameClear(gameData_t * gameData){ setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateLedsInGame(gameData_t * gameData){ - +void updateLedsInGame(gameData_t* gameData) +{ for (int32_t i = 0; i < 8; i++) { - if(gameData->leds[i].r > 4){ + if (gameData->leds[i].r > 4) + { gameData->leds[i].r -= 0x02; - } else if(gameData->leds[i].r <= 4){ + } + else if (gameData->leds[i].r <= 4) + { gameData->leds[i].r = 0x00; } - - if(gameData->leds[i].g > 4){ + + if (gameData->leds[i].g > 4) + { gameData->leds[i].g -= 0x02; - } else if(gameData->leds[i].g <= 4){ + } + else if (gameData->leds[i].g <= 4) + { gameData->leds[i].g = 0x00; } - if(gameData->leds[i].b > 4){ + if (gameData->leds[i].b > 4) + { gameData->leds[i].b -= 0x02; - } else if(gameData->leds[i].b <= 4){ + } + else if (gameData->leds[i].b <= 4) + { gameData->leds[i].b = 0x00; } - } setLeds(gameData->leds, CONFIG_NUM_LEDS); } -void updateTouchInput(gameData_t * gameData){ - if(getTouchJoystick(&(gameData->touchPhi), &(gameData->touchRadius), &(gameData->touchIntensity))){ +void updateTouchInput(gameData_t* gameData) +{ + if (getTouchJoystick(&(gameData->touchPhi), &(gameData->touchRadius), &(gameData->touchIntensity))) + { gameData->isTouched = true; getTouchCartesian(gameData->touchPhi, gameData->touchRadius, &(gameData->touchX), &(gameData->touchY)); - } else { + } + else + { gameData->isTouched = false; } +} + +void updateLedsTitleScreen(gameData_t* gameData) +{ + if (!((gameData->frameCount) % 10) /*|| gameData->frameCount < 20*/) + { + for (int32_t i = 0; i < CONFIG_NUM_LEDS; i++) + { + gameData->leds[i].r += (esp_random() % 6); + + /*if(gameData->frameCount < 4){ + gameData->leds[i].g = gameData->leds[i].g >> 1; + } else*/ + { + gameData->leds[i].g += (esp_random() % 1); + } + + gameData->leds[i].b += (esp_random() % 8); + } + } + + setLeds(gameData->leds, CONFIG_NUM_LEDS); } \ No newline at end of file diff --git a/main/modes/breakout/gameData.h b/main/modes/breakout/gameData.h index 5605d07bd..0bc778128 100644 --- a/main/modes/breakout/gameData.h +++ b/main/modes/breakout/gameData.h @@ -10,6 +10,7 @@ #include "hdw-led.h" #include "breakout_typedef.h" #include "palette.h" +#include "soundManager.h" //============================================================================== // Constants @@ -19,7 +20,7 @@ // Structs //============================================================================== -typedef struct +typedef struct { int16_t btnState; int16_t prevBtnState; @@ -28,24 +29,27 @@ typedef struct uint32_t score; uint8_t lives; + int8_t ballsInPlay; + + uint32_t extraLifeScore; int16_t countdown; uint16_t frameCount; uint16_t targetBlocksBroken; - + uint8_t level; int16_t combo; - //int16_t comboTimer; + // int16_t comboTimer; uint32_t comboScore; entity_t* playerBombs[3]; uint8_t playerTimeBombsCount; bool playerRemoteBombPlaced; - //uint8_t nextBombToDetonate; - //uint8_t nextBombSlot; - //uint8_t bombDetonateCooldown; + // uint8_t nextBombToDetonate; + // uint8_t nextBombSlot; + // uint8_t bombDetonateCooldown; int32_t touchPhi; int32_t touchRadius; @@ -54,12 +58,13 @@ typedef struct int32_t touchX; int32_t touchY; - led_t leds[8 /*CONFIG_NUM_LEDS*/]; + led_t leds[CONFIG_NUM_LEDS]; paletteColor_t bgColor; char initials[3]; uint8_t rank; + bool debugMode; uint8_t changeBgm; @@ -67,21 +72,24 @@ typedef struct bool continuesUsed; uint32_t inGameTimer; + + soundManager_t* soundManager; } gameData_t; //============================================================================== // Functions //============================================================================== -void initializeGameData(gameData_t * gameData); -void initializeGameDataFromTitleScreen(gameData_t * gameData); -void updateLedsHpMeter(entityManager_t *entityManager, gameData_t *gameData); -void scorePoints(gameData_t * gameData, uint16_t points, int16_t incCombo); -void resetGameDataLeds(gameData_t * gameData); -void updateLedsShowHighScores(gameData_t * gameData); -void updateLedsLevelClear(gameData_t * gameData); -void updateLedsGameClear(gameData_t * gameData); -void updateLedsGameOver(gameData_t * gameData); -void updateLedsInGame(gameData_t * gameData); -void updateTouchInput(gameData_t * gameData); +void initializeGameData(gameData_t* gameData, soundManager_t* soundManager); +void initializeGameDataFromTitleScreen(gameData_t* gameData); +void updateLedsHpMeter(entityManager_t* entityManager, gameData_t* gameData); +void scorePoints(gameData_t* gameData, uint16_t points, int16_t incCombo); +void resetGameDataLeds(gameData_t* gameData); +void updateLedsShowHighScores(gameData_t* gameData); +void updateLedsLevelClear(gameData_t* gameData); +void updateLedsGameClear(gameData_t* gameData); +void updateLedsGameOver(gameData_t* gameData); +void updateLedsInGame(gameData_t* gameData); +void updateTouchInput(gameData_t* gameData); +void updateLedsTitleScreen(gameData_t* gameData); #endif \ No newline at end of file diff --git a/main/modes/breakout/leveldef.h b/main/modes/breakout/leveldef.h index 4dc68301d..b9424e2e5 100644 --- a/main/modes/breakout/leveldef.h +++ b/main/modes/breakout/leveldef.h @@ -9,10 +9,10 @@ //============================================================================== // Structs //============================================================================== -typedef struct { +typedef struct +{ char filename[16]; uint16_t timeLimit; } leveldef_t; - #endif diff --git a/main/modes/breakout/soundManager.c b/main/modes/breakout/soundManager.c index a2563a74d..d4617498b 100644 --- a/main/modes/breakout/soundManager.c +++ b/main/modes/breakout/soundManager.c @@ -8,7 +8,8 @@ //============================================================================== // Functions //============================================================================== -void initializeSoundManager(soundManager_t *self){ +void initializeSoundManager(soundManager_t* self) +{ loadSong("sndBreak2.sng", &self->hit1, false); loadSong("sndBreak3.sng", &self->hit2, false); loadSong("sndBounce.sng", &self->hit3, false); @@ -17,9 +18,11 @@ void initializeSoundManager(soundManager_t *self){ loadSong("sndTally.sng", &self->tally, false); loadSong("sndDropBomb.sng", &self->dropBomb, false); loadSong("sndDetonate.sng", &self->detonate, false); + loadSong("sndBrk1up.sng", &self->snd1up, false); } -void freeSoundManager(soundManager_t *self){ +void freeSoundManager(soundManager_t* self) +{ freeSong(&self->hit1); freeSong(&self->hit2); freeSong(&self->hit3); @@ -28,4 +31,5 @@ void freeSoundManager(soundManager_t *self){ freeSong(&self->tally); freeSong(&self->dropBomb); freeSong(&self->detonate); + freeSong(&self->snd1up); } \ No newline at end of file diff --git a/main/modes/breakout/soundManager.h b/main/modes/breakout/soundManager.h index db19dc943..eeadeaef0 100644 --- a/main/modes/breakout/soundManager.h +++ b/main/modes/breakout/soundManager.h @@ -17,7 +17,7 @@ // Structs //============================================================================== -typedef struct +typedef struct { song_t hit1; song_t hit2; @@ -27,13 +27,14 @@ typedef struct song_t tally; song_t dropBomb; song_t detonate; + song_t snd1up; } soundManager_t; //============================================================================== // Functions //============================================================================== -void initializeSoundManager(soundManager_t *self); -void freeSoundManager(soundManager_t *self); +void initializeSoundManager(soundManager_t* self); +void freeSoundManager(soundManager_t* self); #endif \ No newline at end of file diff --git a/main/modes/breakout/sprite.h b/main/modes/breakout/sprite.h index a0295a419..e29efa059 100644 --- a/main/modes/breakout/sprite.h +++ b/main/modes/breakout/sprite.h @@ -11,12 +11,12 @@ //============================================================================== // Structs //============================================================================== -typedef struct { +typedef struct +{ wsg_t wsg; int16_t originX; int16_t originY; box_t collisionBox; } sprite_t; - #endif diff --git a/main/modes/breakout/starfield.c b/main/modes/breakout/starfield.c index e4b232ee6..f572d2b13 100644 --- a/main/modes/breakout/starfield.c +++ b/main/modes/breakout/starfield.c @@ -10,21 +10,24 @@ //============================================================================== // Functions //============================================================================== -void initializeStarfield(starfield_t *self, bool randomColors){ - for(uint16_t i=0; istars[i].x = randomInt(-TFT_WIDTH / 2, TFT_WIDTH / 2); - self->stars[i].y = randomInt(-TFT_HEIGHT / 2, TFT_HEIGHT / 2); - self->stars[i].z = 1 + esp_random() % 1023; - self->randomColors = randomColors; +void initializeStarfield(starfield_t* self, bool randomColors) +{ + for (uint16_t i = 0; i < NUM_STARS; i++) + { + self->stars[i].x = randomInt(-TFT_WIDTH / 2, TFT_WIDTH / 2); + self->stars[i].y = randomInt(-TFT_HEIGHT / 2, TFT_HEIGHT / 2); + self->stars[i].z = 1 + esp_random() % 1023; + self->randomColors = randomColors; self->stars[i].color = esp_random() % cTransparent; } } -void updateStarfield(starfield_t *self, int32_t scale){ - for(uint16_t i = 0; i < NUM_STARS; i++) - { +void updateStarfield(starfield_t* self, int32_t scale) +{ + for (uint16_t i = 0; i < NUM_STARS; i++) + { self->stars[i].z -= scale; - if(self->stars[i].z <= 0) + if (self->stars[i].z <= 0) { self->stars[i].x = randomInt(-TFT_WIDTH / 2, TFT_WIDTH / 2); self->stars[i].y = randomInt(-TFT_HEIGHT / 2, TFT_HEIGHT / 2); @@ -39,11 +42,12 @@ int randomInt(int lowerBound, int upperBound) return esp_random() % (upperBound - lowerBound + 1) + lowerBound; } -void drawStarfield(starfield_t *self){ - //clearDisplay(); +void drawStarfield(starfield_t* self) +{ + // clearDisplay(); /* rendering */ - for(uint16_t i = 0; i < NUM_STARS; i++) + for (uint16_t i = 0; i < NUM_STARS; i++) { /* Move and size the star */ int temp[2]; @@ -51,13 +55,13 @@ void drawStarfield(starfield_t *self){ temp[0] = ((1024 * self->stars[i].x) / self->stars[i].z) + TFT_WIDTH / 2; temp[1] = ((1024 * self->stars[i].y) / self->stars[i].z) + TFT_HEIGHT / 2; - //translate(&temp, TFT_WIDTH / 2, TFT_HEIGHT / 2); + // translate(&temp, TFT_WIDTH / 2, TFT_HEIGHT / 2); /* Draw the star */ paletteColor_t col = self->stars[i].color; - if( self->stars[i].z < 205) + if (self->stars[i].z < 205) { - if(!self->randomColors) + if (!self->randomColors) { col = c555; } @@ -68,7 +72,7 @@ void drawStarfield(starfield_t *self){ } else if (self->stars[i].z < 410) { - if(!self->randomColors) + if (!self->randomColors) { col = c444; } @@ -78,7 +82,7 @@ void drawStarfield(starfield_t *self){ } else if (self->stars[i].z < 614) { - if(!self->randomColors) + if (!self->randomColors) { col = c333; } @@ -87,7 +91,7 @@ void drawStarfield(starfield_t *self){ } else if (self->stars[i].z < 819) { - if(!self->randomColors) + if (!self->randomColors) { col = c222; } @@ -95,7 +99,7 @@ void drawStarfield(starfield_t *self){ } else { - if(!self->randomColors) + if (!self->randomColors) { col = c222; } diff --git a/main/modes/breakout/starfield.h b/main/modes/breakout/starfield.h index 2e7332e4e..ad9972a2c 100644 --- a/main/modes/breakout/starfield.h +++ b/main/modes/breakout/starfield.h @@ -16,7 +16,8 @@ //============================================================================== // Structs //============================================================================== -typedef struct { +typedef struct +{ int16_t x; int16_t y; int16_t z; @@ -24,7 +25,7 @@ typedef struct { paletteColor_t color; } star_t; -typedef struct +typedef struct { star_t stars[NUM_STARS]; bool randomColors; @@ -33,9 +34,9 @@ typedef struct //============================================================================== // Function Prototypes //============================================================================== -void initializeStarfield(starfield_t *self, bool randomColors); -void updateStarfield(starfield_t *self, int32_t scale); +void initializeStarfield(starfield_t* self, bool randomColors); +void updateStarfield(starfield_t* self, int32_t scale); int randomInt(int lowerBound, int upperBound); -void drawStarfield(starfield_t *self); +void drawStarfield(starfield_t* self); #endif diff --git a/main/modes/breakout/tilemap.c b/main/modes/breakout/tilemap.c index 176cb9144..20071bfab 100644 --- a/main/modes/breakout/tilemap.c +++ b/main/modes/breakout/tilemap.c @@ -24,14 +24,14 @@ // Functions //============================================================================== -void initializeTileMap(tilemap_t *tilemap) +void initializeTileMap(tilemap_t* tilemap) { tilemap->mapOffsetX = 0; tilemap->mapOffsetY = 0; - tilemap->tileSpawnEnabled = true; + tilemap->tileSpawnEnabled = true; tilemap->executeTileSpawnColumn = -1; - tilemap->executeTileSpawnRow = -1; + tilemap->executeTileSpawnRow = -1; tilemap->animationFrame = 0; tilemap->animationTimer = 23; @@ -39,7 +39,7 @@ void initializeTileMap(tilemap_t *tilemap) loadTiles(tilemap); } -void drawTileMap(tilemap_t *tilemap) +void drawTileMap(tilemap_t* tilemap) { tilemap->animationTimer--; if (tilemap->animationTimer < 0) @@ -48,27 +48,30 @@ void drawTileMap(tilemap_t *tilemap) tilemap->animationTimer = 23; } - for (uint16_t y = (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2); y < (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_HEIGHT_TILES; y++) + for (uint16_t y = (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2); + y < (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_HEIGHT_TILES; y++) { if (y >= tilemap->mapHeight) { break; } - for (int32_t x = (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2); x < (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_WIDTH_TILES; x++) + for (int32_t x = (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2); + x < (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_WIDTH_TILES; x++) { if (x >= tilemap->mapWidth) { break; - } + } else if (x < 0) { continue; } uint8_t tile = tilemap->map[(y * tilemap->mapWidth) + x]; - - if(tile < TILE_BOUNDARY_1){ + + if (tile < TILE_BOUNDARY_1 || tile == TILE_INVISIBLE_BLOCK) + { continue; } @@ -81,15 +84,22 @@ void drawTileMap(tilemap_t *tilemap) // Draw only non-garbage tiles if (tile > 0 && tile < 128) { - if(needsTransparency(tile)){ - //drawWsgSimpleFast(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, y * TILE_SIZE - tilemap->mapOffsetY); - drawWsgSimple(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, y * TILE_SIZE - tilemap->mapOffsetY); + if (needsTransparency(tile)) + { + // drawWsgSimpleFast(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, y * TILE_SIZE - + // tilemap->mapOffsetY); + drawWsgSimple(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, + y * TILE_SIZE - tilemap->mapOffsetY); } - else { - drawWsgTile(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, y * TILE_SIZE - tilemap->mapOffsetY); + else + { + drawWsgTile(&tilemap->tiles[tile - 1], x * TILE_SIZE - tilemap->mapOffsetX, + y * TILE_SIZE - tilemap->mapOffsetY); } } - else if (tile > 127 && tilemap->tileSpawnEnabled && (tilemap->executeTileSpawnColumn == x || tilemap->executeTileSpawnRow == y || tilemap->executeTileSpawnAll)) + else if (tile > 127 && tilemap->tileSpawnEnabled + && (tilemap->executeTileSpawnColumn == x || tilemap->executeTileSpawnRow == y + || tilemap->executeTileSpawnAll)) { tileSpawnEntity(tilemap, tile - 128, x, y); } @@ -99,13 +109,13 @@ void drawTileMap(tilemap_t *tilemap) tilemap->executeTileSpawnAll = 0; } -void scrollTileMap(tilemap_t *tilemap, int16_t x, int16_t y) +void scrollTileMap(tilemap_t* tilemap, int16_t x, int16_t y) { if (x != 0) { - uint8_t oldTx = tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2; + uint8_t oldTx = tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2; tilemap->mapOffsetX = CLAMP(tilemap->mapOffsetX + x, tilemap->minMapOffsetX, tilemap->maxMapOffsetX); - uint8_t newTx = tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2; + uint8_t newTx = tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2; if (newTx > oldTx) { @@ -123,9 +133,9 @@ void scrollTileMap(tilemap_t *tilemap, int16_t x, int16_t y) if (y != 0) { - uint8_t oldTy = tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2; + uint8_t oldTy = tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2; tilemap->mapOffsetY = CLAMP(tilemap->mapOffsetY + y, tilemap->minMapOffsetY, tilemap->maxMapOffsetY); - uint8_t newTy = tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2; + uint8_t newTy = tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2; if (newTy > oldTy) { @@ -142,29 +152,29 @@ void scrollTileMap(tilemap_t *tilemap, int16_t x, int16_t y) } } -bool loadMapFromFile(tilemap_t *tilemap, const char *name) +bool loadMapFromFile(tilemap_t* tilemap, const char* name) { if (tilemap->map != NULL) { free(tilemap->map); } - + size_t sz; - uint8_t *buf = spiffsReadFile(name, &sz, false); - + uint8_t* buf = spiffsReadFile(name, &sz, false); + if (NULL == buf) { ESP_LOGE("MAP", "Failed to read %s", name); return false; } - uint8_t width = buf[0]; + uint8_t width = buf[0]; uint8_t height = buf[1]; - tilemap->map = (uint8_t *)heap_caps_calloc(width * height, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + tilemap->map = (uint8_t*)heap_caps_calloc(width * height, sizeof(uint8_t), MALLOC_CAP_SPIRAM); memcpy(tilemap->map, &buf[2], width * height); - tilemap->mapWidth = width; + tilemap->mapWidth = width; tilemap->mapHeight = height; tilemap->minMapOffsetX = 0; @@ -180,20 +190,20 @@ bool loadMapFromFile(tilemap_t *tilemap, const char *name) return true; } -bool loadTiles(tilemap_t *tilemap) +bool loadTiles(tilemap_t* tilemap) { // tiles 0 is invisible // remember to subtract 1 from tile index before drawing tile loadWsg("brkTile001.wsg", &tilemap->tiles[0], false); loadWsg("brkTile002.wsg", &tilemap->tiles[1], false); loadWsg("brkTile003.wsg", &tilemap->tiles[2], false); - tilemap->tiles[3] = tilemap->tiles[0]; - tilemap->tiles[4] = tilemap->tiles[0]; - tilemap->tiles[5] = tilemap->tiles[0]; - tilemap->tiles[6] = tilemap->tiles[0]; - tilemap->tiles[7] = tilemap->tiles[0]; - tilemap->tiles[8] = tilemap->tiles[0]; - tilemap->tiles[9] = tilemap->tiles[0]; + loadWsg("brkTile004.wsg", &tilemap->tiles[3], false); + loadWsg("brkTile005.wsg", &tilemap->tiles[4], false); + loadWsg("brkTile006.wsg", &tilemap->tiles[5], false); + loadWsg("brkTile007.wsg", &tilemap->tiles[6], false); + tilemap->tiles[7] = tilemap->tiles[0]; + tilemap->tiles[8] = tilemap->tiles[0]; + tilemap->tiles[9] = tilemap->tiles[0]; tilemap->tiles[10] = tilemap->tiles[0]; tilemap->tiles[11] = tilemap->tiles[0]; tilemap->tiles[12] = tilemap->tiles[0]; @@ -211,13 +221,12 @@ bool loadTiles(tilemap_t *tilemap) loadWsg("brkTile025.wsg", &tilemap->tiles[24], false); loadWsg("brkTile026.wsg", &tilemap->tiles[25], false); loadWsg("brkTile027.wsg", &tilemap->tiles[26], false); + loadWsg("brkTile028.wsg", &tilemap->tiles[27], false); - tilemap->tiles[27] = tilemap->tiles[0]; tilemap->tiles[28] = tilemap->tiles[0]; tilemap->tiles[29] = tilemap->tiles[0]; tilemap->tiles[30] = tilemap->tiles[0]; - loadWsg("brkTile032.wsg", &tilemap->tiles[31], false); loadWsg("brkTile033.wsg", &tilemap->tiles[32], false); loadWsg("brkTile034.wsg", &tilemap->tiles[33], false); @@ -242,22 +251,16 @@ bool loadTiles(tilemap_t *tilemap) loadWsg("brkTile053.wsg", &tilemap->tiles[52], false); loadWsg("brkTile054.wsg", &tilemap->tiles[53], false); loadWsg("brkTile055.wsg", &tilemap->tiles[54], false); - /*loadWsg("brkTile056.wsg", &tilemap->tiles[55], false); + loadWsg("brkTile056.wsg", &tilemap->tiles[55], false); loadWsg("brkTile057.wsg", &tilemap->tiles[56], false); - loadWsg("brkTile058.wsg", &tilemap->tiles[57], false); - loadWsg("brkTile059.wsg", &tilemap->tiles[58], false); - loadWsg("brkTile060.wsg", &tilemap->tiles[59], false); - loadWsg("brkTile061.wsg", &tilemap->tiles[60], false); - loadWsg("brkTile062.wsg", &tilemap->tiles[61], false); - loadWsg("brkTile063.wsg", &tilemap->tiles[62], false);*/ - tilemap->tiles[55] = tilemap->tiles[0]; - tilemap->tiles[56] = tilemap->tiles[0]; + tilemap->tiles[57] = tilemap->tiles[0]; tilemap->tiles[58] = tilemap->tiles[0]; tilemap->tiles[59] = tilemap->tiles[0]; tilemap->tiles[60] = tilemap->tiles[0]; tilemap->tiles[61] = tilemap->tiles[0]; tilemap->tiles[62] = tilemap->tiles[0]; + loadWsg("brkTile064.wsg", &tilemap->tiles[63], false); loadWsg("brkTile065.wsg", &tilemap->tiles[64], false); loadWsg("brkTile066.wsg", &tilemap->tiles[65], false); @@ -323,33 +326,30 @@ bool loadTiles(tilemap_t *tilemap) loadWsg("brkTile126.wsg", &tilemap->tiles[125], false); loadWsg("brkTile127.wsg", &tilemap->tiles[126], false); - - - - return true; } -void tileSpawnEntity(tilemap_t *tilemap, uint8_t objectIndex, uint8_t tx, uint8_t ty) +void tileSpawnEntity(tilemap_t* tilemap, uint8_t objectIndex, uint8_t tx, uint8_t ty) { - entity_t *entityCreated = createEntity(tilemap->entityManager, objectIndex, (tx << TILE_SIZE_IN_POWERS_OF_2) + 4, (ty << TILE_SIZE_IN_POWERS_OF_2) + 4); + entity_t* entityCreated = createEntity(tilemap->entityManager, objectIndex, (tx << TILE_SIZE_IN_POWERS_OF_2) + 4, + (ty << TILE_SIZE_IN_POWERS_OF_2) + 4); if (entityCreated != NULL) { - entityCreated->homeTileX = tx; - entityCreated->homeTileY = ty; + entityCreated->homeTileX = tx; + entityCreated->homeTileY = ty; tilemap->map[ty * tilemap->mapWidth + tx] = 0; } } -uint8_t getTile(tilemap_t *tilemap, uint8_t tx, uint8_t ty) +uint8_t getTile(tilemap_t* tilemap, uint8_t tx, uint8_t ty) { // ty = CLAMP(ty, 0, tilemap->mapHeight - 1); if (/*ty < 0 ||*/ ty >= tilemap->mapHeight) { ty = 0; - //return 0; + // return 0; } if (/*tx < 0 ||*/ tx >= tilemap->mapWidth) @@ -360,7 +360,7 @@ uint8_t getTile(tilemap_t *tilemap, uint8_t tx, uint8_t ty) return tilemap->map[ty * tilemap->mapWidth + tx]; } -void setTile(tilemap_t *tilemap, uint8_t tx, uint8_t ty, uint8_t newTileId) +void setTile(tilemap_t* tilemap, uint8_t tx, uint8_t ty, uint8_t newTileId) { // ty = CLAMP(ty, 0, tilemap->mapHeight - 1); @@ -376,18 +376,19 @@ bool isSolid(uint8_t tileId) { switch (tileId) { - case TILE_EMPTY: - return false; - break; - case TILE_BOUNDARY_1 ... TILE_UNUSED_127: - return true; - break; - default: - return false; + case TILE_EMPTY: + return false; + break; + case TILE_BOUNDARY_1 ... TILE_UNUSED_127: + return true; + break; + default: + return false; } } -bool isBlock(uint8_t tileId){ +bool isBlock(uint8_t tileId) +{ switch (tileId) { case TILE_BLOCK_1x1_RED ... TILE_BLOCK_2x2_BLACK_DR: @@ -395,7 +396,7 @@ bool isBlock(uint8_t tileId){ default: return false; } - + return false; } @@ -404,7 +405,8 @@ bool isBlock(uint8_t tileId){ // return tileId > TILE_INVISIBLE_BLOCK && tileId < TILE_BG_GOAL_ZONE; // } -void unlockScrolling(tilemap_t *tilemap){ +void unlockScrolling(tilemap_t* tilemap) +{ tilemap->minMapOffsetX = 0; tilemap->maxMapOffsetX = tilemap->mapWidth * TILE_SIZE - TILEMAP_DISPLAY_WIDTH_PIXELS; @@ -412,22 +414,27 @@ void unlockScrolling(tilemap_t *tilemap){ tilemap->maxMapOffsetY = tilemap->mapHeight * TILE_SIZE - TILEMAP_DISPLAY_HEIGHT_PIXELS; } -bool needsTransparency(uint8_t tileId){ - switch(tileId) { - case TILE_BOUNDARY_1 ... TILE_UNUSED_31: +bool needsTransparency(uint8_t tileId) +{ + switch (tileId) + { + case TILE_BOUNDARY_1 ... TILE_BLOCK_1x1_BLACK: return false; - case TILE_BLOCK_2x1_RED_L ... TILE_UNUSED_127: + case TILE_BLOCK_1x1_STONE ... TILE_UNUSED_127: return true; default: return false; } } -void freeTilemap(tilemap_t *tilemap){ +void freeTilemap(tilemap_t* tilemap) +{ free(tilemap->map); - for(uint8_t i=0; i<127; i++){ - switch(i){ - //Skip all placeholder tiles, since they reuse other tiles + for (uint8_t i = 0; i < 127; i++) + { + switch (i) + { + // Skip all placeholder tiles, since they reuse other tiles //(see loadTiles) case 3 ... 14: case 27 ... 30: @@ -435,12 +442,47 @@ void freeTilemap(tilemap_t *tilemap){ { break; } - default: { + default: + { freeWsg(&tilemap->tiles[i]); break; } } } +} + +void forceTileSpawnEntitiesWithinView(tilemap_t* tilemap) +{ + for (uint16_t y = (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2); + y < (tilemap->mapOffsetY >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_HEIGHT_TILES; y++) + { + if (y >= tilemap->mapHeight) + { + break; + } + + for (int32_t x = (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2); + x < (tilemap->mapOffsetX >> TILE_SIZE_IN_POWERS_OF_2) + TILEMAP_DISPLAY_WIDTH_TILES; x++) + { + if (x >= tilemap->mapWidth) + { + break; + } + else if (x < 0) + { + continue; + } + uint8_t tile = tilemap->map[(y * tilemap->mapWidth) + x]; + if (tile < 128) + { + continue; + } + else if (tilemap->tileSpawnEnabled) + { + tileSpawnEntity(tilemap, tile - 128, x, y); + } + } + } } \ No newline at end of file diff --git a/main/modes/breakout/tilemap.h b/main/modes/breakout/tilemap.h index e8341041d..94d93d929 100644 --- a/main/modes/breakout/tilemap.h +++ b/main/modes/breakout/tilemap.h @@ -16,12 +16,12 @@ //============================================================================== #define CLAMP(x, l, u) ((x) < l ? l : ((x) > u ? u : (x))) -#define TILEMAP_DISPLAY_WIDTH_PIXELS 280 // The screen size +#define TILEMAP_DISPLAY_WIDTH_PIXELS 280 // The screen size #define TILEMAP_DISPLAY_HEIGHT_PIXELS 240 // The screen size -#define TILEMAP_DISPLAY_WIDTH_TILES 36 // The screen size in tiles + 1 -#define TILEMAP_DISPLAY_HEIGHT_TILES 31 // The screen size in tiles + 1 +#define TILEMAP_DISPLAY_WIDTH_TILES 36 // The screen size in tiles + 1 +#define TILEMAP_DISPLAY_HEIGHT_TILES 31 // The screen size in tiles + 1 -#define TILE_SIZE 8 +#define TILE_SIZE 8 #define TILE_SIZE_IN_POWERS_OF_2 3 #define TILESET_SIZE 128 @@ -29,16 +29,17 @@ //============================================================================== // Enums //============================================================================== -typedef enum { +typedef enum +{ TILE_EMPTY, TILE_BOUNDARY_1, TILE_BOUNDARY_2, TILE_BOUNDARY_3, - TILE_UNUSED_4, - TILE_UNUSED_5, - TILE_UNUSED_6, - TILE_UNUSED_7, - TILE_UNUSED_8, + TILE_BOUNDARY_4, + TILE_BOUNDARY_5, + TILE_BOUNDARY_6, + TILE_BOUNDARY_7, + TILE_INVISIBLE_BLOCK, TILE_UNUSED_9, TILE_UNUSED_A, TILE_UNUSED_B, @@ -58,7 +59,7 @@ typedef enum { TILE_BLOCK_1x1_TAN, TILE_BLOCK_1x1_BROWN, TILE_BLOCK_1x1_BLACK, - TILE_UNUSED_28, + TILE_BLOCK_1x1_STONE, TILE_UNUSED_29, TILE_UNUSED_30, TILE_UNUSED_31, @@ -86,8 +87,8 @@ typedef enum { TILE_BLOCK_2x1_BROWN_R, TILE_BLOCK_2x1_BLACK_L, TILE_BLOCK_2x1_BLACK_R, - TILE_SOLID_UNUSED_56, - TILE_SOLID_UNUSED_57, + TILE_BLOCK_2x1_STONE_L, + TILE_BLOCK_2x1_STONE_R, TILE_SOLID_UNUSED_58, TILE_SOLID_UNUSED_59, TILE_SOLID_UNUSED_60, @@ -134,8 +135,8 @@ typedef enum { TILE_BLOCK_2x2_BROWN_UR, TILE_BLOCK_2x2_BLACK_UL, TILE_BLOCK_2x2_BLACK_UR, - TILE_UNUSED_104, - TILE_UNUSED_105, + TILE_BLOCK_2x2_STONE_UL, + TILE_BLOCK_2x2_STONE_UR, TILE_UNUSED_106, TILE_UNUSED_107, TILE_UNUSED_108, @@ -150,8 +151,8 @@ typedef enum { TILE_BLOCK_2x2_BROWN_DR, TILE_BLOCK_2x2_BLACK_DL, TILE_BLOCK_2x2_BLACK_DR, - TILE_UNUSED_120, - TILE_UNUSED_121, + TILE_BLOCK_2x2_STONE_DL, + TILE_BLOCK_2x2_STONE_DR, TILE_UNUSED_122, TILE_UNUSED_123, TILE_UNUSED_124, @@ -163,23 +164,24 @@ typedef enum { //============================================================================== // Structs //============================================================================== -typedef struct { +typedef struct +{ uint8_t x; uint8_t y; } warp_t; - struct tilemap_t +struct tilemap_t { wsg_t tiles[TILESET_SIZE]; - uint8_t * map; + uint8_t* map; uint8_t mapWidth; uint8_t mapHeight; - + uint16_t totalTargetBlocks; int16_t mapOffsetX; int16_t mapOffsetY; - + int16_t minMapOffsetX; int16_t maxMapOffsetX; int16_t minMapOffsetY; @@ -190,7 +192,7 @@ typedef struct { int16_t executeTileSpawnRow; bool executeTileSpawnAll; - entityManager_t *entityManager; + entityManager_t* entityManager; uint8_t animationFrame; int16_t animationTimer; @@ -199,19 +201,20 @@ typedef struct { //============================================================================== // Prototypes //============================================================================== -void initializeTileMap(tilemap_t * tilemap); -void drawTileMap(tilemap_t * tilemap); -void scrollTileMap(tilemap_t * tilemap, int16_t x, int16_t y); -void drawTile(tilemap_t * tilemap, uint8_t tileId, int16_t x, int16_t y); -bool loadMapFromFile(tilemap_t * tilemap, const char * name); -bool loadTiles(tilemap_t * tilemap); -void tileSpawnEntity(tilemap_t * tilemap, uint8_t objectIndex, uint8_t tx, uint8_t ty); -uint8_t getTile(tilemap_t *tilemap, uint8_t tx, uint8_t ty); -void setTile(tilemap_t *tilemap, uint8_t tx, uint8_t ty, uint8_t newTileId); +void initializeTileMap(tilemap_t* tilemap); +void drawTileMap(tilemap_t* tilemap); +void scrollTileMap(tilemap_t* tilemap, int16_t x, int16_t y); +void drawTile(tilemap_t* tilemap, uint8_t tileId, int16_t x, int16_t y); +bool loadMapFromFile(tilemap_t* tilemap, const char* name); +bool loadTiles(tilemap_t* tilemap); +void tileSpawnEntity(tilemap_t* tilemap, uint8_t objectIndex, uint8_t tx, uint8_t ty); +uint8_t getTile(tilemap_t* tilemap, uint8_t tx, uint8_t ty); +void setTile(tilemap_t* tilemap, uint8_t tx, uint8_t ty, uint8_t newTileId); bool isSolid(uint8_t tileId); bool isBlock(uint8_t tileId); -void unlockScrolling(tilemap_t *tilemap); +void unlockScrolling(tilemap_t* tilemap); bool needsTransparency(uint8_t tileId); -void freeTilemap(tilemap_t *tilemap); +void freeTilemap(tilemap_t* tilemap); +void forceTileSpawnEntitiesWithinView(tilemap_t* tilemap); #endif diff --git a/main/modes/credits/credits_utils.c b/main/modes/credits/credits_utils.c new file mode 100644 index 000000000..5aa91abf6 --- /dev/null +++ b/main/modes/credits/credits_utils.c @@ -0,0 +1,179 @@ +//============================================================================== +// Includes +//============================================================================== + +#include +#include "hdw-bzr.h" +#include "hdw-tft.h" +#include "spiffs_font.h" +#include "spiffs_song.h" +#include "macros.h" +#include "credits_utils.h" + +//============================================================================== +// Functions +//============================================================================== + +/** + * @brief Initialize the credits + * + * @param credits The credits to initialize + * @param font A font to use for the credits + * @param names An array of strings, one per line of the credits + * @param colors Colors for the credit names + * @param numElements The number of names (and colors) for the credits + */ +void initCredits(credits_t* credits, font_t* font, const char* const* names, const paletteColor_t* colors, + int32_t numElements) +{ + // Load some fonts + credits->font = font; + + // Set initial variables + credits->yOffset = TFT_HEIGHT; + credits->tElapsedUs = 0; + credits->scrollMod = 1; + credits->names = names; + credits->colors = colors; + credits->numElements = numElements; + + // Load and play song + loadSong("credits.sng", &credits->song, false); + credits->song.shouldLoop = true; + bzrPlayBgm(&credits->song, BZR_STEREO); +} + +/** + * @brief Deinitialize the credits + * + * @param credits The credits to deinitialize + */ +void deinitCredits(credits_t* credits) +{ + freeSong(&credits->song); +} + +/** + * @brief Draw the credits to the display + * + * @param credits The credits to draw + * @param elapsedUs The time elapsed since this was last called + */ +void drawCredits(credits_t* credits, uint32_t elapsedUs) +{ + credits->tElapsedUs += elapsedUs; + + // If enough time has passed, translate and redraw text + uint32_t updateTime = 100000 / ABS(credits->scrollMod); + if (credits->tElapsedUs > updateTime) + { + credits->tElapsedUs -= updateTime; + + // This static var tracks the vertical scrolling offset + credits->yOffset -= (credits->scrollMod > 0) ? 1 : -1; + } + + // Clear first + clearPxTft(); + + // Draw names until the cursor is off the screen + int16_t yPos = 0; + int16_t idx = 0; + while ((yPos + credits->yOffset) < TFT_HEIGHT) + { + // Only draw names with negative offsets if they're a little on screen + if ((yPos + credits->yOffset) >= -credits->font->height) + { + // If the names have scrolled back to the start, reset the scroll vars + if (0 == (yPos + credits->yOffset) && 0 == idx) + { + credits->yOffset = 0; + yPos = 0; + } + + // Center and draw the text + int16_t tWidth = textWidth(credits->font, credits->names[idx]); + drawText(credits->font, credits->colors[idx], credits->names[idx], (TFT_WIDTH - tWidth) / 2, + (yPos + credits->yOffset)); + } + + // Add more space if the credits end in a newline + size_t nameLen = strlen(credits->names[idx]); + if ((nameLen > 0) && ('\n' == credits->names[idx][nameLen - 1])) + { + yPos += credits->font->height + 8; + } + else + { + yPos += credits->font->height + 1; + } + + // Always update the idx and cursor position, even if the text wasn't drawn + idx = (idx + 1) % credits->numElements; + } +} + +/** + * @brief Credits button callback, either speed up, reverse, or exit credits + * + * @param evt The button event + * @return true if the credits exit, false otherwise + */ +bool creditsButtonCb(credits_t* credits, buttonEvt_t* evt) +{ + if (evt->down) + { + switch (evt->button) + { + case PB_UP: + { + // Scroll faster + credits->scrollMod = 4; + break; + } + case PB_DOWN: + { + // Scroll faster, backwards + credits->scrollMod = -4; + break; + } + case PB_A: + case PB_B: + { + // Exit + return true; + } + case PB_LEFT: + case PB_RIGHT: + case PB_START: + case PB_SELECT: + { + break; + } + } + } + else + { + switch (evt->button) + { + case PB_UP: + case PB_DOWN: + { + // Resume normal scrolling + credits->scrollMod = 1; + break; + } + case PB_A: + case PB_B: + case PB_LEFT: + case PB_RIGHT: + case PB_START: + case PB_SELECT: + { + // Do nothing + break; + } + } + } + return false; +} diff --git a/main/modes/credits/credits_utils.h b/main/modes/credits/credits_utils.h new file mode 100644 index 000000000..f352343e6 --- /dev/null +++ b/main/modes/credits/credits_utils.h @@ -0,0 +1,35 @@ +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "hdw-btn.h" +#include "font.h" + +//============================================================================== +// Structs +//============================================================================== + +typedef struct +{ + font_t* font; + int64_t tElapsedUs; + int8_t scrollMod; + int16_t yOffset; + song_t song; + + const char* const* names; + const paletteColor_t* colors; + int32_t numElements; +} credits_t; + +//============================================================================== +// Function Declarations +//============================================================================== + +void initCredits(credits_t* credits, font_t* font, const char* const* names, const paletteColor_t* colors, + int32_t numElements); +void deinitCredits(credits_t* credits); +void drawCredits(credits_t* credits, uint32_t elapsedUs); +bool creditsButtonCb(credits_t* credits, buttonEvt_t* evt); diff --git a/main/modes/credits/mode_credits.c b/main/modes/credits/mode_credits.c index 1a3d91de1..b8c4595cb 100644 --- a/main/modes/credits/mode_credits.c +++ b/main/modes/credits/mode_credits.c @@ -6,6 +6,7 @@ #include #include "swadge2024.h" +#include "credits_utils.h" #include "mode_credits.h" #include "mainMenu.h" @@ -16,20 +17,6 @@ void creditsEnterMode(void); void creditsExitMode(void); void creditsMainLoop(int64_t elapsedUs); -void creditsButtonCb(buttonEvt_t* evt); - -//============================================================================== -// Structs -//============================================================================== - -typedef struct -{ - font_t font; - int64_t tElapsedUs; - int8_t scrollMod; - int16_t yOffset; - song_t song; -} credits_t; //============================================================================== // Variables @@ -80,17 +67,12 @@ void creditsEnterMode(void) // Allocate memory for this mode credits = (credits_t*)calloc(1, sizeof(credits_t)); - // Load some fonts - loadFont("logbook.font", &credits->font, false); - - // Set initial variables - credits->yOffset = TFT_HEIGHT; - credits->tElapsedUs = 0; - credits->scrollMod = 1; + // Load a font + font_t* creditsFont = (font_t*)calloc(1, sizeof(font_t)); + loadFont("logbook.font", creditsFont, false); - // Load and play song - loadSong("credits.sng", &credits->song, false); - bzrPlayBgm(&credits->song, BZR_STEREO); + // Initialize credits + initCredits(credits, creditsFont, creditNames, creditColors, ARRAY_SIZE(creditNames)); } /** @@ -98,8 +80,12 @@ void creditsEnterMode(void) */ void creditsExitMode(void) { - freeFont(&credits->font); - freeSong(&credits->song); + // Free the font + freeFont(credits->font); + free(credits->font); + // Deinitialize credits + deinitCredits(credits); + // Free memory for this mode free(credits); } @@ -113,121 +99,11 @@ void creditsMainLoop(int64_t elapsedUs) buttonEvt_t evt; while (checkButtonQueueWrapper(&evt)) { - creditsButtonCb(&evt); - } - - credits->tElapsedUs += elapsedUs; - - // If enough time has passed, translate and redraw text - uint32_t updateTime = 100000 / ABS(credits->scrollMod); - if (credits->tElapsedUs > updateTime) - { - credits->tElapsedUs -= updateTime; - - // This static var tracks the vertical scrolling offset - credits->yOffset -= (credits->scrollMod > 0) ? 1 : -1; - - // Clear first - clearPxTft(); - - // Draw names until the cursor is off the screen - int16_t yPos = 0; - int16_t idx = 0; - while ((yPos + credits->yOffset) < TFT_HEIGHT) + if (creditsButtonCb(credits, &evt)) { - // Only draw names with negative offsets if they're a little on screen - if ((yPos + credits->yOffset) >= -credits->font.height) - { - // If the names have scrolled back to the start, reset the scroll vars - if (0 == (yPos + credits->yOffset) && 0 == idx) - { - credits->yOffset = 0; - yPos = 0; - } - - // Center and draw the text - int16_t tWidth = textWidth(&credits->font, creditNames[idx]); - drawText(&credits->font, creditColors[idx], creditNames[idx], (TFT_WIDTH - tWidth) / 2, - (yPos + credits->yOffset)); - } - - // Add more space if the credits end in a newline - size_t nameLen = strlen(creditNames[idx]); - if ((nameLen > 0) && ('\n' == creditNames[idx][nameLen - 1])) - { - yPos += credits->font.height + 8; - } - else - { - yPos += credits->font.height + 1; - } - - // Always update the idx and cursor position, even if the text wasn't drawn - idx = (idx + 1) % ARRAY_SIZE(creditNames); + switchToSwadgeMode(&mainMenuMode); } } -} -/** - * @brief Credits button callback, either speed up, reverse, or exit credits - * - * @param evt The button event - */ -void creditsButtonCb(buttonEvt_t* evt) -{ - if (evt->down) - { - switch (evt->button) - { - case PB_UP: - { - // Scroll faster - credits->scrollMod = 4; - break; - } - case PB_DOWN: - { - // Scroll faster, backwards - credits->scrollMod = -4; - break; - } - case PB_A: - case PB_B: - { - // Exit - switchToSwadgeMode(&mainMenuMode); - break; - } - case PB_LEFT: - case PB_RIGHT: - case PB_START: - case PB_SELECT: - { - break; - } - } - } - else - { - switch (evt->button) - { - case PB_UP: - case PB_DOWN: - { - // Resume normal scrolling - credits->scrollMod = 1; - break; - } - case PB_A: - case PB_B: - case PB_LEFT: - case PB_RIGHT: - case PB_START: - case PB_SELECT: - { - // Do nothing - break; - } - } - } + drawCredits(credits, elapsedUs); } diff --git a/main/modes/dance/dance.c b/main/modes/dance/dance.c index ca3993e98..81e3b628b 100644 --- a/main/modes/dance/dance.c +++ b/main/modes/dance/dance.c @@ -43,6 +43,9 @@ typedef struct uint64_t buttonPressedTimer; + touchSpinState_t spinState; + uint8_t startDanceSpeed; + font_t infoFont; wsg_t arrow; } danceMode_t; @@ -293,14 +296,26 @@ void dancePollTouch(void) int32_t phi, r, intensity; if (getTouchJoystick(&phi, &r, &intensity)) { - // Make sure we are pressing on the edge. - if (intensity > 5000 && r > 512) + if (!danceState->spinState.startSet) { - uint8_t index = ((phi * (sizeof(danceSpeeds) / sizeof(*danceSpeeds) - 1) + 640) / 1280); - - danceState->danceSpeed = index; - danceState->buttonPressedTimer = 0; + danceState->startDanceSpeed = danceState->danceSpeed; } + + getTouchSpins(&danceState->spinState, phi, r); + + // Make sure we are pressing on the edge. + + int32_t speeds = ARRAY_SIZE(danceSpeeds); + int32_t diff + = CLAMP((((danceState->spinState.spins * 360 + danceState->spinState.remainder) * (speeds - 1)) / -360), + -speeds, speeds); + + danceState->danceSpeed = CLAMP(danceState->startDanceSpeed + diff, 0, speeds - 1); + danceState->buttonPressedTimer = 0; + } + else + { + danceState->spinState.startSet = false; } } @@ -322,7 +337,7 @@ void danceRedrawScreen(void) drawWsg(&danceState->arrow, ((TFT_WIDTH - width) / 2) + width + 8, yOff, false, false, 90); // Draw the brightness at the top - char text[18]; + char text[19]; snprintf(text, sizeof(text), "Brightness: %d", getLedBrightnessSetting()); width = textWidth(&(danceState->infoFont), text); yOff = 16; @@ -335,11 +350,11 @@ void danceRedrawScreen(void) yOff += danceState->infoFont.height + 16; if (danceSpeeds[danceState->danceSpeed] > DANCE_SPEED_MULT) { - snprintf(text, sizeof(text), "Y~X: Speed: 1/%dx", danceSpeeds[danceState->danceSpeed] / DANCE_SPEED_MULT); + snprintf(text, sizeof(text), "Spin: Speed: 1/%dx", danceSpeeds[danceState->danceSpeed] / DANCE_SPEED_MULT); } else { - snprintf(text, sizeof(text), "Y~X: Speed: %dx", DANCE_SPEED_MULT / danceSpeeds[danceState->danceSpeed]); + snprintf(text, sizeof(text), "Spin: Speed: %dx", DANCE_SPEED_MULT / danceSpeeds[danceState->danceSpeed]); } width = textWidth(&(danceState->infoFont), text); drawText(&(danceState->infoFont), c555, text, (TFT_WIDTH - width) / 2, yOff); diff --git a/main/modes/factoryTest/factoryTest.c b/main/modes/factoryTest/factoryTest.c index be6dfa65b..42dbb14cc 100644 --- a/main/modes/factoryTest/factoryTest.c +++ b/main/modes/factoryTest/factoryTest.c @@ -176,6 +176,7 @@ void testEnterMode(void) bzrPlayBgm(&test->song, BZR_STEREO); // Clear out accel setting. + accelSetRegistersAndReset(); accelPerformCal(); // Set NVM to indicate test not passed yet diff --git a/main/modes/gamepad/gamepad.c b/main/modes/gamepad/gamepad.c index 11c5b410f..311c46d68 100644 --- a/main/modes/gamepad/gamepad.c +++ b/main/modes/gamepad/gamepad.c @@ -280,6 +280,9 @@ void gamepadEnterMode(void) // We shold go as fast as we can setFrameRateUs(0); + + // Set up the IMU + accelSetRegistersAndReset(); } /** diff --git a/main/modes/mainMenu/mainMenu.c b/main/modes/mainMenu/mainMenu.c index bed8b1844..3a6c786b5 100644 --- a/main/modes/mainMenu/mainMenu.c +++ b/main/modes/mainMenu/mainMenu.c @@ -171,6 +171,9 @@ static void mainMenuEnterMode(void) // End the submenu for settings mainMenu->menu = endSubMenu(mainMenu->menu); + // Show the battery on the main menu + setShowBattery(mainMenu->menu, true); + // Initialize menu renderer mainMenu->renderer = initMenuLogbookRenderer(&mainMenu->logbook); } diff --git a/main/modes/pushy/pushy.c b/main/modes/pushy/pushy.c index 254efeddb..786bec483 100644 --- a/main/modes/pushy/pushy.c +++ b/main/modes/pushy/pushy.c @@ -28,8 +28,29 @@ // clang-format off -#define LOGFIRE false -#define LOGPUSHY false +#define LOGFIRE false +#define LOGPUSHY false +#define VIDEO false +#define GENERATE_COLOR_WHEEL false + +#if VIDEO +#define PUSHY_BPM 80 +#define PUSHY_HOLD_BEATS 0.5 +#define PUSHY_HOLD_US ((int64_t)(PUSHY_HOLD_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000)) + +#define PUSHY_69_AT_BEATS 8 +#define PUSHY_420_AT_BEATS 16 +#define PUSHY_6969_AT_BEATS 24 +#define PUSHY_42069_AT_BEATS 32 +#define PUSHY_69420_AT_BEATS 36 + +#define PUSHY_BEAT_DROP_AT_US ((int64_t)((15 + 35776 / 44100.0) * 1000 * 1000)) +#define PUSHY_69_AT_US ((int64_t)(PUSHY_69_AT_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000 + PUSHY_BEAT_DROP_AT_US)) +#define PUSHY_420_AT_US ((int64_t)(PUSHY_420_AT_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000 + PUSHY_BEAT_DROP_AT_US)) +#define PUSHY_6969_AT_US ((int64_t)(PUSHY_6969_AT_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000 + PUSHY_BEAT_DROP_AT_US)) +#define PUSHY_42069_AT_US ((int64_t)(PUSHY_42069_AT_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000 + PUSHY_BEAT_DROP_AT_US)) +#define PUSHY_69420_AT_US ((int64_t)(PUSHY_69420_AT_BEATS / (PUSHY_BPM / 60.0) * 1000 * 1000 + PUSHY_BEAT_DROP_AT_US)) +#endif #define NUM_DIGITS 8 #define NUM_PUSHY_COLORS 11 // 0-9 and "off" @@ -83,6 +104,13 @@ typedef struct bool rainbowDigits[NUM_DIGITS]; ///< A bitmap of digits that should be rainbow, from most significant digit at [0] to least significant digit at [NUM_DIGITS] bool weedDigits[NUM_DIGITS]; ///< A bitmap of digits that should be weed colored, from most significant digit at [0] to least significant digit at [NUM_DIGITS] float weedHue; ///< The hue to display on digits that are weed colored +#if VIDEO + int64_t lockoutUs; + bool reachedRainbow; + bool reachedWeed; + bool reachedDoubleRainbow; ///< All the way + int64_t audioTrackUs; +#endif paletteColor_t colors[NUM_PUSHY_COLORS]; ///< Colors for each digit 0-9 uint8_t rainbowHues[NUM_PUSHY_COLORS]; ///< Hues to display on digits that are rainbow @@ -185,6 +213,17 @@ static void pushyEnterMode(void) pushy->rainbowTimer = EFFECT_MAX; pushy->weedTimer = EFFECT_MAX; +#if VIDEO + pushy->audioTrackUs = PUSHY_BEAT_DROP_AT_US; +#endif + +#if GENERATE_COLOR_WHEEL + for (int i = 0; i < 255; i++) + { + printf("%" PRIu8 "\n", (uint8_t)paletteHsvToHex(i, 255, 255)); + } +#endif + // Initialize default color values // clang-format off pushy->colors[0] = paletteHsvToHex( 0, 0, BRIGHTNESS); // white @@ -223,7 +262,9 @@ static void pushyExitMode(void) // Save score to NVS if (pushy->lastSaveCounter != pushy->counter) { +#if !VIDEO writeNvs32(pushyCounterKey, (int32_t)pushy->counter); +#endif } // Free the font @@ -237,13 +278,105 @@ static void pushyExitMode(void) * @brief This function is called periodically and frequently. It will either draw the menu or play the game, depending * on which screen is currently being displayed * - * @param elapsedUs The time that has elapsed since the last call to this function, in microseconds + * @param elapsedUs The time that has elapsed since the last call to this function, in microseconds. First call is + * nonzero */ static void pushyMainLoop(int64_t elapsedUs) { pushy->buttonPushedUs += elapsedUs; +#if VIDEO + pushy->audioTrackUs += elapsedUs; + + uint32_t oldCounter = pushy->counter; + + // clang-format off + if (pushy->audioTrackUs < (PUSHY_BEAT_DROP_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 0; + } + else if (pushy->audioTrackUs < PUSHY_69_AT_US) + { + pushy->counter = (0 + (69 - 0) * (pushy->audioTrackUs - (PUSHY_BEAT_DROP_AT_US + PUSHY_HOLD_US)) / (double)(PUSHY_69_AT_US - (PUSHY_BEAT_DROP_AT_US + PUSHY_HOLD_US))); + } + else if (pushy->audioTrackUs < (PUSHY_69_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 69; + } + else if (pushy->audioTrackUs < PUSHY_420_AT_US) + { + pushy->counter = (69 + (420 - 69) * (pushy->audioTrackUs - (PUSHY_69_AT_US + PUSHY_HOLD_US)) / (double)(PUSHY_420_AT_US - (PUSHY_69_AT_US + PUSHY_HOLD_US))); + } + else if (pushy->audioTrackUs < (PUSHY_420_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 420; + } + else if (pushy->audioTrackUs < PUSHY_6969_AT_US) + { + pushy->counter = (420 + (6969 - 420) * ((pushy->audioTrackUs - (PUSHY_420_AT_US + PUSHY_HOLD_US)) / (double)(PUSHY_6969_AT_US - (PUSHY_420_AT_US + PUSHY_HOLD_US)))); + } + else if (pushy->audioTrackUs < (PUSHY_6969_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 6969; + } + else if (pushy->audioTrackUs < PUSHY_42069_AT_US) + { + pushy->counter = (6969 + (42069 - 6969) * ((pushy->audioTrackUs - (PUSHY_6969_AT_US + PUSHY_HOLD_US)) / (double)(PUSHY_42069_AT_US - (PUSHY_6969_AT_US + PUSHY_HOLD_US)))); + } + else if (pushy->audioTrackUs < (PUSHY_42069_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 42069; + } + else if (pushy->audioTrackUs < PUSHY_69420_AT_US) + { + pushy->counter = (42069 + (69420 - 42069) * ((pushy->audioTrackUs - (PUSHY_42069_AT_US + PUSHY_HOLD_US)) / (double)(PUSHY_69420_AT_US - (PUSHY_42069_AT_US + PUSHY_HOLD_US)))); + } + else if (pushy->audioTrackUs < (PUSHY_69420_AT_US + PUSHY_HOLD_US)) + { + pushy->counter = 69420; + } + else + { + // Do nothing, continue holding 69420 + } + // clang-format on + + pushy->fireCounter += pushy->counter - oldCounter; + pushy->buttonPushedUs = 0; + if ((uint32_t)(oldCounter / SHUFFLE_AT_MOD) < (uint32_t)(pushy->counter / SHUFFLE_AT_MOD)) + { + shuffleColors(); + } + + // if (pushy->lockoutUs == 0) +#endif + { + readButton(); + } +#if VIDEO + // else + // { + // pushy->lockoutUs = MAX(pushy->lockoutUs - elapsedUs, 0); + // } - readButton(); + // if (!pushy->reachedRainbow && pushy->counter >= 69) + // { + // pushy->lockoutUs = 1 * 1000 * 1000; + // pushy->reachedRainbow = true; + // pushy->counter = 69; + // } + // else if (!pushy->reachedWeed && pushy->counter >= 420) + // { + // pushy->lockoutUs = 5 * 1000 * 1000; + // pushy->reachedWeed = true; + // pushy->counter = 420; + // } + // else if (!pushy->reachedDoubleRainbow && pushy->counter >= 6969) + // { + // pushy->lockoutUs = 5 * 1000 * 1000; + // pushy->reachedDoubleRainbow = true; + // pushy->counter = 6969; + // } +#endif // If score has changed, save if last input was longer ago than our threshold or if score is a multiple of 100 if (pushy->lastSaveCounter != pushy->counter && pushy->buttonPushedUs > IDLE_SECONDS_UNTIL_SAVE * 1000 * 1000) @@ -298,15 +431,23 @@ static void pushyBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t // Save score to NVS static void saveMemory(void) { +#if !VIDEO writeNvs32(pushyCounterKey, (int32_t)pushy->counter); +#endif pushy->lastSaveCounter = pushy->counter; } static void shuffleColors(void) { +#if !VIDEO for (uint8_t i = 0; i < NUM_PUSHY_COLORS - 1; i++) { uint8_t n = esp_random() % (NUM_PUSHY_COLORS - 1); +#else + for (uint8_t i = (pushy->counter == 0); i < NUM_PUSHY_COLORS - 1; i++) + { + uint8_t n = esp_random() % (NUM_PUSHY_COLORS - pushy->counter - 1) + (pushy->counter == 0); +#endif #if LOGPUSHY printf("gonna swap the next two colors: %" PRIu8 ", %" PRIu8 "\n", i, n); #endif @@ -326,7 +467,7 @@ static void readButton(void) pushy->btnState = evt.state; // Check if the A button was pressed - if (evt.down && (PB_A == evt.button)) + if (evt.down && PB_A == evt.button) { pushy->counter++; pushy->fireCounter++; @@ -341,6 +482,39 @@ static void readButton(void) } } } + +#if VIDEO + if (pushy->btnState & PB_LEFT) + { + pushy->counter++; + pushy->fireCounter++; + pushy->buttonPushedUs = 0; + if (pushy->counter % SHUFFLE_AT_MOD == 0) + { + shuffleColors(); + } + } + if (pushy->btnState & PB_DOWN) + { + pushy->counter += 10; + pushy->fireCounter += 10; + pushy->buttonPushedUs = 0; + if (pushy->counter % SHUFFLE_AT_MOD == 0) + { + shuffleColors(); + } + } + if (pushy->btnState & PB_RIGHT) + { + pushy->counter += 100; + pushy->fireCounter += 100; + pushy->buttonPushedUs = 0; + if (pushy->counter % SHUFFLE_AT_MOD == 0) + { + shuffleColors(); + } + } +#endif } static void displayCounter(char const* counterStr) @@ -412,7 +586,11 @@ static void updateEffects(char const* counterStr) { for (int i = 0; i < NUM_PUSHY_COLORS; i++) { +#if !VIDEO pushy->rainbowHues[i] = (pushy->rainbowHues[i] + 2 % 255); +#else + pushy->rainbowHues[i] = (pushy->rainbowHues[i] + 8 % 255); +#endif } } @@ -461,7 +639,7 @@ static void displayFire(void) int count = getFireCount(); - led_t color = LedEHSVtoHEXhelper((uint8_t)(count / 2.5), 255, 250, true); + led_t color = LedEHSVtoHEXhelper((uint8_t)(count / 2.5), 255, 255, true); for (int i = 0; i < CONFIG_NUM_LEDS; i++) { diff --git a/main/modes/quickSettings/quickSettings.c b/main/modes/quickSettings/quickSettings.c index 2ccceac22..28cebe321 100644 --- a/main/modes/quickSettings/quickSettings.c +++ b/main/modes/quickSettings/quickSettings.c @@ -43,6 +43,7 @@ typedef struct bool showLeds; song_t jingle; void* buzzerState; + led_t ledState[CONFIG_NUM_LEDS + 1]; wsg_t iconGeneric; wsg_t iconSfxOn; @@ -171,13 +172,20 @@ static void quickSettingsEnterMode(void) // calloc() is used instead of malloc() because calloc() also initializes the allocated memory to zeros. quickSettings = calloc(1, sizeof(quickSettingsMenu_t)); - // Load a font - loadFont("ibm_vga8.font", &quickSettings->font, true); - // Save the buzzer state quickSettings->buzzerState = bzrSave(); bzrStop(true); + // Save the LED state + getLedState(quickSettings->ledState, CONFIG_NUM_LEDS + 1); + + // Clear the LEDs + led_t leds[CONFIG_NUM_LEDS] = {0}; + setLeds(leds, ARRAY_SIZE(leds)); + + // Load a font + loadFont("ibm_vga8.font", &quickSettings->font, true); + // Load the buzzer song loadSong("jingle.sng", &quickSettings->jingle, true); @@ -249,8 +257,14 @@ static void quickSettingsExitMode(void) // Free the buzzer song freeSong(&quickSettings->jingle); + bzrStop(true); + // Restore the buzzer state bzrRestore(quickSettings->buzzerState); + bzrResume(); + + // Restore the LED state + setLeds(quickSettings->ledState, CONFIG_NUM_LEDS + 1); // Free the font freeFont(&quickSettings->font); diff --git a/main/modes/ray/enemies/ray_enemy.c b/main/modes/ray/enemies/ray_enemy.c index d586f82b4..1c6d6abe8 100644 --- a/main/modes/ray/enemies/ray_enemy.c +++ b/main/modes/ray/enemies/ray_enemy.c @@ -11,6 +11,21 @@ #include "ray_enemy_hidden.h" #include "ray_enemy_boss.h" +//============================================================================== +// Typedefs +//============================================================================== + +typedef void (*rayEnemyMove_t)(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +typedef int32_t (*rayEnemyGetTimer_t)(rayEnemy_t* enemy, rayEnemyTimerType_t type); +typedef rayMapCellType_t (*rayEnemyGetBullet_t)(rayEnemy_t* enemy); + +typedef struct ray_enemy +{ + rayEnemyMove_t move; + rayEnemyGetTimer_t getTimer; + rayEnemyGetBullet_t getBullet; +} enemyFuncs_t; + //============================================================================== // Const data //============================================================================== @@ -22,36 +37,60 @@ static const enemyFuncs_t enemyFuncs[] = { { // OBJ_ENEMY_NORMAL - .moveAnimate = rayEnemyNormalMoveAnimate, - .getShot = rayEnemyNormalGetShot, + .move = rayEnemyNormalMove, + .getTimer = rayEnemyNormalGetTimer, + .getBullet = rayEnemyNormalGetBullet, }, { // OBJ_ENEMY_STRONG - .moveAnimate = rayEnemyStrongMoveAnimate, - .getShot = rayEnemyStrongGetShot, + .move = rayEnemyStrongMove, + .getTimer = rayEnemyStrongGetTimer, + .getBullet = rayEnemyStrongGetBullet, }, { // OBJ_ENEMY_ARMORED - .moveAnimate = rayEnemyArmoredMoveAnimate, - .getShot = rayEnemyArmoredGetShot, + .move = rayEnemyArmoredMove, + .getTimer = rayEnemyArmoredGetTimer, + .getBullet = rayEnemyArmoredGetBullet, }, { // OBJ_ENEMY_FLAMING - .moveAnimate = rayEnemyFlamingMoveAnimate, - .getShot = rayEnemyFlamingGetShot, + .move = rayEnemyFlamingMove, + .getTimer = rayEnemyFlamingGetTimer, + .getBullet = rayEnemyFlamingGetBullet, }, { // OBJ_ENEMY_HIDDEN - .moveAnimate = rayEnemyHiddenMoveAnimate, - .getShot = rayEnemyHiddenGetShot, + .move = rayEnemyHiddenMove, + .getTimer = rayEnemyHiddenGetTimer, + .getBullet = rayEnemyHiddenGetBullet, }, { // OBJ_ENEMY_BOSS - .moveAnimate = rayEnemyBossMoveAnimate, - .getShot = rayEnemyBossGetShot, + .move = rayEnemyBossMove, + .getTimer = rayEnemyBossGetTimer, + .getBullet = rayEnemyBossGetBullet, }, }; +// clang-format off +/** @brief Table of damage taken per enemy, per bullet, BOSS is not in here */ +static const uint32_t eDamageTable[5][5] = { + // OBJ_BULLET_NORMAL, OBJ_BULLET_CHARGE, OBJ_BULLET_ICE, OBJ_BULLET_MISSILE, OBJ_BULLET_XRAY + { 25, 100, 34, 100, 25,}, // OBJ_ENEMY_NORMAL + { 10, 100, 34, 50, 25,}, // OBJ_ENEMY_STRONG + { 10, 50, 25, 100, 25,}, // OBJ_ENEMY_ARMORED + { 10, 34, 50, 25, 25,}, // OBJ_ENEMY_FLAMING + { 0, 0, 0, 0, 50,}, // OBJ_ENEMY_HIDDEN +}; +// clang-format on + +//============================================================================== +// Function Prototypes +//============================================================================== + +static bool animateEnemy(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); + //============================================================================== // Functions //============================================================================== @@ -71,14 +110,185 @@ void rayEnemiesMoveAnimate(ray_t* ray, uint32_t elapsedUs) // Get a pointer from the linked list rayEnemy_t* enemy = ((rayEnemy_t*)currentNode->val); - // Move enemies and run timers like animation - enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].moveAnimate(ray, enemy, elapsedUs); + // If this enemy is warping in + if (0 < enemy->warpTimer) + { + // Run down the warp timer + enemy->warpTimer -= elapsedUs; + // Iterate to the next node and continue + currentNode = currentNode->next; + continue; + } - // Iterate to the next node - currentNode = currentNode->next; + // Copy the elapsed time in case the enemy is frozen + uint32_t eElapsedUs = elapsedUs; + + // If the enemy is frozen + if (0 < enemy->freezeTimer) + { + // Decrement the timer + enemy->freezeTimer -= eElapsedUs; + // Slow time for other timers + eElapsedUs /= 3; + } + + // Move enemies in the walking state, or if it's a non-dead boss + if ((E_WALKING_1 == enemy->state) || (E_WALKING_2 == enemy->state) + || ((OBJ_ENEMY_BOSS == enemy->c.type) && (E_DEAD != enemy->state))) + { + enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].move(ray, enemy, eElapsedUs); + } + + // Run other timers if not dead + if (E_DEAD != enemy->state) + { + // Run the shot timer down to zero + enemy->shootTimer -= eElapsedUs; + if (enemy->shootTimer <= 0) + { + // Try to transition to shooting + if (rayEnemyTransitionState(enemy, E_SHOOTING)) + { + // If successful, restart the shot timer + enemy->shootTimer = enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].getTimer(enemy, SHOT); + } + } + + // Run the block timer down to zero + enemy->blockTimer -= eElapsedUs; + if (enemy->blockTimer <= 0) + { + // Try to transition to blocking + if (rayEnemyTransitionState(enemy, E_BLOCKING)) + { + // If successful, restart the block timer + enemy->blockTimer = enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].getTimer(enemy, BLOCK); + } + } + + if (OBJ_ENEMY_BOSS == enemy->c.type) + { + // Special boss timer, pick a new weakness every 4s + enemy->bossTimer -= elapsedUs; + if (enemy->bossTimer <= 0) + { + enemy->bossTimer += 4000000; + + // Pick a new boss state + enemy->bossState + = (enemy->bossState + (1 + esp_random() % (NUM_BOSS_STATES - 1))) % NUM_BOSS_STATES; + + // Update all sprites the boss uses + if (B_NORMAL == enemy->bossState) + { + enemy->sprites = &ray->enemyTex[OBJ_ENEMY_BOSS - OBJ_ENEMY_NORMAL]; + } + else + { + enemy->sprites = &ray->bossTex[enemy->bossState]; + } + // Update the current sprite + enemy->c.sprite = &enemy->sprites[0][enemy->state][enemy->animFrame]; + } + } + + // Run the invincible timer down to zero + if (0 < enemy->invincibleTimer) + { + enemy->invincibleTimer -= eElapsedUs; + } + } + + // Animate the enemy + if (animateEnemy(ray, enemy, eElapsedUs)) + { + // Enemy was killed + checkScriptKill(ray, enemy->c.id, &enemy->sprites[0][E_WALKING_1][0]); + + // save the next node + node_t* nextNode = currentNode->next; + + // Remove the lock + if (ray->targetedObj == &(enemy->c)) + { + ray->targetedObj = NULL; + } + + // Randomly drop a pickup where the enemy was + switch (esp_random() % 4) + { + case 0: + { + // 25% health first + if (ray->p.i.health != ray->p.i.maxHealth) + { + rayCreateCommonObj(ray, OBJ_ITEM_PICKUP_ENERGY, 0x100, enemy->c.posX, enemy->c.posY); + } + // Only create if missiles are unlocked and health is at max + else if ((ray->p.i.missileLoadOut) && (ray->p.i.numMissiles != ray->p.i.maxNumMissiles)) + { + rayCreateCommonObj(ray, OBJ_ITEM_PICKUP_MISSILE, 0x100, enemy->c.posX, enemy->c.posY); + } + break; + } + case 1: + { + // 25% missiles first, if unlocked + if ((ray->p.i.missileLoadOut) && (ray->p.i.numMissiles != ray->p.i.maxNumMissiles)) + { + rayCreateCommonObj(ray, OBJ_ITEM_PICKUP_MISSILE, 0x100, enemy->c.posX, enemy->c.posY); + } + // Only create if missiles are at max + else if (ray->p.i.health != ray->p.i.maxHealth) + { + rayCreateCommonObj(ray, OBJ_ITEM_PICKUP_ENERGY, 0x100, enemy->c.posX, enemy->c.posY); + } + break; + } + default: + { + // No drop + break; + } + } + + // Unlink and free + removeEntry(&ray->enemies, currentNode); + free(enemy); + + // Set the next node + currentNode = nextNode; + } + else + { + // Iterate to the next node + currentNode = currentNode->next; + } } } +/** + * @brief Get the next shot timer for an enemy + * + * @param enemy The shooting enemy + * @return int32_t The time in uS until the next shot + */ +int32_t getTimerForEnemy(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].getTimer(enemy, type); +} + +/** + * @brief Get the bullet type for an enemy + * + * @param enemy The shooting enemy + * @return The bullet type + */ +rayMapCellType_t getBulletForEnemy(rayEnemy_t* enemy) +{ + return enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].getBullet(enemy); +} + /** * @brief This is called when an enemy is shot. It adds damage based on bullet type, checks scripts, and handles freeing * defeated enemies @@ -86,9 +296,231 @@ void rayEnemiesMoveAnimate(ray_t* ray, uint32_t elapsedUs) * @param ray The entire game state * @param enemy The enemy which was shot * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive */ -bool rayEnemyGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +void rayEnemyGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +{ + int32_t damageDivide = 1; + // Don't get shot when blocking or dying + if (E_BLOCKING == enemy->state) + { + if (OBJ_BULLET_MISSILE != bullet) + { + // Play SFX + bzrPlaySfx(&ray->sfx_e_block, BZR_RIGHT); + return; + } + else + { + // Missiles break the block, but do half damage + damageDivide = 2; + rayEnemyTransitionState(enemy, E_WALKING_1); + } + } + else if (E_DEAD == enemy->state) + { + // No SFX + return; + } + + // Don't get shot when invincible + // Ignore this for now, being invincible when in E_HURT is enough + // if (0 < enemy->invincibleTimer) + // { + // return; + // } + + // Figure out the damage for this shot + int32_t damage = 0; + if (OBJ_ENEMY_BOSS == enemy->c.type) + { + damage = rayEnemyBossGetShot(ray, enemy, bullet); + } + else + { + damage = eDamageTable[enemy->c.type - OBJ_ENEMY_NORMAL][bullet - OBJ_BULLET_NORMAL]; + } + + // Apply damage + enemy->health -= ((damage * ray->p.i.damageMult) / damageDivide); + + if (enemy->health <= 0) + { + // Transition to dying + rayEnemyTransitionState(enemy, E_DEAD); + // Play SFX + bzrPlaySfx(&ray->sfx_e_dead, BZR_RIGHT); + + // Make LEDs green + ray->ledHue = 85; + + // If the boss died + if (OBJ_ENEMY_BOSS == enemy->c.type) + { + // Resume normal music + bzrPlayBgm(&ray->songs[ray->p.mapId], BZR_STEREO); + } + } + // If the enemy took + else if (0 < damage) + { + // Transition to hurt + rayEnemyTransitionState(enemy, E_HURT); + + // Don't get stun-locked. Hurt animation is 200000*4, so double that + // enemy->invincibleTimer = 200000 * 8; + + // If it was ice damage + if (OBJ_BULLET_ICE == bullet) + { + // Slow it for a moment + enemy->freezeTimer = 3200000; + // Play SFX + bzrPlaySfx(&ray->sfx_e_freeze, BZR_RIGHT); + } + else + { + // Play SFX + bzrPlaySfx(&ray->sfx_e_damage, BZR_RIGHT); + } + + // Make LEDs green + ray->ledHue = 85; + } +} + +/** + * @brief Transition from the current animation state to the next + * + * @param enemy The enemy to transition + * @param newState The new state to transition to + * @return true if the transition was allowed, false if it was not + */ +bool rayEnemyTransitionState(rayEnemy_t* enemy, rayEnemyState_t newState) +{ + // clang-format off + const bool transitionTable[E_NUM_STATES][E_NUM_STATES] = { + {false, true, true, true, true, true }, // E_WALKING_1, don't transition to self + {true, false, true, true, true, true }, // E_WALKING_2, don't transition to self + {true, true, false, true , false, true }, // E_SHOOTING, transition to E_WALKING or E_HURT + {true, true, false, false, false, true }, // E_HURT, transition to E_WALKING or E_DEAD + {true, true, false, false, false, false}, // E_BLOCKING, transition to E_WALKING + {false, false, false, false, false, false} // E_DEAD, don't transition to anything + }; + // clang-format on + + if (transitionTable[enemy->state][newState]) + { + // Switch to the new state + enemy->state = newState; + enemy->animTimer = 0; + enemy->animFrame = 0; + enemy->animTimerLimit = 200000; + // Pick the sprites + enemy->c.sprite = &enemy->sprites[0][newState][0]; + if ((E_WALKING_1 == newState) || (E_WALKING_2 == newState)) + { + enemy->animTimerLimit = 125000; + } + return true; + } + return false; +} + +/** + * @brief Animate a single enemy + * + * @param ray The entire game state + * @param enemy The enemy to animate + * @param elapsedUs The elapsed time since this function was last called + * @return True if the enemy died, false if not + */ +static bool animateEnemy(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { - return enemyFuncs[enemy->c.type - OBJ_ENEMY_NORMAL].getShot(ray, enemy, bullet); + // Accumulate time + enemy->animTimer += elapsedUs; + // Check if it's time to transition states + if (enemy->animTimer >= enemy->animTimerLimit) + { + // Decrement timer + enemy->animTimer -= enemy->animTimerLimit; + + // Increment to the next frame + enemy->animFrame++; + + // If the animation is over + if (enemy->animFrame >= NUM_ANIM_FRAMES) + { + if (E_DEAD == enemy->state) + { + // Dead, caller unlinks and frees the enemy + return true; + } + else + { + if (E_WALKING_1 == enemy->state) + { + // Return to walking + rayEnemyTransitionState(enemy, E_WALKING_2); + } + else + { + // Return to walking + rayEnemyTransitionState(enemy, E_WALKING_1); + } + } + } + else + { + // Pick the next sprite + enemy->c.sprite = &enemy->sprites[0][enemy->state][enemy->animFrame]; + + // If this is the 3rd frame of shooting + if ((E_SHOOTING == enemy->state) && (2 == enemy->animFrame)) + { + // Spawn a bullet + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + fastNormVec(&xDiff, &yDiff); + rayCreateBullet(ray, getBulletForEnemy(enemy), enemy->c.posX, enemy->c.posY, xDiff, yDiff, false); + } + } + } + return false; } + +/** + * @brief Switch sprites for all enemies to the X-Ray alternate + * + * @param ray The entire game state + * @param isXray true to switch to X-Ray sprites, false to switch to normal sprites + */ +void switchEnemiesToXray(ray_t* ray, bool isXray) +{ + // Assign each enemy a distance from the player + node_t* currentNode = ray->enemies.first; + while (currentNode != NULL) + { + // Get a pointer from the linked list + rayEnemy_t* enemy = ((rayEnemy_t*)currentNode->val); + + // If this is a hidden enemy + if (OBJ_ENEMY_HIDDEN == enemy->c.type) + { + // Switch all the sprites + if (isXray) + { + enemy->sprites = &ray->hiddenXRTex; + } + else + { + enemy->sprites = &ray->enemyTex[OBJ_ENEMY_HIDDEN - OBJ_ENEMY_NORMAL]; + } + + // Switch the current sprite + enemy->c.sprite = &enemy->sprites[0][enemy->state][enemy->animFrame]; + } + + // Iterate to the next node + currentNode = currentNode->next; + } +} \ No newline at end of file diff --git a/main/modes/ray/enemies/ray_enemy.h b/main/modes/ray/enemies/ray_enemy.h index c3b12377b..699535277 100644 --- a/main/modes/ray/enemies/ray_enemy.h +++ b/main/modes/ray/enemies/ray_enemy.h @@ -1,15 +1,19 @@ #pragma once #include "mode_ray.h" +#include "ray_map.h" +#include "ray_object.h" -typedef void (*rayEnemyMoveAnimate_t)(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -typedef bool (*rayEnemyGetShot_t)(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); - -typedef struct ray_enemy +/// @brief Types of timers for enemy actions +typedef enum { - rayEnemyMoveAnimate_t moveAnimate; - rayEnemyGetShot_t getShot; -} enemyFuncs_t; + SHOT, ///< A timer for shooting + BLOCK, ///< A timer for blocking +} rayEnemyTimerType_t; void rayEnemiesMoveAnimate(ray_t* ray, uint32_t elapsedUs); -bool rayEnemyGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +bool rayEnemyTransitionState(rayEnemy_t* enemy, rayEnemyState_t newState); +void switchEnemiesToXray(ray_t* ray, bool isXray); +int32_t getTimerForEnemy(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t getBulletForEnemy(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_armored.c b/main/modes/ray/enemies/ray_enemy_armored.c index e85944231..a168b7b33 100644 --- a/main/modes/ray/enemies/ray_enemy_armored.c +++ b/main/modes/ray/enemies/ray_enemy_armored.c @@ -1,26 +1,130 @@ +#include "ray_enemy.h" #include "ray_enemy_armored.h" /** - * @brief Run timers for an armored enemy, which include AI, movement, and animation + * @brief Run timers for an armored enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyArmoredMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyArmoredMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // Pick an initial direction to move in + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + + // If the enemy is doing nothing + if (DOING_NOTHING == enemy->behavior) + { + // Move orthogonal to the player + if (ABS(xDiff) > ABS(yDiff)) + { + enemy->behavior = MOVE_POS_Y; + } + else + { + enemy->behavior = MOVE_POS_X; + } + } + +// Player is 40000 * 6 +#define SPEED_DENOM (int32_t)(40000 * 18) + + q24_8 delX = 0; + q24_8 delY = 0; + switch (enemy->behavior) + { + case MOVE_POS_X: + { + delX = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_NEG_X: + { + delX = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_POS_Y: + { + delY = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_NEG_Y: + { + delY = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + default: + { + // Do nothing + break; + } + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // Move if in bounds + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + enemy->c.posX += delX; + enemy->c.posY += delY; + } + else + { + // Bounce off walls + switch (enemy->behavior) + { + case MOVE_POS_X: + { + enemy->behavior = MOVE_NEG_X; + break; + } + case MOVE_NEG_X: + { + enemy->behavior = MOVE_POS_X; + break; + } + case MOVE_POS_Y: + { + enemy->behavior = MOVE_NEG_Y; + break; + } + case MOVE_NEG_Y: + { + enemy->behavior = MOVE_POS_Y; + break; + } + default: + { + // Do nothing + break; + } + } + } } /** - * @brief This is called when an armored enemy is shot. It adds damage based on bullet type, checks scripts, and handles - * freeing defeated enemies + * @brief Get the time until the next shot is taken * - * @param ray The entire game state - * @param enemy The enemy which was shot - * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot + */ +int32_t rayEnemyArmoredGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return 2000000 + (esp_random() % 2000000); +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type */ -bool rayEnemyArmoredGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +rayMapCellType_t rayEnemyArmoredGetBullet(rayEnemy_t* enemy) { - return false; + return OBJ_BULLET_E_ARMOR; } diff --git a/main/modes/ray/enemies/ray_enemy_armored.h b/main/modes/ray/enemies/ray_enemy_armored.h index 9b5840a0c..d70ce3bbf 100644 --- a/main/modes/ray/enemies/ray_enemy_armored.h +++ b/main/modes/ray/enemies/ray_enemy_armored.h @@ -2,5 +2,6 @@ #include "mode_ray.h" -void rayEnemyArmoredMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyArmoredGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyArmoredMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyArmoredGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyArmoredGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_boss.c b/main/modes/ray/enemies/ray_enemy_boss.c index dee8c3790..9c5dfec5d 100644 --- a/main/modes/ray/enemies/ray_enemy_boss.c +++ b/main/modes/ray/enemies/ray_enemy_boss.c @@ -1,14 +1,109 @@ +#include "ray_enemy.h" #include "ray_enemy_boss.h" /** - * @brief Run timers for a boss enemy, which include AI, movement, and animation + * @brief Run timers for a boss enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyBossMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyBossMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // Pick a new direction every 1s + enemy->behaviorTimer -= elapsedUs; + if (enemy->behaviorTimer <= 0) + { + enemy->behaviorTimer += 1000000; + + // Randomize movement + switch (esp_random() % 8) + { + case 0: + { + enemy->behavior = MOVE_AWAY_PLAYER; + break; + } + case 1 ... 2: + { + enemy->behavior = MOVE_STRAFE_R; + break; + } + case 3 ... 4: + { + enemy->behavior = MOVE_STRAFE_L; + break; + } + case 5 ... 7: + { + enemy->behavior = MOVE_TOWARDS_PLAYER; + break; + } + } + } + + // Reverse behavior if too close to the player + q24_8 xDist = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDist = SUB_FX(ray->p.posY, enemy->c.posY); + q24_8 distToPlayer = ADD_FX(MUL_FX(xDist, xDist), MUL_FX(yDist, yDist)); + if (distToPlayer < TO_FX(4) && (MOVE_TOWARDS_PLAYER == enemy->behavior)) + { + enemy->behavior = MOVE_AWAY_PLAYER; + } + + // Find the vector from the enemy to the player and normalize it + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + fastNormVec(&xDiff, &yDiff); + +// Player is 40000 * 6 +#define SPEED_DENOM (int32_t)(40000 * 9) + + q24_8 delX = 0; + q24_8 delY = 0; + switch (enemy->behavior) + { + case MOVE_AWAY_PLAYER: + { + delX = -(xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_TOWARDS_PLAYER: + { + delX = (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_STRAFE_L: + { + delX = (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_STRAFE_R: + { + delX = -(yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + default: + { + // Do nothing + break; + } + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // Move if in bounds + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + enemy->c.posX += delX; + enemy->c.posY += delY; + } } /** @@ -18,9 +113,96 @@ void rayEnemyBossMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) * @param ray The entire game state * @param enemy The enemy which was shot * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @return The damage for this shot in this state + */ +int32_t rayEnemyBossGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +{ + int32_t damage = 0; + switch (enemy->bossState) + { + case B_NORMAL: + { + if (OBJ_BULLET_NORMAL == bullet) + { + damage = 2; + } + else if (OBJ_BULLET_CHARGE == BULLET) + { + damage = 4; + } + break; + } + case B_MISSILE: + { + if (OBJ_BULLET_MISSILE == bullet) + { + damage = 2; + } + break; + } + case B_ICE: + { + if (OBJ_BULLET_ICE == bullet) + { + damage = 2; + } + break; + } + case B_XRAY: + { + if (OBJ_BULLET_XRAY == bullet) + { + damage = 2; + } + break; + } + default: + { + break; + } + } + + return damage; +} + +/** + * @brief Get the time until the next shot is taken + * + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot + */ +int32_t rayEnemyBossGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return 4 * 200000; +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type */ -bool rayEnemyBossGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +rayMapCellType_t rayEnemyBossGetBullet(rayEnemy_t* enemy) { - return false; + switch (enemy->bossState) + { + default: + case B_NORMAL: + { + return OBJ_BULLET_E_NORMAL; + } + case B_MISSILE: + { + return OBJ_BULLET_E_ARMOR; + } + case B_ICE: + { + return OBJ_BULLET_E_FLAMING; + } + case B_XRAY: + { + return OBJ_BULLET_E_HIDDEN; + } + } } diff --git a/main/modes/ray/enemies/ray_enemy_boss.h b/main/modes/ray/enemies/ray_enemy_boss.h index f95012c83..a75452a8a 100644 --- a/main/modes/ray/enemies/ray_enemy_boss.h +++ b/main/modes/ray/enemies/ray_enemy_boss.h @@ -2,5 +2,7 @@ #include "mode_ray.h" -void rayEnemyBossMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyBossGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyBossMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyBossGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +int32_t rayEnemyBossGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyBossGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_flaming.c b/main/modes/ray/enemies/ray_enemy_flaming.c index cd05f4719..3c423821d 100644 --- a/main/modes/ray/enemies/ray_enemy_flaming.c +++ b/main/modes/ray/enemies/ray_enemy_flaming.c @@ -1,26 +1,153 @@ +#include "ray_enemy.h" #include "ray_enemy_flaming.h" /** - * @brief Run timers for a flaming enemy, which include AI, movement, and animation + * @brief Run timers for a flaming enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyFlamingMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyFlamingMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // If the enemy is doing nothing + if (DOING_NOTHING == enemy->behavior) + { + // Pick a random starting direction + enemy->behavior = MOVE_NE + (esp_random() % 4); + } + +// Player is 40000 * 6 +#define SPEED_DENOM (int32_t)(40000 * 18) + + q24_8 delX = 0; + q24_8 delY = 0; + switch (enemy->behavior) + { + case MOVE_NE: + { + delX = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_SE: + { + delX = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_SW: + { + delX = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_NW: + { + delX = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + default: + { + break; + } + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // If the cell can be moved into + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + // Move into it + enemy->c.posX += delX; + enemy->c.posY += delY; + } + else if (!isPassableCell(&ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY)])) + { + // Collision on X axis, invert that + switch (enemy->behavior) + { + case MOVE_NE: + { + enemy->behavior = MOVE_NW; + break; + } + case MOVE_SE: + { + enemy->behavior = MOVE_SW; + break; + } + case MOVE_SW: + { + enemy->behavior = MOVE_SE; + break; + } + case MOVE_NW: + { + enemy->behavior = MOVE_NE; + break; + } + default: + { + break; + } + } + } + else + { + // Collision on Y axis, invert that + switch (enemy->behavior) + { + case MOVE_NE: + { + enemy->behavior = MOVE_SE; + break; + } + case MOVE_SE: + { + enemy->behavior = MOVE_NE; + break; + } + case MOVE_SW: + { + enemy->behavior = MOVE_NW; + break; + } + case MOVE_NW: + { + enemy->behavior = MOVE_SW; + break; + } + default: + { + break; + } + } + } } /** - * @brief This is called when a flaming enemy is shot. It adds damage based on bullet type, checks scripts, and handles - * freeing defeated enemies + * @brief Get the time until the next shot is taken * - * @param ray The entire game state - * @param enemy The enemy which was shot - * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot + */ +int32_t rayEnemyFlamingGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return 2000000 + (esp_random() % 2000000); +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type */ -bool rayEnemyFlamingGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +rayMapCellType_t rayEnemyFlamingGetBullet(rayEnemy_t* enemy) { - return false; + return OBJ_BULLET_E_FLAMING; } diff --git a/main/modes/ray/enemies/ray_enemy_flaming.h b/main/modes/ray/enemies/ray_enemy_flaming.h index 798b81f41..3e4e1fb8f 100644 --- a/main/modes/ray/enemies/ray_enemy_flaming.h +++ b/main/modes/ray/enemies/ray_enemy_flaming.h @@ -2,5 +2,6 @@ #include "mode_ray.h" -void rayEnemyFlamingMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyFlamingGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyFlamingMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyFlamingGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyFlamingGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_hidden.c b/main/modes/ray/enemies/ray_enemy_hidden.c index c52a3bfc5..81acc551a 100644 --- a/main/modes/ray/enemies/ray_enemy_hidden.c +++ b/main/modes/ray/enemies/ray_enemy_hidden.c @@ -1,26 +1,114 @@ +#include "ray_enemy.h" #include "ray_enemy_hidden.h" /** - * @brief Run timers for a hidden enemy, which include AI, movement, and animation + * @brief Run timers for a hidden enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyHiddenMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyHiddenMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // Pick a new direction every 1s + enemy->behaviorTimer -= elapsedUs; + if (enemy->behaviorTimer <= 0) + { + enemy->behaviorTimer += 1000000; + + // Randomize Strafe + if (esp_random() % 2) + { + enemy->behavior = MOVE_STRAFE_R; + } + else + { + enemy->behavior = MOVE_STRAFE_L; + } + } + + // Find the vector from the enemy to the player and normalize it + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + fastNormVec(&xDiff, &yDiff); + +// Player is 40000 * 6 +#define SPEED_DENOM_RETREAT (int32_t)(40000 * 6) +#define SPEED_DENOM_STRAFE (int32_t)(40000 * 16) + + q24_8 delX = 0; + q24_8 delY = 0; + + // Try to stay a constant-ish distance away + q24_8 xDist = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDist = SUB_FX(ray->p.posY, enemy->c.posY); + q24_8 distToPlayer = ADD_FX(MUL_FX(xDist, xDist), MUL_FX(yDist, yDist)); + if (distToPlayer < TO_FX(16)) + { + delX -= (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_RETREAT; + delY -= (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_RETREAT; + } + else if (distToPlayer > TO_FX(17)) + { + delX += (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_RETREAT; + delY += (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_RETREAT; + } + + // Do some strafing + if (MOVE_STRAFE_L == enemy->behavior) + { + delX += (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_STRAFE; + delY -= (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_STRAFE; + } + else + { + delX -= (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_STRAFE; + delY += (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM_STRAFE; + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // Move if in bounds + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + enemy->c.posX += delX; + enemy->c.posY += delY; + } + else + { + // Could not move into wall, reverse the strafe + if (MOVE_STRAFE_L == enemy->behavior) + { + enemy->behavior = MOVE_STRAFE_R; + } + else + { + enemy->behavior = MOVE_STRAFE_L; + } + } } /** - * @brief This is called when a hidden enemy is shot. It adds damage based on bullet type, checks scripts, and handles - * freeing defeated enemies + * @brief Get the time until the next shot is taken * - * @param ray The entire game state - * @param enemy The enemy which was shot - * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot + */ +int32_t rayEnemyHiddenGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return 2000000 + (esp_random() % 2000000); +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type */ -bool rayEnemyHiddenGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +rayMapCellType_t rayEnemyHiddenGetBullet(rayEnemy_t* enemy) { - return false; + return OBJ_BULLET_E_HIDDEN; } diff --git a/main/modes/ray/enemies/ray_enemy_hidden.h b/main/modes/ray/enemies/ray_enemy_hidden.h index 0bd2f1872..fa19b585c 100644 --- a/main/modes/ray/enemies/ray_enemy_hidden.h +++ b/main/modes/ray/enemies/ray_enemy_hidden.h @@ -2,5 +2,6 @@ #include "mode_ray.h" -void rayEnemyHiddenMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyHiddenGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyHiddenMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyHiddenGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyHiddenGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_normal.c b/main/modes/ray/enemies/ray_enemy_normal.c index 76cafe18b..3a524a413 100644 --- a/main/modes/ray/enemies/ray_enemy_normal.c +++ b/main/modes/ray/enemies/ray_enemy_normal.c @@ -1,26 +1,151 @@ +#include "ray_enemy.h" #include "ray_enemy_normal.h" /** - * @brief Run timers for a normal enemy, which include AI, movement, and animation + * @brief Run timers for a normal enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyNormalMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyNormalMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // Pick a new direction every 2s + enemy->behaviorTimer -= elapsedUs; + if (enemy->behaviorTimer <= 0) + { + enemy->behaviorTimer += 2000000; + + // Find the vector from the enemy to the player and normalize it + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + + // Pick the movement direction on the grid + if (esp_random() % 2 == 0) + { + if (xDiff > 0) + { + enemy->behavior = MOVE_POS_X; + } + else + { + enemy->behavior = MOVE_NEG_X; + } + } + else + { + if (yDiff > 0) + { + enemy->behavior = MOVE_POS_Y; + } + else + { + enemy->behavior = MOVE_NEG_Y; + } + } + } + + // Reverse behavior if too close to the player + q24_8 xDist = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDist = SUB_FX(ray->p.posY, enemy->c.posY); + q24_8 distToPlayer = ADD_FX(MUL_FX(xDist, xDist), MUL_FX(yDist, yDist)); + if (distToPlayer < TO_FX(4)) + { + switch (enemy->behavior) + { + case MOVE_POS_X: + { + enemy->behavior = MOVE_NEG_X; + break; + } + case MOVE_NEG_X: + { + enemy->behavior = MOVE_POS_X; + break; + } + case MOVE_POS_Y: + { + enemy->behavior = MOVE_NEG_Y; + break; + } + case MOVE_NEG_Y: + { + enemy->behavior = MOVE_POS_Y; + break; + } + default: + { + // Do nothing + break; + } + } + } + +// Player is 40000 * 6 +#define SPEED_DENOM (int32_t)(40000 * 18) + + q24_8 delX = 0; + q24_8 delY = 0; + switch (enemy->behavior) + { + case MOVE_POS_X: + { + delX = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_NEG_X: + { + delX = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_POS_Y: + { + delY = (TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_NEG_Y: + { + delY = -(TO_FX(1) * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + default: + { + // Do nothing + break; + } + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // Move if in bounds + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + enemy->c.posX += delX; + enemy->c.posY += delY; + } } /** - * @brief This is called when a normal enemy is shot. It adds damage based on bullet type, checks scripts, and handles - * freeing defeated enemies + * @brief Get the time until the next shot is taken * - * @param ray The entire game state - * @param enemy The enemy which was shot - * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot + */ +int32_t rayEnemyNormalGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) +{ + return 2000000 + (esp_random() % 2000000); +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type */ -bool rayEnemyNormalGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +rayMapCellType_t rayEnemyNormalGetBullet(rayEnemy_t* enemy) { - return true; + return OBJ_BULLET_E_NORMAL; } diff --git a/main/modes/ray/enemies/ray_enemy_normal.h b/main/modes/ray/enemies/ray_enemy_normal.h index f8f68770c..1cf3aceab 100644 --- a/main/modes/ray/enemies/ray_enemy_normal.h +++ b/main/modes/ray/enemies/ray_enemy_normal.h @@ -2,5 +2,6 @@ #include "mode_ray.h" -void rayEnemyNormalMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyNormalGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyNormalMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyNormalGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyNormalGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/enemies/ray_enemy_strong.c b/main/modes/ray/enemies/ray_enemy_strong.c index d139f5e35..cfd9cc97c 100644 --- a/main/modes/ray/enemies/ray_enemy_strong.c +++ b/main/modes/ray/enemies/ray_enemy_strong.c @@ -1,30 +1,130 @@ +#include "ray_enemy.h" #include "ray_enemy_strong.h" /** - * @brief Run timers for a strong enemy, which include AI, movement, and animation + * @brief Run timers for a strong enemy, which include AI, and movement * * @param ray The entire game state * @param enemy The enemy to run timers for * @param elapsedUs The elapsed time since this function was last called */ -void rayEnemyStrongMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) +void rayEnemyStrongMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs) { + // Pick a new direction every 2s + enemy->behaviorTimer -= elapsedUs; + if (enemy->behaviorTimer <= 0) + { + enemy->behaviorTimer += 2000000; + + // Randomize movement + switch (esp_random() % 8) + { + case 0: + { + enemy->behavior = MOVE_AWAY_PLAYER; + break; + } + case 1 ... 2: + { + enemy->behavior = MOVE_STRAFE_R; + break; + } + case 3 ... 4: + { + enemy->behavior = MOVE_STRAFE_L; + break; + } + case 5 ... 7: + { + enemy->behavior = MOVE_TOWARDS_PLAYER; + break; + } + } + } + + // Reverse behavior if too close to the player + q24_8 xDist = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDist = SUB_FX(ray->p.posY, enemy->c.posY); + q24_8 distToPlayer = ADD_FX(MUL_FX(xDist, xDist), MUL_FX(yDist, yDist)); + if (distToPlayer < TO_FX(4) && (MOVE_TOWARDS_PLAYER == enemy->behavior)) + { + enemy->behavior = MOVE_AWAY_PLAYER; + } + + // Find the vector from the enemy to the player and normalize it + q24_8 xDiff = SUB_FX(ray->p.posX, enemy->c.posX); + q24_8 yDiff = SUB_FX(ray->p.posY, enemy->c.posY); + fastNormVec(&xDiff, &yDiff); + +// Player is 40000 * 6 +#define SPEED_DENOM (int32_t)(40000 * 18) + + q24_8 delX = 0; + q24_8 delY = 0; + switch (enemy->behavior) + { + case MOVE_AWAY_PLAYER: + { + delX = -(xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_TOWARDS_PLAYER: + { + delX = (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_STRAFE_L: + { + delX = (yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = -(xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + case MOVE_STRAFE_R: + { + delX = -(yDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + delY = (xDiff * (int32_t)(elapsedUs)) / SPEED_DENOM; + break; + } + default: + { + // Do nothing + break; + } + } + + q24_8 marginX = (delX > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + q24_8 marginY = (delY > 0 ? 1 : -1) * TO_FX_FRAC(1, 2); + + // Move if in bounds + if (isPassableCell( + &ray->map.tiles[FROM_FX(enemy->c.posX + delX + marginX)][FROM_FX(enemy->c.posY + delY + marginY)])) + { + enemy->c.posX += delX; + enemy->c.posY += delY; + } } /** - * @brief This is called when a strong enemy is shot. It adds damage based on bullet type, checks scripts, and handles - * freeing defeated enemies + * @brief Get the time until the next shot is taken * - * @param ray The entire game state - * @param enemy The enemy which was shot - * @param bullet The type of bullet it was shot by - * @return true if the enemy was killed, false if it's still alive + * @param enemy The enemy taking the shot + * @param type the timer of timer to get + * @return The time, in uS, until the next shot */ -bool rayEnemyStrongGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet) +int32_t rayEnemyStrongGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type) { - if (OBJ_BULLET_CHARGE == bullet) - { - return true; - } - return false; + return 2000000 + (esp_random() % 2000000); +} + +/** + * @brief Get the bullet this enemy fires + * + * @param enemy The shooting enemy + * @return The bullet type + */ +rayMapCellType_t rayEnemyStrongGetBullet(rayEnemy_t* enemy) +{ + return OBJ_BULLET_E_STRONG; } diff --git a/main/modes/ray/enemies/ray_enemy_strong.h b/main/modes/ray/enemies/ray_enemy_strong.h index d53ac5d20..e4652ef91 100644 --- a/main/modes/ray/enemies/ray_enemy_strong.h +++ b/main/modes/ray/enemies/ray_enemy_strong.h @@ -2,5 +2,6 @@ #include "mode_ray.h" -void rayEnemyStrongMoveAnimate(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); -bool rayEnemyStrongGetShot(ray_t* ray, rayEnemy_t* enemy, rayMapCellType_t bullet); +void rayEnemyStrongMove(ray_t* ray, rayEnemy_t* enemy, uint32_t elapsedUs); +int32_t rayEnemyStrongGetTimer(rayEnemy_t* enemy, rayEnemyTimerType_t type); +rayMapCellType_t rayEnemyStrongGetBullet(rayEnemy_t* enemy); diff --git a/main/modes/ray/fp_math.c b/main/modes/ray/fp_math.c index 90c251ee5..3bb2083a8 100644 --- a/main/modes/ray/fp_math.c +++ b/main/modes/ray/fp_math.c @@ -16,20 +16,20 @@ * Outputs are in the range [0x00, 0xB5], equivalent to [0, sqrt(2)] */ static const uint8_t ratioToXLut[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, - 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - 0x26, 0x27, 0x28, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4A, 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x57, 0x58, - 0x59, 0x5A, 0x5B, 0x5C, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x60, 0x61, 0x62, 0x63, 0x64, 0x64, 0x65, 0x66, 0x67, 0x67, - 0x68, 0x69, 0x6A, 0x6A, 0x6B, 0x6C, 0x6D, 0x6D, 0x6E, 0x6F, 0x70, 0x70, 0x71, 0x72, 0x72, 0x73, 0x74, 0x75, 0x75, - 0x76, 0x77, 0x77, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x81, 0x81, 0x82, - 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x86, 0x87, 0x88, 0x88, 0x89, 0x89, 0x8A, 0x8B, 0x8B, 0x8C, 0x8C, 0x8D, 0x8E, - 0x8E, 0x8F, 0x8F, 0x90, 0x90, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x97, 0x98, 0x98, - 0x99, 0x99, 0x9A, 0x9A, 0x9B, 0x9B, 0x9C, 0x9C, 0x9D, 0x9D, 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, - 0xA2, 0xA2, 0xA3, 0xA3, 0xA4, 0xA4, 0xA5, 0xA5, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA8, 0xA8, 0xA9, 0xA9, 0xA9, 0xAA, - 0xAA, 0xAB, 0xAB, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAF, 0xAF, 0xAF, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, - 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB5, 0xB5, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x61, 0x62, 0x63, 0x64, 0x65, 0x65, 0x66, 0x67, + 0x68, 0x68, 0x69, 0x6A, 0x6B, 0x6B, 0x6C, 0x6D, 0x6E, 0x6E, 0x6F, 0x70, 0x71, 0x71, 0x72, 0x73, 0x73, 0x74, 0x75, + 0x76, 0x76, 0x77, 0x78, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0x80, 0x80, 0x81, 0x82, + 0x82, 0x83, 0x83, 0x84, 0x85, 0x85, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x8A, 0x8A, 0x8B, 0x8B, 0x8C, 0x8D, 0x8D, + 0x8E, 0x8E, 0x8F, 0x8F, 0x90, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x95, 0x95, 0x96, 0x97, 0x97, 0x98, + 0x98, 0x99, 0x99, 0x9A, 0x9A, 0x9B, 0x9B, 0x9C, 0x9C, 0x9D, 0x9D, 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA0, 0xA0, 0xA1, + 0xA1, 0xA2, 0xA2, 0xA3, 0xA3, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA6, 0xA6, 0xA7, 0xA7, 0xA8, 0xA8, 0xA9, 0xA9, 0xA9, + 0xAA, 0xAA, 0xAB, 0xAB, 0xAB, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAF, 0xAF, 0xAF, 0xB0, 0xB0, 0xB1, 0xB1, + 0xB1, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB5, }; /** @@ -42,16 +42,16 @@ static const uint8_t ratioToXLut[] = { * Values of 0x00 in this table must be treated as 0x0100. This is so values can be 8 bit */ static const uint8_t complNormLut[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, - 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, - 0xFA, 0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF7, 0xF7, 0xF7, 0xF7, 0xF6, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, - 0xF4, 0xF4, 0xF4, 0xF4, 0xF3, 0xF3, 0xF3, 0xF2, 0xF2, 0xF1, 0xF1, 0xF1, 0xF0, 0xF0, 0xF0, 0xEF, 0xEF, 0xEF, 0xEE, - 0xEE, 0xED, 0xED, 0xEC, 0xEC, 0xEC, 0xEB, 0xEB, 0xEA, 0xEA, 0xE9, 0xE9, 0xE9, 0xE8, 0xE8, 0xE7, 0xE7, 0xE6, 0xE6, - 0xE5, 0xE5, 0xE4, 0xE4, 0xE3, 0xE3, 0xE2, 0xE2, 0xE1, 0xE1, 0xE0, 0xDF, 0xDF, 0xDE, 0xDE, 0xDD, 0xDD, 0xDC, 0xDB, - 0xDB, 0xDA, 0xDA, 0xD9, 0xD8, 0xD8, 0xD7, 0xD6, 0xD6, 0xD5, 0xD4, 0xD4, 0xD3, 0xD2, 0xD2, 0xD1, 0xD0, 0xCF, 0xCF, - 0xCE, 0xCD, 0xCC, 0xCC, 0xCB, 0xCA, 0xC9, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0, 0xBF, - 0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, 0xF8, 0xF8, 0xF7, 0xF7, 0xF7, 0xF7, 0xF6, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, 0xF5, 0xF4, + 0xF4, 0xF4, 0xF3, 0xF3, 0xF3, 0xF2, 0xF2, 0xF2, 0xF1, 0xF1, 0xF1, 0xF0, 0xF0, 0xF0, 0xEF, 0xEF, 0xEE, 0xEE, 0xEE, + 0xED, 0xED, 0xEC, 0xEC, 0xEC, 0xEB, 0xEB, 0xEA, 0xEA, 0xE9, 0xE9, 0xE9, 0xE8, 0xE8, 0xE7, 0xE7, 0xE6, 0xE6, 0xE5, + 0xE5, 0xE4, 0xE4, 0xE3, 0xE3, 0xE2, 0xE2, 0xE1, 0xE1, 0xE0, 0xDF, 0xDF, 0xDE, 0xDE, 0xDD, 0xDD, 0xDC, 0xDB, 0xDB, + 0xDA, 0xDA, 0xD9, 0xD8, 0xD8, 0xD7, 0xD6, 0xD6, 0xD5, 0xD5, 0xD4, 0xD3, 0xD2, 0xD2, 0xD1, 0xD0, 0xD0, 0xCF, 0xCE, + 0xCD, 0xCD, 0xCC, 0xCB, 0xCA, 0xCA, 0xC9, 0xC8, 0xC7, 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC2, 0xC1, 0xC0, 0xBF, + 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB7, 0xB6, 0xB5, }; //============================================================================== @@ -148,6 +148,10 @@ void fastNormVec(q24_8* xp, q24_8* yp) #ifdef LUT_GEN_FUNCS + #include + #include + #include + typedef struct { int32_t x; @@ -155,6 +159,97 @@ typedef struct float err; } testResult_t; +/** + * @brief Convert a floating point to q24_8 + * + * @param fl Floating point input + * @return Fixed point output + */ +q24_8 floatToFix(float fl) +{ + int sign = (fl >= 0) ? 1 : -1; + fl *= sign; + + q24_8 fx = (q24_8)((int32_t)fl * (1 << FRAC_BITS)); + + float deciPart = fl - (int)fl; + + float deciBit = 0.5f; + for (int i = 0; i < 8; i++) + { + if (deciPart >= deciBit) + { + deciPart -= deciBit; + fx = fx | (0x80 >> i); + } + deciBit /= 2; + } + return fx * sign; +} + +/** + * @brief Convert a q24_8 to floating point + * + * @param fx Fixed point input + * @return Floating point output + */ +float fixToFloat(q24_8 fx) +{ + float fl = (float)(fx / (1 << FRAC_BITS)); + + if (fx >= 0) + { + float decimal = 0.5f; + for (int i = 7; i >= 0; i--) + { + if (fx & (1 << i)) + { + fl += (decimal); + } + decimal /= 2; + } + } + else + { + if (0 != (fx & 0xFF)) + { + fl -= 1 / 256.0f; + float decimal = 0.5f; + for (int i = 7; i >= 0; i--) + { + if (!(fx & (1 << i))) + { + fl -= (decimal); + } + decimal /= 2; + } + } + } + return fl; +} + +/** + * @brief Function to convert from a ratio between X and Y vectors to the normalized length of the X vector + * + * @param x The ratio between X and Y vector lengths + * @return float The normalized X vector + */ +float ratioToX(float r) +{ + return r / sqrt((r * r) + 1); +} + +/** + * @brief Lookup table to find the complimentary Y vector for a normalized X vector + * + * @param x The normalized X vector + * @return The Y vector + */ +float complNorm(float x) +{ + return sqrt(1 - (x * x)); +} + /** * @brief Comparator function to sort testResult_t by error * diff --git a/main/modes/ray/mode_ray.c b/main/modes/ray/mode_ray.c index 1b404e799..54cb26d5c 100644 --- a/main/modes/ray/mode_ray.c +++ b/main/modes/ray/mode_ray.c @@ -14,6 +14,8 @@ #include "ray_pause.h" #include "ray_script.h" #include "ray_warp_screen.h" +#include "ray_death_screen.h" +#include "ray_credits.h" //============================================================================== // Function Prototypes @@ -24,7 +26,7 @@ static void rayExitMode(void); static void rayMainLoop(int64_t elapsedUs); static void rayBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h, int16_t up, int16_t upNum); static void rayMenuCb(const char* label, bool selected, uint32_t settingVal); -static void rayStartGame(void); +static void rayInitMenu(void); //============================================================================== // Const Variables @@ -34,11 +36,12 @@ const char rayName[] = "Magtroid Pocket"; const char rayPlayStr[] = "Play"; const char rayResetStr[] = "Reset Data"; const char rayConfirmStr[] = "Really Reset Data"; +const char rayCreditsStr[] = "Credits"; const char rayExitStr[] = "Exit"; /// @brief A list of the map names const char* const rayMapNames[] = { - "World 0", "World 1", "World 2", "World 3", "World 4", "World 5", + "Station Zero", "Vinegrasp", "Floriss", "Station One", "Mosspire", "Scalderia", }; /// @brief A list of the map colors, in order @@ -51,11 +54,18 @@ const paletteColor_t rayMapColors[] = { c500, // Red }; +/// @brief The songs to play, must be in map order +const char* const songFiles[] + = {"base_0.sng", "jungle_0.sng", "cave_0.sng", "base_1.sng", "jungle_1.sng", "cave_1.sng", "ray_boss.sng"}; + /// @brief The NVS key to save and load player data const char RAY_NVS_KEY[] = "ray"; // The NVS key to save and load visited tiles const char* const RAY_NVS_VISITED_KEYS[] = {"rv0", "rv1", "rv2", "rv3", "rv4", "rv5"}; +/// @brief The NVS key to unlock Sip on the menu +const char MAGTROID_UNLOCK_KEY[] = "zip_unlock"; + //============================================================================== // Variables //============================================================================== @@ -91,33 +101,61 @@ static void rayEnterMode(void) // Allocate memory ray = calloc(1, sizeof(ray_t)); - // Initialize the menu - ray->menu = initMenu(rayName, rayMenuCb); - addSingleItemToMenu(ray->menu, rayPlayStr); - ray->menu = startSubMenu(ray->menu, rayResetStr); - addSingleItemToMenu(ray->menu, rayConfirmStr); - ray->menu = endSubMenu(ray->menu); - addSingleItemToMenu(ray->menu, rayExitStr); - // Load fonts loadFont("logbook.font", &ray->logbook, true); loadFont("ibm_vga8.font", &ray->ibm, true); - // Initialize a renderer - ray->renderer = initMenuLogbookRenderer(&ray->logbook); + // Initialize the menu + rayInitMenu(); + + // Force draw a loading screen + fillDisplayArea(0, 0, TFT_WIDTH, TFT_HEIGHT, c100); + const char loadingStr[] = "Loading..."; + int32_t tWidth = textWidth(&ray->logbook, loadingStr); + drawText(&ray->logbook, c542, loadingStr, (TFT_WIDTH - tWidth) / 2, (TFT_HEIGHT - ray->logbook.height) / 2); + drawDisplayTft(NULL); // Initialize texture manager and environment textures loadEnvTextures(ray); - // Initialize enemy templates and textures - initEnemyTemplates(ray); + // Load songs + for (int32_t sIdx = 0; sIdx < ARRAY_SIZE(songFiles); sIdx++) + { + loadSong(songFiles[sIdx], &ray->songs[sIdx], false); + ray->songs[sIdx].shouldLoop = true; + } + + // Load SFX + loadSong("r_door_open.sng", &ray->sfx_door_open, false); + loadSong("r_e_damage.sng", &ray->sfx_e_damage, false); + loadSong("r_e_freeze.sng", &ray->sfx_e_freeze, false); + loadSong("r_p_charge.sng", &ray->sfx_p_charge, false); + loadSong("r_p_damage.sng", &ray->sfx_p_damage, false); + loadSong("r_p_shoot.sng", &ray->sfx_p_shoot, false); + loadSong("r_e_block.sng", &ray->sfx_e_block, false); + loadSong("r_e_dead.sng", &ray->sfx_e_dead, false); + loadSong("r_item_get.sng", &ray->sfx_item_get, false); + loadSong("r_p_charge_start.sng", &ray->sfx_p_charge_start, false); + loadSong("r_p_missile.sng", &ray->sfx_p_missile, false); + loadSong("r_p_ice.sng", &ray->sfx_p_ice, false); + loadSong("r_p_xray.sng", &ray->sfx_p_xray, false); + loadSong("r_warp.sng", &ray->sfx_warp, false); + loadSong("r_lava_dmg.sng", &ray->sfx_lava_dmg, false); + loadSong("r_health.sng", &ray->sfx_health, false); + loadSong("r_game_over.sng", &ray->sfx_game_over, false); // Set the menu as the screen - ray->screen = RAY_MENU; + raySwitchToScreen(RAY_MENU); + + // Start a blink for dialog and pause and such + ray->blinkTimer = BLINK_US; // Turn off LEDs led_t leds[CONFIG_NUM_LEDS] = {0}; setLeds(leds, CONFIG_NUM_LEDS); + + // Set frame rate to 60 FPS + setFrameRateUs(16666); } /** @@ -135,6 +173,31 @@ static void rayExitMode(void) // Free the textures freeAllTex(ray); + // Free songs + for (int32_t sIdx = 0; sIdx < ARRAY_SIZE(songFiles); sIdx++) + { + freeSong(&ray->songs[sIdx]); + } + + // Free SFX + freeSong(&ray->sfx_door_open); + freeSong(&ray->sfx_e_damage); + freeSong(&ray->sfx_e_freeze); + freeSong(&ray->sfx_p_charge); + freeSong(&ray->sfx_p_damage); + freeSong(&ray->sfx_p_shoot); + freeSong(&ray->sfx_e_block); + freeSong(&ray->sfx_e_dead); + freeSong(&ray->sfx_item_get); + freeSong(&ray->sfx_p_charge_start); + freeSong(&ray->sfx_p_missile); + freeSong(&ray->sfx_p_ice); + freeSong(&ray->sfx_p_xray); + freeSong(&ray->sfx_warp); + freeSong(&ray->sfx_lava_dmg); + freeSong(&ray->sfx_health); + freeSong(&ray->sfx_game_over); + // Free the font freeFont(&ray->ibm); freeFont(&ray->logbook); @@ -150,6 +213,37 @@ static void rayExitMode(void) */ void rayFreeCurrentState(ray_t* cRay) { + // Zero and NULL the door timer + ray->doorTimer = 0; + // Head bob + ray->posZ = 0; + ray->bobTimer = 0; + ray->bobCount = 0; + // Gun shake + ray->gunShakeL = false; + ray->gunShakeTimer = 0; + ray->gunShakeX = 0; + // Strafe and lock + ray->isStrafing = false; + ray->targetedObj = NULL; + // Player timers + ray->floorEffectTimer = 0; + ray->chargeTimer = 0; + ray->pRotationTimer = 0; + ray->playerInLava = false; + // Dialog variables + ray->dialogText = NULL; + ray->nextDialogText = NULL; + ray->dialogPortrait = NULL; + ray->btnLockoutUs = 0; + // Pause menu variables + ray->blinkTimer = 0; + ray->blink = false; + // Item rotation + ray->itemRotateTimer = 0; + ray->itemRotateDeg = 0; + ray->itemRotateMirror = false; + // Set invalid IDs for all bullets for (uint16_t objIdx = 0; objIdx < MAX_RAY_BULLETS; objIdx++) { @@ -188,6 +282,83 @@ void rayFreeCurrentState(ray_t* cRay) */ static void rayMainLoop(int64_t elapsedUs) { + // Run a button lockout, regardless of mode + if (0 < ray->btnLockoutUs) + { + ray->btnLockoutUs -= elapsedUs; + if (0 >= ray->btnLockoutUs) + { + ray->btnLockoutUs = 0; + // Restart blinks when the lockout ends + ray->blink = true; + ray->blinkTimer = BLINK_US; + } + } + + // Run a timer to blink things + ray->blinkTimer -= elapsedUs; + while (0 >= ray->blinkTimer) + { + ray->blink = !ray->blink; + ray->blinkTimer += BLINK_US; + } + + // 0 is red + // 85 is green + // 170 is blue + // If the LED is not at the target hue + if (ray->ledHue != ray->targetLedHue) + { + ray->ledTimer -= elapsedUs; + while (0 >= ray->ledTimer) + { + ray->ledTimer += 7812; + + // Find the decision point to either increment or decrement to the target + int32_t decisionPoint = (ray->targetLedHue + 128) % 256; + bool shouldIncrement = false; + if (decisionPoint < ray->targetLedHue) + { + if ((decisionPoint < ray->ledHue) && (ray->ledHue < ray->targetLedHue)) + { + shouldIncrement = true; + } + else + { + shouldIncrement = false; + } + } + else + { + if ((ray->targetLedHue < ray->ledHue) && (ray->ledHue < decisionPoint)) + { + shouldIncrement = false; + } + else + { + shouldIncrement = true; + } + } + + // Adjust the hue with wraparound + if (shouldIncrement) + { + ray->ledHue = (ray->ledHue + 1) % 255; + } + else + { + if (0 == ray->ledHue) + { + ray->ledHue = 255; + } + else + { + ray->ledHue--; + } + } + } + } + switch (ray->screen) { case RAY_MENU: @@ -215,21 +386,25 @@ static void rayMainLoop(int64_t elapsedUs) // Draw the walls after floor & ceiling castWalls(ray); // Draw sprites after walls - rayObjCommon_t* centeredSprite = castSprites(ray); + rayEnemy_t* closestEnemy = NULL; + rayObjCommon_t* centeredEnemy = castSprites(ray, &closestEnemy); // Draw the HUD after sprites drawHud(ray); + // Light LEDs, radar to the closest enemy + rayLightLeds(ray, closestEnemy); + // Run timers for head-bob, doors, etc. runEnvTimers(ray, elapsedUs); // Check buttons for the player and move player accordingly - rayPlayerCheckButtons(ray, centeredSprite, elapsedUs); + rayPlayerCheckButtons(ray, centeredEnemy, elapsedUs); // Check the joystick for the player and update loadout accordingly rayPlayerCheckJoystick(ray, elapsedUs); - // Check for lava damage - rayPlayerCheckLava(ray, elapsedUs); + // Check for floor effects + rayPlayerCheckFloorEffect(ray, elapsedUs); // Move objects including enemies and bullets moveRayObjects(ray, elapsedUs); @@ -238,17 +413,13 @@ static void rayMainLoop(int64_t elapsedUs) checkRayCollisions(ray); // Check for time-based scripts - if (checkScriptTime(ray, elapsedUs)) - { - // Script warped, return - return; - } + checkScriptTime(ray, elapsedUs); // If the warp timer is active if (ray->warpTimerUs > 0) { // Switch to showing the warp screen - ray->screen = RAY_WARP_SCREEN; + raySwitchToScreen(RAY_WARP_SCREEN); // Do the warp in the background warpToDestination(ray); } @@ -258,7 +429,7 @@ static void rayMainLoop(int64_t elapsedUs) case RAY_DIALOG: { // Render first - rayDialogRender(ray); + rayDialogRender(ray, elapsedUs); // Then check buttons rayDialogCheckButtons(ray); break; @@ -277,6 +448,16 @@ static void rayMainLoop(int64_t elapsedUs) rayWarpScreenRender(ray, elapsedUs); break; } + case RAY_DEATH_SCREEN: + { + rayDeathScreenRender(ray, elapsedUs); + break; + } + case RAY_CREDITS: + { + rayCreditsRender(ray, elapsedUs); + break; + } } } @@ -297,6 +478,9 @@ static void rayBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h { case RAY_MENU: case RAY_DIALOG: + case RAY_DEATH_SCREEN: + case RAY_PAUSE: + case RAY_CREDITS: { // Do nothing break; @@ -307,12 +491,6 @@ static void rayBackgroundDrawCallback(int16_t x, int16_t y, int16_t w, int16_t h castFloorCeiling(ray, y, y + h); break; } - case RAY_PAUSE: - { - // Draw a black background - fillDisplayArea(x, y, x + w, y + h, c000); - break; - } case RAY_WARP_SCREEN: { drawWarpBackground(x, y, w, h); @@ -347,6 +525,10 @@ static void rayMenuCb(const char* label, bool selected, uint32_t settingVal) // Return up one menu ray->wasReset = true; } + else if (label == rayCreditsStr) + { + rayShowCredits(ray); + } else if (label == rayExitStr) { switchToSwadgeMode(&mainMenuMode); @@ -357,8 +539,11 @@ static void rayMenuCb(const char* label, bool selected, uint32_t settingVal) /** * @brief Start the game from the menu */ -static void rayStartGame(void) +void rayStartGame(void) { + // Stop the buzzer to not interfere with loading data + bzrStop(true); + // Clear all lists rayFreeCurrentState(ray); @@ -366,12 +551,8 @@ static void rayStartGame(void) bool initFromScratch = initializePlayer(ray); // Load the map and object data - // Construct the map name - char mapName[] = "0.rmh"; - mapName[0] = '0' + ray->p.mapId; - // Load the new map q24_8 pStartX = 0, pStartY = 0; - loadRayMap(mapName, ray, &pStartX, &pStartY, true); + loadRayMap(ray->p.mapId, ray, &pStartX, &pStartY, true); // If the player was initialized from scratch if (initFromScratch) @@ -379,11 +560,84 @@ static void rayStartGame(void) // Set the starting position from the map ray->p.posX = pStartX; ray->p.posY = pStartY; + // Save the starting position + raySavePlayer(ray); } // Mark the starting tile as visited markTileVisited(&ray->map, FROM_FX(ray->p.posX), FROM_FX(ray->p.posY)); + // Set the default hue (blue) + ray->targetLedHue = 170; + // Set the initial screen - ray->screen = RAY_GAME; + raySwitchToScreen(RAY_GAME); +} + +/** + * @brief Switch to a new ray screen, initialize as necessary + * + * @param newScreen The new screen to switch to + */ +void raySwitchToScreen(rayScreen_t newScreen) +{ + // Set the new screen + ray->screen = newScreen; + + // Initialize depending on the screen + switch (newScreen) + { + case RAY_MENU: + { + // Reinit menu + rayInitMenu(); + break; + } + case RAY_GAME: + case RAY_DIALOG: + case RAY_PAUSE: + case RAY_WARP_SCREEN: + case RAY_DEATH_SCREEN: + case RAY_CREDITS: + default: + { + break; + } + } +} + +/** + * @brief Initialize the main menu + */ +static void rayInitMenu(void) +{ + // Tear down old menu, if it exists + if (NULL != ray->renderer) + { + deinitMenuLogbookRenderer(ray->renderer); + } + if (NULL != ray->menu) + { + deinitMenu(ray->menu); + } + + // Initialize new one + ray->menu = initMenu(rayName, rayMenuCb); + addSingleItemToMenu(ray->menu, rayPlayStr); + ray->menu = startSubMenu(ray->menu, rayResetStr); + addSingleItemToMenu(ray->menu, rayConfirmStr); + ray->menu = endSubMenu(ray->menu); + + // Only show credits if the game was beaten + int32_t magtroidUnlocked = false; + readNvs32(MAGTROID_UNLOCK_KEY, &magtroidUnlocked); + if (magtroidUnlocked) + { + addSingleItemToMenu(ray->menu, rayCreditsStr); + } + + addSingleItemToMenu(ray->menu, rayExitStr); + + // Initialize a renderer + ray->renderer = initMenuLogbookRenderer(&ray->logbook); } diff --git a/main/modes/ray/mode_ray.h b/main/modes/ray/mode_ray.h index 059a26a77..c612b6d09 100644 --- a/main/modes/ray/mode_ray.h +++ b/main/modes/ray/mode_ray.h @@ -8,14 +8,13 @@ #include "swadge2024.h" #include "fp_math.h" #include "starfield.h" +#include "esp_random.h" +#include "credits_utils.h" //============================================================================== // Defines //============================================================================== -/** Use test textures. TODO: DELETE THIS */ -#define TEST_TEX 1 - /** The number of total maps */ #define NUM_MAPS 6 /** The number of keys per map */ @@ -24,9 +23,9 @@ #define MISSILE_UPGRADES_PER_MAP 3 /** The player's starting max health */ -#define GAME_START_HEALTH 50 +#define GAME_START_HEALTH 100 /** How much health is gained for each energy tank found */ -#define HEALTH_PER_E_TANK 25 +#define HEALTH_PER_E_TANK 100 /** The number of energy tank pickups per map */ #define E_TANKS_PER_MAP 1 /** The player's total maximum possible health */ @@ -35,8 +34,8 @@ /** The maximum number of missiles possible */ #define MAX_MISSILES_EVER 99 -/** Microseconds per one damage when standing in lava */ -#define US_PER_LAVA_DAMAGE 500000 +/** Microseconds per effect when standing in lava or on heal */ +#define US_PER_FLOOR_EFFECT 500000 /** Microseconds to charge the charge beam */ #define CHARGE_TIME_US 1048576 @@ -44,13 +43,20 @@ /** The number of bullets tracked at a given point in time */ #define MAX_RAY_BULLETS 32 -/** The number of non-walking frames in an animation */ -#define NUM_NON_WALK_FRAMES 4 -/** The number of walking frames in an animation (non-walking doubled) */ -#define NUM_WALK_FRAMES (NUM_NON_WALK_FRAMES * 2) +/** The number of frames in an animation */ +#define NUM_ANIM_FRAMES 4 /** The time to swap out and swap in a gun, in microseconds */ -#define LOADOUT_TIMER_US (1 << 18) +#define LOADOUT_TIMER_US (1 << 17) + +/** The blink time for pause and dialog items */ +#define BLINK_US 500000 + +/** The number of distinct enemies */ +#define NUM_ENEMIES (OBJ_ENEMY_BOSS - OBJ_ENEMY_NORMAL + 1) + +/** The time in uS for an enemy to warp in*/ +#define E_WARP_TIME 1000000 /** * @brief Helper macro to check if a cell is of a given type @@ -89,25 +95,29 @@ typedef enum __attribute__((packed)) EMPTY = 0, // Equivalent to (BG | META | 0), // Special delete tile, only used in map editor DELETE = (BG | META | 1), - // Background tiles - BG_FLOOR = (BG | FLOOR | 1), - BG_FLOOR_WATER = (BG | FLOOR | 2), - BG_FLOOR_LAVA = (BG | FLOOR | 3), - BG_CEILING = (BG | FLOOR | 4), - BG_WALL_1 = (BG | WALL | 1), - BG_WALL_2 = (BG | WALL | 2), - BG_WALL_3 = (BG | WALL | 3), - BG_WALL_4 = (BG | WALL | 4), - BG_WALL_5 = (BG | WALL | 5), - BG_DOOR = (BG | DOOR | 1), - BG_DOOR_CHARGE = (BG | DOOR | 2), - BG_DOOR_MISSILE = (BG | DOOR | 3), - BG_DOOR_ICE = (BG | DOOR | 4), - BG_DOOR_XRAY = (BG | DOOR | 5), - BG_DOOR_SCRIPT = (BG | DOOR | 6), - BG_DOOR_KEY_A = (BG | DOOR | 7), - BG_DOOR_KEY_B = (BG | DOOR | 8), - BG_DOOR_KEY_C = (BG | DOOR | 9), + // Background tiles, floor + BG_FLOOR = (BG | FLOOR | 1), + BG_FLOOR_WATER = (BG | FLOOR | 2), + BG_FLOOR_LAVA = (BG | FLOOR | 3), + BG_CEILING = (BG | FLOOR | 4), + BG_FLOOR_HEAL = (BG | FLOOR | 5), + // Walls + BG_WALL_1 = (BG | WALL | 1), + BG_WALL_2 = (BG | WALL | 2), + BG_WALL_3 = (BG | WALL | 3), + BG_WALL_4 = (BG | WALL | 4), + BG_WALL_5 = (BG | WALL | 5), + // Doors + BG_DOOR = (BG | DOOR | 1), + BG_DOOR_CHARGE = (BG | DOOR | 2), + BG_DOOR_MISSILE = (BG | DOOR | 3), + BG_DOOR_ICE = (BG | DOOR | 4), + BG_DOOR_XRAY = (BG | DOOR | 5), + BG_DOOR_SCRIPT = (BG | DOOR | 6), + BG_DOOR_KEY_A = (BG | DOOR | 7), + BG_DOOR_KEY_B = (BG | DOOR | 8), + BG_DOOR_KEY_C = (BG | DOOR | 9), + BG_DOOR_ARTIFACT = (BG | DOOR | 10), // Enemies OBJ_ENEMY_START_POINT = (OBJ | ENEMY | 1), OBJ_ENEMY_NORMAL = (OBJ | ENEMY | 2), @@ -134,14 +144,26 @@ typedef enum __attribute__((packed)) OBJ_ITEM_PICKUP_ENERGY = (OBJ | ITEM | 13), OBJ_ITEM_PICKUP_MISSILE = (OBJ | ITEM | 14), // Bullets - OBJ_BULLET_NORMAL = (OBJ | BULLET | 15), - OBJ_BULLET_CHARGE = (OBJ | BULLET | 16), - OBJ_BULLET_ICE = (OBJ | BULLET | 17), - OBJ_BULLET_MISSILE = (OBJ | BULLET | 18), - OBJ_BULLET_XRAY = (OBJ | BULLET | 19), + OBJ_BULLET_NORMAL = (OBJ | BULLET | 1), + OBJ_BULLET_CHARGE = (OBJ | BULLET | 2), + OBJ_BULLET_ICE = (OBJ | BULLET | 3), + OBJ_BULLET_MISSILE = (OBJ | BULLET | 4), + OBJ_BULLET_XRAY = (OBJ | BULLET | 5), + OBJ_BULLET_E_NORMAL = (OBJ | BULLET | 6), + OBJ_BULLET_E_STRONG = (OBJ | BULLET | 7), + OBJ_BULLET_E_ARMOR = (OBJ | BULLET | 8), + OBJ_BULLET_E_FLAMING = (OBJ | BULLET | 9), + OBJ_BULLET_E_HIDDEN = (OBJ | BULLET | 10), // Scenery OBJ_SCENERY_TERMINAL = (OBJ | SCENERY | 1), OBJ_SCENERY_PORTAL = (OBJ | SCENERY | 2), + OBJ_SCENERY_F1 = (OBJ | SCENERY | 3), + OBJ_SCENERY_F2 = (OBJ | SCENERY | 4), + OBJ_SCENERY_F3 = (OBJ | SCENERY | 5), + OBJ_SCENERY_F4 = (OBJ | SCENERY | 6), + OBJ_SCENERY_F5 = (OBJ | SCENERY | 7), + OBJ_SCENERY_F6 = (OBJ | SCENERY | 8), + OBJ_SCENERY_F7 = (OBJ | SCENERY | 9), } rayMapCellType_t; /** @@ -149,11 +171,32 @@ typedef enum __attribute__((packed)) */ typedef enum { - E_WALKING, ///< The enemy is walking - E_SHOOTING, ///< The enemy is shooting (may move while shooting) - E_HURT, ///< The enemy was shot + E_WALKING_1, ///< The enemy is walking, half cycle + E_WALKING_2, ///< The enemy is walking, the other half + E_SHOOTING, ///< The enemy is shooting (may move while shooting) + E_HURT, ///< The enemy was shot + E_BLOCKING, ///< The enemy is blocking + E_DEAD, ///< The enemy is dead + E_NUM_STATES, ///< The number of enemy states } rayEnemyState_t; +typedef enum +{ + DOING_NOTHING, + MOVE_POS_X, + MOVE_NEG_X, + MOVE_POS_Y, + MOVE_NEG_Y, + MOVE_STRAFE_L, + MOVE_STRAFE_R, + MOVE_TOWARDS_PLAYER, + MOVE_AWAY_PLAYER, + MOVE_NE, + MOVE_SE, + MOVE_SW, + MOVE_NW, +} rayEnemyBehavior_t; + /** * @brief All the possible loadouts */ @@ -167,6 +210,44 @@ typedef enum NUM_LOADOUTS ///< The number of loadouts } rayLoadout_t; +/** + * @brief All the possible environments + */ +typedef enum +{ + V_BASE, ///< Sci-fi base / space station + V_JUNGLE, ///< Jungle with alien ruins + V_CAVE, ///< Cave with lava + NUM_ENVS, ///< The number of environments +} rayEnv_t; + +/** + * @brief All the possible textures per-environments + */ +typedef enum +{ + TX_WALL_1, ///< Wall 1 + TX_WALL_2, ///< Wall 2 + TX_WALL_3, ///< Wall 3 + TX_WALL_4, ///< Wall 4 + TX_WALL_5, ///< Wall 5 + TX_FLOOR, ///< The floor texture + TX_CEILING, ///< The ceiling texture + NUM_ENV_TEXES, ///< The number of per-environment textures +} rayEnvTex_t; + +/** + * @brief All the possible boss states + */ +typedef enum +{ + B_MISSILE, ///< Weak to missiles + B_ICE, ///< Weak to ice + B_XRAY, ///< Weak to xray + B_NORMAL, ///< Weak to normal + NUM_BOSS_STATES, ///< The number of boss states +} rayBossState_t; + /** * @brief Types of events that trigger scripts */ @@ -235,11 +316,13 @@ typedef enum */ typedef enum { - RAY_MENU, ///< The main menu is being shown - RAY_GAME, ///< The game loop is being shown - RAY_DIALOG, ///< A dialog box is being shown - RAY_PAUSE, ///< The pause menu is being shown - RAY_WARP_SCREEN, ///< The warp screen animation is being shown + RAY_MENU, ///< The main menu is being shown + RAY_GAME, ///< The game loop is being shown + RAY_DIALOG, ///< A dialog box is being shown + RAY_PAUSE, ///< The pause menu is being shown + RAY_WARP_SCREEN, ///< The warp screen animation is being shown + RAY_DEATH_SCREEN, ///< The player has died + RAY_CREDITS, ///< Showing the credits for the game } rayScreen_t; /** @@ -292,8 +375,9 @@ typedef struct */ typedef struct { - bool isActive; ///< true if the script is active, false if it is not - ifOp_t ifOp; ///< The type of condition that triggers the script + bool isActive; ///< true if the script is active, false if it is not + int32_t resetTimerSec; ///< Timer to not re-trigger the script immediately + ifOp_t ifOp; ///< The type of condition that triggers the script /// A union of arguments for the condition that triggers the script union { @@ -417,14 +501,22 @@ typedef struct */ typedef struct { - rayObjCommon_t c; ///< Common object properties - rayEnemyState_t state; ///< This enemy's current state - uint32_t animTimer; ///< A timer used for this enemy's animations - uint32_t animTimerLimit; ///< The time at which the texture should switch - uint32_t animTimerFrame; ///< The current animation frame - wsg_t* walkSprites[NUM_NON_WALK_FRAMES]; ///< The walking sprites for this enemy - wsg_t* shootSprites[NUM_NON_WALK_FRAMES]; ///< The shooting sprites for this enemy - wsg_t* hurtSprites[NUM_NON_WALK_FRAMES]; ///< The getting shot sprites for this enemy + rayObjCommon_t c; ///< Common object properties + int32_t health; ///< The enemy's health + rayEnemyState_t state; ///< This enemy's current state + rayEnemyBehavior_t behavior; ///< What the enemy is currently doing + int32_t warpTimer; ///< A timer for warping in + rayBossState_t bossState; ///< The current boss state, unused for non-boss + int32_t bossTimer; ///< A timer for changing bossState, unused for non-boss + int32_t behaviorTimer; ///< A timer used for this enemy's behaviors + int32_t shootTimer; ///< A timer used for this enemy's shooting + int32_t blockTimer; ///< A timer used for this enemy's blocking + int32_t invincibleTimer; ///< Timer for being invincible + int32_t freezeTimer; ///< Timer for slowdown after ice beam + int32_t animTimer; ///< A timer used for this enemy's animations + int32_t animTimerLimit; ///< The time at which the texture should switch + int32_t animFrame; ///< The current animation frame + wsg_t (*sprites)[E_NUM_STATES][NUM_ANIM_FRAMES]; ///< All of this enemy's sprites } rayEnemy_t; /** @@ -452,6 +544,7 @@ typedef struct // Key items bool artifacts[NUM_MAPS]; ///< List of acquired artifacts rayKeyState_t keys[NUM_MAPS][NUM_KEYS]; ///< The number of small keys the player currently has + int32_t damageMult; ///< A damage multiplier } rayInventory_t; /** @@ -514,18 +607,24 @@ typedef struct int32_t loadoutChangeTimer; ///< A timer used for swapping loadouts bool forceLoadoutSwap; ///< Force the loadout to change without touch input - int32_t lavaTimer; ///< Timer to apply lava damage - int32_t chargeTimer; ///< Timer to charge shots - -#ifdef TEST_TEX - wsg_t testTextures[8]; ///< Test textures, TODO DELETE THESE -#endif - namedTexture_t* loadedTextures; ///< A list of loaded textures - uint8_t* typeToIdxMap; ///< A map of rayMapCellType_t to respective textures - wsg_t guns[NUM_LOADOUTS]; ///< Textures for the HUD guns - wsg_t portrait; ///< A portrait used for text dialogs - - rayEnemy_t eTemplates[6]; ///< Enemy type templates, copied when initializing enemies + int32_t floorEffectTimer; ///< Timer for effects when standing on a tile + bool playerInLava; ///< Track if the player is standing in lava + int32_t chargeTimer; ///< Timer to charge shots + int32_t playerShotCooldown; ///< Cooldown timer between shots + int32_t gunShakeTimer; ///< Timer to shake the gun when charged + int32_t gunShakeX; ///< Offset to draw gun at when shaking + bool gunShakeL; ///< true if the gun is shaking to the left, false otherwise + int32_t pRotationTimer; ///< timer for player rotation + + namedTexture_t* loadedTextures; ///< A list of loaded textures + uint8_t* typeToIdxMap; ///< A map of rayMapCellType_t to respective textures + wsg_t envTex[NUM_ENVS][NUM_ENV_TEXES]; ///< The environment textures + wsg_t guns[NUM_LOADOUTS]; ///< Textures for the HUD guns + wsg_t portrait; ///< A portrait used for text dialogs + wsg_t missileHUDicon; ///< A missile icon drawn in the HUD + wsg_t enemyTex[NUM_ENEMIES][E_NUM_STATES][NUM_ANIM_FRAMES]; ///< The enemy textures + wsg_t hiddenXRTex[E_NUM_STATES][NUM_ANIM_FRAMES]; ///< The textures for X-Ray hidden enemies + wsg_t bossTex[NUM_BOSS_STATES - 1][E_NUM_STATES][NUM_ANIM_FRAMES]; ///< The textures for the boss font_t ibm; ///< A font to draw the HUD font_t logbook; ///< A font to draw the menu @@ -534,14 +633,46 @@ typedef struct const char* nextDialogText; ///< A pointer to the next dialog text, if it doesn't fit in one box wsg_t* dialogPortrait; ///< A portrait to draw above the dialog text - uint32_t pauseBlinkTimer; ///< A timer to blink things on the pause menu - bool pauseBlink; ///< Boolean for two draw states on the pause menu + int32_t btnLockoutUs; ///< A timer to block buttons when first showing a dialog + int32_t blinkTimer; ///< A timer to blink things on the pause menu + bool blink; ///< Boolean for two draw states on the pause menu list_t scripts[NUM_IF_OP_TYPES]; ///< An array of lists of scripts uint32_t scriptTimer; ///< A microsecond timer to check for time based scripts uint32_t secondsSinceStart; ///< The number of seconds since this map was loaded starfield_t starfield; ///< Starfield used for warp animation + + song_t songs[NUM_MAPS + 1]; ///< Per-map background music, plus a boss theme + song_t sfx_door_open; ///< SFX when a door opens + song_t sfx_e_damage; ///< SFX when an enemy takes damage + song_t sfx_e_freeze; ///< SFX when an enemy is frozen + song_t sfx_p_charge; ///< SFX when the charge beam is shot + song_t sfx_p_damage; ///< SFX when the player takes damage + song_t sfx_p_shoot; ///< SFX when the a normal beam is shot + song_t sfx_e_block; ///< SFX when an enemy blocks a shot + song_t sfx_e_dead; ///< SFX when an enemy dies + song_t sfx_item_get; ///< SFX when an item is obtained + song_t sfx_p_charge_start; ///< SFX when the charge beam starts to charge + song_t sfx_p_missile; ///< SFX when a missile is shot + song_t sfx_p_ice; ///< SFX when the ice beam is shot + song_t sfx_p_xray; ///< SFX when th xray beam is shot + song_t sfx_warp; ///< SFX when the player warps + song_t sfx_lava_dmg; ///< SFX when standing in lava + song_t sfx_health; ///< SFX when picking up health + song_t sfx_game_over; ///< SFX when the game is over + + int32_t itemRotateTimer; ///< A timer to 'rotate' items by scaling the X direction + int32_t itemRotateDeg; ///< The number of degrees all items are 'rotated' by + bool itemRotateMirror; ///< If items should be drawn mirrored + + int32_t ledTimer; ///< A timer to change LED hue + int32_t ledHue; ///< The current LED hue + int32_t targetLedHue; ///< The target LED hue + + credits_t credits; ///< Credits shown when the game is won + + const char* deathText; ///< Text shown on the death screen } ray_t; //============================================================================== @@ -554,11 +685,14 @@ extern const char* const rayMapNames[]; extern const paletteColor_t rayMapColors[]; extern const char RAY_NVS_KEY[]; extern const char* const RAY_NVS_VISITED_KEYS[]; +extern const char MAGTROID_UNLOCK_KEY[]; //============================================================================== // Functions //============================================================================== void rayFreeCurrentState(ray_t* ray); +void rayStartGame(void); +void raySwitchToScreen(rayScreen_t newScreen); #endif diff --git a/main/modes/ray/ray_credits.c b/main/modes/ray/ray_credits.c new file mode 100644 index 000000000..425dc81a4 --- /dev/null +++ b/main/modes/ray/ray_credits.c @@ -0,0 +1,116 @@ +//============================================================================== +// Includes +//============================================================================== + +#include "ray_credits.h" +#include "credits_utils.h" +#include "ray_pause.h" + +//============================================================================== +// Variables +//============================================================================== + +/// @brief Credits text +static const char* rayCreditNames[] = { + "Percentage", + "Complete: 100%", + "", + "", + "----------------\n", + "Magtroid Pocket\n", + "----------------\n", + "", + "~ Programming ~\n", + "Adam Feinstein\n", + "", + "~ Art ~\n", + "Adam Feinstein\n", + "AllieCat Cosplay\n", + "Greg Lord (gplord)\n", + "Kaitie Lawson\n", + "", + "~ Music ~\n", + "Joe Newman\n", + "", + "~ Story ~\n", + "Adam Feinstein\n", + "Joe Newman\n", + "", + "~ Testing ~\n", + "Greg Lord (gplord)\n", + "Joe Newman\n", + "Jonathan Moriarty\n", + "", + "~ Team Lead ~\n", + "Adam Feinstein\n", + "", + "", + "See you next\n", + "adventure,\n", + "Bounty Hunter!\n", + "", + "", + "----------------\n", + "", +}; + +/// @brief Credits colors. Must be same length as rayCreditNames +static const paletteColor_t rayCreditColors[] = { + c224, c224, c000, c000, c542, c542, c542, c000, c521, c521, c000, c424, c424, c424, + c424, c424, c000, c241, c241, c000, c503, c503, c503, c000, c205, c205, c205, c205, + c000, c440, c440, c000, c000, c555, c555, c555, c000, c000, c555, c000, +}; + +//============================================================================== +// Functions +//============================================================================== + +/** + * @brief Show the credits screen and set up the button lockout + * + * @param ray The entire game state + */ +void rayShowCredits(ray_t* ray) +{ + ray->btnLockoutUs = 2000000; + + // Make sure player data is loaded for the completion string + rayStartGame(); + raySwitchToScreen(RAY_CREDITS); + + // Write the completion string + static char completionStr[20]; + sprintf(completionStr, "Complete: %" PRId32 "%%", getItemCompletePct(ray)); + // Swap the completion string into the credits array + rayCreditNames[1] = completionStr; + + // Stop music + bzrStop(true); + + // Init credits, which starts music + initCredits(&ray->credits, &ray->logbook, rayCreditNames, rayCreditColors, ARRAY_SIZE(rayCreditNames)); +} + +/** + * @brief Draw the foreground for the credits screen and run the timer + * + * @param ray The entire game state + * @param elapsedUs The elapsed time since this function was last called + */ +void rayCreditsRender(ray_t* ray, uint32_t elapsedUs) +{ + buttonEvt_t evt; + while (checkButtonQueueWrapper(&evt)) + { + if (creditsButtonCb(&ray->credits, &evt)) + { + bzrStop(true); + deinitCredits(&ray->credits); + // Return to the menu + raySwitchToScreen(RAY_MENU); + return; + } + } + + drawCredits(&ray->credits, elapsedUs); +} diff --git a/main/modes/ray/ray_credits.h b/main/modes/ray/ray_credits.h new file mode 100644 index 000000000..491ceb3b5 --- /dev/null +++ b/main/modes/ray/ray_credits.h @@ -0,0 +1,9 @@ +#ifndef _RAY_CREDITS_H_ +#define _RAY_CREDITS_H_ + +#include "mode_ray.h" + +void rayShowCredits(ray_t* ray); +void rayCreditsRender(ray_t* ray, uint32_t elapsedUs); + +#endif \ No newline at end of file diff --git a/main/modes/ray/ray_death_screen.c b/main/modes/ray/ray_death_screen.c new file mode 100644 index 000000000..cc5fae6ef --- /dev/null +++ b/main/modes/ray/ray_death_screen.c @@ -0,0 +1,103 @@ +//============================================================================== +// Includes +//============================================================================== + +#include "ray_death_screen.h" + +//============================================================================== +// Constant data +//============================================================================== + +static const char* const deathTexts[] = { + "GG no re", + "Skill Issue", + "F", + "YOUR HEAD ASPLODE", + "You may have died, but you are not safe from taxes", + "Pro Tip: Shoot the enemies until they die", + "Your suit didn't disintegrate revealing a bikini-clad bird, you just died", + "Should have ducked", + "I guess the galaxy will never be at peace", + "Turns out main characters *can* die, who knew?", + "Runtime error 0x00001337 SEGMENTATION FAULT nah just kidding you died", + "Have you tried turning it off and then on again?", + "Try again, but do better", + "Remember when you used to give the controller to a friend to beat the hard levels? Yeah, good times...", + "Game Over. Insert two quarters to continue.", + "One life remaining... Just kidding!", + "Would you like to purchase better armor for $5? Too bad, we don't pay to win!", + "You seem to be experiencing cognitive and/or coordination difficulties. Emergency medical services have been " + "alerted.", +}; + +//============================================================================== +// Functions +//============================================================================== + +/** + * @brief Show the death screen and set up the button lockout + * + * @param ray The entire game state + */ +void rayShowDeathScreen(ray_t* ray) +{ + ray->btnLockoutUs = 2000000; + raySwitchToScreen(RAY_DEATH_SCREEN); + // Stop BGM when dead + bzrStop(true); + bzrPlaySfx(&ray->sfx_game_over, BZR_RIGHT); + + // Pick random text to display + ray->deathText = deathTexts[esp_random() % ARRAY_SIZE(deathTexts)]; +} + +/** + * @brief Draw the foreground for the death screen and run the timer + * + * @param ray The entire game state + * @param elapsedUs The elapsed time since this function was last called + */ +void rayDeathScreenRender(ray_t* ray, uint32_t elapsedUs) +{ + // Check the button queue + buttonEvt_t evt; + while (checkButtonQueueWrapper(&evt)) + { + if (0 == ray->btnLockoutUs) + { + // If A was pressed + if (evt.down) + { + if ((PB_A == evt.button) || (PB_B == evt.button)) + { + // Return to the menu + raySwitchToScreen(RAY_MENU); + } + } + } + } + + // Fill dark red background + fillDisplayArea(0, 0, TFT_WIDTH, TFT_HEIGHT, c100); + +#define DEATH_TEXT_MARGIN 25 + + // Measure the height of the wrapped text + uint16_t tHeight = textWordWrapHeight(&ray->logbook, ray->deathText, TFT_WIDTH - (DEATH_TEXT_MARGIN * 2), + TFT_HEIGHT - (DEATH_TEXT_MARGIN * 2)); + + // Set the offsets + int16_t xOff = DEATH_TEXT_MARGIN; + int16_t yOff = (TFT_HEIGHT - tHeight) / 2; + + drawTextWordWrap(&ray->logbook, c542, ray->deathText, &xOff, &yOff, TFT_WIDTH - xOff, TFT_HEIGHT - yOff); + + // Blink an arrow to show there's more dialog + if (ray->blink && 0 == ray->btnLockoutUs) + { +#define TRIANGLE_OFFSET 20 + drawTriangleOutlined(TFT_WIDTH - TRIANGLE_OFFSET - 16, TFT_HEIGHT - TRIANGLE_OFFSET - 4, + TFT_WIDTH - TRIANGLE_OFFSET - 4, TFT_HEIGHT - TRIANGLE_OFFSET - 10, + TFT_WIDTH - TRIANGLE_OFFSET - 16, TFT_HEIGHT - TRIANGLE_OFFSET - 16, c100, c542); + } +} diff --git a/main/modes/ray/ray_death_screen.h b/main/modes/ray/ray_death_screen.h new file mode 100644 index 000000000..04bf6868f --- /dev/null +++ b/main/modes/ray/ray_death_screen.h @@ -0,0 +1,9 @@ +#ifndef _RAY_DEATH_SCREEN_H_ +#define _RAY_DEATH_SCREEN_H_ + +#include "mode_ray.h" + +void rayShowDeathScreen(ray_t* ray); +void rayDeathScreenRender(ray_t* ray, uint32_t elapsedUs); + +#endif \ No newline at end of file diff --git a/main/modes/ray/ray_dialog.c b/main/modes/ray/ray_dialog.c index c402dffb3..6df760d4f 100644 --- a/main/modes/ray/ray_dialog.c +++ b/main/modes/ray/ray_dialog.c @@ -1,9 +1,10 @@ //============================================================================== -// Inclues +// Includes //============================================================================== #include "fill.h" #include "ray_dialog.h" +#include "esp_wifi.h" //============================================================================== // Defines @@ -17,6 +18,21 @@ #define DIALOG_BG_COLOR c000 #define DIALOG_TEXT_COLOR c240 +//============================================================================== +// Constant text +//============================================================================== + +const char* const macPuzzleText[] = { + "WARNING DATA CORRUPTED. Seek other bounty hunters to reconstruct data.\n\n4! is too excited, subtract 12 from " + "it\n[=/+._?@\n}+&)(/&?\n+[:&${)}", + "WARNING DATA CORRUPTED. Seek other bounty hunters to reconstruct data.\n\n.?%?-}{;\nTake the next answer, like a " + "tree find the square\n&,?:)/&:\n:/{#_!&,", + "WARNING DATA CORRUPTED. Seek other bounty hunters to reconstruct data.\n\n:#:$/{)]\n{?$-}*].\nArgon's number is " + "nice, but in two it must split\n/}%-%?}%", + "WARNING DATA CORRUPTED. Seek other bounty hunters to reconstruct data.\n\n{@#??_[!\n#,;{(;-{\n]#_!]=,.\nAverage " + "two prior, that's it, almost there", +}; + //============================================================================== // Functions //============================================================================== @@ -30,9 +46,19 @@ */ void rayShowDialog(ray_t* ray, const char* dialogText, wsg_t* dialogPortrait) { - ray->screen = RAY_DIALOG; - ray->dialogText = dialogText; + raySwitchToScreen(RAY_DIALOG); + if (0 == strcmp("MAC_PZL", dialogText)) + { + uint8_t macAddr[6]; + esp_wifi_get_mac(WIFI_IF_STA, macAddr); + ray->dialogText = macPuzzleText[macAddr[5] % 4]; + } + else + { + ray->dialogText = dialogText; + } ray->dialogPortrait = dialogPortrait; + ray->btnLockoutUs = 2000000; } /** @@ -47,19 +73,22 @@ void rayDialogCheckButtons(ray_t* ray) buttonEvt_t evt; while (checkButtonQueueWrapper(&evt)) { - // If A was pressed - if (PB_A == evt.button && evt.down) + if (0 == ray->btnLockoutUs) { - // If there is more dialog - if (NULL != ray->nextDialogText) - { - // Show the next part of the dialog - ray->dialogText = ray->nextDialogText; - } - else + // If A was pressed + if (PB_A == evt.button && evt.down) { - // Dialog over, return to game - ray->screen = RAY_GAME; + // If there is more dialog + if (NULL != ray->nextDialogText) + { + // Show the next part of the dialog + ray->dialogText = ray->nextDialogText; + } + else + { + // Dialog over, return to game + raySwitchToScreen(RAY_GAME); + } } } } @@ -69,8 +98,9 @@ void rayDialogCheckButtons(ray_t* ray) * @brief Render the current dialog box * * @param ray The entire game state + * @param elapsedUs The elapsed time since this function was last called */ -void rayDialogRender(ray_t* ray) +void rayDialogRender(ray_t* ray, uint32_t elapsedUs) { // Draw the background text box, outline drawRect(DIALOG_MARGIN, // @@ -113,4 +143,13 @@ void rayDialogRender(ray_t* ray) &yOff, // TFT_WIDTH - DIALOG_MARGIN - TEXT_MARGIN, // TFT_HEIGHT - DIALOG_MARGIN - TEXT_MARGIN); + + // Blink an arrow to show there's more dialog + if (ray->blink && 0 == ray->btnLockoutUs) + { + drawTriangleOutlined(TFT_WIDTH - DIALOG_MARGIN - 16, TFT_HEIGHT - DIALOG_MARGIN - 4, + TFT_WIDTH - DIALOG_MARGIN - 4, TFT_HEIGHT - DIALOG_MARGIN - 10, + TFT_WIDTH - DIALOG_MARGIN - 16, TFT_HEIGHT - DIALOG_MARGIN - 16, DIALOG_BG_COLOR, + DIALOG_TEXT_COLOR); + } } diff --git a/main/modes/ray/ray_dialog.h b/main/modes/ray/ray_dialog.h index 08068ba1a..a4e7b1968 100644 --- a/main/modes/ray/ray_dialog.h +++ b/main/modes/ray/ray_dialog.h @@ -5,6 +5,6 @@ void rayShowDialog(ray_t* ray, const char* dialogText, wsg_t* dialogPortrait); void rayDialogCheckButtons(ray_t* ray); -void rayDialogRender(ray_t* ray); +void rayDialogRender(ray_t* ray, uint32_t elapsedUs); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_map.c b/main/modes/ray/ray_map.c index fbd6d9243..f741fb06d 100644 --- a/main/modes/ray/ray_map.c +++ b/main/modes/ray/ray_map.c @@ -15,6 +15,7 @@ #include "ray_tex_manager.h" #include "ray_renderer.h" #include "ray_script.h" +#include "ray_enemy.h" //============================================================================== // Functions @@ -24,27 +25,28 @@ * @brief Load a RMH from ROM to RAM. RMHs placed in the spiffs_image folder * before compilation will be automatically flashed to ROM * - * @param name The filename of the RMH to load + * @param mapId The map ID to load * @param ray The ray_t to load the map into * @param pStartX The starting X coordinate for this map * @param pStartY The starting Y coordinate for this map * @param spiRam true to load to SPI RAM, false to load to normal RAM. SPI RAM is more plentiful but slower to access * than normal RAM */ -void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bool spiRam) +void loadRayMap(int32_t mapId, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bool spiRam) { // Convenience inventory to know what not to spawn rayInventory_t* inv = &ray->p.i; - // Map ID is the first digit of the name - int16_t mapId = name[0] - '0'; - // Pick the allocation type uint32_t caps = spiRam ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DEFAULT; // Convenience pointers rayMap_t* map = &ray->map; + // Construct map name + char name[] = "0.rmh"; + name[0] = '0' + mapId; + // Read and decompress the file uint32_t decompressedSize = 0; uint8_t* fileData = readHeatshrinkFile(name, &decompressedSize, spiRam); @@ -107,7 +109,7 @@ void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bo // Allocate a new object if ((oType & 0x60) == ENEMY) { - rayCreateEnemy(ray, oType, id, x, y); + rayCreateEnemy(ray, oType, id, TO_FX(x) + TO_FX_FRAC(1, 2), TO_FX(y) + TO_FX_FRAC(1, 2)); } else { @@ -216,7 +218,8 @@ void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bo // Create this object if it wasn't already picked up if (shouldCreate) { - rayCreateCommonObj(ray, oType, id, x, y); + rayCreateCommonObj(ray, oType, id, TO_FX(x) + TO_FX_FRAC(1, 2), + TO_FX(y) + TO_FX_FRAC(1, 2)); } } } @@ -224,11 +227,18 @@ void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bo } } + // Reset script timers + ray->scriptTimer = 0; + ray->secondsSinceStart = 0; + // Load Scripts loadScripts(ray, &fileData[fileIdx], decompressedSize - fileIdx, caps); // Free the file data free(fileData); + + // Play this map's music + bzrPlayBgm(&ray->songs[ray->p.mapId], BZR_STEREO); } /** @@ -237,27 +247,45 @@ void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bo * @param ray The entire game state * @param type The type of enemy to spawn * @param id The ID for this enemy - * @param x The X cell position for this enemy - * @param y The Y cell position for this enemy + * @param x The X position for this enemy + * @param y The Y position for this enemy */ -void rayCreateEnemy(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x, int32_t y) +void rayCreateEnemy(ray_t* ray, rayMapCellType_t type, int32_t id, q24_8 x, q24_8 y) { // Allocate the enemy rayEnemy_t* newObj = (rayEnemy_t*)heap_caps_calloc(1, sizeof(rayEnemy_t), MALLOC_CAP_SPIRAM); - // Copy enemy data from the template (sprite indices, type) - memcpy(newObj, &(ray->eTemplates[type - OBJ_ENEMY_NORMAL]), sizeof(rayEnemy_t)); - - // Set ID - newObj->c.id = id; - - // Set spatial values - newObj->c.posX = TO_FX(x) + TO_FX_FRAC(1, 2); - newObj->c.posY = TO_FX(y) + TO_FX_FRAC(1, 2); - newObj->c.radius = TO_FX_FRAC(newObj->c.sprite->w, 2 * TEX_WIDTH); + // Set type and ID first + newObj->c.type = type; + newObj->c.id = id; + + // Set initial enemy state + newObj->health = 100; + newObj->behavior = DOING_NOTHING; + newObj->behaviorTimer = esp_random() % 1000000; + newObj->shootTimer = getTimerForEnemy(newObj, SHOT); + newObj->blockTimer = getTimerForEnemy(newObj, BLOCK); + newObj->sprites = &ray->enemyTex[type - OBJ_ENEMY_NORMAL]; + newObj->warpTimer = E_WARP_TIME; + + // This sets state, animTimer, animTimerLimit, animFrame, and c.sprite + newObj->state = E_WALKING_2; + rayEnemyTransitionState(newObj, E_WALKING_1); + + // Set initial common state + newObj->c.posX = x; + newObj->c.posY = y; + newObj->c.radius = TO_FX_FRAC(newObj->c.sprite->w, 2 * TEX_WIDTH); + newObj->c.spriteMirrored = false; // Add it to the linked list push(&ray->enemies, newObj); + + // If the boss was spawned, play the theme + if (OBJ_ENEMY_BOSS == type) + { + bzrPlayBgm(&ray->songs[6], BZR_STEREO); + } } /** @@ -266,10 +294,10 @@ void rayCreateEnemy(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x, in * @param ray The entire game state * @param type The type of object to spawn * @param id The ID for this object - * @param x The X cell position for this object - * @param y The Y cell position for this object + * @param x The X position for this object + * @param y The Y position for this object */ -void rayCreateCommonObj(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x, int32_t y) +void rayCreateCommonObj(ray_t* ray, rayMapCellType_t type, int32_t id, q24_8 x, q24_8 y) { rayObjCommon_t* newObj = (rayObjCommon_t*)heap_caps_calloc(1, sizeof(rayObjCommon_t), MALLOC_CAP_SPIRAM); @@ -279,8 +307,8 @@ void rayCreateCommonObj(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x newObj->id = id; // Set spatial values - newObj->posX = TO_FX(x) + TO_FX_FRAC(1, 2); - newObj->posY = TO_FX(y) + TO_FX_FRAC(1, 2); + newObj->posX = x; + newObj->posY = y; newObj->radius = TO_FX_FRAC(newObj->sprite->w, 2 * TEX_WIDTH); // Add it to the linked list diff --git a/main/modes/ray/ray_map.h b/main/modes/ray/ray_map.h index 8f60dabeb..8563a773f 100644 --- a/main/modes/ray/ray_map.h +++ b/main/modes/ray/ray_map.h @@ -3,11 +3,11 @@ #include "mode_ray.h" -void loadRayMap(const char* name, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bool spiRam); +void loadRayMap(int32_t mapId, ray_t* ray, q24_8* pStartX, q24_8* pStartY, bool spiRam); void freeRayMap(rayMap_t* map); bool isPassableCell(rayMapCell_t* cell); void markTileVisited(rayMap_t* map, int16_t x, int16_t y); -void rayCreateEnemy(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x, int32_t y); -void rayCreateCommonObj(ray_t* ray, rayMapCellType_t type, int32_t id, int32_t x, int32_t y); +void rayCreateEnemy(ray_t* ray, rayMapCellType_t type, int32_t id, q24_8 x, q24_8 y); +void rayCreateCommonObj(ray_t* ray, rayMapCellType_t type, int32_t id, q24_8 x, q24_8 y); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_object.c b/main/modes/ray/ray_object.c index dc07b9062..35b804054 100644 --- a/main/modes/ray/ray_object.c +++ b/main/modes/ray/ray_object.c @@ -16,57 +16,12 @@ //============================================================================== static bool objectsIntersect(const rayObjCommon_t* obj1, const rayObjCommon_t* obj2); -static void moveRayBullets(ray_t* ray, int32_t elapsedUs); +static void moveRayBullets(ray_t* ray, uint32_t elapsedUs); //============================================================================== // Functions //============================================================================== -/** - * @brief Initialize templates for enemy creation. This also loads enemy sprites - * - * @param ray The entire game state - */ -void initEnemyTemplates(ray_t* ray) -{ - // The names of the different types of enemies - const char* eTypes[] = { - "NORMAL", "STRONG", "ARMORED", "FLAMING", "HIDDEN", "BOSS", - }; - - // The types of enemies - const rayMapCellType_t types[] = { - OBJ_ENEMY_NORMAL, OBJ_ENEMY_STRONG, OBJ_ENEMY_ARMORED, OBJ_ENEMY_FLAMING, OBJ_ENEMY_HIDDEN, OBJ_ENEMY_BOSS, - }; - - // An empty buffer to build strings - char buf[64] = {0}; - - // For each enemy type - for (int32_t eIdx = 0; eIdx < ARRAY_SIZE(ray->eTemplates); eIdx++) - { - // Set the type - ray->eTemplates[eIdx].c.type = types[eIdx]; - - // Set the time for each animation state - ray->eTemplates[eIdx].animTimerLimit = 250000; - - // Load textures for all states - for (int32_t frIdx = 0; frIdx < ARRAY_SIZE(ray->eTemplates->hurtSprites); frIdx++) - { - // Load the textures - snprintf(buf, sizeof(buf) - 1, "E_%s_WALK_%" PRId32 ".wsg", eTypes[eIdx], frIdx); - ray->eTemplates[eIdx].walkSprites[frIdx] = loadTexture(ray, buf, EMPTY); - snprintf(buf, sizeof(buf) - 1, "E_%s_SHOOT_%" PRId32 ".wsg", eTypes[eIdx], frIdx); - ray->eTemplates[eIdx].shootSprites[frIdx] = loadTexture(ray, buf, EMPTY); - snprintf(buf, sizeof(buf) - 1, "E_%s_HURT_%" PRId32 ".wsg", eTypes[eIdx], frIdx); - ray->eTemplates[eIdx].hurtSprites[frIdx] = loadTexture(ray, buf, EMPTY); - } - // Set initial texture - ray->eTemplates[eIdx].c.sprite = ray->eTemplates[eIdx].walkSprites[0]; - } -} - /** * @brief Create a bullet with an owner, type, position, and velocity * @@ -121,7 +76,7 @@ void rayCreateBullet(ray_t* ray, rayMapCellType_t bulletType, q24_8 posX, q24_8 * @param ray The entire game state * @param elapsedUs The elapsed time since this function was last called */ -void moveRayObjects(ray_t* ray, int32_t elapsedUs) +void moveRayObjects(ray_t* ray, uint32_t elapsedUs) { moveRayBullets(ray, elapsedUs); rayEnemiesMoveAnimate(ray, elapsedUs); @@ -133,7 +88,7 @@ void moveRayObjects(ray_t* ray, int32_t elapsedUs) * @param ray The entire game state * @param elapsedUs The elapsed time since this function was last called */ -static void moveRayBullets(ray_t* ray, int32_t elapsedUs) +static void moveRayBullets(ray_t* ray, uint32_t elapsedUs) { // For convenience int32_t rayMapId = ray->p.mapId; @@ -145,68 +100,114 @@ static void moveRayBullets(ray_t* ray, int32_t elapsedUs) rayBullet_t* obj = &(ray->bullets[i]); if (-1 != obj->c.id) { - // Update the bullet's position - // TODO justify the scaling factor, assuming velXY is a unit vector - obj->c.posX += (obj->velX * elapsedUs) / 100000; - obj->c.posY += (obj->velY * elapsedUs) / 100000; + // Update the bullet's position. 100000 was picked out of a hat! + obj->c.posX += (obj->velX * (int32_t)elapsedUs) / 100000; + obj->c.posY += (obj->velY * (int32_t)elapsedUs) / 100000; // Get the cell the bullet is in now rayMapCell_t* cell = &ray->map.tiles[FROM_FX(obj->c.posX)][FROM_FX(obj->c.posY)]; - // If a wall is it - if (CELL_IS_TYPE(cell->type, BG | WALL)) + // If the bullet hit something + if (!isPassableCell(cell)) { - // Check for shot wall scripts - if (checkScriptShootWall(ray, FROM_FX(obj->c.posX), FROM_FX(obj->c.posY))) + // If this is a player's bullet + if (1 == obj->c.id) { - // Script warped, return - return; - } - - // Destroy this bullet - memset(obj, 0, sizeof(rayBullet_t)); - obj->c.id = -1; - } - // Else if a door is hit - else if (CELL_IS_TYPE(cell->type, BG | DOOR)) - { - // If the door is closed - if (0 == cell->doorOpen) - { - // Check if the bullet type can open the door - if ((BG_DOOR == cell->type) // Normal doors are openable by anything - || (BG_DOOR_CHARGE == cell->type && OBJ_BULLET_CHARGE == obj->c.type) - // || (BG_DOOR_SCRIPT == cell->type) // Script doors aren't openable with bullets - || (BG_DOOR_MISSILE == cell->type && OBJ_BULLET_MISSILE == obj->c.type) - || (BG_DOOR_ICE == cell->type && OBJ_BULLET_ICE == obj->c.type) - || (BG_DOOR_XRAY == cell->type && OBJ_BULLET_XRAY == obj->c.type) - || (BG_DOOR_KEY_A == cell->type && KEY == ray->p.i.keys[rayMapId][0]) - || (BG_DOOR_KEY_B == cell->type && KEY == ray->p.i.keys[rayMapId][1]) - || (BG_DOOR_KEY_C == cell->type && KEY == ray->p.i.keys[rayMapId][2])) + // If it hit a wall + if (CELL_IS_TYPE(cell->type, BG | WALL)) { - // Start opening the door - cell->openingDirection = 1; - // Destroy this bullet - memset(obj, 0, sizeof(rayBullet_t)); - obj->c.id = -1; - - // If this door requires a key - if ((BG_DOOR_KEY_A == cell->type) || // - (BG_DOOR_KEY_B == cell->type) || // - (BG_DOOR_KEY_C == cell->type)) - { - // Use the key - ray->p.i.keys[rayMapId][cell->type - BG_DOOR_KEY_A] = OPEN_KEY; - } + // Check wall scripts + checkScriptShootWall(ray, FROM_FX(obj->c.posX), FROM_FX(obj->c.posY)); } - else + // If it hit a door + else if (CELL_IS_TYPE(cell->type, BG | DOOR)) { - // Shot a closed door it couldn't open - // destroy this bullet - memset(obj, 0, sizeof(rayBullet_t)); - obj->c.id = -1; + // If the door is closed + if (0 == cell->doorOpen) + { + bool opened = false; + switch (cell->type) + { + case BG_DOOR: + { + opened = true; + break; + } + case BG_DOOR_CHARGE: + { + opened = (OBJ_BULLET_CHARGE == obj->c.type); + break; + } + case BG_DOOR_MISSILE: + { + opened = (OBJ_BULLET_MISSILE == obj->c.type); + break; + } + case BG_DOOR_ICE: + { + opened = (OBJ_BULLET_ICE == obj->c.type); + break; + } + case BG_DOOR_XRAY: + { + opened = (OBJ_BULLET_XRAY == obj->c.type); + break; + } + case BG_DOOR_SCRIPT: + { + // Script doors aren't openable by bullets + break; + } + case BG_DOOR_KEY_A: + case BG_DOOR_KEY_B: + case BG_DOOR_KEY_C: + { + // Open the door if the player has the appropriate key + opened = (KEY == ray->p.i.keys[rayMapId][cell->type - BG_DOOR_KEY_A]); + if (opened) + { + // Mark the key as used + ray->p.i.keys[rayMapId][cell->type - BG_DOOR_KEY_A] = OPEN_KEY; + } + break; + } + case BG_DOOR_ARTIFACT: + { + // Check if all artifacts have been collected + opened = true; + for (int16_t aIdx = 0; aIdx < ARRAY_SIZE(ray->p.i.artifacts); aIdx++) + { + if (!ray->p.i.artifacts[aIdx]) + { + opened = false; + break; + } + } + break; + } + default: + { + // Not a door, somehow + break; + } + } + + // If the door was opened + if (opened) + { + // Start opening the door + cell->openingDirection = 1; + + // Play SFX + bzrPlaySfx(&ray->sfx_door_open, BZR_RIGHT); + } + } } } + + // Destroy this bullet + memset(obj, 0, sizeof(rayBullet_t)); + obj->c.id = -1; } } } @@ -250,7 +251,42 @@ void checkRayCollisions(ray_t* ray) // An enemy's bullet if (objectsIntersect(&player, &bullet->c)) { - // TODO Player got shot, apply damage + // Determine the damage per-bullet + int32_t dmg = 0; + switch (bullet->c.type) + { + case OBJ_BULLET_E_NORMAL: + { + dmg = 10; + break; + } + case OBJ_BULLET_E_STRONG: + { + dmg = 15; + break; + } + case OBJ_BULLET_E_ARMOR: + { + dmg = 20; + break; + } + case OBJ_BULLET_E_FLAMING: + { + dmg = 25; + break; + } + case OBJ_BULLET_E_HIDDEN: + { + dmg = 30; + break; + } + default: + { + break; + } + } + // Player got shot, apply damage + rayPlayerDecrementHealth(ray, dmg); // De-allocate the bullet bullet->c.id = -1; } @@ -269,13 +305,9 @@ void checkRayCollisions(ray_t* ray) if (objectsIntersect(&player, item)) { // Touch the item - rayPlayerTouchItem(ray, item->type, ray->p.mapId, item->id); + rayPlayerTouchItem(ray, item, ray->p.mapId); // Check scripts - if (checkScriptGet(ray, item->id, item->sprite)) - { - // Script warped, return - return; - } + checkScriptGet(ray, item->id, item->sprite); // Mark this item for removal toRemove = currentNode; @@ -305,8 +337,6 @@ void checkRayCollisions(ray_t* ray) { // Get a pointer from the linked list rayEnemy_t* enemy = ((rayEnemy_t*)currentNode->val); - // Used for iterating - bool enemyWasKilled = false; // Iterate through all bullets for (uint16_t bIdx = 0; bIdx < MAX_RAY_BULLETS; bIdx++) @@ -317,44 +347,16 @@ void checkRayCollisions(ray_t* ray) // A player's bullet if (objectsIntersect(&enemy->c, &bullet->c)) { + // Decrease HP based on the shot and enemy type + rayEnemyGetShot(ray, enemy, bullet->c.type); // De-allocate the bullet bullet->c.id = -1; - - // Enemy got shot, apply damage - if (rayEnemyGetShot(ray, enemy, bullet->c.type)) - { - // Enemy was killed - checkScriptKill(ray, enemy->c.id, enemy->walkSprites[0]); - - // save the next node - node_t* nextNode = currentNode->next; - - // Remove the lock - if (ray->targetedObj == enemy) - { - ray->targetedObj = NULL; - } - - // Unlink and free - removeEntry(&ray->enemies, currentNode); - free(enemy); - - // Set the next node - currentNode = nextNode; - enemyWasKilled = true; - - break; - } } } } - // If the enemy was killed, iteration already happened - if (!enemyWasKilled) - { - // Iterate to the next node - currentNode = currentNode->next; - } + // Iterate to the next + currentNode = currentNode->next; } // Check if a bullet or the player touches scenery @@ -367,11 +369,7 @@ void checkRayCollisions(ray_t* ray) // Check if the player touches scenery if (objectsIntersect(&player, scenery)) { - if (checkScriptTouch(ray, scenery->id, scenery->sprite)) - { - // Script warped, return - return; - } + checkScriptTouch(ray, scenery->id, scenery->sprite); } // Iterate through all bullets @@ -387,11 +385,7 @@ void checkRayCollisions(ray_t* ray) bullet->c.id = -1; // Scenery was shot - if (checkScriptShootObjs(ray, scenery->id, scenery->sprite)) - { - // Script warped, return - return; - } + checkScriptShootObjs(ray, scenery->id, scenery->sprite); } } } diff --git a/main/modes/ray/ray_object.h b/main/modes/ray/ray_object.h index eabce0d71..bdd78a5bf 100644 --- a/main/modes/ray/ray_object.h +++ b/main/modes/ray/ray_object.h @@ -3,10 +3,9 @@ #include "mode_ray.h" -void initEnemyTemplates(ray_t* ray); void rayCreateBullet(ray_t* ray, rayMapCellType_t bulletType, q24_8 posX, q24_8 posY, q24_8 velX, q24_8 velY, bool isPlayer); -void moveRayObjects(ray_t* ray, int32_t elapsedUs); +void moveRayObjects(ray_t* ray, uint32_t elapsedUs); void checkRayCollisions(ray_t* ray); #endif diff --git a/main/modes/ray/ray_pause.c b/main/modes/ray/ray_pause.c index 751efe974..9c35e61c8 100644 --- a/main/modes/ray/ray_pause.c +++ b/main/modes/ray/ray_pause.c @@ -3,12 +3,7 @@ //============================================================================== #include "ray_pause.h" - -//============================================================================== -// Defines -//============================================================================== - -#define PAUSE_BLINK_US 500000 +#include "ray_tex_manager.h" //============================================================================== // Enums @@ -113,6 +108,7 @@ const rayWorldMapLine_t warpLines[] = { static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs); static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs); +static void drawPlayerIndicator(ray_t* ray, int16_t cX, int16_t cY); //============================================================================== // Functions @@ -125,7 +121,8 @@ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs); */ void rayShowPause(ray_t* ray) { - ray->screen = RAY_PAUSE; + raySwitchToScreen(RAY_PAUSE); + bzrPause(); } /** @@ -142,15 +139,31 @@ void rayPauseCheckButtons(ray_t* ray) // If A was pressed if (evt.down) { - if (PB_START == evt.button) - { - // Pause over, return to game - ray->screen = RAY_GAME; - } - if ((PB_A == evt.button) || (PB_B == evt.button)) + switch (evt.button) { - // Switch between local map and world map - ray->pauseScreen = (ray->pauseScreen + 1) % RP_NUM_SCREENS; + case PB_UP: + case PB_DOWN: + case PB_LEFT: + case PB_RIGHT: + case PB_A: + case PB_B: + { + // Switch between local map and world map + ray->pauseScreen = (ray->pauseScreen + 1) % RP_NUM_SCREENS; + break; + } + case PB_START: + { + // Pause over, return to game + raySwitchToScreen(RAY_GAME); + bzrResume(); + break; + } + default: + case PB_SELECT: + { + break; + } } } } @@ -164,6 +177,9 @@ void rayPauseCheckButtons(ray_t* ray) */ void rayPauseRender(ray_t* ray, uint32_t elapsedUs) { + // Clear to black first + clearPxTft(); + // Render based on the displayed screen switch (ray->pauseScreen) { @@ -180,12 +196,17 @@ void rayPauseRender(ray_t* ray, uint32_t elapsedUs) } } - // Run a timer to blink things - ray->pauseBlinkTimer += elapsedUs; - if (ray->pauseBlinkTimer > PAUSE_BLINK_US) + if (ray->blink) { - ray->pauseBlinkTimer -= PAUSE_BLINK_US; - ray->pauseBlink = !ray->pauseBlink; +#define TRIANGLE_OFFSET_X 20 +#define TRIANGLE_OFFSET_Y 0 + drawTriangleOutlined(TFT_WIDTH - TRIANGLE_OFFSET_X - 16, TFT_HEIGHT - TRIANGLE_OFFSET_Y - 4, + TFT_WIDTH - TRIANGLE_OFFSET_X - 4, TFT_HEIGHT - TRIANGLE_OFFSET_Y - 10, + TFT_WIDTH - TRIANGLE_OFFSET_X - 16, TFT_HEIGHT - TRIANGLE_OFFSET_Y - 16, c100, c542); + + drawTriangleOutlined(TRIANGLE_OFFSET_X + 16, TFT_HEIGHT - TRIANGLE_OFFSET_Y - 4, TRIANGLE_OFFSET_X + 4, + TFT_HEIGHT - TRIANGLE_OFFSET_Y - 10, TRIANGLE_OFFSET_X + 16, + TFT_HEIGHT - TRIANGLE_OFFSET_Y - 16, c100, c542); } } @@ -197,12 +218,15 @@ void rayPauseRender(ray_t* ray, uint32_t elapsedUs) */ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) { + int16_t tWidth = textWidth(&ray->ibm, rayMapNames[ray->p.mapId]); + drawText(&ray->ibm, rayMapColors[ray->p.mapId], rayMapNames[ray->p.mapId], (TFT_WIDTH - tWidth) / 2, 2); + // Figure out the largest cell size to draw the whole map centered on the screen int16_t cellSizeW = TFT_WIDTH / ray->map.w; - int16_t cellSizeH = TFT_HEIGHT / ray->map.h; + int16_t cellSizeH = (TFT_HEIGHT - (ray->ibm.height + 4)) / ray->map.h; int16_t cellSize = MIN(cellSizeW, cellSizeH); int16_t cellOffX = (TFT_WIDTH - (ray->map.w * cellSize)) / 2; - int16_t cellOffY = (TFT_HEIGHT - (ray->map.h * cellSize)) / 2; + int16_t cellOffY = (ray->ibm.height + 4) + (((TFT_HEIGHT - (ray->ibm.height + 4)) - (ray->map.h * cellSize)) / 2); // For each cell for (int16_t y = 0; y < ray->map.h; y++) @@ -232,17 +256,17 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) } case BG_DOOR_CHARGE: { - color = c234; + color = c404; break; } case BG_DOOR_MISSILE: { - color = c400; + color = c500; break; } case BG_DOOR_ICE: { - color = c004; + color = c005; break; } case BG_DOOR_XRAY: @@ -250,7 +274,7 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) // Hide XRAY doors until the player gets the xrayLoadOut if (ray->p.i.xrayLoadOut) { - color = c020; + color = c050; } else { @@ -265,10 +289,23 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) break; } case BG_DOOR_KEY_A: + { + color = c541; + break; + } case BG_DOOR_KEY_B: + { + color = c423; + break; + } case BG_DOOR_KEY_C: { - color = c440; + color = c234; + break; + } + case BG_DOOR_ARTIFACT: + { + color = c245; break; } default: @@ -297,6 +334,11 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) color = c113; break; } + case BG_FLOOR_HEAL: + { + color = c030; + break; + } default: { // Can't reach here @@ -315,13 +357,64 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) } } + // Look through scenery for warp points + node_t* currentNode = ray->scenery.first; + while (currentNode != NULL) + { + // Get a pointer from the linked list + rayObjCommon_t* obj = ((rayObjCommon_t*)currentNode->val); + + // Look for portals + if (OBJ_SCENERY_PORTAL == obj->type) + { + // Found a portal, look for corresponding script + node_t* scriptNode = ray->scripts[TOUCH].first; + while (NULL != scriptNode) + { + rayScript_t* scr = scriptNode->val; + // If this is the right script for this object + if ((TOUCH == scr->ifOp) && (WARP == scr->thenOp) && (scr->ifArgs.idList.ids[0] == obj->id)) + { + // And the player has visited the other end of the warp + if (ray->p.mapsVisited[scr->thenArgs.warpDest.mapId]) + { + // Draw a number indicating the warp destination + char num[8]; + snprintf(num, sizeof(num) - 1, "%1d", scr->thenArgs.warpDest.mapId + 1); + tWidth = textWidth(&ray->ibm, num); + drawText(&ray->ibm, c555, num, + cellOffX + (cellSize * FROM_FX(obj->posX)) + (cellSize - tWidth) / 2, + cellOffY + (cellSize * FROM_FX(obj->posY)) + (cellSize - ray->ibm.height) / 2); + } + break; + } + scriptNode = scriptNode->next; + } + } + + // Iterate to the next node + currentNode = currentNode->next; + } + // The player's location blinks, so draw it when appropriate - if (ray->pauseBlink) + int16_t cX = cellOffX + FROM_FX(cellSize * ray->p.posX); + int16_t cY = cellOffY + FROM_FX(cellSize * ray->p.posY); + drawPlayerIndicator(ray, cX, cY); +} + +/** + * @brief Draw the blinking player indicator on the pause screen + * + * @param ray The entire game state + * @param cX The X pixel to center on + * @param cY The Y pixel to center on + */ +static void drawPlayerIndicator(ray_t* ray, int16_t cX, int16_t cY) +{ + if (ray->blink) { // Draw a circle for the player - int16_t cX = cellOffX + FROM_FX(cellSize * ray->p.posX); - int16_t cY = cellOffY + FROM_FX(cellSize * ray->p.posY); - int16_t cR = cellSize / 2; + int16_t cR = 6; drawCircle(cX, cY, cR, c145); // Draw a line for the player's direction @@ -340,12 +433,10 @@ static void rayPauseRenderLocalMap(ray_t* ray, uint32_t elapsedUs) */ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs) { - fillDisplayArea(0, 0, TFT_WIDTH, TFT_HEIGHT, c100); - -#define MAP_X_MARGIN 16 -#define MAP_Y_MARGIN 36 -#define MAP_Y_MIDGAP 24 -#define MAP_SIZE 72 +#define MAP_X_MARGIN 16 +#define MAP_Y_MARGIN 36 +#define MAP_Y_MID_GAP 16 +#define MAP_SIZE 72 #define MAP_ROWS 2 #define MAP_COLS 3 @@ -355,6 +446,11 @@ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs) // Save coordinates for where to draw warp lines int16_t warpCoords[NUM_MAPS][NUM_MAP_CORNERS][2]; + // A texture to draw after artifacts are acquired + wsg_t* artifactWsg = getTexByType(ray, OBJ_ITEM_ARTIFACT); + int16_t aAOffX = (MAP_SIZE - artifactWsg->w) / 2; + int16_t aAOffY = (MAP_SIZE - artifactWsg->h) / 2; + // For all six maps in a 3x2 grid for (int16_t mapY = 0; mapY < MAP_ROWS; mapY++) { @@ -368,14 +464,20 @@ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs) { // Find the box coordinates int16_t startX = MAP_X_MARGIN + mapX * (MAP_SIZE + MAP_X_MARGIN); - int16_t startY = MAP_Y_MARGIN + mapY * (MAP_SIZE + MAP_Y_MIDGAP); + int16_t startY = MAP_Y_MARGIN + mapY * (MAP_SIZE + MAP_Y_MID_GAP); int16_t endX = startX + MAP_SIZE; int16_t endY = startY + MAP_SIZE; - // Draw the black box, outlined - fillDisplayArea(startX + 1, startY + 1, endX - 1, endY - 1, c000); + // Draw the dark red box, outlined + fillDisplayArea(startX + 1, startY + 1, endX - 1, endY - 1, c100); drawRect(startX, startY, endX, endY, rayMapColors[mapId]); + // Draw an artifact if was acquired here + if (ray->p.i.artifacts[mapId]) + { + drawWsgSimple(artifactWsg, startX + aAOffX, startY + aAOffY); + } + // Draw the name, either above or below the box int16_t tWidth = textWidth(&ray->ibm, rayMapNames[mapId]); if (0 == mapY) @@ -398,6 +500,14 @@ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs) warpCoords[mapId][BOTTOM_LEFT][0] = startX + WARP_POINT_INDENT; warpCoords[mapId][BOTTOM_LEFT][1] = endY - WARP_POINT_INDENT - 1; + + if (ray->p.mapId == mapId) + { + int16_t pPosX = startX + (MAP_SIZE * ray->p.posX) / TO_FX(ray->map.w); + int16_t pPosY = startY + (MAP_SIZE * ray->p.posY) / TO_FX(ray->map.h); + + drawPlayerIndicator(ray, pPosX, pPosY); + } } } } @@ -422,4 +532,69 @@ static void rayPauseRenderWorldMap(ray_t* ray, uint32_t elapsedUs) 6); } } + + // Draw the string + char collectionStr[32] = {0}; + snprintf(collectionStr, sizeof(collectionStr) - 1, "Percentage Complete: %" PRId32 "%%", getItemCompletePct(ray)); + int16_t tWidth = textWidth(&ray->ibm, collectionStr); + drawText(&ray->ibm, c555, collectionStr, (TFT_WIDTH - tWidth) / 2, TFT_HEIGHT - ray->ibm.height - 10); } + +/** + * @brief Get the percentage of items collected, 0 to 100 + * + * @return The percentage of items collected + */ +int32_t getItemCompletePct(ray_t* ray) +{ + // Count all the possible items in the game + int32_t numTotalItems = 6 + // energy tanks + ((2 * 6) + 1) + // Missile expansions; + 6 + // Artifacts + 2 + // Suits + 5; // Beams + + // Start counting what the player has + int32_t numAcquiredItems = 0; + + // For each map + for (int32_t mIdx = 0; mIdx < NUM_MAPS; mIdx++) + { + // Count energy tanks + for (int32_t eIdx = 0; eIdx < E_TANKS_PER_MAP; eIdx++) + { + if (-1 != ray->p.i.healthPickUps[mIdx][eIdx]) + { + numAcquiredItems++; + } + } + + // Count missile upgrades + for (int32_t sIdx = 0; sIdx < MISSILE_UPGRADES_PER_MAP; sIdx++) + { + if (-1 != ray->p.i.missilesPickUps[mIdx][sIdx]) + { + numAcquiredItems++; + } + } + + // Count artifacts + if (ray->p.i.artifacts[mIdx]) + { + numAcquiredItems++; + } + } + + // Count beams + numAcquiredItems += (ray->p.i.beamLoadOut ? 1 : 0); + numAcquiredItems += (ray->p.i.chargePowerUp ? 1 : 0); + numAcquiredItems += (ray->p.i.missileLoadOut ? 1 : 0); + numAcquiredItems += (ray->p.i.iceLoadOut ? 1 : 0); + numAcquiredItems += (ray->p.i.xrayLoadOut ? 1 : 0); + + // Count suits + numAcquiredItems += (ray->p.i.lavaSuit ? 1 : 0); + numAcquiredItems += (ray->p.i.waterSuit ? 1 : 0); + + return (numAcquiredItems * 100) / numTotalItems; +} \ No newline at end of file diff --git a/main/modes/ray/ray_pause.h b/main/modes/ray/ray_pause.h index fa5988023..c347253b4 100644 --- a/main/modes/ray/ray_pause.h +++ b/main/modes/ray/ray_pause.h @@ -6,5 +6,6 @@ void rayShowPause(ray_t* ray); void rayPauseCheckButtons(ray_t* ray); void rayPauseRender(ray_t* ray, uint32_t elapsedUs); +int32_t getItemCompletePct(ray_t* ray); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_player.c b/main/modes/ray/ray_player.c index 11f7ceb71..54439ed2c 100644 --- a/main/modes/ray/ray_player.c +++ b/main/modes/ray/ray_player.c @@ -10,6 +10,29 @@ #include "ray_map.h" #include "ray_pause.h" #include "ray_script.h" +#include "ray_death_screen.h" +#include "ray_enemy.h" +#include "ray_dialog.h" + +//============================================================================== +// Const data +//============================================================================== + +/** @brief random dialog when a missile expansion is acquired */ +const char* const missilePickupDialog[] = { + "Hey, you can hold more missiles now! Where? ...You don't want to know!", + "Hey, this wasn't the critical path, but at least you can express your frustration with " + "these additional missiles!", + "Watch, these five missiles are going to come in SO handy, just you wait.", + "Look at you, overachiever! Have some missiles for being such a good completionist.", + "Wow, who just leaves a bunch of missiles lying around? This is an all-ages event, come on.", + "Did you know that missiles go through enemy shields? Bet you thought we made them have " + "limited ammo for nothing, huh!", + "Why yes, this is a missile expansion! Mazel Tov!", +}; + +/** @brief special dialog for one missile */ +const char* missileSwimDialog = "All that swimming just for a missile upgrade? LAME."; //============================================================================== // Functions @@ -56,6 +79,9 @@ bool initializePlayer(ray_t* ray) // Set initial health ray->p.i.maxHealth = GAME_START_HEALTH; ray->p.i.health = GAME_START_HEALTH; + + // Set damage multiplier to 1; + ray->p.i.damageMult = 1; } else { @@ -71,6 +97,30 @@ bool initializePlayer(ray_t* ray) ray->planeX = -MUL_FX(TO_FX(2) / 3, ray->p.dirY); ray->planeY = MUL_FX(TO_FX(2) / 3, ray->p.dirX); + // Always start with at most ten missiles to not get locked behind doors + if (ray->p.i.missileLoadOut) + { + if (10 > ray->p.i.numMissiles) + { + if (10 > ray->p.i.maxNumMissiles) + { + ray->p.i.numMissiles = ray->p.i.maxNumMissiles; + } + else + { + ray->p.i.maxNumMissiles = 10; + } + } + } + + // Set the next loadout to current, to not swap + ray->nextLoadout = ray->p.loadout; + ray->loadoutChangeTimer = 0; + ray->forceLoadoutSwap = 0; + + // Always reload with full health + ray->p.i.health = ray->p.i.maxHealth; + return initFromScratch; } @@ -99,10 +149,10 @@ void raySaveVisitedTiles(ray_t* ray) * @brief Check button inputs for the player. This will move the player and shoot bullets * * @param ray The entire game state - * @param centeredSprite The sprite currently centered in the view + * @param centeredEnemy The enemy currently centered in the view, may be NULL * @param elapsedUs The elapsed time since this function was last called */ -void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t elapsedUs) +void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredEnemy, uint32_t elapsedUs) { // For convenience q24_8 pPosX = ray->p.posX; @@ -136,10 +186,10 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t // Set strafe to true ray->isStrafing = true; // If there is a centered sprite - if (centeredSprite) + if (centeredEnemy) { // Lock onto it - ray->targetedObj = centeredSprite; + ray->targetedObj = centeredEnemy; } } else @@ -157,36 +207,39 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t if (evt.down) { - // A was pressed - // Check ammo for the missile loadout - if (LO_MISSILE == ray->p.loadout) + if (0 >= ray->playerShotCooldown) { - if (0 < ray->p.i.numMissiles) + // A was pressed + // Check ammo for the missile loadout + if (LO_MISSILE == ray->p.loadout) { - // Decrement missile count - ray->p.i.numMissiles--; - // Fire a missile - bullet = OBJ_BULLET_MISSILE; + if (0 < ray->p.i.numMissiles) + { + // Decrement missile count + ray->p.i.numMissiles--; + // Fire a missile + bullet = OBJ_BULLET_MISSILE; + } } - } - else - { - // Start charging if applicable - if (LO_NORMAL == ray->p.loadout && ray->p.i.chargePowerUp) + else { - // Start charging - ray->chargeTimer = 1; + // Start charging if applicable + if (LO_NORMAL == ray->p.loadout && ray->p.i.chargePowerUp) + { + // Start charging + ray->chargeTimer = 1; + } + + // Fire according to loadout + const rayMapCellType_t bulletMap[NUM_LOADOUTS] = { + EMPTY, + OBJ_BULLET_NORMAL, ///< Normal loadout + OBJ_BULLET_MISSILE, ///< Missile loadout + OBJ_BULLET_ICE, ///< Ice beam loadout + OBJ_BULLET_XRAY ///< X-Ray loadout + }; + bullet = bulletMap[ray->p.loadout]; } - - // Fire according to loadout - const rayMapCellType_t bulletMap[NUM_LOADOUTS] = { - EMPTY, - OBJ_BULLET_NORMAL, ///< Normal loadout - OBJ_BULLET_MISSILE, ///< Missile loadout - OBJ_BULLET_ICE, ///< Ice beam loadout - OBJ_BULLET_XRAY ///< X-Ray loadout - }; - bullet = bulletMap[ray->p.loadout]; } } else @@ -205,10 +258,52 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t { // Fire a shot rayCreateBullet(ray, bullet, pPosX, pPosY, pDirX, pDirY, true); + + // Play SFX depending on bullet + switch (bullet) + { + case OBJ_BULLET_CHARGE: + { + ray->playerShotCooldown = 240000; + bzrPlaySfx(&ray->sfx_p_charge, BZR_RIGHT); + break; + } + case OBJ_BULLET_MISSILE: + { + ray->playerShotCooldown = 240000; + bzrPlaySfx(&ray->sfx_p_missile, BZR_RIGHT); + break; + } + case OBJ_BULLET_ICE: + { + ray->playerShotCooldown = 480000; + bzrPlaySfx(&ray->sfx_p_ice, BZR_RIGHT); + break; + } + case OBJ_BULLET_XRAY: + { + ray->playerShotCooldown = 240000; + bzrPlaySfx(&ray->sfx_p_xray, BZR_RIGHT); + break; + } + case OBJ_BULLET_NORMAL: + default: + { + ray->playerShotCooldown = 120000; + bzrPlaySfx(&ray->sfx_p_shoot, BZR_RIGHT); + break; + } + } } } } + // Count down shot cooldown + if (0 < ray->playerShotCooldown) + { + ray->playerShotCooldown -= elapsedUs; + } + // If charging the beam if (0 < ray->chargeTimer && ray->chargeTimer <= CHARGE_TIME_US) { @@ -226,6 +321,14 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t // Strafing is either locked or unlocked if (ray->isStrafing) { + if (NULL != ray->targetedObj) + { + // lock on the target before moving + pDirX = ray->targetedObj->posX - pPosX; + pDirY = ray->targetedObj->posY - pPosY; + fastNormVec(&pDirX, &pDirY); + } + if (ray->btnState & PB_RIGHT) { // Strafe right @@ -241,46 +344,46 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t } else { - // Assume rightward rotation, 5 degrees every 40000uS - int32_t rotateDeg = ((5 * (int32_t)elapsedUs) / 40000) % 360; - if (ray->btnState & PB_RIGHT) - { - // Rotate right, leave as-is - } - else if (ray->btnState & PB_LEFT) - { - // Rotate left, reverse direction - rotateDeg = 360 - rotateDeg; - } - else - { - // No rotation, zero it out - rotateDeg = 0; - } - - // If we should rotate - if (rotateDeg) + if (ray->btnState & (PB_RIGHT | PB_LEFT)) { - // Do trig functions, only once - int32_t sinVal = getSin1024(rotateDeg); - int32_t cosVal = getCos1024(rotateDeg); - // Find the rotated X and Y vectors - q24_8 newX = (pDirX * cosVal) - (pDirY * sinVal); - q24_8 newY = (pDirX * sinVal) + (pDirY * cosVal); - // Normalize the vector - fastNormVec(&newX, &newY); - - // Recompute the camera plane, orthogonal to the direction vector and scaled to 2/3 - ray->planeX = -MUL_FX(TO_FX(2) / 3, newY); - ray->planeY = MUL_FX(TO_FX(2) / 3, newX); + // Assume rightward rotation, 1 degree every 8000uS + int32_t rotateDeg = 0; + ray->pRotationTimer -= elapsedUs; + while (0 >= ray->pRotationTimer) + { + ray->pRotationTimer += 8000; + rotateDeg++; + } - // Save new direction vector - ray->p.dirX = newX; - ray->p.dirY = newY; + if (0 != rotateDeg) + { + if (ray->btnState & PB_LEFT) + { + // Rotate left, reverse direction + rotateDeg = 360 - rotateDeg; + } - // Also update the local copy - pDirX = newX; - pDirY = newY; + // Do trig functions, only once + int32_t sinVal = getSin1024(rotateDeg); + int32_t cosVal = getCos1024(rotateDeg); + // Find the rotated X and Y vectors + q24_8 newX = (pDirX * cosVal) - (pDirY * sinVal); + q24_8 newY = (pDirX * sinVal) + (pDirY * cosVal); + // Normalize the vector + fastNormVec(&newX, &newY); + + // Save new direction vector + ray->p.dirX = newX; + ray->p.dirY = newY; + + // Recompute the camera plane, orthogonal to the direction vector and scaled to 2/3 + ray->planeX = -MUL_FX(TO_FX(2) / 3, ray->p.dirY); + ray->planeY = MUL_FX(TO_FX(2) / 3, ray->p.dirX); + + // Also update the local copy + pDirX = newX; + pDirY = newY; + } } } @@ -316,9 +419,9 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t // If the player is in water if (isInWater) { - // Slow down movement by a fourth - deltaX /= 4; - deltaY /= 4; + // Slow down movement by a 8x + deltaX /= 8; + deltaY /= 8; } // Boundary checks are longer than the move dist to not get right up on the wall @@ -355,29 +458,25 @@ void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t markTileVisited(&ray->map, newCellX, newCellY); // Check scripts when entering cells - if (checkScriptEnter(ray, newCellX, newCellY)) - { - // Script warped, return - return; - } + checkScriptEnter(ray, newCellX, newCellY); } + } - // After moving position, recompute direction to targeted object - if (ray->isStrafing && ray->targetedObj) - { - // Re-lock on the target after moving - pDirX = ray->targetedObj->posX - pPosX; - pDirY = ray->targetedObj->posY - pPosY; - fastNormVec(&pDirX, &pDirY); - - // Set the player's direction - ray->p.dirX = pDirX; - ray->p.dirY = pDirY; - - // Recompute the 2d rayCaster version of camera plane, orthogonal to the direction vector and scaled to 2/3 - ray->planeX = -MUL_FX(TO_FX(2) / 3, pDirY); - ray->planeY = MUL_FX(TO_FX(2) / 3, pDirX); - } + // Finally, if there is a targeted object, orient towards it + if (ray->targetedObj) + { + // Re-lock on the target + pDirX = ray->targetedObj->posX - pPosX; + pDirY = ray->targetedObj->posY - pPosY; + fastNormVec(&pDirX, &pDirY); + + // Set the player's direction + ray->p.dirX = pDirX; + ray->p.dirY = pDirY; + + // Recompute the 2d rayCaster version of camera plane, orthogonal to the direction vector and scaled to 2/3 + ray->planeX = -MUL_FX(TO_FX(2) / 3, ray->p.dirY); + ray->planeY = MUL_FX(TO_FX(2) / 3, ray->p.dirX); } } @@ -451,6 +550,16 @@ void rayPlayerCheckJoystick(ray_t* ray, uint32_t elapsedUs) { if (ray->p.loadout != ray->nextLoadout) { + // If swapping to or from XRAY, also swap hidden enemy sprites + if (LO_XRAY == ray->nextLoadout) + { + switchEnemiesToXray(ray, true); + } + else if (LO_XRAY == ray->p.loadout) + { + switchEnemiesToXray(ray, false); + } + // Swap the loadout ray->p.loadout = ray->nextLoadout; // Set the timer for the load in @@ -470,12 +579,14 @@ void rayPlayerCheckJoystick(ray_t* ray, uint32_t elapsedUs) * @brief This handles what happens when a player touches an item * * @param ray The whole game state - * @param type The type of item touched + * @param item The item that was touched * @param mapId The current map ID, used to track non-unique persistent pick-ups - * @param itemId The item's ID */ -void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_t itemId) +void rayPlayerTouchItem(ray_t* ray, rayObjCommon_t* item, int32_t mapId) { + rayMapCellType_t type = item->type; + int32_t itemId = item->id; + // Assume saving after picking up an item bool saveAfterObtain = true; rayInventory_t* inventory = &ray->p.i; @@ -558,6 +669,18 @@ void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_ // Save the coordinates inventory->missilesPickUps[mapId][idx] = itemId; + + // World 3, Missile ID 12 gets special dialog + if (3 == ray->p.mapId && 12 == item->id) + { + rayShowDialog(ray, missileSwimDialog, item->sprite); + } + else + { + // Show random dialog + int32_t dialogIdx = esp_random() % ARRAY_SIZE(missilePickupDialog); + rayShowDialog(ray, missilePickupDialog[dialogIdx], item->sprite); + } break; } } @@ -592,12 +715,32 @@ void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_ case OBJ_ITEM_ARTIFACT: { inventory->artifacts[mapId] = true; + + // Check if all artifacts have been collected + bool collected = true; + for (int16_t aIdx = 0; aIdx < ARRAY_SIZE(inventory->artifacts); aIdx++) + { + if (!inventory->artifacts[aIdx]) + { + collected = false; + break; + } + } + + // If all were collected + if (collected) + { + // Increase damage output by 2 + inventory->damageMult = 2; + } break; } case OBJ_ITEM_PICKUP_ENERGY: { - // Transient, add 20 health, not going over the max - inventory->health = MIN(inventory->health + 20, inventory->maxHealth); + // Transient, add (GAME_START_HEALTH / 2) health, not going over the max + inventory->health = MIN(inventory->health + (GAME_START_HEALTH / 2), inventory->maxHealth); + // Play SFX + bzrPlaySfx(&ray->sfx_health, BZR_RIGHT); // Don't save after energy saveAfterObtain = false; break; @@ -635,6 +778,8 @@ void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_ // Autosave raySavePlayer(ray); raySaveVisitedTiles(ray); + // Play SFX + bzrPlaySfx(&ray->sfx_item_get, BZR_RIGHT); } } @@ -644,24 +789,78 @@ void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_ * @param ray The entire game state * @param elapsedUs The elapsed time since this function was last called */ -void rayPlayerCheckLava(ray_t* ray, uint32_t elapsedUs) +void rayPlayerCheckFloorEffect(ray_t* ray, uint32_t elapsedUs) { - // If the player is in lava without the lava suit + // If the player is in lava without the lava suit if ((!ray->p.i.lavaSuit) && (BG_FLOOR_LAVA == ray->map.tiles[FROM_FX(ray->p.posX)][FROM_FX(ray->p.posY)].type)) { // Run a timer to take lava damage - ray->lavaTimer += elapsedUs; - if (ray->lavaTimer <= US_PER_LAVA_DAMAGE) + ray->floorEffectTimer += elapsedUs; + if (ray->floorEffectTimer <= US_PER_FLOOR_EFFECT) { - ray->lavaTimer -= US_PER_LAVA_DAMAGE; - if (ray->p.i.health) - { - ray->p.i.health--; - if (0 == ray->p.i.health) - { - // TODO game over - } - } + ray->floorEffectTimer -= US_PER_FLOOR_EFFECT; + rayPlayerDecrementHealth(ray, 1); + } + + // If the player is entering lava + if (false == ray->playerInLava) + { + ray->playerInLava = true; + // Start looping SFX + ray->sfx_lava_dmg.shouldLoop = true; + bzrPlaySfx(&ray->sfx_lava_dmg, BZR_RIGHT); } } + else if (BG_FLOOR_HEAL == ray->map.tiles[FROM_FX(ray->p.posX)][FROM_FX(ray->p.posY)].type) + { + // Run a timer to heal + ray->floorEffectTimer += elapsedUs; + if (ray->floorEffectTimer <= US_PER_FLOOR_EFFECT) + { + ray->floorEffectTimer -= US_PER_FLOOR_EFFECT; + rayPlayerDecrementHealth(ray, -1); + } + } + else if (true == ray->playerInLava) + { + ray->playerInLava = false; + // Stop looping SFX + ray->sfx_lava_dmg.shouldLoop = true; + } +} + +/** + * @brief Decrement player health and check for death + * + * @param ray The entire game state + * @param health The amount of health to decrement + */ +void rayPlayerDecrementHealth(ray_t* ray, int32_t health) +{ + // Decrement health + ray->p.i.health -= health; + + if (health > 0) + { + // Play SFX + bzrPlaySfx(&ray->sfx_p_damage, BZR_RIGHT); + } + + // Make LEDs red + ray->ledHue = 0; + + // Check for death + if (0 >= ray->p.i.health) + { + // load the last save + rayStartGame(); + + // Show the death screen + rayShowDeathScreen(ray); + } + else if (ray->p.i.health > ray->p.i.maxHealth) + { + // Never go over the max health + ray->p.i.health = ray->p.i.maxHealth; + } } diff --git a/main/modes/ray/ray_player.h b/main/modes/ray/ray_player.h index e427d24a0..c95b45561 100644 --- a/main/modes/ray/ray_player.h +++ b/main/modes/ray/ray_player.h @@ -6,9 +6,10 @@ bool initializePlayer(ray_t* ray); void rayPlayerCheckButtons(ray_t* ray, rayObjCommon_t* centeredSprite, uint32_t elapsedUs); void rayPlayerCheckJoystick(ray_t* ray, uint32_t elapsesUs); -void rayPlayerTouchItem(ray_t* ray, rayMapCellType_t type, int32_t mapId, int32_t itemId); -void rayPlayerCheckLava(ray_t* ray, uint32_t elapsedUs); +void rayPlayerTouchItem(ray_t* ray, rayObjCommon_t* item, int32_t mapId); +void rayPlayerCheckFloorEffect(ray_t* ray, uint32_t elapsedUs); void raySavePlayer(ray_t* ray); void raySaveVisitedTiles(ray_t* ray); +void rayPlayerDecrementHealth(ray_t* ray, int32_t health); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_renderer.c b/main/modes/ray/ray_renderer.c index 966b90949..1a8aa9f7f 100644 --- a/main/modes/ray/ray_renderer.c +++ b/main/modes/ray/ray_renderer.c @@ -97,7 +97,7 @@ void castFloorCeiling(ray_t* ray, int32_t firstRow, int32_t lastRow) // Set a pointer for textures later paletteColor_t* texture = NULL; // The ceiling texture is always this - paletteColor_t* ceilTexture = getTexByType(ray, BG_CEILING)->px; + paletteColor_t* ceilTexture = ray->envTex[ray->p.mapId % NUM_ENVS][TX_CEILING].px; // Save these to not resolve pointers later uint32_t mapW = ray->map.w; @@ -197,21 +197,16 @@ void castFloorCeiling(ray_t* ray, int32_t firstRow, int32_t lastRow) { // Get the next cell texture rayMapCellType_t type = ray->map.tiles[cellX][cellY].type; - // Always draw floor under doors - if (CELL_IS_TYPE(type, BG | DOOR)) - { - type = BG_FLOOR; - } -#ifdef TEST_TEX - if ((ray->p.mapId < 4) && (BG_FLOOR_LAVA != type) && (BG_FLOOR_WATER != type)) + // Water, lava, and heal are special + if ((BG_FLOOR_LAVA == type) || (BG_FLOOR_WATER == type) || (BG_FLOOR_HEAL == type)) { - texture = ray->testTextures[ray->p.mapId * 2].px; + texture = getTexByType(ray, type)->px; } else -#endif { - texture = getTexByType(ray, type)->px; + // Otherwise draw normal floor for this map + texture = ray->envTex[ray->p.mapId % NUM_ENVS][TX_FLOOR].px; } } else @@ -513,22 +508,18 @@ void castWalls(ray_t* ray) // Pick the texture based on the map tile paletteColor_t* tex; + rayMapCellType_t type = ray->map.tiles[mapX][mapY].type; if (xrayOverride) { - tex = getTexByType(ray, BG_WALL_1)->px; + tex = ray->envTex[ray->p.mapId % NUM_ENVS][TX_WALL_1].px; + } + else if (BG_WALL_1 <= type && type <= BG_WALL_5) + { + tex = ray->envTex[ray->p.mapId % NUM_ENVS][type - BG_WALL_1].px; } else { -#ifdef TEST_TEX - if (ray->p.mapId < 4 && !CELL_IS_TYPE(ray->map.tiles[mapX][mapY].type, BG | DOOR)) - { - tex = ray->testTextures[ray->p.mapId * 2 + 1].px; - } - else -#endif - { - tex = getTexByType(ray, ray->map.tiles[mapX][mapY].type)->px; - } + tex = getTexByType(ray, type)->px; } // Draw a vertical strip @@ -684,12 +675,14 @@ static int objDistComparator(const void* obj1, const void* obj2) * This is called from the main loop. * * @param ray The entire game state - * @return The closest sprite in the lock zone, i.e. center of the display. This may be NULL if there are no centered - * sprites. + * @param closestEnemy Return pointer to the closest enemy to the player. The return may be NULL + * @return The closest enemy in the lock zone, i.e. center of the display. This may be NULL if there are no centered + * enemies. */ -rayObjCommon_t* castSprites(ray_t* ray) +rayObjCommon_t* castSprites(ray_t* ray, rayEnemy_t** closestEnemy) { - rayObjCommon_t* lockedObj = NULL; + rayObjCommon_t* lockedEnemy = NULL; + *closestEnemy = NULL; // Setup to draw SETUP_FOR_TURBO(); @@ -780,6 +773,9 @@ rayObjCommon_t* castSprites(ray_t* ray) // Sort the sprites by distance qsort(allObjs, allObjsIdx, sizeof(objDist_t), objDistComparator); + // Calculate the width modifier for 'rotated' items + int32_t widthMod = getSin1024(ray->itemRotateDeg); + // after sorting the sprites, do the projection and draw them for (int i = 0; i < allObjsIdx; i++) { @@ -789,6 +785,12 @@ rayObjCommon_t* castSprites(ray_t* ray) // Make sure this object slot is occupied if (-1 != obj->id) { + bool isEnemy = CELL_IS_TYPE(obj->type, OBJ | ENEMY); + if (isEnemy) + { + *closestEnemy = (rayEnemy_t*)obj; + } + // Get WSG dimensions for convenience uint32_t tWidth = obj->sprite->w; uint32_t tHeight = obj->sprite->h; @@ -836,6 +838,22 @@ rayObjCommon_t* castSprites(ray_t* ray) spriteWidth = -spriteWidth; } + // If this is an item that should rotate + if (CELL_IS_TYPE(obj->type, OBJ | ITEM) && (OBJ_ITEM_ENERGY_TANK != obj->type) + && (OBJ_ITEM_PICKUP_ENERGY != obj->type) && (OBJ_ITEM_PICKUP_MISSILE != obj->type)) + { + // Scale this item's width according to current rotation + spriteWidth = (spriteWidth * widthMod) / 1024; + // If this scales to 0, don't draw it + if (0 == spriteWidth) + { + // If this sprite has zero width, don't draw it + continue; + } + // Copy the global mirror to this object + obj->spriteMirrored = ray->itemRotateMirror; + } + // This is the texture step per-screen-pixel q16_16 texXDelta = (tWidth << 16) / spriteWidth; // This is the inital texture X coordinate @@ -891,6 +909,25 @@ rayObjCommon_t* castSprites(ray_t* ray) // Find the pixel Y coordinate where the sprite draw starts. It may be negative int32_t drawStartY = (-spriteHeight + TFT_HEIGHT) / 2 + spritePosZ; + + // If this is an enemy + bool drawWarpLine = false; + if (isEnemy) + { + rayEnemy_t* enemy = (rayEnemy_t*)obj; + // And the enemy is warping in + if (0 < enemy->warpTimer) + { + // Start drawing at an offset Y + int32_t offset = ((enemy->warpTimer * spriteHeight) / E_WARP_TIME); + drawStartY += offset; + // Start drawing within the sprite + initialTexY = texYDelta * (offset); + + drawWarpLine = true; + } + } + if (drawStartY < 0) { // Advance the initial texture Y coordinate by the difference @@ -914,15 +951,30 @@ rayObjCommon_t* castSprites(ray_t* ray) if (transformY < ray->wallDistBuffer[stripe]) { // Check if this should be locked onto - if (((TFT_WIDTH / 2) - LOCK_ZONE) <= stripe && stripe <= ((TFT_WIDTH / 2) + LOCK_ZONE)) + if (((TFT_WIDTH / 2) - LOCK_ZONE) <= stripe && stripe <= ((TFT_WIDTH / 2) + LOCK_ZONE) + && CELL_IS_TYPE(obj->type, OBJ | ENEMY)) { // Closest sprites are drawn last, so override the lock - lockedObj = obj; + lockedEnemy = obj; } // Reset the texture Y coordinate q16_16 texY = initialTexY; + // If an enemy is warping in + if (drawWarpLine) + { + // Draw a line above the partial sprite + if (0 <= drawStartY - 1) + { + TURBO_SET_PIXEL(stripe, drawStartY - 1, c303); + if (0 <= drawStartY - 2) + { + TURBO_SET_PIXEL(stripe, drawStartY - 2, c550); + } + } + } + // for every pixel of the current stripe for (int32_t y = drawStartY; y < drawEndY; y++) { @@ -944,9 +996,45 @@ rayObjCommon_t* castSprites(ray_t* ray) } texX += texXDelta; } + + // If this is a blocking enemy + if ((isEnemy) && (E_BLOCKING == ((rayEnemy_t*)obj)->state)) + { + // Draw a circle shield with wallDistBuffer checks + // Drawing is largely copied from drawCircleInner() + int32_t r = spriteHeight / 2; + int32_t xm = spriteScreenX; + int32_t ym = (TFT_HEIGHT / 2) + spritePosZ; + int32_t x = -r, y = 0, err = 2 - 2 * r; /* bottom left to top right */ + do + { + int32_t cdX = xm - x; + if ((0 <= cdX) && (cdX < TFT_WIDTH) && (transformY < ray->wallDistBuffer[cdX])) + { + TURBO_SET_PIXEL_BOUNDS((cdX), (ym + y), c550); + TURBO_SET_PIXEL_BOUNDS((cdX), (ym - y), c550); + } + cdX = xm - y; + if ((0 <= cdX) && (cdX < TFT_WIDTH) && (transformY < ray->wallDistBuffer[cdX])) + { + TURBO_SET_PIXEL_BOUNDS((cdX), (ym - x), c550); + TURBO_SET_PIXEL_BOUNDS((cdX), (ym + x), c550); + } + + r = err; + if (r <= y) + { + err += ++y * 2 + 1; /* e_xy+e_y < 0 */ + } + if (r > x || err > y) /* e_xy+e_x > 0 or no 2nd y-step */ + { + err += ++x * 2 + 1; /* -> x-step now */ + } + } while (x < 0); + } } } - return lockedObj; + return lockedEnemy; } /** @@ -977,30 +1065,37 @@ void drawHud(ray_t* ray) yOffset += ((ray->loadoutChangeTimer * gun->h) / LOADOUT_TIMER_US); } } - drawWsgSimple(gun, TFT_WIDTH - gun->w, yOffset); + drawWsgSimple(gun, TFT_WIDTH - gun->w + ray->gunShakeX, yOffset); } - // If the player has missiles - if (ray->p.i.missileLoadOut) - { - // Draw a count of missiles - char missileStr[16] = {0}; - snprintf(missileStr, sizeof(missileStr) - 1, "M:%02" PRId32 "/%02" PRId32, ray->p.i.numMissiles, - ray->p.i.maxNumMissiles); - drawText(&ray->ibm, c555, missileStr, 40, TFT_HEIGHT - ray->ibm.height); - } - - // Draw a count of Keys - char keyStr[16] = "K:"; + // Draw Keys + int16_t xOff = 40; + const rayMapCellType_t kTypes[] = {OBJ_ITEM_KEY_A, OBJ_ITEM_KEY_B, OBJ_ITEM_KEY_C}; for (int16_t kIdx = 0; kIdx < NUM_KEYS; kIdx++) { if (KEY == ray->p.i.keys[ray->p.mapId][kIdx]) { - char thisKeyStr[] = {'0' + kIdx, 0}; - strcat(keyStr, thisKeyStr); + wsg_t* keyTex = getTexByType(ray, kTypes[kIdx]); + drawWsgSimpleHalf(keyTex, xOff, TFT_HEIGHT - (keyTex->h / 2)); + xOff += (keyTex->w / 2) - 4; } } - drawText(&ray->ibm, c555, keyStr, 100, TFT_HEIGHT - ray->ibm.height); + + // If the player has missiles + if (ray->p.i.missileLoadOut) + { + xOff = 103; + // Get texture and string + wsg_t* mTex = &ray->missileHUDicon; + char missileStr[16] = {0}; + snprintf(missileStr, sizeof(missileStr) - 1, "%02" PRId32, ray->p.i.numMissiles); + + // Draw missile icon + drawWsgSimple(mTex, xOff, TFT_HEIGHT - mTex->h); + xOff += (mTex->w) + 2; + // Draw a count of missiles + drawText(&ray->ibm, c555, missileStr, xOff, TFT_HEIGHT - (mTex->h + ray->ibm.height) / 2); + } #define BAR_END_MARGIN 40 #define BAR_SIDE_MARGIN 8 @@ -1028,22 +1123,22 @@ void drawHud(ray_t* ray) chargeIndicatorStart, // BAR_SIDE_MARGIN + BAR_WIDTH, // TFT_HEIGHT - BAR_END_MARGIN, // - c550); + c420); fillDisplayArea(TFT_WIDTH - BAR_SIDE_MARGIN - BAR_WIDTH, // chargeIndicatorStart, // TFT_WIDTH - BAR_SIDE_MARGIN, // TFT_HEIGHT - BAR_END_MARGIN, // - c550); + c420); // Draw side bars according to suit colors - paletteColor_t sideBarColor = c432; + paletteColor_t sideBarColor = c552; if (ray->p.i.waterSuit) { - sideBarColor = c223; + sideBarColor = c125; } else if (ray->p.i.lavaSuit) { - sideBarColor = c510; + sideBarColor = c500; } fillDisplayArea(BAR_SIDE_MARGIN, // BAR_END_MARGIN, // @@ -1055,6 +1150,73 @@ void drawHud(ray_t* ray) TFT_WIDTH - BAR_SIDE_MARGIN, // chargeIndicatorStart, // sideBarColor); + + // Draw target if locked on + if (NULL != ray->targetedObj) + { + // Pick color based on loadout + paletteColor_t color = c114; + switch (ray->p.loadout) + { + default: + case LO_NORMAL: + { + color = c114; + break; + } + case LO_MISSILE: + { + color = c401; + break; + } + case LO_ICE: + { + color = c135; + break; + } + case LO_XRAY: + { + color = c130; + break; + } + } +#define T_SIZE 20 +#define T_THICK 3 +#define T_ARM 7 + // Draw some brackets + fillDisplayArea(TFT_WIDTH / 2 - T_SIZE, // + TFT_HEIGHT / 2 - T_SIZE, // + TFT_WIDTH / 2 - T_SIZE + T_THICK, // + TFT_HEIGHT / 2 + T_SIZE, // + color); + fillDisplayArea(TFT_WIDTH / 2 + T_SIZE - T_THICK, // + TFT_HEIGHT / 2 - T_SIZE, // + TFT_WIDTH / 2 + T_SIZE, // + TFT_HEIGHT / 2 + T_SIZE, // + color); + + fillDisplayArea(TFT_WIDTH / 2 - T_SIZE + T_THICK, // + TFT_HEIGHT / 2 - T_SIZE, // + TFT_WIDTH / 2 - T_SIZE + T_THICK + T_ARM, // + TFT_HEIGHT / 2 - T_SIZE + T_THICK, // + color); + fillDisplayArea(TFT_WIDTH / 2 - T_SIZE + T_THICK, // + TFT_HEIGHT / 2 + T_SIZE - T_THICK, // + TFT_WIDTH / 2 - T_SIZE + T_THICK + T_ARM, // + TFT_HEIGHT / 2 + T_SIZE, // + color); + + fillDisplayArea(TFT_WIDTH / 2 + T_SIZE - T_THICK - T_ARM, // + TFT_HEIGHT / 2 - T_SIZE, // + TFT_WIDTH / 2 + T_SIZE - T_THICK, // + TFT_HEIGHT / 2 - T_SIZE + T_THICK, // + color); + fillDisplayArea(TFT_WIDTH / 2 + T_SIZE - T_THICK - T_ARM, // + TFT_HEIGHT / 2 + T_SIZE - T_THICK, // + TFT_WIDTH / 2 + T_SIZE - T_THICK, // + TFT_HEIGHT / 2 + T_SIZE, // + color); + } } /** @@ -1163,4 +1325,140 @@ void runEnvTimers(ray_t* ray, uint32_t elapsedUs) } } } + + // "Rotate" item renders by one degree every 16384uS + ray->itemRotateTimer -= elapsedUs; + while (ray->itemRotateTimer <= 0) + { + ray->itemRotateTimer += 16384; + ray->itemRotateDeg++; + // Only rotate between 0 and 179 degrees + if (180 <= ray->itemRotateDeg) + { + ray->itemRotateDeg = 0; + // Mirror sprites every rotation to account for asymmetry + ray->itemRotateMirror = !ray->itemRotateMirror; + } + } + + // If the gun is charged + if (ray->chargeTimer >= CHARGE_TIME_US) + { + // Run a timer to shake it left and right + ray->gunShakeTimer -= elapsedUs; + while (ray->gunShakeTimer <= 0) + { + ray->gunShakeTimer += 10000; + if (true == ray->gunShakeL) + { + ray->gunShakeX++; + if (10 <= ray->gunShakeX) + { + ray->gunShakeL = false; + } + } + else + { + ray->gunShakeX--; + if (0 >= ray->gunShakeX) + { + ray->gunShakeL = true; + } + } + } + } + else + { + // If the gun is not charged, make sure this is reset + ray->gunShakeX = 0; + } +} + +/** + * @brief Draw LEDs as a radar pointing to the closest enemy + * + * @param ray The entire game state + * @param closestEnemy The closest enemy, may be NULL + */ +void rayLightLeds(ray_t* ray, rayEnemy_t* closestEnemy) +{ + led_t leds[CONFIG_NUM_LEDS] = {0}; + bool ledsSet = false; + + if (NULL != closestEnemy) + { + // Angles around a circle at 45 degree increments (one per LED) + // clang-format off + const q24_8 normLedAngles[CONFIG_NUM_LEDS][2] = { + {0xFFFFFF9E, 0x000000EC}, + {0xFFFFFF14, 0x00000062}, + {0xFFFFFF14, 0xFFFFFF9E}, + {0xFFFFFF9E, 0xFFFFFF14}, + {0x00000062, 0xFFFFFF14}, + {0x000000EC, 0xFFFFFF9E}, + {0x000000EC, 0x00000062}, + {0x00000062, 0x000000EC}, + }; + // clang-format on + + // Find the player's view angle + int32_t pDegrees = cordicAtan2(ray->p.dirX, -ray->p.dirY); + // Negate it + if (pDegrees != 0) + { + pDegrees = 360 - pDegrees; + } + + // Get a vector from the player to the enemy + q24_8 xDiff = SUB_FX(closestEnemy->c.posX, ray->p.posX); + q24_8 yDiff = SUB_FX(closestEnemy->c.posY, ray->p.posY); + + // Get a magnitude, for brightness + q24_8 dist = ADD_FX(MUL_FX(xDiff, xDiff), MUL_FX(yDiff, yDiff)); + + // Rotate the enemy vector in relation to the player + int32_t pSin = getSin1024(pDegrees); + int32_t pCos = getCos1024(pDegrees); + q24_8 eRotAngleX = ((xDiff * pCos) - (yDiff * pSin)) / 1024; + q24_8 eRotAngleY = ((xDiff * pSin) + (yDiff * pCos)) / 1024; + + // Normalize the vector + fastNormVec(&eRotAngleX, &eRotAngleY); + +#define MAX_RADAR_DIST 32768 + + // Calculate each LED's brightness + if (dist < MAX_RADAR_DIST) + { + int32_t brightness = MAX_RADAR_DIST - dist; + for (int32_t lIdx = 0; lIdx < ARRAY_SIZE(leds); lIdx++) + { + // The brightness is the dot product between the LED's vector and the vector to the enemy + // dotProd of two normalized vectors is between -1 and 1 + q24_8 dotProd = ADD_FX(MUL_FX(normLedAngles[lIdx][0], eRotAngleX), // + MUL_FX(normLedAngles[lIdx][1], eRotAngleY)); + // Shift dotProd to the range 0 to 1, which is actually 0 to 256 + dotProd = ADD_FX(TO_FX(1), dotProd) / 2; + + // Light the LED + int32_t ledVal = (dotProd * brightness) / MAX_RADAR_DIST; + leds[lIdx] = LedEHSVtoHEXhelper(ray->ledHue, 0xFF, CLAMP(ledVal, 0, 0xFF), true); + } + // Note the LEDs are set + ledsSet = true; + } + } + + // If the LEDs are not set (no enemy or out of range) + if (!ledsSet) + { + // Light all evenly + for (int32_t lIdx = 0; lIdx < ARRAY_SIZE(leds); lIdx++) + { + leds[lIdx] = LedEHSVtoHEXhelper(ray->ledHue, 0xFF, 0x80, true); + } + } + + // Set the LEDs + setLeds(leds, CONFIG_NUM_LEDS); } diff --git a/main/modes/ray/ray_renderer.h b/main/modes/ray/ray_renderer.h index fad5e2f9f..749c2e126 100644 --- a/main/modes/ray/ray_renderer.h +++ b/main/modes/ray/ray_renderer.h @@ -11,7 +11,8 @@ void runEnvTimers(ray_t* ray, uint32_t elapsedUs); void castFloorCeiling(ray_t* ray, int32_t firstRow, int32_t lastRow); void castWalls(ray_t* ray); -rayObjCommon_t* castSprites(ray_t* ray); +rayObjCommon_t* castSprites(ray_t* ray, rayEnemy_t** closestEnemy); void drawHud(ray_t* ray); +void rayLightLeds(ray_t* ray, rayEnemy_t* closestEnemy); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_script.c b/main/modes/ray/ray_script.c index 06f54774d..c62f383e9 100644 --- a/main/modes/ray/ray_script.c +++ b/main/modes/ray/ray_script.c @@ -4,10 +4,12 @@ #include "ray_player.h" #include "ray_map.h" #include "ray_warp_screen.h" +#include "hdw-nvs.h" +#include "ray_credits.h" -static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait); -static bool checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* portrait); -static bool checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y); +static void executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait); +static void checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* portrait); +static void checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y); static void freeScript(rayScript_t* script); /** @@ -27,8 +29,8 @@ void loadScripts(ray_t* ray, const uint8_t* fileData, uint32_t fileSize, uint32_ // For each script for (int sIdx = 0; sIdx < numScripts; sIdx++) { - // Read the script length - uint8_t scriptLen = (fileData[fileIdx] << 8) | (fileData[fileIdx + 1]); + // Read the script length (don't actually care) + // uint8_t scriptLen = (fileData[fileIdx] << 8) | (fileData[fileIdx + 1]); fileIdx += 2; // Allocate a script @@ -285,9 +287,8 @@ static void freeScript(rayScript_t* script) * @param scriptList The list of scripts to check * @param id The ID to check * @param portrait A portrait to draw on dialogs - * @return true if the script warped and memory is unsafe to use */ -static bool checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* portrait) +static void checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* portrait) { // Iterate over all nodes node_t* currentNode = scriptList->first; @@ -366,14 +367,10 @@ static bool checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* por if (shouldExecute) { // Do it - if (executeScriptEvent(ray, script, portrait)) - { - // Script warped, return - return true; - } + executeScriptEvent(ray, script, portrait); - // Mark it as inactive if this is a one time script - script->isActive = (ALWAYS == script->ifArgs.idList.oneTime); + // Mark it as inactive if this is a one time script and the reset timer is inactive + script->isActive = (ALWAYS == script->ifArgs.idList.oneTime) && (0 == script->resetTimerSec); // Reset the triggered IDs memset(script->ifArgs.idList.idsTriggered, false, sizeof(bool) * script->ifArgs.idList.numIds); @@ -383,7 +380,6 @@ static bool checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* por // Move to the next script currentNode = currentNode->next; } - return false; } /** @@ -392,11 +388,10 @@ static bool checkScriptId(ray_t* ray, list_t* scriptList, int32_t id, wsg_t* por * @param ray The entire game state * @param id The ID of the shot object * @param portrait A portrait to draw on dialogs - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptShootObjs(ray_t* ray, int32_t id, wsg_t* portrait) +void checkScriptShootObjs(ray_t* ray, int32_t id, wsg_t* portrait) { - return checkScriptId(ray, &ray->scripts[SHOOT_OBJS], id, portrait); + checkScriptId(ray, &ray->scripts[SHOOT_OBJS], id, portrait); } /** @@ -405,11 +400,10 @@ bool checkScriptShootObjs(ray_t* ray, int32_t id, wsg_t* portrait) * @param ray The entire game state * @param id The ID of the dead enemy * @param portrait A portrait to draw on dialogs - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptKill(ray_t* ray, int32_t id, wsg_t* portrait) +void checkScriptKill(ray_t* ray, int32_t id, wsg_t* portrait) { - return checkScriptId(ray, &ray->scripts[KILL], id, portrait); + checkScriptId(ray, &ray->scripts[KILL], id, portrait); } /** @@ -418,11 +412,10 @@ bool checkScriptKill(ray_t* ray, int32_t id, wsg_t* portrait) * @param ray The entire game state * @param id The ID of the item obtained * @param portrait A portrait to draw on dialogs - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptGet(ray_t* ray, int32_t id, wsg_t* portrait) +void checkScriptGet(ray_t* ray, int32_t id, wsg_t* portrait) { - return checkScriptId(ray, &ray->scripts[GET], id, portrait); + checkScriptId(ray, &ray->scripts[GET], id, portrait); } /** @@ -431,11 +424,10 @@ bool checkScriptGet(ray_t* ray, int32_t id, wsg_t* portrait) * @param ray The entire game state * @param id The ID of the object touched * @param portrait A portrait to draw on dialogs - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptTouch(ray_t* ray, int32_t id, wsg_t* portrait) +void checkScriptTouch(ray_t* ray, int32_t id, wsg_t* portrait) { - return checkScriptId(ray, &ray->scripts[TOUCH], id, portrait); + checkScriptId(ray, &ray->scripts[TOUCH], id, portrait); } /** @@ -445,9 +437,8 @@ bool checkScriptTouch(ray_t* ray, int32_t id, wsg_t* portrait) * @param scriptList The list of scripts to check * @param x The X coordinate of the cell * @param y The Y coordinate of the cell - * @return true if the script warped and memory is unsafe to use */ -static bool checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y) +static void checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y) { // Iterate over all nodes node_t* currentNode = scriptList->first; @@ -526,14 +517,10 @@ static bool checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y if (shouldExecute) { // Do it - if (executeScriptEvent(ray, script, &ray->portrait)) - { - // Script warped, return - return true; - } + executeScriptEvent(ray, script, &ray->portrait); - // Mark it as inactive if this is a one time script - script->isActive = (ALWAYS == script->ifArgs.cellList.oneTime); + // Mark it as inactive if this is a one time script and the reset timer is inactive + script->isActive = (ALWAYS == script->ifArgs.cellList.oneTime) && (0 == script->resetTimerSec); // Reset the triggered cells memset(script->ifArgs.cellList.cellsTriggered, false, sizeof(bool) * script->ifArgs.cellList.numCells); @@ -543,7 +530,6 @@ static bool checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y // Move to the next script currentNode = currentNode->next; } - return false; } /** @@ -552,11 +538,10 @@ static bool checkScriptCell(ray_t* ray, list_t* scriptList, int32_t x, int32_t y * @param ray The entire game state * @param x The X coordinate of the shot wall * @param y The Y coordinate of the shot wall - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptShootWall(ray_t* ray, int32_t x, int32_t y) +void checkScriptShootWall(ray_t* ray, int32_t x, int32_t y) { - return checkScriptCell(ray, &ray->scripts[SHOOT_WALLS], x, y); + checkScriptCell(ray, &ray->scripts[SHOOT_WALLS], x, y); } /** @@ -565,11 +550,10 @@ bool checkScriptShootWall(ray_t* ray, int32_t x, int32_t y) * @param ray The entire game state * @param x The X coordinate of the cell entered * @param y The Y coordinate of the cell entered - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptEnter(ray_t* ray, int32_t x, int32_t y) +void checkScriptEnter(ray_t* ray, int32_t x, int32_t y) { - return checkScriptCell(ray, &ray->scripts[ENTER], x, y); + checkScriptCell(ray, &ray->scripts[ENTER], x, y); } /** @@ -577,9 +561,8 @@ bool checkScriptEnter(ray_t* ray, int32_t x, int32_t y) * * @param ray The entire game state * @param elapsedUs The time since this function was called last, in microseconds - * @return true if the script warped and memory is unsafe to use */ -bool checkScriptTime(ray_t* ray, uint32_t elapsedUs) +void checkScriptTime(ray_t* ray, uint32_t elapsedUs) { // Keep track of elapsed microseconds ray->scriptTimer += elapsedUs; @@ -604,11 +587,8 @@ bool checkScriptTime(ray_t* ray, uint32_t elapsedUs) if (script->ifArgs.time <= ray->secondsSinceStart) { // Do it - if (executeScriptEvent(ray, script, &ray->portrait)) - { - // Script warped, return - return true; - } + executeScriptEvent(ray, script, &ray->portrait); + // Mark it as inactive script->isActive = false; } @@ -617,8 +597,35 @@ bool checkScriptTime(ray_t* ray, uint32_t elapsedUs) // Move to the next currentNode = currentNode->next; } + + // For all script types + for (int16_t sIdx = 0; sIdx < ARRAY_SIZE(ray->scripts); sIdx++) + { + // For all scripts + currentNode = ray->scripts[sIdx].first; + while (currentNode != NULL) + { + // Get the script + rayScript_t* script = currentNode->val; + + // If there is time on the timer + if (0 < script->resetTimerSec) + { + // Decrement + script->resetTimerSec--; + // If it expired + if (0 == script->resetTimerSec) + { + // Reactivate the script + script->isActive = true; + } + } + + // Move to the next + currentNode = currentNode->next; + } + } } - return false; } /** @@ -627,9 +634,8 @@ bool checkScriptTime(ray_t* ray, uint32_t elapsedUs) * @param ray The entire game state * @param script The script which should be executed * @param portrait A portrait to draw on dialogs - * @param true if the player warped and scripts reloaded, false if there was no warp */ -static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) +static void executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) { switch (script->thenOp) { @@ -644,6 +650,8 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) ray->map.tiles[x][y].openingDirection = 1; // Mark it as permanently open ray->map.visitedTiles[(y * ray->map.w) + x] = SCRIPT_DOOR_OPEN; + // Play SFX + bzrPlaySfx(&ray->sfx_door_open, BZR_RIGHT); } break; } @@ -660,6 +668,8 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) } case SPAWN: { + // Start timer to not re-trigger immediately + script->resetTimerSec = 90; // Create objects for (int32_t sIdx = 0; sIdx < script->thenArgs.spawnList.numSpawns; sIdx++) { @@ -693,7 +703,7 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) if (!enemyExists) { - rayCreateEnemy(ray, type, id, x, y); + rayCreateEnemy(ray, type, id, TO_FX(x) + TO_FX_FRAC(1, 2), TO_FX(y) + TO_FX_FRAC(1, 2)); } } else if (ITEM == (type & 0x60)) @@ -719,7 +729,7 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) if (!itemExists) { - rayCreateCommonObj(ray, type, id, x, y); + rayCreateCommonObj(ray, type, id, TO_FX(x) + TO_FX_FRAC(1, 2), TO_FX(y) + TO_FX_FRAC(1, 2)); } } else if (SCENERY == (type & 0x60)) @@ -745,7 +755,7 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) if (!sceneryExists) { - rayCreateCommonObj(ray, type, id, x, y); + rayCreateCommonObj(ray, type, id, TO_FX(x) + TO_FX_FRAC(1, 2), TO_FX(y) + TO_FX_FRAC(1, 2)); } } } @@ -811,15 +821,16 @@ static bool executeScriptEvent(ray_t* ray, rayScript_t* script, wsg_t* portrait) // Save parameters because scripts will be freed in the process setWarpDestination(ray, script->thenArgs.warpDest.mapId, script->thenArgs.warpDest.pos.x, script->thenArgs.warpDest.pos.y); - return true; } break; } case WIN: { - // TODO unlock something or whatever. + // Unlock zip on the menu + writeNvs32(MAGTROID_UNLOCK_KEY, 1); + // Jump to credits! + rayShowCredits(ray); break; } } - return false; } diff --git a/main/modes/ray/ray_script.h b/main/modes/ray/ray_script.h index 2d10bf1e0..c892dab31 100644 --- a/main/modes/ray/ray_script.h +++ b/main/modes/ray/ray_script.h @@ -6,12 +6,12 @@ void loadScripts(ray_t* ray, const uint8_t* fileData, uint32_t fileSize, uint32_t caps); void freeScripts(ray_t* ray); -bool checkScriptShootObjs(ray_t* ray, int32_t id, wsg_t* portrait); -bool checkScriptKill(ray_t* ray, int32_t id, wsg_t* portrait); -bool checkScriptGet(ray_t* ray, int32_t id, wsg_t* portrait); -bool checkScriptTouch(ray_t* ray, int32_t id, wsg_t* portrait); -bool checkScriptShootWall(ray_t* ray, int32_t x, int32_t y); -bool checkScriptEnter(ray_t* ray, int32_t x, int32_t y); -bool checkScriptTime(ray_t* ray, uint32_t elapsedUs); +void checkScriptShootObjs(ray_t* ray, int32_t id, wsg_t* portrait); +void checkScriptKill(ray_t* ray, int32_t id, wsg_t* portrait); +void checkScriptGet(ray_t* ray, int32_t id, wsg_t* portrait); +void checkScriptTouch(ray_t* ray, int32_t id, wsg_t* portrait); +void checkScriptShootWall(ray_t* ray, int32_t x, int32_t y); +void checkScriptEnter(ray_t* ray, int32_t x, int32_t y); +void checkScriptTime(ray_t* ray, uint32_t elapsedUs); #endif \ No newline at end of file diff --git a/main/modes/ray/ray_tex_manager.c b/main/modes/ray/ray_tex_manager.c index 3b92a969b..3eb0fcb59 100644 --- a/main/modes/ray/ray_tex_manager.c +++ b/main/modes/ray/ray_tex_manager.c @@ -14,10 +14,9 @@ //============================================================================== /** - * The maximum number of loaded sprites. - * TODO pick a better number for all textures + * The maximum number of loaded named textures */ -#define MAX_LOADED_TEXTURES 128 +#define MAX_LOADED_TEXTURES 64 /// Helper macro to load textures #define LOAD_TEXTURE(r, t) loadTexture(r, #t ".wsg", t) @@ -26,11 +25,6 @@ // Functions //============================================================================== -#ifdef TEST_TEX -const char* const testTexNames[] = {"ICE_FLOOR.wsg", "ICE_WALL.wsg", "JUN_FLOOR.wsg", "JUN_WALL.wsg", - "LAV_FLOOR.wsg", "LAV_WALL.wsg", "SPA_FLOOR.wsg", "SPA_WALL.wsg"}; -#endif - /** * @brief Allocate memory and preload all environment textures * @@ -38,6 +32,7 @@ const char* const testTexNames[] = {"ICE_FLOOR.wsg", "ICE_WALL.wsg", "JUN_FLOOR. */ void loadEnvTextures(ray_t* ray) { + // Load a portrait for dialogs loadWsg("CHO_PORTRAIT.wsg", &ray->portrait, true); // Load HUD textures @@ -45,29 +40,77 @@ void loadEnvTextures(ray_t* ray) loadWsg("GUN_MISSILE.wsg", &ray->guns[LO_MISSILE], true); loadWsg("GUN_ICE.wsg", &ray->guns[LO_ICE], true); loadWsg("GUN_XRAY.wsg", &ray->guns[LO_XRAY], true); - -#ifdef TEST_TEX - for (int tIdx = 0; tIdx < ARRAY_SIZE(testTexNames); tIdx++) - { - loadWsg(testTexNames[tIdx], &ray->testTextures[tIdx], true); - } -#endif + loadWsg("HUD_MISSILE.wsg", &ray->missileHUDicon, true); // Allocate space for the textures ray->loadedTextures = heap_caps_calloc(MAX_LOADED_TEXTURES, sizeof(namedTexture_t), MALLOC_CAP_SPIRAM); // Types are 8 bit, non sequential, so allocate a 256 element array. Probably too many ray->typeToIdxMap = heap_caps_calloc(256, sizeof(uint8_t), MALLOC_CAP_SPIRAM); - // Load everything by type! - LOAD_TEXTURE(ray, BG_FLOOR); + // String buffer to load filenames + char fName[32]; + + // MUST be in the same order as rayEnv_t + const char* const env_types[] = {"BASE", "JUNGLE", "CAVE"}; + // MUST be in the same order as rayEnvTex_t + const char* const env_texes[] = {"WALL_1", "WALL_2", "WALL_3", "WALL_4", "WALL_5", "FLOOR", "CEILING"}; + // Load all environment textures + for (rayEnv_t e = 0; e < NUM_ENVS; e++) + { + for (rayEnvTex_t t = 0; t < NUM_ENV_TEXES; t++) + { + snprintf(fName, sizeof(fName) - 1, "BG_%s_%s.wsg", env_types[e], env_texes[t]); + loadWsg(fName, &ray->envTex[e][t], true); + } + } + + // MUST be in teh same order as rayMapCellType_t + const char* const enemyTypes[] = {"NORMAL", "STRONG", "ARMORED", "FLAMING", "HIDDEN", "BOSS"}; + // MUST be int the same order as rayEnemyState_t + const char* const enemyAnimations[] = {"WALK_0", "WALK_1", "SHOOT", "HURT", "BLOCK", "DEAD"}; + // Load all enemy textures + for (int32_t eIdx = 0; eIdx < NUM_ENEMIES; eIdx++) + { + for (rayEnemyState_t aIdx = 0; aIdx < E_NUM_STATES; aIdx++) + { + for (int32_t fIdx = 0; fIdx < NUM_ANIM_FRAMES; fIdx++) + { + snprintf(fName, sizeof(fName) - 1, "E_%s_%s_%" PRId32 ".wsg", enemyTypes[eIdx], enemyAnimations[aIdx], + fIdx); + loadWsg(fName, &ray->enemyTex[eIdx][aIdx][fIdx], true); + + // Also load alt-textures for the hidden enemy + if (eIdx == (OBJ_ENEMY_HIDDEN - OBJ_ENEMY_NORMAL)) + { + snprintf(fName, sizeof(fName) - 1, "E_%s_%s_%" PRId32 "_X.wsg", enemyTypes[eIdx], + enemyAnimations[aIdx], fIdx); + loadWsg(fName, &ray->hiddenXRTex[aIdx][fIdx], true); + } + // Also load alt-textures for the boss + else if (eIdx == (OBJ_ENEMY_BOSS - OBJ_ENEMY_NORMAL)) + { + snprintf(fName, sizeof(fName) - 1, "E_%s_%s_%" PRId32 "_M.wsg", enemyTypes[eIdx], + enemyAnimations[aIdx], fIdx); + loadWsg(fName, &ray->bossTex[B_MISSILE][aIdx][fIdx], true); + + snprintf(fName, sizeof(fName) - 1, "E_%s_%s_%" PRId32 "_I.wsg", enemyTypes[eIdx], + enemyAnimations[aIdx], fIdx); + loadWsg(fName, &ray->bossTex[B_ICE][aIdx][fIdx], true); + + snprintf(fName, sizeof(fName) - 1, "E_%s_%s_%" PRId32 "_X.wsg", enemyTypes[eIdx], + enemyAnimations[aIdx], fIdx); + loadWsg(fName, &ray->bossTex[B_XRAY][aIdx][fIdx], true); + } + } + } + } + + // Special floor tiles LOAD_TEXTURE(ray, BG_FLOOR_WATER); LOAD_TEXTURE(ray, BG_FLOOR_LAVA); - LOAD_TEXTURE(ray, BG_CEILING); - LOAD_TEXTURE(ray, BG_WALL_1); - LOAD_TEXTURE(ray, BG_WALL_2); - LOAD_TEXTURE(ray, BG_WALL_3); - LOAD_TEXTURE(ray, BG_WALL_4); - LOAD_TEXTURE(ray, BG_WALL_5); + LOAD_TEXTURE(ray, BG_FLOOR_HEAL); + + // Doors LOAD_TEXTURE(ray, BG_DOOR); LOAD_TEXTURE(ray, BG_DOOR_CHARGE); LOAD_TEXTURE(ray, BG_DOOR_MISSILE); @@ -77,6 +120,9 @@ void loadEnvTextures(ray_t* ray) LOAD_TEXTURE(ray, BG_DOOR_KEY_A); LOAD_TEXTURE(ray, BG_DOOR_KEY_B); LOAD_TEXTURE(ray, BG_DOOR_KEY_C); + LOAD_TEXTURE(ray, BG_DOOR_ARTIFACT); + + // Items LOAD_TEXTURE(ray, OBJ_ITEM_BEAM); LOAD_TEXTURE(ray, OBJ_ITEM_CHARGE_BEAM); LOAD_TEXTURE(ray, OBJ_ITEM_MISSILE); @@ -91,13 +137,31 @@ void loadEnvTextures(ray_t* ray) LOAD_TEXTURE(ray, OBJ_ITEM_ARTIFACT); LOAD_TEXTURE(ray, OBJ_ITEM_PICKUP_ENERGY); LOAD_TEXTURE(ray, OBJ_ITEM_PICKUP_MISSILE); + + // Bullets LOAD_TEXTURE(ray, OBJ_BULLET_NORMAL); LOAD_TEXTURE(ray, OBJ_BULLET_CHARGE); LOAD_TEXTURE(ray, OBJ_BULLET_ICE); LOAD_TEXTURE(ray, OBJ_BULLET_MISSILE); LOAD_TEXTURE(ray, OBJ_BULLET_XRAY); + LOAD_TEXTURE(ray, OBJ_BULLET_E_NORMAL); + LOAD_TEXTURE(ray, OBJ_BULLET_E_STRONG); + LOAD_TEXTURE(ray, OBJ_BULLET_E_ARMOR); + LOAD_TEXTURE(ray, OBJ_BULLET_E_FLAMING); + LOAD_TEXTURE(ray, OBJ_BULLET_E_HIDDEN); + + // Scenery LOAD_TEXTURE(ray, OBJ_SCENERY_TERMINAL); LOAD_TEXTURE(ray, OBJ_SCENERY_PORTAL); + + // Friends + LOAD_TEXTURE(ray, OBJ_SCENERY_F1); + LOAD_TEXTURE(ray, OBJ_SCENERY_F2); + LOAD_TEXTURE(ray, OBJ_SCENERY_F3); + LOAD_TEXTURE(ray, OBJ_SCENERY_F4); + LOAD_TEXTURE(ray, OBJ_SCENERY_F5); + LOAD_TEXTURE(ray, OBJ_SCENERY_F6); + LOAD_TEXTURE(ray, OBJ_SCENERY_F7); } /** @@ -170,13 +234,40 @@ void freeAllTex(ray_t* ray) freeWsg(&ray->guns[LO_MISSILE]); freeWsg(&ray->guns[LO_ICE]); freeWsg(&ray->guns[LO_XRAY]); + freeWsg(&ray->missileHUDicon); -#ifdef TEST_TEX - for (int tIdx = 0; tIdx < ARRAY_SIZE(testTexNames); tIdx++) + // Free all environment textures + for (rayEnv_t e = 0; e < NUM_ENVS; e++) { - freeWsg(&ray->testTextures[tIdx]); + for (rayEnvTex_t t = 0; t < NUM_ENV_TEXES; t++) + { + freeWsg(&ray->envTex[e][t]); + } + } + + // Free all enemy textures + for (int32_t eIdx = 0; eIdx < NUM_ENEMIES; eIdx++) + { + for (int32_t aIdx = 0; aIdx < E_NUM_STATES; aIdx++) + { + for (int32_t fIdx = 0; fIdx < NUM_ANIM_FRAMES; fIdx++) + { + freeWsg(&ray->enemyTex[eIdx][aIdx][fIdx]); + + // Also free alt-textures for the hidden enemy + if (eIdx == (OBJ_ENEMY_HIDDEN - OBJ_ENEMY_NORMAL)) + { + freeWsg(&ray->hiddenXRTex[aIdx][fIdx]); + } + else if (eIdx == (OBJ_ENEMY_BOSS - OBJ_ENEMY_NORMAL)) + { + freeWsg(&ray->bossTex[B_MISSILE][aIdx][fIdx]); + freeWsg(&ray->bossTex[B_ICE][aIdx][fIdx]); + freeWsg(&ray->bossTex[B_XRAY][aIdx][fIdx]); + } + } + } } -#endif if (ray->loadedTextures) { diff --git a/main/modes/ray/ray_warp_screen.c b/main/modes/ray/ray_warp_screen.c index 5e323f188..99c734034 100644 --- a/main/modes/ray/ray_warp_screen.c +++ b/main/modes/ray/ray_warp_screen.c @@ -49,9 +49,14 @@ void rayWarpScreenRender(ray_t* ray, uint32_t elapsedUs) if (ray->warpTimerUs <= 0) { // Return to the game - ray->screen = RAY_GAME; + raySwitchToScreen(RAY_GAME); // Don't warp again ray->warpTimerUs = 0; + // Stop warp SFX + ray->sfx_warp.shouldLoop = false; + bzrStop(true); + // Play music + bzrPlayBgm(&ray->songs[ray->p.mapId], BZR_STEREO); } } @@ -81,6 +86,9 @@ void setWarpDestination(ray_t* ray, int32_t mapId, int16_t posX, int16_t posY) */ void warpToDestination(ray_t* ray) { + // Stop BGM when manipulating data + bzrStop(true); + // Save the current map's visited tiles raySaveVisitedTiles(ray); @@ -90,12 +98,11 @@ void warpToDestination(ray_t* ray) // Free the scripts rayFreeCurrentState(ray); - // Construct the map name - char mapName[] = "0.rmh"; - mapName[0] = '0' + ray->warpDestMapId; // Load the new map q24_8 pStartX = 0, pStartY = 0; - loadRayMap(mapName, ray, &pStartX, &pStartY, true); + loadRayMap(ray->warpDestMapId, ray, &pStartX, &pStartY, true); + // Stop again after loading the map starts + bzrStop(true); // Set the map ID ray->p.mapId = ray->warpDestMapId; @@ -121,9 +128,22 @@ void warpToDestination(ray_t* ray) ray->planeX = -MUL_FX(TO_FX(2) / 3, ray->p.dirY); ray->planeY = MUL_FX(TO_FX(2) / 3, ray->p.dirX); + // Give the player one missile after warping to not get stuck behind doors + if (ray->p.i.missileLoadOut) + { + if (0 == ray->p.i.numMissiles) + { + ray->p.i.numMissiles++; + } + } + // Save after warping raySavePlayer(ray); // Mark the starting tile as visited markTileVisited(&ray->map, FROM_FX(ray->p.posX), FROM_FX(ray->p.posY)); + + // Loop SFX after saving + ray->sfx_warp.shouldLoop = true; + bzrPlaySfx(&ray->sfx_warp, BZR_RIGHT); } diff --git a/partitions.csv b/partitions.csv index 209e1e36b..55a2419de 100644 --- a/partitions.csv +++ b/partitions.csv @@ -3,5 +3,5 @@ # Note: if you change the size of the nvs partition, make sure to update NVS_PARTITION_SIZE in `components/hdw-nvs/nvs_manager.h` nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 1M, -storage, data, spiffs, , 0xF0000, +factory, app, factory, 0x10000, 0x1F8000, +storage, data, spiffs, , 0x1F8000, diff --git a/tools/breakout_editor/2manypaddles.tmx b/tools/breakout_editor/2manypaddles.tmx new file mode 100644 index 000000000..83af05e45 --- /dev/null +++ b/tools/breakout_editor/2manypaddles.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,0,0,0,0,0,0,46,45,46,45,46,45,46,45,46,23,45,46,45,46,45,46,45,46,45,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,65,66,33,34,33,34,33,34,33,34,17,17,17,33,34,33,34,33,34,33,34,65,66,0,0,0,0,0,0, +0,0,0,0,0,0,81,82,47,48,47,48,47,48,47,48,24,24,47,47,48,47,48,47,48,47,48,81,82,0,0,0,0,0,0, +0,0,0,0,0,77,65,79,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,0,23,23,23,23,23,0,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,23,24,24,24,24,24,23,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,23,24,0,0,0,0,0,24,23,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,23,24,0,0,0,0,0,24,23,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,131,0,93,81,95,0,0,132,131,0,23,24,0,0,146,0,0,24,23,145,132,131,0,0,96,82,94,0,132,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,23,24,0,0,0,0,0,24,23,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,23,24,24,24,24,24,23,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,0,23,23,23,23,23,0,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,82,94,0,0,0,0,0, +0,0,0,0,0,77,65,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,66,78,0,0,0,0,0, +0,0,0,0,0,93,81,95,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,96,82,94,0,0,0,0,0, +0,0,0,0,0,0,65,66,47,48,47,48,47,48,47,48,24,24,47,47,48,47,48,47,48,47,48,65,66,0,0,0,0,0,0, +0,0,0,0,0,0,81,82,33,34,33,34,33,34,33,34,17,17,17,33,34,33,34,33,34,33,34,81,82,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,46,45,46,45,46,45,46,45,46,23,45,46,45,46,45,46,45,46,45,0,0,0,0,0,0,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0 + + + diff --git a/tools/breakout_editor/angles.tmx b/tools/breakout_editor/angles.tmx new file mode 100644 index 000000000..1ff89e2e3 --- /dev/null +++ b/tools/breakout_editor/angles.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,18,2,0,0,0,0,0,0,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,2,0,0,0,0,18,18,18,2,17,17,17,17,17,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,2,0,0,18,18,18,18,2,17,17,17,17,17,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,2,18,18,18,18,18,2,17,17,17,17,17,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,2,18,18,18,18,2,17,17,17,17,17,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,2,18,18,18,2,17,17,17,17,17,2,19,19,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,4,0,0, +0,0,4,131,0,0,0,0,0,0,0,20,20,20,20,20,2,22,2,21,21,21,21,21,0,0,0,0,0,0,0,132,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,20,20,20,2,22,22,22,2,21,21,21,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,20,2,22,22,22,22,22,2,21,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,2,22,22,22,22,22,22,22,2,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,2,22,22,22,22,22,22,22,22,22,2,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0 + + + diff --git a/tools/breakout_editor/b.tmx b/tools/breakout_editor/b.tmx new file mode 100644 index 000000000..7c5cf8064 --- /dev/null +++ b/tools/breakout_editor/b.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,1,0,1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,0,0,0,1,1,1,2,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,2,1,1,1,1,0,0, +0,0,0,0,0,0,1,1,2,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,2,1,1,1,1,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,55,56,55,56,55,56,1,1,0,1,1,1,1,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,55,56,55,56,55,55,56,1,0,1,1,1,1,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,1,1,1,1,1,1,55,56,55,56,1,55,56,1,0,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,1,1,1,1,1,1,55,56,55,56,1,55,56,1,0,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,131,145,0,1,1,1,1,1,1,1,1,55,56,55,56,55,56,56,1,0,1,1,1,1,1,1,1,0,132,0,0,0, +0,0,0,0,0,0,1,1,1,1,1,1,1,1,55,56,55,56,55,55,55,56,0,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,1,1,1,1,1,1,55,56,55,56,1,146,55,56,0,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,1,1,1,1,1,1,55,56,55,56,1,1,55,56,0,1,1,1,1,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,55,56,55,56,1,1,56,56,0,1,1,1,1,1,2,1,1,1,1,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,55,56,55,56,55,55,56,1,0,1,1,1,1,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,2,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,1,2,1,1,1,1,0,0, +0,0,0,0,0,0,1,1,2,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,2,1,1,0,0,0,0, +0,0,0,0,0,0,1,1,2,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,2,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,1,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/bombrings.tmx b/tools/breakout_editor/bombrings.tmx new file mode 100644 index 000000000..5e3ff4655 --- /dev/null +++ b/tools/breakout_editor/bombrings.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,6,6,6,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,6,6,6,2,0,0, +0,0,4,6,17,6,0,0,0,0,0,0,0,0,0,0,1,130,0,0,0,0,0,0,0,0,0,0,0,6,17,6,4,0,0, +0,0,4,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,4,0,0, +0,0,6,6,6,0,0,0,0,0,0,0,0,6,6,6,0,0,0,6,6,6,0,0,0,0,0,0,0,0,6,6,6,0,0, +0,0,6,17,6,0,0,0,0,0,0,0,0,6,17,6,0,0,0,6,17,6,0,0,0,0,0,0,0,0,6,17,6,0,0, +0,0,6,6,6,0,0,0,0,0,0,0,0,6,6,6,0,0,0,6,6,6,0,0,0,0,0,0,0,0,6,6,6,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,6,17,6,0,0,0,0,0,6,17,6,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,6,17,6,0,0,0,6,17,6,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,6,6,6,0,0,6,6,6,0,0,0,0,0,0,0,6,6,6,0,0,6,6,6,0,0,0,4,0,0, +0,0,4,0,0,0,6,17,6,0,0,6,17,6,0,0,0,0,0,0,0,6,17,6,0,0,6,17,6,0,0,0,4,0,0, +0,0,4,0,0,0,6,6,6,0,0,6,6,6,0,0,0,0,0,0,0,6,6,6,0,0,6,6,6,0,0,0,4,0,0, +0,0,4,0,0,6,6,6,0,0,0,0,6,6,6,0,0,0,0,0,6,6,6,0,0,0,0,6,6,6,0,0,4,0,0, +0,0,4,0,0,6,17,6,0,0,0,0,6,17,6,0,0,0,0,0,6,17,6,0,0,0,0,6,17,6,0,0,4,0,0, +0,0,4,0,0,6,6,6,0,0,0,0,6,6,6,0,0,0,0,0,6,6,6,0,0,0,0,6,6,6,0,0,4,0,0, +0,0,4,0,0,0,6,6,6,0,0,6,6,6,0,0,0,0,0,0,0,6,6,6,0,0,6,6,6,0,0,0,4,0,0, +0,0,4,0,0,0,6,17,6,0,0,6,17,6,0,0,0,0,0,0,0,6,17,6,0,0,6,17,6,0,0,0,4,0,0, +0,0,4,0,0,0,6,6,6,0,0,6,6,6,0,0,0,0,0,0,0,6,6,6,0,0,6,6,6,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0 + + + diff --git a/tools/breakout_editor/breakout-tiles.png b/tools/breakout_editor/breakout-tiles.png index 0f6d6c8d9..95d74768d 100644 Binary files a/tools/breakout_editor/breakout-tiles.png and b/tools/breakout_editor/breakout-tiles.png differ diff --git a/tools/breakout_editor/corner.tmx b/tools/breakout_editor/corner.tmx new file mode 100644 index 000000000..a8568ac4c --- /dev/null +++ b/tools/breakout_editor/corner.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,65,66,71,72,65,66,39,40,17,17,20,20,17,17,39,40,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,81,82,87,88,81,82,39,40,17,17,20,20,17,17,39,40,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,71,72,65,66,39,40,17,17,20,20,17,17,20,20,17,17,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,87,88,81,82,39,40,17,17,20,20,17,17,20,20,17,17,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,65,66,71,72,33,34,20,20,17,17,20,20,17,17,20,20,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,81,82,87,88,33,34,20,20,17,17,20,20,17,17,20,20,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,71,72,65,66,39,40,17,17,20,20,17,17,20,20,17,17,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,87,88,81,82,39,40,17,17,20,20,17,17,20,20,17,17,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,65,66,71,72,33,34,39,40,17,17,20,20,17,17,39,40,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,81,82,87,88,33,34,39,40,17,17,20,20,17,17,39,40,8,0,0, +0,0,0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,33,34,39,40,33,34,39,40,33,34,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,33,34,39,40,33,34,39,40,33,34,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,71,72,65,66,71,72,65,66,71,72,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,87,88,81,82,87,88,81,82,87,88,8,0,0, +0,0,131,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0 + + + diff --git a/tools/breakout_editor/devito.tmx b/tools/breakout_editor/devito.tmx new file mode 100644 index 000000000..4d0d1cb35 --- /dev/null +++ b/tools/breakout_editor/devito.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,1,1,0,0,0,18,19,25,25,19,18,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,1,0,0,0,18,0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,19,19,19,19,18,18,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,27,27,26,26,26,26,18,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,27,27,26,26,26,26,26,26,18,27,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,27,28,28,28,28,28,28,28,28,28,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,27,27,27,28,25,25,28,25,25,28,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,27,27,28,25,27,28,25,27,28,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,26,26,26,28,28,26,28,28,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,26,26,26,26,26,26,26,26,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,26,26,26,28,28,28,18,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,26,18,26,26,26,26,26,18,28,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,26,26,26,18,18,26,26,26,28,28,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/firework.tmx b/tools/breakout_editor/firework.tmx new file mode 100644 index 000000000..07835452e --- /dev/null +++ b/tools/breakout_editor/firework.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,19,0,17,0,0,0,22,0,0,0,17,0,19,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,24,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,131,0,0,0,0,0,0,18,0,0,0,22,0,24,0,28,0,24,0,22,0,0,0,18,0,0,0,0,0,0,132,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,24,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,19,0,17,0,0,0,22,0,0,0,17,0,19,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/flipflop.tmx b/tools/breakout_editor/flipflop.tmx new file mode 100644 index 000000000..2dae40261 --- /dev/null +++ b/tools/breakout_editor/flipflop.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,45,46,45,46,45,46,45,46,45,46,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,45,46,45,46,45,46,45,46,45,46,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,45,46,45,46,45,46,45,46,45,46,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,45,46,45,46,45,46,45,46,45,46,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/flower.tmx b/tools/breakout_editor/flower.tmx new file mode 100644 index 000000000..ffa537d11 --- /dev/null +++ b/tools/breakout_editor/flower.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,67,68,83,84,67,68,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,83,84,55,56,83,84,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,35,36,28,47,48,28,35,36,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,67,68,55,56,67,68,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,83,84,67,68,83,84,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,56,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,51,52,51,52,51,52,51,52,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,51,52,53,54,53,54,53,54,51,52,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,51,52,45,46,45,46,45,46,45,46,51,52,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,51,52,43,44,43,44,43,44,43,44,43,44,51,52,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,51,52,0,0,0,0,0,0,0,0,0,0,0,0,51,52,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,51,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,51,52,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0 + + + diff --git a/tools/breakout_editor/foosball.tmx b/tools/breakout_editor/foosball.tmx new file mode 100644 index 000000000..8c6e96308 --- /dev/null +++ b/tools/breakout_editor/foosball.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,5,5,37,38,37,38,37,38,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,37,38,37,38,37,38,5,5,0,0, +0,0,5,5,37,38,37,38,37,38,5,18,18,18,18,18,18,18,18,18,18,18,18,18,5,37,38,37,38,37,38,5,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,18,18,18,18,18,18,18,18,18,18,18,18,18,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,18,18,18,18,18,18,18,18,18,18,18,18,18,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,35,36,35,36,35,36,18,35,36,35,36,35,36,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,0,0,0,35,36,35,36,35,36,35,36,35,36,5,0,0, +0,0,5,41,42,41,42,41,42,41,42,41,42,0,0,0,0,0,0,0,0,0,41,42,41,42,41,42,41,42,41,42,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,41,42,41,42,41,42,21,41,42,41,42,41,42,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,21,21,21,21,21,21,21,21,21,21,21,21,21,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,0,0,0,0,0,0,0,5,21,21,21,21,21,21,21,21,21,21,21,21,21,5,0,0,0,0,0,0,0,5,0,0, +0,0,5,5,43,44,43,44,43,44,5,21,21,21,21,21,21,21,21,21,21,21,21,21,5,43,44,43,44,43,44,5,5,0,0, +0,0,5,5,43,44,43,44,43,44,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,43,44,43,44,43,44,5,5,0,0 + + + diff --git a/tools/breakout_editor/gaylordogo.tmx b/tools/breakout_editor/gaylordogo.tmx new file mode 100644 index 000000000..26c86df64 --- /dev/null +++ b/tools/breakout_editor/gaylordogo.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,18,1,0,0,0,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,35,36,1,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,18,67,68,0,18,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,83,84,0,0,83,84,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,35,36,0,0,0,0,67,68,18,0,67,68,83,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,18,67,68,18,0,83,84,67,68,83,84,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,83,84,67,68,35,36,83,84,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,1,83,84,18,1,1,1,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,18,67,68,67,68,1,1,1,1,1,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,67,68,83,84,83,84,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,35,36,83,84,0,0,67,68,1,1,1,1,18,67,68,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,18,83,84,1,1,1,1,1,83,84,0,0,0,0,0,0,0,0,0,0,0,145,132,0,0,0, +0,0,4,0,0,0,0,0,67,68,67,68,18,1,1,1,1,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,1,83,84,83,84,67,68,67,68,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,35,36,0,0,0,83,84,83,84,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,18,0,0,0,67,68,35,36,67,68,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,35,36,0,0,0,83,84,67,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,67,68,83,0,67,68,67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,83,84,0,0,83,84,83,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,67,68,0,0,0,18,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,83,84,0,0,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,35,36,0,0,0,0,35,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/getMorGet.tmx b/tools/breakout_editor/getMorGet.tmx new file mode 100644 index 000000000..f8cc9fd25 --- /dev/null +++ b/tools/breakout_editor/getMorGet.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,19,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,1,20,19,19,22,1,1,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,1,1,1,20,22,17,22,1,1,1,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,19,19,1,1,20,22,22,17,17,22,1,1,19,19,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,19,19,17,20,20,22,22,17,17,22,22,20,19,19,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,17,17,20,22,22,22,17,17,17,22,20,20,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,17,17,17,22,22,19,19,17,17,20,20,20,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,20,17,17,22,20,19,19,22,17,20,20,22,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,20,17,17,17,20,20,22,22,20,20,20,22,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,20,20,17,20,20,20,22,22,22,20,22,22,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,20,20,20,20,20,20,22,22,22,22,22,22,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,22,20,20,20,20,20,22,22,22,22,22,17,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,131,0,0,0,0,0,0,20,20,22,20,20,22,20,20,22,22,17,22,22,17,22,22,0,0,0,0,0,132,4,0,0, +0,0,4,0,0,0,0,0,0,0,20,20,22,22,1,0,20,20,22,22,0,0,17,17,22,22,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,20,22,0,0,0,20,20,22,22,0,0,0,17,22,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,22,22,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,22,22,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,22,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0 + + + diff --git a/tools/breakout_editor/halloween.tmx b/tools/breakout_editor/halloween.tmx new file mode 100644 index 000000000..f28ed0b37 --- /dev/null +++ b/tools/breakout_editor/halloween.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,130,71,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,71,88,0,88,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,71,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,18,35,36,87,88,35,36,18,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,18,35,36,35,36,5,18,35,36,35,36,35,36,18,5,35,36,35,36,18,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,18,35,36,35,36,5,5,5,18,35,36,35,36,18,5,5,5,35,36,35,36,18,0,0,0,0,0,4,0,0, +0,0,4,0,0,35,36,35,36,18,5,5,5,35,36,35,36,35,36,5,5,5,18,35,36,35,36,0,0,0,0,0,4,0,0, +0,0,4,0,0,18,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,18,0,0,0,0,0,4,0,0, +0,0,4,0,0,35,36,35,36,35,36,35,36,35,36,55,56,35,36,35,36,35,36,35,36,35,36,0,0,0,0,0,4,0,0, +0,0,4,0,0,18,35,36,28,18,35,36,35,36,18,55,56,18,35,36,35,36,18,28,35,36,18,0,0,0,0,0,4,0,0, +0,0,4,0,0,35,36,18,55,56,18,35,36,18,55,56,55,56,18,35,36,18,55,56,18,35,36,0,0,0,0,0,4,0,0, +0,0,4,0,0,18,35,36,18,55,56,28,35,36,35,36,35,36,35,36,28,55,56,18,35,36,18,0,0,0,0,0,4,0,0, +0,0,4,0,0,35,36,35,36,28,55,56,35,36,55,56,55,56,35,36,55,56,28,35,36,35,36,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,35,36,35,36,35,36,28,55,56,55,56,55,56,28,35,36,35,36,35,36,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,18,35,36,35,36,35,36,18,28,35,36,28,18,35,36,35,36,35,36,18,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,18,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,18,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,18,35,36,35,36,35,36,35,36,35,36,35,36,35,36,18,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,18,35,36,18,0,0,0,0,0,0,18,35,36,18,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0 + + + diff --git a/tools/breakout_editor/intersection.tmx b/tools/breakout_editor/intersection.tmx new file mode 100644 index 000000000..094a23de4 --- /dev/null +++ b/tools/breakout_editor/intersection.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,0,2,3,3,3,3,3,2,0,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,0,0,4,5,5,5,5,5,4,0,0,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,0,0,4,5,5,5,5,5,4,0,0,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,0,2,3,3,3,3,3,2,0,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,24,24,21,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,25,25,24,24,21,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,24,24,25,25,24,24,21,24,17,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,24,21,21,21,24,24,24,21,24,17,17,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,21,24,24,24,21,21,21,24,24,17,17,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,131,4,5,5,5,4,0,0,0,24,24,24,24,21,21,24,24,24,17,17,0,0,0,4,5,5,5,4,132,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,17,24,24,24,21,24,24,24,17,17,17,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,17,24,24,21,24,24,17,17,17,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,21,17,17,17,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,21,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,4,5,5,5,4,0,0,0,0,2,5,5,5,5,5,5,2,0,0,0,0,0,4,5,5,5,4,0,0,0,0, +0,0,0,0,2,3,3,3,2,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,2,3,3,3,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/intro.tmx b/tools/breakout_editor/intro.tmx index 2442d925b..d02a669ae 100644 --- a/tools/breakout_editor/intro.tmx +++ b/tools/breakout_editor/intro.tmx @@ -13,9 +13,9 @@ 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,0,0,0,4,0,0, 0,0,4,0,0,0,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,37,38,0,0,4,0,0, -0,0,4,0,0,35,36,35,36,35,36,35,36,35,36,1,1,1,1,35,36,35,36,35,36,35,36,35,36,0,0,0,4,0,0, -0,0,4,0,0,0,35,36,35,36,35,36,35,36,35,36,1,1,35,36,35,36,35,36,35,36,35,36,35,36,0,0,4,0,0, -0,0,4,0,0,33,34,33,34,33,34,33,34,33,34,1,1,1,1,33,34,33,34,33,34,33,34,33,34,0,0,0,4,0,0, +0,0,4,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,0,4,0,0, +0,0,4,0,0,0,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,35,36,0,0,4,0,0, +0,0,4,0,0,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,4,0,0, 0,0,4,0,0,0,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,0,0,4,0,0, 0,0,4,0,0,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,33,34,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, diff --git a/tools/breakout_editor/leftside.tmx b/tools/breakout_editor/leftside.tmx index d75ecabcf..d312b9e23 100644 --- a/tools/breakout_editor/leftside.tmx +++ b/tools/breakout_editor/leftside.tmx @@ -11,28 +11,28 @@ 0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,75,75,73,74,75,75,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,91,91,89,90,91,91,89,90,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,75,73,74,75,75,73,74,75,75,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,91,89,90,91,91,89,90,91,91,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,75,75,73,74,75,75,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,91,91,89,90,91,91,89,90,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,75,73,74,75,75,73,74,75,75,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,91,89,90,91,91,89,90,91,91,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,22,22,73,74,22,22,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,22,22,89,90,22,22,89,90,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,75,73,74,22,22,73,74,75,75,0,0,4,0,0, -0,0,0,131,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,91,89,90,22,22,89,90,91,91,1,1,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,22,22,73,74,22,22,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,22,22,89,90,22,22,89,90,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,75,73,74,75,75,73,74,75,75,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,91,89,90,91,91,89,90,91,91,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,75,75,73,74,75,75,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,91,91,89,90,91,91,89,90,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,75,73,74,75,75,73,74,75,75,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,91,91,89,90,91,91,89,90,91,91,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,75,75,73,74,75,75,73,74,0,0,4,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,91,91,89,90,91,91,89,90,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,41,42,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,21,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,21,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,41,42,41,42,41,42,41,42,21,21,22,22,21,21,0,0,4,0,0, +0,0,0,131,145,0,0,0,0,0,0,0,0,0,43,44,43,44,43,44,43,44,43,44,22,22,22,22,22,22,1,1,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,22,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,22,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 diff --git a/tools/breakout_editor/lumberjacks.tmx b/tools/breakout_editor/lumberjacks.tmx new file mode 100755 index 000000000..d2496639a --- /dev/null +++ b/tools/breakout_editor/lumberjacks.tmx @@ -0,0 +1,38 @@ + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,1073741877,1073741878,53,54,0,0,0,0,0,0,0,0,55,56,55,56,55,56,55,56,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,1073741851,1073741850,1073741850,1073741850,1073741850,1073741851,1073741851,0,0,0,0,0,28,21,20,20,20,20,20,20,21,28,0,0,0,8,0,0, +0,0,8,0,0,0,1073741851,1073741850,1073741850,1073741843,1073741843,1073741843,1073741843,1073741851,0,0,0,0,0,28,22,22,20,20,20,20,20,20,21,28,0,0,8,0,0, +0,0,8,0,0,1073741851,1073741850,1073741850,1073741850,1073741850,1073741843,1073741850,1073741850,1073741850,1073741851,0,0,0,0,0,28,22,22,22,20,20,20,20,20,28,0,0,8,0,0, +0,0,8,0,1073741851,1073741850,1073741841,1073741850,1073741850,1073741841,1073741841,1073741850,1073741841,1073741841,1073741851,0,0,0,0,0,28,26,26,26,26,26,26,20,20,28,0,0,8,0,0, +0,0,8,0,1073741851,1073741850,1073741841,1073741850,1073741850,1073741842,1073741841,1073741850,1073741860,1073741841,1073741851,0,0,0,0,0,28,20,19,26,20,19,26,20,20,20,28,0,8,0,0, +0,0,8,0,0,1073741851,1073741841,1073741841,1073741850,1073741850,1073741850,1073741850,1073741850,1073741850,1073741851,0,0,0,0,0,28,20,20,26,20,20,26,26,20,20,28,0,8,0,0, +0,0,8,0,0,1073741851,1073741841,1073741841,1073741841,1073741841,1073741841,1073741848,1073741848,1073741848,1073741851,0,0,0,0,0,28,26,26,26,19,26,26,26,26,28,0,0,8,0,0, +0,0,8,0,0,1073741851,1073741849,1073741841,1073741841,1073741841,1073741841,1073741841,1073741841,1073741848,1073741848,1073741851,0,0,0,0,0,28,19,19,19,19,26,26,28,0,0,0,8,0,0, +0,0,8,0,0,0,1073741851,1073741849,1073741841,1073741841,1073741841,1073741841,1073741841,1073741841,1073741849,1073741851,0,0,0,0,0,28,28,26,26,26,26,28,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,1073741877,1073741878,1073741877,1073741878,1073741877,1073741878,1073741877,1073741878,0,0,0,0,0,0,0,0,55,56,55,56,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,2,7,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,7,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/m_attack.tmx b/tools/breakout_editor/m_attack.tmx new file mode 100644 index 000000000..4bb6a42cf --- /dev/null +++ b/tools/breakout_editor/m_attack.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,23,45,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,24,24,24,24,24,43,44,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,23,24,25,24,24,24,24,24,18,17,22,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,78,24,25,19,19,18,24,25,19,19,18,17,75,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,94,25,19,19,19,19,17,19,19,19,19,18,91,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,78,24,19,19,19,18,19,19,19,18,19,19,18,17,75,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,94,17,19,19,18,17,19,19,18,17,19,18,17,17,91,0,0,0,0,0,0,0,0,0,0, +0,0,0,131,1,0,0,0,0,0,23,17,17,19,18,17,19,19,18,17,19,18,17,17,22,0,0,0,0,0,0,132,0,0,0, +0,0,0,0,0,0,0,0,0,0,78,24,17,19,18,24,17,18,17,17,19,18,17,17,75,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,94,24,17,19,18,24,24,17,24,17,19,18,17,17,91,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,78,24,17,18,24,24,24,24,17,19,17,17,75,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,92,17,17,18,24,24,24,24,17,19,17,17,91,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,22,17,18,24,24,24,24,17,19,17,22,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,22,18,17,17,17,17,17,18,22,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,44,22,43,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/mag03.tmx b/tools/breakout_editor/mag03.tmx new file mode 100644 index 000000000..a645fb2f6 --- /dev/null +++ b/tools/breakout_editor/mag03.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,2,0,0, +0,0,4,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,130,0,0,0,0,0,0,0,0,0,0,1,1,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,97,98,0,0,97,98,0,0,0,0,0,97,98,0,0,0,97,98,97,98,97,98,0,0,0,4,0,0, +0,0,4,0,0,0,25,113,114,0,0,113,114,25,0,0,0,25,113,114,25,0,0,113,114,113,114,113,114,0,0,0,4,0,0, +0,0,4,0,0,97,98,25,25,97,98,25,25,97,98,0,97,98,0,0,97,98,0,97,98,25,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,113,114,0,0,113,114,0,0,113,114,0,113,114,0,146,113,114,0,113,114,0,0,0,0,0,1,0,4,0,0, +0,0,4,0,0,97,98,0,0,97,98,0,0,97,98,0,97,98,97,98,97,98,0,97,98,0,0,97,98,97,25,0,4,0,0, +0,0,4,0,0,113,114,0,0,113,114,0,0,113,114,0,113,114,113,114,113,114,0,113,114,0,0,113,114,113,1,0,4,0,0, +0,0,4,0,0,97,98,0,0,0,0,0,0,97,98,0,97,98,0,0,97,98,0,97,98,97,98,97,98,0,1,0,4,0,0, +0,0,4,0,0,113,114,0,0,0,0,0,0,113,114,0,113,114,0,0,113,114,0,113,114,113,114,113,114,0,1,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,6,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,0 + + + diff --git a/tools/breakout_editor/outtaMyWay.tmx b/tools/breakout_editor/outtaMyWay.tmx new file mode 100644 index 000000000..5432e586c --- /dev/null +++ b/tools/breakout_editor/outtaMyWay.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,2,0,0,0,0,0,2,2,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,4,0,0,0,0,0,4,4,0,0,0,0,0,4,4,0,0,0,0,0,4,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,4,65,66,33,34,17,4,4,20,20,20,20,20,4,4,43,44,43,44,22,4,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,4,81,82,17,65,66,4,4,20,39,40,20,20,4,4,43,44,22,43,44,4,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,4,17,33,34,81,82,4,4,20,20,39,40,20,4,4,22,43,44,43,44,4,0,0,0,0,4,0,0, +0,0,4,79,80,79,80,4,17,65,66,33,34,4,4,20,71,72,20,20,4,4,43,44,22,43,44,4,77,78,77,78,4,0,0, +0,0,4,95,96,95,96,4,17,81,82,17,17,4,4,20,87,88,20,20,4,4,43,44,43,44,22,4,93,94,93,94,4,0,0, +0,0,4,47,48,47,48,4,33,34,65,66,17,4,4,20,20,71,72,20,4,4,43,44,22,43,44,4,45,46,45,46,4,0,0, +0,0,4,24,24,24,24,4,33,34,81,82,65,4,4,20,20,87,88,20,4,4,22,43,44,43,44,4,23,23,23,23,4,0,0, +0,0,4,0,0,0,0,24,65,66,33,34,81,19,19,20,39,40,20,20,21,21,43,44,22,43,44,23,0,0,0,0,4,0,0, +0,0,4,0,146,0,0,24,81,82,17,65,66,19,19,20,20,39,40,20,21,21,43,44,43,44,22,23,0,0,146,0,4,0,0, +0,0,4,0,0,0,0,24,17,33,34,81,82,19,19,20,20,20,20,20,21,21,43,44,22,43,44,23,0,0,0,0,4,0,0, +0,0,2,3,3,3,3,4,3,3,3,3,3,4,4,3,3,3,3,3,4,4,3,3,3,3,3,4,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/snake.tmx b/tools/breakout_editor/snake.tmx new file mode 100644 index 000000000..b09bd2b9a --- /dev/null +++ b/tools/breakout_editor/snake.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0, +0,0,0,0,8,77,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,93,94,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,41,42,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,73,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,46,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,89,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,25,45,46,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,45,46,25,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,74,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,45,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,90,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,131,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,78,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,94,8,0,0,0,0, +0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/starlite.tmx b/tools/breakout_editor/starlite.tmx index 8c0160fc4..6239b6949 100644 --- a/tools/breakout_editor/starlite.tmx +++ b/tools/breakout_editor/starlite.tmx @@ -8,8 +8,8 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -34,8 +34,8 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0 +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0 diff --git a/tools/breakout_editor/superhard.tmx b/tools/breakout_editor/superhard.tmx index 0478ef459..3675c1e4f 100644 --- a/tools/breakout_editor/superhard.tmx +++ b/tools/breakout_editor/superhard.tmx @@ -7,8 +7,8 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,0, 0,0,4,0,0,0,0,0,0,0,0,6,0,0,0,0,130,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, @@ -17,9 +17,9 @@ 0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,1,17,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,1,1,1,6,6,6,6,0,0,0,6,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,1,6,6,6,6,0,0,0,6,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,19,18,19,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,18,17,18,6,6,6,6,0,0,0,6,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,0,19,18,19,6,6,6,6,0,0,0,6,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,6,6,6,6,6,6,6,6,6,0,0,0,6,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0, 0,0,4,131,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,132,4,0,0, diff --git a/tools/breakout_editor/swdglnd-character.tmx b/tools/breakout_editor/swdglnd-character.tmx index 9f518909c..4bfc5af95 100644 --- a/tools/breakout_editor/swdglnd-character.tmx +++ b/tools/breakout_editor/swdglnd-character.tmx @@ -9,8 +9,7 @@ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,23,45,46,45,46,45,46,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,77,78,77,78,77,78,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,23,93,94,93,94,93,94,23,0,77,78,0,0,0,0,0,0,0,0,0,4,0,0, @@ -33,8 +32,9 @@ 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0 diff --git a/tools/breakout_editor/themaze.tmx b/tools/breakout_editor/themaze.tmx new file mode 100644 index 000000000..4cdd33ad3 --- /dev/null +++ b/tools/breakout_editor/themaze.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,22,22,22,0,0,0,0,0,2,0,0,0,0,0,0,22,22,22,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,22,22,22,0,0,0,0,0,2,0,0,0,0,0,0,22,22,22,1,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,22,22,22,0,0,0,0,0,2,0,0,0,0,0,0,22,22,22,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,2,2,2,2,2,2,0,0,2,0,0,0,0,0,0,22,22,22,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,2,2,2,0,0,2,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,2,2,2,17,17,2,0,0,0,0,17,17,0,0,1,0,0,2,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,2,2,2,17,17,2,0,0,0,0,17,17,0,0,0,0,0,2,0,0,0,0,0,4,0,0, +0,0,4,2,2,2,17,17,17,2,2,2,17,17,2,0,0,0,0,17,17,0,0,0,0,0,2,17,17,17,17,17,4,0,0, +0,0,4,2,2,2,17,17,17,2,2,2,17,17,2,2,2,2,2,2,2,2,2,0,0,0,2,17,17,17,17,17,4,0,0, +0,0,4,2,2,2,17,17,17,2,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,17,17,17,17,17,4,0,0, +0,0,4,2,2,6,6,6,6,6,2,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,4,0,0, +0,0,4,2,6,17,146,146,146,20,6,2,0,0,0,0,0,0,0,0,0,0,2,22,22,22,2,0,0,0,0,0,4,0,0, +0,0,4,6,17,20,22,17,20,22,17,6,2,2,2,2,2,2,2,22,22,22,2,22,22,22,2,0,0,0,0,0,4,0,0, +0,0,6,17,20,22,17,20,22,17,20,22,6,2,0,0,0,0,2,0,0,0,17,1,0,0,2,0,0,0,0,0,4,0,0, +0,0,6,20,22,17,20,22,17,20,22,17,6,2,0,0,0,0,2,0,0,0,17,1,0,0,2,0,0,0,0,0,4,0,0, +0,0,6,22,17,20,22,17,20,22,17,20,6,2,0,0,0,0,2,0,0,0,17,1,0,0,2,0,0,0,0,0,4,0,0, +0,0,6,17,20,22,17,20,22,17,20,22,6,2,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,4,0,0, +0,0,6,20,22,17,20,22,17,20,22,17,6,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,6,17,20,22,17,20,22,17,6,2,2,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,2,6,22,17,20,22,17,6,2,2,2,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,2,2,6,6,6,6,6,2,2,2,2,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,1,1,1,1,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,1,1,1,1,1,0,0,0,0,0,0,4,0,0, +0,0,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,0 + + + diff --git a/tools/breakout_editor/tinyhuge.tmx b/tools/breakout_editor/tinyhuge.tmx new file mode 100644 index 000000000..c8413e1b4 --- /dev/null +++ b/tools/breakout_editor/tinyhuge.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,69,70,67,68,69,70,67,68,69,70,67,68,69,70,67,68,69,70,67,68,69,70,0,0,0,0,8,0,0, +0,0,8,0,0,0,85,86,83,84,85,86,83,84,85,86,83,84,85,86,83,84,85,86,83,84,85,86,0,0,0,0,8,0,0, +0,0,8,0,0,0,67,68,69,70,67,68,69,70,67,68,69,70,67,68,69,70,67,68,69,70,67,68,0,0,0,0,8,0,0, +0,0,8,0,0,0,83,84,85,86,83,84,85,86,83,84,85,86,83,84,85,86,83,84,85,86,83,84,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,19,18,19,18,19,18,19,18,19,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,18,19,18,19,18,19,18,19,18,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,0,0, +0,0,8,1,1,1,1,1,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,1,1,1,1,1,1,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0 + + + diff --git a/tools/breakout_editor/trifecta.tmx b/tools/breakout_editor/trifecta.tmx new file mode 100644 index 000000000..901371923 --- /dev/null +++ b/tools/breakout_editor/trifecta.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,65,66,71,72,65,66,71,72,65,66,1,71,72,65,66,71,72,65,66,71,72,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,81,82,87,88,81,82,87,88,81,82,1,87,88,81,82,87,88,81,82,87,88,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,71,72,75,76,71,72,75,76,71,72,1,75,76,71,72,75,76,71,72,75,76,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,87,88,91,92,87,88,91,92,87,88,1,91,92,87,88,91,92,87,88,91,92,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,65,66,71,72,65,66,71,72,1,65,66,71,72,65,66,71,72,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,81,82,87,88,81,82,87,88,1,81,82,87,88,81,82,87,88,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,71,72,75,76,71,72,75,76,1,71,72,75,76,71,72,75,76,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,87,88,91,92,87,88,91,92,1,87,88,91,92,87,88,91,92,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,65,66,71,72,65,66,1,71,72,65,66,71,72,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,81,82,87,88,81,82,1,87,88,81,82,87,88,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,71,72,75,76,71,72,1,75,76,71,72,75,76,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,87,88,91,92,87,88,1,91,92,87,88,91,92,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,131,0,0,0,0,0,0,0,2,3,3,3,3,3,3,3,3,3,3,3,2,0,0,0,0,0,0,0,132,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0 + + + diff --git a/tools/breakout_editor/upsidedown.tmx b/tools/breakout_editor/upsidedown.tmx index 5ff16db19..c686e863b 100644 --- a/tools/breakout_editor/upsidedown.tmx +++ b/tools/breakout_editor/upsidedown.tmx @@ -23,13 +23,13 @@ 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,75,76,21,75,76,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,0,0,75,76,91,92,21,91,92,75,76,0,0,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,0,0,75,76,91,92,75,76,21,75,76,91,92,75,76,0,0,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,0,0,77,78,91,92,75,76,91,92,21,91,92,75,76,91,92,77,78,0,0,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,47,48,93,94,75,76,91,92,75,76,21,75,76,91,92,75,76,93,94,47,48,0,0,0,0,4,0,0, -0,0,4,0,0,0,0,47,48,77,78,91,92,75,76,91,92,0,91,92,75,76,91,92,77,78,47,48,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,73,74,20,73,74,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,75,76,89,90,20,89,90,75,76,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,0,0,75,76,91,92,73,74,20,73,74,91,92,75,76,0,0,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,0,0,77,78,91,92,75,76,89,90,20,89,90,75,76,91,92,77,78,0,0,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,47,48,93,94,75,76,91,92,73,74,20,73,74,91,92,75,76,93,94,47,48,0,0,0,0,4,0,0, +0,0,4,0,0,0,0,47,48,77,78,91,92,75,76,89,90,0,89,90,75,76,91,92,77,78,47,48,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,47,48,93,94,75,76,91,92,0,0,0,0,0,91,92,75,76,93,94,47,48,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,47,48,77,78,91,92,0,0,0,0,0,0,0,0,0,91,92,77,78,47,48,0,0,0,0,4,0,0, 0,0,4,0,0,0,0,47,48,93,94,0,0,0,0,0,0,0,0,0,0,0,0,0,93,94,47,48,0,0,0,0,4,0,0, diff --git a/tools/breakout_editor/wallball.tmx b/tools/breakout_editor/wallball.tmx new file mode 100644 index 000000000..dbc6ad534 --- /dev/null +++ b/tools/breakout_editor/wallball.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,71,72,71,72,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,87,88,87,88,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,71,72,69,70,69,70,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,87,88,85,86,85,86,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,145,132,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,67,68,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,83,84,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,69,70,67,68,77,78,77,78,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,85,86,83,84,93,94,93,94,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,78,77,78,77,78,1,1,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,94,93,94,93,94,1,1,0,0, +0,0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0 + + + diff --git a/tools/breakout_editor/wtf.tmx b/tools/breakout_editor/wtf.tmx new file mode 100644 index 000000000..6bd8adfa3 --- /dev/null +++ b/tools/breakout_editor/wtf.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,8,0,0,0,39,0,39,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,39,0,39,0,0,0,8,0,0, +0,0,8,0,22,0,0,39,0,0,22,0,0,0,0,0,1,0,0,0,0,0,0,0,22,0,0,39,0,0,22,0,8,0,0, +0,0,8,0,22,24,24,24,24,24,22,0,0,0,0,0,0,0,0,0,0,0,0,0,22,24,24,24,24,24,22,0,8,0,0, +0,0,8,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,8,0,0, +0,0,8,0,0,0,39,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,39,0,0,0,8,0,0, +0,0,8,0,0,39,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,39,0,0,8,0,0, +0,0,2,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,2,19,19,19,19,19,19,19,2,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,71,72,0,0,0,0,2,2,5,19,19,19,19,19,5,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,87,88,0,0,0,2,2,5,5,5,19,19,19,5,5,5,2,2,0,0,0,0,0,0,0,0,0,1,0, +0,0,0,0,0,0,71,72,0,0,0,2,5,5,5,5,5,19,5,5,5,5,5,2,0,77,78,77,78,77,78,0,0,0,0, +1,1,0,131,0,0,87,88,0,0,0,2,2,5,5,5,19,19,19,5,5,5,2,2,0,93,94,93,94,93,94,132,0,1,0, +0,0,0,0,0,0,71,72,0,0,0,0,2,2,5,19,19,19,19,19,5,2,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,87,88,0,0,0,0,1,2,19,19,19,19,19,19,19,2,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,75,76,24,0,24,0,24,0,24,75,76,0,0,0,0,0,0,0,0,0,2,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,91,92,0,24,0,24,0,24,0,91,92,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,21,0,8,0,0, +0,0,8,0,1,21,0,0,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,2,0,0,21,0,0,8,0,0, +0,0,8,0,1,0,21,2,0,0,0,0,0,0,2,0,0,99,0,0,2,0,0,0,0,0,0,2,21,0,0,0,8,0,0, +0,0,8,0,1,0,2,21,0,0,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,0,1,21,2,0,0,0,8,0,0, +0,0,8,0,1,2,0,0,21,0,0,0,2,0,53,54,0,116,0,53,54,0,2,0,0,1,21,0,0,2,0,0,8,0,0, +0,0,8,0,2,0,0,0,0,21,0,2,0,0,0,0,0,0,0,0,0,0,0,2,1,21,0,0,0,0,2,0,8,0,0, +0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0 + + + diff --git a/tools/breakout_editor/xmarks.tmx b/tools/breakout_editor/xmarks.tmx new file mode 100644 index 000000000..8533061f0 --- /dev/null +++ b/tools/breakout_editor/xmarks.tmx @@ -0,0 +1,41 @@ + + + + + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,2,0,0, +0,0,8,71,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,8,0,0, +0,0,8,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,8,0,0, +0,0,8,0,0,79,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,80,0,0,8,0,0, +0,0,8,0,0,95,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,96,0,0,8,0,0, +0,0,8,0,0,0,0,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,81,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,67,68,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,83,84,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,69,70,0,0,0,0,0,0,0,0,0,69,70,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,85,86,41,42,41,42,26,41,42,41,42,85,86,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,69,70,41,42,41,42,26,41,42,41,42,69,70,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,0,0,85,86,0,0,0,0,0,0,0,0,0,85,86,0,0,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,67,68,0,0,0,0,0,0,0,0,0,0,0,0,0,67,68,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,0,0,83,84,0,0,0,0,0,0,0,0,0,0,0,0,0,83,84,0,0,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,65,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65,66,0,0,0,0,8,0,0, +0,0,8,0,0,0,0,81,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,82,0,0,0,0,8,0,0, +0,0,8,0,0,79,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,80,0,0,8,0,0, +0,0,8,0,0,95,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,95,96,0,0,8,0,0, +0,0,8,71,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,72,8,0,0, +0,0,2,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,88,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/tools/breakout_editor/zip.tmx b/tools/breakout_editor/zip.tmx new file mode 100644 index 000000000..7b372f27f --- /dev/null +++ b/tools/breakout_editor/zip.tmx @@ -0,0 +1,41 @@ + + + + + + + + +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,1, +1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0, +1,1,4,0,0,0,0,0,0,0,0,0,1,21,21,21,21,21,21,21,21,21,21,21,21,1,0,1,1,0,0,0,4,1,0, +1,1,4,0,0,0,0,0,0,0,0,1,21,21,21,21,21,21,21,21,21,21,21,21,21,21,1,0,1,0,1,0,4,1,1, +1,1,4,0,0,0,1,0,0,0,1,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,1,0,0,1,0,4,1,1, +1,1,4,0,0,0,1,21,0,0,1,21,21,21,26,18,26,18,26,26,18,26,18,26,21,21,21,21,0,0,1,0,4,1,1, +1,1,4,0,0,0,0,21,21,0,21,21,21,26,18,26,5,146,18,26,146,5,26,26,18,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,18,26,26,26,5,5,26,26,5,5,26,26,18,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,26,26,146,5,18,26,5,5,18,26,5,146,26,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,18,26,5,5,26,26,5,146,26,26,5,5,26,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,26,18,26,26,18,18,26,26,18,18,26,26,26,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,18,26,47,47,47,47,47,47,47,47,47,24,18,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,21,21,21,26,18,95,95,95,95,95,95,95,95,95,96,26,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,0,21,21,21,21,21,26,26,47,47,47,47,47,47,47,24,18,18,21,21,90,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,0,21,21,21,21,21,21,18,26,18,26,18,26,18,26,18,26,21,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,21,21,23,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,0,0,4,1,1, +1,1,4,0,0,0,21,21,23,0,0,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,0,4,1,1, +1,1,4,0,0,0,21,23,0,0,0,21,21,23,23,23,23,23,23,23,23,23,23,23,23,23,23,21,21,21,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,21,21,23,23,0,0,0,0,0,0,0,0,23,23,21,21,1,23,23,21,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,21,21,23,0,0,0,0,0,0,0,0,0,0,23,23,21,0,23,23,21,1,0,4,1,1, +1,1,4,0,0,0,1,0,0,21,21,23,0,0,0,0,0,0,0,0,0,0,0,0,23,21,0,0,23,21,1,0,4,1,1, +1,1,4,0,0,0,0,0,0,21,23,23,0,0,0,0,0,0,0,0,0,0,0,0,23,21,0,0,23,21,1,0,4,1,1, +1,1,4,0,0,0,0,0,0,21,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,1,1, +1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1,129,0,0,0,0,1,1,1,1,1,0,0,0,0,0,4,1,1, +1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1 + + + diff --git a/tools/rayMapEditor/README.md b/tools/rayMapEditor/README.md index 95d081b3e..562c46bb8 100644 --- a/tools/rayMapEditor/README.md +++ b/tools/rayMapEditor/README.md @@ -109,6 +109,13 @@ These are the objects that can be spawned | `OBJ_ITEM_PICKUP_MISSILE` | Pickup, missiles | | `OBJ_SCENERY_TERMINAL` | Scenery, computer terminal | | `OBJ_SCENERY_PORTAL` | Scenery, portal | +| `OBJ_SCENERY_F1` | Scenery, a friend | +| `OBJ_SCENERY_F2` | Scenery, a friend | +| `OBJ_SCENERY_F3` | Scenery, a friend | +| `OBJ_SCENERY_F4` | Scenery, a friend | +| `OBJ_SCENERY_F5` | Scenery, a friend | +| `OBJ_SCENERY_F6` | Scenery, a friend | +| `OBJ_SCENERY_F7` | Scenery, a friend | ### Script Examples diff --git a/tools/rayMapEditor/openAll.sh b/tools/rayMapEditor/openAll.sh index 1f5b2dd65..1f23518b7 100755 --- a/tools/rayMapEditor/openAll.sh +++ b/tools/rayMapEditor/openAll.sh @@ -1,8 +1,8 @@ #!/bin/bash -python ray_map_editor.py ../../assets/ray/0.rmd & -python ray_map_editor.py ../../assets/ray/1.rmd & -python ray_map_editor.py ../../assets/ray/2.rmd & -python ray_map_editor.py ../../assets/ray/3.rmd & -python ray_map_editor.py ../../assets/ray/4.rmd & -python ray_map_editor.py ../../assets/ray/5.rmd & +python ray_map_editor.py ../../assets/ray/maps/0.rmd & +python ray_map_editor.py ../../assets/ray/maps/1.rmd & +python ray_map_editor.py ../../assets/ray/maps/2.rmd & +python ray_map_editor.py ../../assets/ray/maps/3.rmd & +python ray_map_editor.py ../../assets/ray/maps/4.rmd & +python ray_map_editor.py ../../assets/ray/maps/5.rmd & diff --git a/tools/rayMapEditor/rme_model.py b/tools/rayMapEditor/rme_model.py index cd4ed05cb..2e0d70a1f 100644 --- a/tools/rayMapEditor/rme_model.py +++ b/tools/rayMapEditor/rme_model.py @@ -74,13 +74,13 @@ def getNextId(self): self.currentId = (self.currentId + 1) % 256 def getPaletteType(self, x, y): - if x < len(objTiles): + if x < len(bgTiles): # backgrounds in the first columns if 0 <= y and y < len(bgTiles[x]): return bgTiles[x][y] else: # objects i the other columns - x = x - len(objTiles) + x = x - len(bgTiles) if 0 <= y and y < len(objTiles[x]): return objTiles[x][y] return None diff --git a/tools/rayMapEditor/rme_script_editor.py b/tools/rayMapEditor/rme_script_editor.py index 308b6b164..ecad52fb1 100644 --- a/tools/rayMapEditor/rme_script_editor.py +++ b/tools/rayMapEditor/rme_script_editor.py @@ -382,10 +382,11 @@ def toBytes(self) -> bytearray: for id in self.thenArgs[kIds]: bytes.append(id) if kText in self.thenArgs.keys(): - textLen = len(self.thenArgs[kText]) + unescapedText = self.thenArgs[kText].replace('\\n', '\n').encode() + textLen = len(unescapedText) bytes.append((textLen >> 8) & 255) bytes.append((textLen >> 0) & 255) - bytes.extend(self.thenArgs[kText].encode()) + bytes.extend(unescapedText) if kMap in self.thenArgs.keys(): bytes.append(self.thenArgs[kMap]) if kCell in self.thenArgs.keys(): @@ -494,7 +495,8 @@ def fromBytes(self, bytes: bytearray): (bytes[idx + 1]) idx = idx + 2 # Read text - self.thenArgs[kText] = str(bytes[idx:idx + textLen], 'ascii') + self.thenArgs[kText] = str( + bytes[idx:idx + textLen], 'ascii').replace('\n', '\\n') idx = idx + textLen elif thenOpType.WARP == self.thenOp: # Read the map diff --git a/tools/rayMapEditor/rme_tiles.py b/tools/rayMapEditor/rme_tiles.py index 173b7596f..291acf3ab 100644 --- a/tools/rayMapEditor/rme_tiles.py +++ b/tools/rayMapEditor/rme_tiles.py @@ -26,6 +26,7 @@ class tileType(Enum): BG_FLOOR_WATER = (BG | FLOOR | 2) BG_FLOOR_LAVA = (BG | FLOOR | 3) BG_CEILING = (BG | FLOOR | 4) + BG_FLOOR_HEAL = (BG | FLOOR | 5) BG_WALL_1 = (BG | WALL | 1) BG_WALL_2 = (BG | WALL | 2) BG_WALL_3 = (BG | WALL | 3) @@ -40,6 +41,7 @@ class tileType(Enum): BG_DOOR_KEY_A = (BG | DOOR | 7) BG_DOOR_KEY_B = (BG | DOOR | 8) BG_DOOR_KEY_C = (BG | DOOR | 9) + BG_DOOR_ARTIFACT = (BG | DOOR | 10) # Self and Enemies OBJ_ENEMY_START_POINT = (OBJ | ENEMY | 1) OBJ_ENEMY_NORMAL = (OBJ | ENEMY | 2) @@ -66,20 +68,33 @@ class tileType(Enum): OBJ_ITEM_PICKUP_ENERGY = (OBJ | ITEM | 13) OBJ_ITEM_PICKUP_MISSILE = (OBJ | ITEM | 14) # Bullets - OBJ_BULLET_NORMAL = (OBJ | BULLET | 15) - OBJ_BULLET_CHARGE = (OBJ | BULLET | 16) - OBJ_BULLET_ICE = (OBJ | BULLET | 17) - OBJ_BULLET_MISSILE = (OBJ | BULLET | 18) - OBJ_BULLET_XRAY = (OBJ | BULLET | 19) + OBJ_BULLET_NORMAL = (OBJ | BULLET | 1) + OBJ_BULLET_CHARGE = (OBJ | BULLET | 2) + OBJ_BULLET_ICE = (OBJ | BULLET | 3) + OBJ_BULLET_MISSILE = (OBJ | BULLET | 4) + OBJ_BULLET_XRAY = (OBJ | BULLET | 5) + OBJ_BULLET_E_NORMAL = (OBJ | BULLET | 6) + OBJ_BULLET_E_STRONG = (OBJ | BULLET | 7) + OBJ_BULLET_E_ARMOR = (OBJ | BULLET | 8) + OBJ_BULLET_E_FLAMING = (OBJ | BULLET | 9) + OBJ_BULLET_E_HIDDEN = (OBJ | BULLET | 10) # Scenery OBJ_SCENERY_TERMINAL = (OBJ | SCENERY | 1) OBJ_SCENERY_PORTAL = (OBJ | SCENERY | 2) + OBJ_SCENERY_F1 = (OBJ | SCENERY | 3) + OBJ_SCENERY_F2 = (OBJ | SCENERY | 4) + OBJ_SCENERY_F3 = (OBJ | SCENERY | 5) + OBJ_SCENERY_F4 = (OBJ | SCENERY | 6) + OBJ_SCENERY_F5 = (OBJ | SCENERY | 7) + OBJ_SCENERY_F6 = (OBJ | SCENERY | 8) + OBJ_SCENERY_F7 = (OBJ | SCENERY | 9) bgTiles: list[list[tileType]] = [ [ tileType.BG_FLOOR, tileType.BG_FLOOR_WATER, tileType.BG_FLOOR_LAVA, + tileType.BG_FLOOR_HEAL, tileType.BG_WALL_1, tileType.BG_WALL_2, tileType.BG_WALL_3, @@ -96,6 +111,7 @@ class tileType(Enum): tileType.BG_DOOR_KEY_A, tileType.BG_DOOR_KEY_B, tileType.BG_DOOR_KEY_C, + tileType.BG_DOOR_ARTIFACT, ] ] @@ -124,8 +140,17 @@ class tileType(Enum): tileType.OBJ_ITEM_SUIT_LAVA, tileType.OBJ_ITEM_ENERGY_TANK, tileType.OBJ_ITEM_ARTIFACT, + ], + [ tileType.OBJ_SCENERY_TERMINAL, tileType.OBJ_SCENERY_PORTAL, + tileType.OBJ_SCENERY_F1, + tileType.OBJ_SCENERY_F2, + tileType.OBJ_SCENERY_F3, + tileType.OBJ_SCENERY_F4, + tileType.OBJ_SCENERY_F5, + tileType.OBJ_SCENERY_F6, + tileType.OBJ_SCENERY_F7, tileType.DELETE ] ] diff --git a/tools/rayMapEditor/rme_view.py b/tools/rayMapEditor/rme_view.py index f585b4985..9fea9596f 100644 --- a/tools/rayMapEditor/rme_view.py +++ b/tools/rayMapEditor/rme_view.py @@ -116,7 +116,7 @@ def __init__(self): # Set up the canvasses self.paletteCanvas: tk.Canvas = tk.Canvas( - content, background=elemBgColor, width=self.paletteCellSize * 4, height=self.paletteCellSize * 8, + content, background=elemBgColor, width=self.paletteCellSize * 5, height=self.paletteCellSize * 8, highlightthickness=borderThickness, highlightbackground=borderColor) self.mapCanvas: tk.Canvas = tk.Canvas( content, background=elemBgColor, highlightthickness=borderThickness, highlightbackground=borderColor) @@ -222,21 +222,23 @@ def loadAllTextures(self): # Load all textures self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_FLOOR, '../../assets/ray/env/BG_FLOOR.png') + tileType.BG_FLOOR, '../../assets/ray/env/BASE/BG_BASE_FLOOR.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.BG_FLOOR_WATER, '../../assets/ray/env/BG_FLOOR_WATER.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.BG_FLOOR_LAVA, '../../assets/ray/env/BG_FLOOR_LAVA.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_WALL_1, '../../assets/ray/env/BG_WALL_1.png') + tileType.BG_FLOOR_HEAL, '../../assets/ray/env/BG_FLOOR_HEAL.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_WALL_2, '../../assets/ray/env/BG_WALL_2.png') + tileType.BG_WALL_1, '../../assets/ray/env/BASE/BG_BASE_WALL_1.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_WALL_3, '../../assets/ray/env/BG_WALL_3.png') + tileType.BG_WALL_2, '../../assets/ray/env/BASE/BG_BASE_WALL_2.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_WALL_4, '../../assets/ray/env/BG_WALL_4.png') + tileType.BG_WALL_3, '../../assets/ray/env/BASE/BG_BASE_WALL_3.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.BG_WALL_5, '../../assets/ray/env/BG_WALL_5.png') + tileType.BG_WALL_4, '../../assets/ray/env/BASE/BG_BASE_WALL_4.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.BG_WALL_5, '../../assets/ray/env/BASE/BG_BASE_WALL_5.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.BG_DOOR, '../../assets/ray/doors/BG_DOOR.png') self.loadTexture(self.texMapPalette, self.texMapMap, @@ -255,20 +257,22 @@ def loadAllTextures(self): tileType.BG_DOOR_KEY_B, '../../assets/ray/doors/BG_DOOR_KEY_B.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.BG_DOOR_KEY_C, '../../assets/ray/doors/BG_DOOR_KEY_C.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.BG_DOOR_ARTIFACT, '../../assets/ray/doors/BG_DOOR_ARTIFACT.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.OBJ_ENEMY_START_POINT, 'imgs/OBJ_ENEMY_START_POINT.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_NORMAL, '../../assets/ray/enemies/NORMAL/E_NORMAL_WALK_0.png') + tileType.OBJ_ENEMY_NORMAL, '../../assets/ray/enemies/NORMAL/E_NORMAL_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_STRONG, '../../assets/ray/enemies/STRONG/E_STRONG_WALK_0.png') + tileType.OBJ_ENEMY_STRONG, '../../assets/ray/enemies/STRONG/E_STRONG_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_ARMORED, '../../assets/ray/enemies/ARMORED/E_ARMORED_WALK_0.png') + tileType.OBJ_ENEMY_ARMORED, '../../assets/ray/enemies/ARMORED/E_ARMORED_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_FLAMING, '../../assets/ray/enemies/FLAMING/E_FLAMING_WALK_0.png') + tileType.OBJ_ENEMY_FLAMING, '../../assets/ray/enemies/FLAMING/E_FLAMING_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_HIDDEN, '../../assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0.png') + tileType.OBJ_ENEMY_HIDDEN, '../../assets/ray/enemies/HIDDEN/E_HIDDEN_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, - tileType.OBJ_ENEMY_BOSS, '../../assets/ray/enemies/BOSS/E_BOSS_WALK_0.png') + tileType.OBJ_ENEMY_BOSS, '../../assets/ray/enemies/BOSS/E_BOSS_WALK_0_0.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.OBJ_ITEM_BEAM, '../../assets/ray/items/OBJ_ITEM_BEAM.png') self.loadTexture(self.texMapPalette, self.texMapMap, @@ -301,6 +305,20 @@ def loadAllTextures(self): tileType.OBJ_SCENERY_TERMINAL, '../../assets/ray/scenery/OBJ_SCENERY_TERMINAL.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.OBJ_SCENERY_PORTAL, '../../assets/ray/scenery/OBJ_SCENERY_PORTAL.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F1, '../../assets/ray/friends/OBJ_SCENERY_F1.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F2, '../../assets/ray/friends/OBJ_SCENERY_F2.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F3, '../../assets/ray/friends/OBJ_SCENERY_F3.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F4, '../../assets/ray/friends/OBJ_SCENERY_F4.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F5, '../../assets/ray/friends/OBJ_SCENERY_F5.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F6, '../../assets/ray/friends/OBJ_SCENERY_F6.png') + self.loadTexture(self.texMapPalette, self.texMapMap, + tileType.OBJ_SCENERY_F7, '../../assets/ray/friends/OBJ_SCENERY_F7.png') self.loadTexture(self.texMapPalette, self.texMapMap, tileType.DELETE, 'imgs/DELETE.png') @@ -526,8 +544,9 @@ def scriptTextChanged(self, event: tk.Event): self.scriptTextEntry.tag_add( tag, str(line) + '.0', str(line) + '.0 lineend') if script.isValid(): - self.scriptTextEntry.tag_configure( - tag, background="green", foreground="black") + # self.scriptTextEntry.tag_configure( + # tag, background="green", foreground="black") + pass else: self.scriptTextEntry.tag_configure( tag, background="red", foreground="black") diff --git a/tools/spiffs_file_preprocessor/.gitignore b/tools/spiffs_file_preprocessor/.gitignore index 441f7fce0..b80db4651 100644 --- a/tools/spiffs_file_preprocessor/.gitignore +++ b/tools/spiffs_file_preprocessor/.gitignore @@ -1 +1,3 @@ -spiffs_file_preprocessor \ No newline at end of file +spiffs_file_preprocessor +in +out \ No newline at end of file diff --git a/tools/spiffs_file_preprocessor/.vscode/c_cpp_properties.json b/tools/spiffs_file_preprocessor/.vscode/c_cpp_properties.json index 16b60fc25..405ce14c4 100644 --- a/tools/spiffs_file_preprocessor/.vscode/c_cpp_properties.json +++ b/tools/spiffs_file_preprocessor/.vscode/c_cpp_properties.json @@ -6,11 +6,9 @@ "${workspaceFolder}/**" ], "defines": [], - "windowsSdkVersion": "10.0.18362.0", - "compilerPath": "C:/msys64/usr/bin/gcc.exe", "cStandard": "c17", "cppStandard": "c++17", - "intelliSenseMode": "windows-gcc-x64" + "intelliSenseMode": "gcc-x64" } ], "version": 4 diff --git a/tools/spiffs_file_preprocessor/.vscode/launch.json b/tools/spiffs_file_preprocessor/.vscode/launch.json index 6bfe2f111..a983e64f3 100644 --- a/tools/spiffs_file_preprocessor/.vscode/launch.json +++ b/tools/spiffs_file_preprocessor/.vscode/launch.json @@ -11,16 +11,15 @@ "program": "${workspaceFolder}/spiffs_file_preprocessor", "args": [ "-i", - "../../assets", + "./in", "-o", - "../../spiffs_image" + "./out" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", - "miDebuggerPath": "C:/msys64/mingw64/bin/gdb.exe", "setupCommands": [ { "description": "Enable pretty-printing for gdb", diff --git a/tools/spiffs_file_preprocessor/src/midi_processor.c b/tools/spiffs_file_preprocessor/src/midi_processor.c index 018f9d574..2cd816583 100644 --- a/tools/spiffs_file_preprocessor/src/midi_processor.c +++ b/tools/spiffs_file_preprocessor/src/midi_processor.c @@ -246,8 +246,8 @@ void process_midi(const char* inFile, const char* outDir) notes[trackIdx] = calloc((2 * track->nbOfNotes) + 1, sizeof(musicalNote_t)); /* For each note */ - unsigned long int lastNoteStart = track->notes[0].timeBeforeAppear; - unsigned long int introRest = lastNoteStart; + unsigned long int lastNoteStart = 0; + unsigned long int introRest = track->notes[0].timeBeforeAppear; for (int midiNoteIdx = 0; midiNoteIdx < track->nbOfNotes; midiNoteIdx++) { @@ -337,7 +337,7 @@ void process_midi(const char* inFile, const char* outDir) { // Pad out track 1 to be the same length as track 0 notes[1][noteIdxs[1]].note = SILENCE; - notes[1][noteIdxs[1]].timeMs = totalLength[1] - totalLength[0]; + notes[1][noteIdxs[1]].timeMs = totalLength[0] - totalLength[1]; noteIdxs[1]++; } } @@ -414,10 +414,10 @@ static void checkMidiEvents(MidiParser* midiParser, unsigned long int lastNoteSt for (int evtIdx = 0; evtIdx < track->nbOfEvents; evtIdx++) { Event* evt = &track->events[evtIdx]; - // printf("%5d: %s\n", evt->timeToAppear, evt->type); + // printf("%5d: %d\n", evt->timeToAppear, evt->type); // If this event occurs between the notes we're at, process it - if ((0 == lastNoteStart && 0 == thisNoteStart && 0 == evt->timeToAppear) + if ((0 == lastNoteStart && 0 == evt->timeToAppear) || (lastNoteStart < evt->timeToAppear && evt->timeToAppear <= thisNoteStart)) { switch (evt->type) @@ -426,7 +426,7 @@ static void checkMidiEvents(MidiParser* midiParser, unsigned long int lastNoteSt { // printf( // " Tempo infos: time signature %i/%i 1/4 note is %i ticks %i\n", - // , + // ((unsigned char *)evt->infos)[0], // ((unsigned char *)evt->infos)[1], // ((unsigned char *)evt->infos)[2], // ((unsigned char *)evt->infos)[3]