[
  {
    "path": "README.md",
    "content": "# Doom Flipper Zero edition\n\n <div style=\"text-align:center\"><img src=\"assets/intro-screen.png\"/></div>\n\n## Will it run Doom?\nAs tradition goes, Doom is being ported to almost every possible embedded electronic device. Therefore I did an attempt to come up with something close to Doom and still compatible on the Flipper Zero's hardware.<br> This is not the actual Doom game but a port made from yet another Doom port to the Arduino Nano (https://github.com/daveruiz/doom-nano/). This port is basically a raycasting engine, using Doom sprites.<br>\nThis version is very basic and might be improved over time.\n\n## How to install on Flipper Zero\nDuring the porting process, minor changes were made to the workings (and build options) of the current firmware. These changes are documented here and are necessary in order to get a working firmware build that contains this Doom port.\n### Modifying the firmware & build options\n * In the `sites/cc.scons` add the following values to the `CCFLAGS` section:\n ```\n ...\n\"-Wno-unused-parameter\",\n\"-Wno-type-limits\",\n\"-Wno-unused-variable\",\n...\n ```\n * In `applications/gui/canvas_i.h` comment out the following line:<br>\n `uint8_t* canvas_get_buffer(Canvas* canvas);` --> `//uint8_t* canvas_get_buffer(Canvas* canvas);`\n\n * In `applications/gui/canvas.h` add the following lines:\n ```\n uint8_t* canvas_get_buffer(Canvas* canvas);\n void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon);\n ```\n * In `applications/gui/canvas.c` add the following function:\n ```\n void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon){\n     furi_assert(canvas);\n     furi_assert(icon);\n\n     x += canvas->offset_x;\n     y += canvas->offset_y;\n     uint8_t* icon_data = NULL;\n     furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data);\n     u8g2_DrawXBM(&canvas->fb, x, y, w, h, icon_data);\n }\n ```\n\n### Installing the plugin in the firmware\n * Make a folder called Doom in the applications folder. Add all the source files (also the compiled folder and it's files) in the Doom folder.\n * Make the `applications/meta/application.fam` look like the following:\n ```\n App(\n     appid=\"basic_plugins\",\n     name=\"Basic applications for plug-in menu\",\n     apptype=FlipperAppType.METAPACKAGE,\n     provides=[\n         ...\n         \"doom_game\",\n         ...\n\n     ],\n )\n ```\n\nIf all went well the only thing left to do is building the firmware and installing it to the Flipper.\n\n## Screenshots\n![Intro screen](assets/screenshot-intro2.jpg)\n\n![Start screen](assets/screenshot-start2.jpg)\n\n![Imp](assets/screenshot-imp2.jpg)\n\n![Medkit](assets/screenshot-medkit2.jpg)\n"
  },
  {
    "path": "application.fam",
    "content": "App(\n    appid=\"doom_game\",\n    name=\"Doom\",\n    apptype=FlipperAppType.PLUGIN,\n    entry_point=\"doom_app\",\n    cdefines=[\"APP_DOOM_GAME\"],\n    requires=[\"gui\"],\n    stack_size=1 * 1024,\n    icon=\"A_Plugins_14\",\n    order=30,\n)\n"
  },
  {
    "path": "compiled/assets_icons.c",
    "content": "#include \"assets_icons.h\"\n\n#include <gui/icon_i.h>\n\n\n\n\n\n// Inverted icons\n\nconst uint8_t _I_fire_inv_0[] = {0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x30,0x00,0x40,0xee,0x00,0x80,0xe6,0x00,0x80,0xa7,0x01,0x80,0xc7,0x03,0x40,0x45,0x03,0xe0,0x41,0x07,0xf8,0x82,0x9f,0xb9,0x01,0x3e,0x7c,0x00,0x7a,0x6e,0x00,0x56,0x1c,0x00,0x6c,0xf4,0x01,0x3a,0x6c,0x00,0x7e,0xfc,0x00,0x1a,0x08,0x00,0x3c,0x11,0x00,0x00,0x00,0x00,0x00,};\nconst uint8_t* const _I_fire_inv[] = {_I_fire_inv_0};\n\nconst uint8_t _I_gun_inv_0[] = {0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x1b,0x00,0x00,0x80,0x23,0x00,0x00,0x40,0x20,0x00,0x00,0x40,0x40,0x00,0x00,0x40,0x57,0x00,0x00,0x20,0x8b,0x00,0x00,0x90,0x11,0x01,0x00,0x98,0x00,0x00,0x00,0xb0,0x43,0x01,0x00,0x94,0x81,0x03,0x00,0xd0,0x45,0x04,0x00,0x8c,0x02,0x02,0x00,0xc4,0x00,0x03,0x00,0xc8,0x00,0x02,0x00,0x4e,0x40,0x00,0x00,0x92,0x00,0x02,0x80,0x07,0x15,0x04,0xe0,0x8f,0x00,0x0c,0xd0,0x9d,0x07,0x17,0xe0,0x3a,0xc0,0x3f,0xe0,0xf7,0xff,0x77,0xe0,0xae,0xfe,0x4b,0xd8,0xdd,0xff,0x4d,0x88,0xea,0xbe,0x26,0x4c,0xf5,0xff,0x17,0xc8,0xfa,0xae,0x0b,0xcc,0xff,0xdf,0x19,0xe8,0xeb,0xa7,0x00,0xd8,0xf1,0x4d,0x0c,0xc0,0xbe,0x1a,0x08,0xf6,0xfd,0x37,0x04,};\nconst uint8_t* const _I_gun_inv[] = {_I_gun_inv_0};\n\nconst uint8_t _I_gun_mask_inv_0[] = {0x01,0x00,0x53,0x00,0x00,0x0c,0x38,0x04,0x38,0x09,0xf8,0x0c,0x78,0x17,0xf0,0x18,0xf8,0x00,0x67,0xff,0x01,0xaf,0xc3,0xff,0x01,0x80,0x7e,0x3f,0xf0,0x38,0x07,0xf0,0x0e,0x40,0x31,0x03,0x8f,0xfb,0xff,0x07,0x01,0x94,0x3c,0x0e,0xc0,0x35,0xff,0x85,0xc8,0x06,0x30,0x7e,0x00,0x0c,0x61,0xe2,0xe1,0xff,0xc7,0xc5,0xc3,0xff,0x9f,0x80,0xca,0xfe,0x03,0x2f,0xf8,0x0c,0xc6,0xc2,0x03,0x4b,0xf8,0xa8,0x42,0xe2,0x03,0x28,0xf8,0x1e,0x80,0x68,0x1e,0x28,0x78,};\nconst uint8_t* const _I_gun_mask_inv[] = {_I_gun_mask_inv_0};\n\nconst uint8_t _I_logo_inv_0[] = {0x01,0x00,0x71,0x01,0x00,0x44,0x0a,0x21,0x00,0xc0,0x48,0x20,0x91,0x0c,0x05,0x20,0x14,0x30,0x80,0x71,0x80,0x8e,0x03,0x00,0x85,0x40,0x22,0x98,0x8a,0x00,0x20,0x60,0xa0,0x83,0xa8,0x50,0x20,0xd8,0x00,0x41,0xcd,0x01,0x03,0x82,0xc3,0xc3,0x61,0xf0,0xa8,0xf0,0x44,0x6c,0x14,0x68,0x26,0x16,0x3b,0x0a,0x89,0xcd,0x24,0x14,0x0a,0x96,0x32,0x1b,0x11,0x85,0xc4,0x62,0x92,0x00,0x88,0xe1,0x30,0xb1,0x18,0x54,0x46,0x6d,0x28,0xa0,0x70,0x82,0x23,0x51,0xa5,0x54,0x62,0x90,0x1b,0x05,0x0b,0x19,0x15,0x89,0x86,0x86,0x69,0x42,0xb0,0xf5,0xb2,0x9a,0x58,0xac,0xae,0xaf,0x35,0x85,0x50,0xb8,0xda,0x69,0x6d,0x6e,0x95,0x9b,0x9b,0x50,0xac,0x9c,0xac,0x6e,0x36,0x37,0x2b,0xad,0xed,0xa2,0x41,0xa1,0xd7,0x6b,0x42,0x23,0x3f,0xdb,0x75,0xad,0x5d,0x6c,0x2c,0x37,0xbf,0x5b,0x0d,0x0e,0x5a,0xc5,0xca,0xdb,0xef,0x6b,0xf6,0xea,0xff,0xde,0x6d,0x4d,0xfb,0x75,0xe5,0xfb,0xfd,0xde,0xfe,0x6d,0xe7,0xb9,0x7b,0xba,0xff,0xdb,0xfd,0xaf,0xbf,0x77,0xc7,0xd9,0xf3,0x5f,0x79,0xed,0x3c,0x10,0x3f,0x79,0x7d,0xbf,0x9f,0xed,0xff,0xf7,0xe7,0x5f,0xff,0xbd,0xae,0xbd,0xd6,0xfe,0xdf,0x62,0x34,0xbf,0xdf,0xde,0x77,0x6b,0xe9,0x7f,0xbf,0xf5,0x38,0x77,0xe7,0xef,0x7b,0xb9,0xf4,0xbf,0x7f,0xde,0xbd,0xb8,0x34,0x3f,0xbb,0x5f,0xbb,0xff,0xff,0xbf,0xda,0x80,0x63,0xfb,0xa1,0xfe,0xc1,0x05,0xdf,0x11,0x8f,0xce,0xdd,0xf2,0xff,0xff,0x40,0xe3,0xff,0xf3,0xfd,0xe9,0x42,0xb1,0xfc,0x84,0xc4,0x32,0x3f,0xbb,0xf0,0x10,0x7e,0x60,0x82,0xfe,0xdc,0xe8,0xc1,0x11,0x07,0x97,0xff,0xfd,0x7f,0xbf,0x82,0x07,0x8f,0xff,0xf8,0x82,0x06,0xef,0x7e,0x04,0x0e,0x0f,0xff,0xe0,0x9f,0xfe,0x04,0x67,0x01,0x9f,0x60,0x21,0xff,0x0d,0xf8,0x68,0xa0,0x11,0xcc,0x04,0x1f,0xc1,0xbf,0x0d,0x0c,0xfe,0x01,0x08,0x80,0x40,0xb8,0x1f,0xc0,0x88,0xc7,0xe0,0x00,0x03,0xe4,0x5f,0xff,0xf0,0xf0,0x42,0x70,0x03,0x43,0x03,0x04,0x28,0x68,0x60,0x20,0x87,0x03,0xa4,0x03,0xc1,0x7f,0x1a,0x08,0x45,0x86,0x8b,0x00,0xc0,0x5f,0xe1,0xc0,0x85,0x80,0x5f,0xe0,0x80,0x86,0xfe,0x01,0xda,0x01,0x78,0x04,0x3c,0xc0,};\nconst uint8_t* const _I_logo_inv[] = {_I_logo_inv_0};\n\nconst Icon I_fire_inv = {.width=24,.height=20,.frame_count=1,.frame_rate=0,.frames=_I_fire_inv};\nconst Icon I_gun_inv = {.width=32,.height=32,.frame_count=1,.frame_rate=0,.frames=_I_gun_inv};\nconst Icon I_gun_mask_inv = {.width=32,.height=32,.frame_count=1,.frame_rate=0,.frames=_I_gun_mask_inv};\nconst Icon I_logo_inv = {.width=72,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_logo_inv};\n\nconst uint8_t  space[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\nconst uint8_t  zero[]  = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};\nconst uint8_t  one[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x70};\nconst uint8_t  two[] ={0x00, 0x60, 0x90, 0x20, 0x40, 0xf0};\nconst uint8_t  three[]  = {0x00, 0x60, 0x90, 0x20, 0x90, 0x60};\nconst uint8_t  four[]  = {0x00, 0x90, 0x90, 0xf0, 0x10, 0x10};\nconst uint8_t  five[]  = {0x00, 0xf0, 0x80, 0xe0, 0x10, 0xe0};\nconst uint8_t  six[]  = {0x00, 0x60, 0x80, 0xe0, 0x90, 0x60};\nconst uint8_t  seven[]  = {0x00, 0xf0, 0x10, 0x10, 0x10, 0x10};\nconst uint8_t  eight[]  = {0x00, 0x60, 0x90, 0x60, 0x90, 0x60};\nconst uint8_t  nine[]  = {0x00, 0x60, 0x90, 0x70, 0x10, 0x60};\nconst uint8_t  A[]  = {0x00, 0x60, 0x90, 0xf0, 0x90, 0x90};\nconst uint8_t  B[]  = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0xe0};\nconst uint8_t  C[]  = {0x00, 0x60, 0x90, 0x80, 0x90, 0x60};\nconst uint8_t  D[]  = {0x00, 0xe0, 0x90, 0x90, 0x90, 0xe0};\nconst uint8_t  E[]  = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0xf0};\nconst uint8_t  F[]  = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80};\nconst uint8_t  G[]  = {0x00, 0x60, 0x80, 0x80, 0x90, 0x60};\nconst uint8_t  H[]  = {0x00, 0x90, 0x90, 0xf0, 0x90, 0x90};\nconst uint8_t  I[]  = {0x00, 0x20, 0x20, 0x20, 0x20, 0x20};\nconst uint8_t  J[]  = {0x00, 0x10, 0x10, 0x10, 0x90, 0x60};\nconst uint8_t  K[]  = {0x00, 0x90, 0xa0, 0xc0, 0xa0, 0x90};\nconst uint8_t  L[]  = {0x00, 0x80, 0x80, 0x80, 0x80, 0xf0};\nconst uint8_t  M[]  = {0x00, 0x90, 0xf0, 0x90, 0x90, 0x90};\nconst uint8_t  N[]  = {0x00, 0x90, 0xd0, 0xb0, 0x90, 0x90};\nconst uint8_t  O[]  = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};\nconst uint8_t  P[]  = {0x00, 0xe0, 0x90, 0xe0, 0x80, 0x80};\nconst uint8_t  Q[]  = {0x00, 0x60, 0x90, 0x90, 0xb0, 0x70};\nconst uint8_t  R[]  = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0x90};\nconst uint8_t  S[]  = {0x00, 0x60, 0x80, 0x60, 0x10, 0xe0};\nconst uint8_t  T[]  = {0x00, 0xe0, 0x40, 0x40, 0x40, 0x40};\nconst uint8_t  U[]  = {0x00, 0x90, 0x90, 0x90, 0x90, 0x60};\nconst uint8_t  V[]  = {0x00, 0x90, 0x90, 0x90, 0x60, 0x60};\nconst uint8_t  W[]  = {0x00, 0x90, 0x90, 0x90, 0xf0, 0x90};\nconst uint8_t  X[]  = {0x00, 0x90, 0x90, 0x60, 0x90, 0x90};\nconst uint8_t  Y[]  = {0x00, 0x90, 0x90, 0x60, 0x60, 0x60};\nconst uint8_t  Z[]  = {0x00, 0xf0, 0x10, 0x60, 0x80, 0xf0};\nconst uint8_t  dot[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x40};\nconst uint8_t  comma[]  = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40};\nconst uint8_t  dash[]  = {0x00, 0x00, 0x00, 0x60, 0x00, 0x00};\nconst uint8_t  underscore[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0xf0};\nconst uint8_t  bracket_open[]  = {0x00, 0x20, 0x40, 0x40, 0x40, 0x20};\nconst uint8_t  bracket_close[]  = {0x00, 0x40, 0x20, 0x20, 0x20, 0x40};\nconst uint8_t  cross_left[]  = {0x10, 0x10, 0x70, 0x70, 0x10, 0x10};\nconst uint8_t  cross_right[]  = {0x80, 0x80, 0xe0, 0xe0, 0x80, 0x80};\nconst uint8_t  pacman_left[]  = {0x00, 0x30, 0x50, 0x70, 0x70, 0x00};\nconst uint8_t  pacman_right[]  = {0x00, 0xc0, 0x60, 0xe0, 0xe0, 0xe0};\nconst uint8_t  box[]  = {0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00};\nconst uint8_t *char_arr[48] = {space,zero,one,two,three,four,five,six,seven,eight,nine,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,dot,comma,dash,underscore,bracket_open,bracket_close,cross_left,cross_right,pacman_left,pacman_right,box};\nconst uint8_t gradient[] = {  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x00, 0x00,  0x88, 0x88,  0x00, 0x00,  0x22, 0x22,  0x00, 0x00,  0x8a, 0x8a,  0x00, 0x00,  0x22, 0x22,  0x00, 0x00,  0xaa, 0xaa,  0x10, 0x10,  0xaa, 0xaa,  0x00, 0x00,  0xaa, 0xaa,  0x01, 0x01,  0xaa, 0xaa,  0x44, 0x44,  0xaa, 0xaa,  0x55, 0x55,  0xaa, 0xaa,  0x44, 0x44,  0xaa, 0xaa,  0x15, 0x55,  0xaa, 0xaa,  0x55, 0x55,  0xaa, 0xaa,  0x55, 0x55,  0xbb, 0xbb,  0x55, 0x55,  0xaa, 0xea,  0x55, 0x55,  0xbb, 0xbb,  0x55, 0x55,  0xff, 0xff,  0x55, 0x55,  0xfb, 0xfb,  0x55, 0x55,  0xff, 0xff,  0x55, 0x55,  0xbb, 0xbf,  0x57, 0x57,  0xff, 0xff,  0xdd, 0xdd,  0xff, 0xff,  0x77, 0x75,  0xff, 0xff,  0xdd, 0xdd,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff,  0xff, 0xff};\n//const uint8_t gun[] = {0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x27, 0xff, 0xff, 0xfe, 0x3b, 0xff, 0xff, 0xfd, 0xfb, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xfd, 0x15, 0xff, 0xff, 0xfb, 0x2e, 0xff, 0xff, 0xf6, 0x77, 0x7f, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xf2, 0x3d, 0x7f, 0xff, 0xd6, 0x7e, 0x3f, 0xff, 0xf4, 0x5d, 0xdf, 0xff, 0xce, 0xbf, 0xbf, 0xff, 0xdc, 0xff, 0x3f, 0xff, 0xec, 0xff, 0xbf, 0xff, 0x8d, 0xfd, 0xff, 0xff, 0xb6, 0xff, 0xbf, 0xfe, 0x1f, 0x57, 0xdf, 0xf8, 0x0e, 0xff, 0xcf, 0xf4, 0x46, 0x1f, 0x17, 0xf8, 0xa3, 0xfc, 0x03, 0xf8, 0x10, 0x00, 0x11, 0xf8, 0x8a, 0x80, 0x2d, 0xe4, 0x44, 0x00, 0x4d, 0xee, 0xa8, 0x82, 0x9b, 0xcd, 0x50, 0x00, 0x17, 0xec, 0xa0, 0x8a, 0x2f, 0xcc, 0x00, 0x04, 0x67, 0xe8, 0x28, 0x1a, 0xff, 0xe4, 0x70, 0x4d, 0xcf, 0xfc, 0x82, 0xa7, 0xef, 0x90, 0x40, 0x13, 0xdf};\n// const uint8_t gun_mask[] = {0xff, 0xff, 0x8f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f};\nconst uint8_t gun[] = {0x00, 0x00, 0x20, 0x00,0x00, 0x00, 0xd8, 0x00,0x00, 0x01, 0xc4, 0x00,0x00, 0x02, 0x04, 0x00,0x00, 0x02, 0x02, 0x00,0x00, 0x02, 0xea, 0x00,0x00, 0x04, 0xd1, 0x00,0x00, 0x09, 0x88, 0x80,0x00, 0x19, 0x00, 0x00,0x00, 0x0d, 0xc2, 0x80,0x00, 0x29, 0x81, 0xc0,0x00, 0x0b, 0xa2, 0x20,0x00, 0x31, 0x40, 0x40,0x00, 0x23, 0x00, 0xc0,0x00, 0x13, 0x00, 0x40,0x00, 0x72, 0x02, 0x00,0x00, 0x49, 0x00, 0x40,0x01, 0xe0, 0xa8, 0x20,0x07, 0xf1, 0x00, 0x30,0x0b, 0xb9, 0xe0, 0xe8,0x07, 0x5c, 0x03, 0xfc,0x07, 0xef, 0xff, 0xee,0x07, 0x75, 0x7f, 0xd2,0x1b, 0xbb, 0xff, 0xb2,0x11, 0x57, 0x7d, 0x64,0x32, 0xaf, 0xff, 0xe8,0x13, 0x5f, 0x75, 0xd0,0x33, 0xff, 0xfb, 0x98,0x17, 0xd7, 0xe5, 0x00,0x1b, 0x8f, 0xb2, 0x30,0x03, 0x7d, 0x58, 0x10,0x6f, 0xbf, 0xec, 0x20};\nconst uint8_t gun_mask[] = {0x00, 0x00, 0x70, 0x00,0x00, 0x01, 0xfc, 0x00,0x00, 0x03, 0xfe, 0x00,0x00, 0x07, 0xfe, 0x00,0x00, 0x07, 0xff, 0x00,0x00, 0x07, 0xff, 0x00,0x00, 0x0f, 0xff, 0x80,0x00, 0x1f, 0xff, 0xc0,0x00, 0x3f, 0xff, 0x80,0x00, 0x3f, 0xff, 0xc0,0x00, 0x7f, 0xff, 0xe0,0x00, 0x7f, 0xff, 0xf0,0x00, 0x7f, 0xff, 0xe0,0x00, 0x7f, 0xff, 0xe0,0x00, 0x7f, 0xff, 0xe0,0x00, 0xff, 0xff, 0xc0,0x00, 0xff, 0xff, 0xe0,0x03, 0xff, 0xff, 0xf0,0x0f, 0xff, 0xff, 0xf8,0x1f, 0xff, 0xff, 0xfc,0x1f, 0xff, 0xff, 0xfe,0x1f, 0xff, 0xff, 0xff,0x1f, 0xff, 0xff, 0xff,0x3f, 0xff, 0xff, 0xff,0x3f, 0xff, 0xff, 0xfe,0x7f, 0xff, 0xff, 0xfc,0x7f, 0xff, 0xff, 0xf8,0x7f, 0xff, 0xff, 0xfc,0x7f, 0xff, 0xff, 0xf8,0x7f, 0xff, 0xff, 0xf8,0x7f, 0xff, 0xff, 0xf8,0xff, 0xff, 0xff, 0xf0};\n\nconst uint8_t imp_inv[] = {0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x01, 0x80, 0x00,0x00, 0x02, 0x80, 0x00,0x00, 0x07, 0x40, 0x00,0x00, 0x02, 0x80, 0x00,0x00, 0x01, 0x00, 0x00,0x01, 0x0f, 0xb3, 0x00,0x00, 0xd0, 0x4e, 0x00,0x00, 0x79, 0x8c, 0x00,0x00, 0x1c, 0x19, 0x00,0x01, 0x8a, 0x20, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x03, 0x00,0x02, 0x00, 0x00, 0x00,0x03, 0x02, 0x00, 0x00,0x00, 0x00, 0x00, 0x40,0x02, 0x08, 0x00, 0x80,0x00, 0x00, 0x01, 0x00,0x01, 0x8e, 0x30, 0x00,0x00, 0x04, 0x10, 0x00,0x00, 0x0c, 0x20, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x10, 0x00,0x00, 0x06, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x20, 0x00,0x00, 0x01, 0x00, 0x00,0x00, 0x02, 0x20, 0x00,0x00, 0x05, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x01, 0x80, 0x00,0x00, 0x02, 0x40, 0x00,0x00, 0x03, 0xe0, 0x00,0x00, 0x04, 0x00, 0x00,0x00, 0x01, 0xa1, 0x80,0x01, 0x80, 0x13, 0x00,0x00, 0xf3, 0x8a, 0x00,0x00, 0x09, 0x94, 0x00,0x00, 0x88, 0x38, 0x80,0x00, 0x00, 0x00, 0x00,0x00, 0x02, 0x23, 0x00,0x00, 0x00, 0x00, 0x40,0x01, 0x80, 0x00, 0x80,0x00, 0x00, 0x01, 0x00,0x00, 0xe2, 0x80, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x0c, 0x20, 0x00,0x00, 0x04, 0x30, 0x00,0x00, 0x02, 0x20, 0x00,0x00, 0x00, 0x40, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x01, 0x00, 0x00,0x00, 0x02, 0x20, 0x00,0x00, 0x06, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x02, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0xa0, 0x00,0x00, 0x00, 0x48, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x04, 0x00,0x00, 0x00, 0x0a, 0x00,0x00, 0x00, 0x1f, 0x00,0x00, 0x02, 0x2a, 0x80,0x00, 0x01, 0x05, 0x00,0x00, 0x01, 0xae, 0x20,0x00, 0x01, 0x24, 0x40,0x00, 0x02, 0xac, 0x80,0x00, 0x02, 0x86, 0x00,0x00, 0x03, 0x20, 0x20,0x00, 0x04, 0x30, 0x40,0x00, 0x0c, 0x00, 0x00,0x00, 0x00, 0x00, 0x40,0x00, 0x00, 0x20, 0x20,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x08, 0x20,0x00, 0x01, 0x00, 0x00,0x00, 0x02, 0x1a, 0x00,0x00, 0x00, 0x1c, 0x00,0x00, 0x00, 0x38, 0x00,0x00, 0x04, 0x00, 0x00,0x00, 0x02, 0x98, 0x00,0x00, 0x00, 0x18, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x36, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x20, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x04, 0x00,0x00, 0x00, 0x0a, 0x00,0x00, 0x00, 0x08, 0x40,0x00, 0x00, 0x00, 0x80,0x00, 0x01, 0xd6, 0x80,0x00, 0x02, 0xbf, 0x80,0x00, 0x06, 0x61, 0xa0,0x00, 0x0c, 0xe8, 0x80,0x00, 0x0c, 0x10, 0x00,0x00, 0x1a, 0x22, 0x00,0x00, 0x12, 0x40, 0x00,0x00, 0x06, 0x0c, 0x00,0x00, 0x04, 0x0d, 0x00,0x00, 0x3a, 0x03, 0x00,0x00, 0x10, 0x02, 0x00,0x00, 0x60, 0x0a, 0x00,0x00, 0x50, 0x04, 0x00,0x00, 0x20, 0x03, 0x00,0x00, 0x00, 0x04, 0x00,0x00, 0x20, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x20, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x40, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x02, 0x24, 0x00,0x00, 0x01, 0x08, 0x00,0x00, 0x01, 0x18, 0x00,0x00, 0x01, 0x41, 0x40,0x02, 0x33, 0xb6, 0x80,0x01, 0x9c, 0x04, 0x00,0x08, 0xfa, 0x02, 0x08,0x05, 0x00, 0x01, 0x0c,0x27, 0x83, 0xa2, 0x2a,0x00, 0x04, 0x00, 0x00,0x02, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00};//{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0f, 0xb3, 0x00, 0x00, 0xd0, 0x4e, 0x00, 0x00, 0x79, 0x8c, 0x00, 0x00, 0x1c, 0x19, 0x00, 0x01, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8e, 0x30, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\nconst uint8_t imp_mask_inv[] = {0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x03, 0xc0, 0x00,0x00, 0x03, 0xc0, 0x00,0x00, 0x07, 0xe0, 0x00,0x00, 0x07, 0xe0, 0x00,0x00, 0x03, 0xe0, 0x00,0x01, 0x07, 0xf1, 0x80,0x00, 0xdf, 0xfe, 0x00,0x00, 0x3f, 0xfe, 0x00,0x00, 0x7f, 0xff, 0x00,0x01, 0xff, 0xff, 0x80,0x00, 0xff, 0xff, 0x80,0x01, 0xff, 0xff, 0x80,0x03, 0xcf, 0xf1, 0xc0,0x01, 0xc7, 0xf1, 0xc0,0x01, 0x87, 0xf1, 0xc0,0x03, 0x0f, 0xf9, 0x80,0x03, 0x0f, 0xfb, 0x80,0x01, 0x8f, 0xff, 0x80,0x03, 0x9f, 0x79, 0x00,0x00, 0x1f, 0x7c, 0x00,0x00, 0x0f, 0x78, 0x00,0x00, 0x0f, 0x78, 0x00,0x00, 0x07, 0x30, 0x00,0x00, 0x07, 0x38, 0x00,0x00, 0x07, 0x30, 0x00,0x00, 0x07, 0x30, 0x00,0x00, 0x03, 0x78, 0x00,0x00, 0x07, 0x30, 0x00,0x00, 0x0f, 0x80, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x03, 0xc0, 0x00,0x00, 0x07, 0xc0, 0x00,0x00, 0x07, 0xe0, 0x00,0x00, 0x07, 0xc0, 0x00,0x01, 0x07, 0xe1, 0x00,0x00, 0x8f, 0xfa, 0x00,0x00, 0xff, 0xfe, 0x00,0x00, 0x3f, 0xfe, 0x00,0x01, 0x7f, 0xff, 0x80,0x00, 0xff, 0xff, 0x00,0x01, 0xff, 0xff, 0x80,0x03, 0xcf, 0xfb, 0xc0,0x03, 0x87, 0xf1, 0xc0,0x03, 0xcf, 0xf3, 0xc0,0x01, 0xcf, 0xf1, 0x80,0x00, 0xcf, 0xf1, 0x00,0x00, 0x0f, 0xfb, 0x80,0x00, 0x1e, 0x78, 0x00,0x00, 0x0e, 0x78, 0x00,0x00, 0x1e, 0x78, 0x00,0x00, 0x0f, 0x70, 0x00,0x00, 0x0f, 0x78, 0x00,0x00, 0x07, 0x70, 0x00,0x00, 0x07, 0x70, 0x00,0x00, 0x07, 0x38, 0x00,0x00, 0x03, 0x30, 0x00,0x00, 0x03, 0x20, 0x00,0x00, 0x07, 0x30, 0x00,0x00, 0x05, 0x70, 0x00,0x00, 0x00, 0x78, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x0e, 0x00,0x00, 0x00, 0x1f, 0x00,0x00, 0x00, 0x1f, 0x00,0x00, 0x03, 0x3f, 0x80,0x00, 0x01, 0x3f, 0x00,0x00, 0x01, 0xff, 0x30,0x00, 0x03, 0xff, 0xc0,0x00, 0x03, 0xff, 0xc0,0x00, 0x03, 0xff, 0x80,0x00, 0x07, 0xff, 0xe0,0x00, 0x07, 0xff, 0xc0,0x00, 0x05, 0xff, 0xe0,0x00, 0x00, 0xfc, 0xe0,0x00, 0x01, 0xfc, 0xe0,0x00, 0x01, 0xfc, 0x70,0x00, 0x03, 0xfc, 0x38,0x00, 0x03, 0xfe, 0x70,0x00, 0x07, 0xfc, 0x00,0x00, 0x07, 0x9e, 0x00,0x00, 0x0f, 0xbc, 0x00,0x00, 0x0f, 0x3e, 0x00,0x00, 0x07, 0x9c, 0x00,0x00, 0x03, 0x9c, 0x00,0x00, 0x03, 0xb8, 0x00,0x00, 0x03, 0x98, 0x00,0x00, 0x01, 0x98, 0x00,0x00, 0x02, 0x1c, 0x00,0x00, 0x00, 0x36, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x20, 0x00,0x00, 0x00, 0x38, 0x00,0x00, 0x00, 0x1f, 0x00,0x00, 0x00, 0x1f, 0x40,0x00, 0x00, 0x3e, 0x80,0x00, 0x01, 0xff, 0x80,0x00, 0x03, 0xff, 0x80,0x00, 0x07, 0xff, 0xe0,0x00, 0x0e, 0xff, 0xc0,0x00, 0x0c, 0xff, 0x80,0x00, 0x1f, 0xfe, 0x00,0x00, 0x13, 0xfc, 0x00,0x00, 0x07, 0xfe, 0x00,0x00, 0x1f, 0xff, 0x00,0x00, 0x3f, 0x9f, 0x00,0x00, 0x3e, 0x0f, 0x00,0x00, 0x7c, 0x0f, 0x00,0x00, 0x78, 0x0f, 0x00,0x00, 0x78, 0x07, 0x80,0x00, 0x78, 0x07, 0x40,0x00, 0x38, 0x07, 0x80,0x00, 0x30, 0x07, 0x00,0x00, 0x30, 0x01, 0x00,0x01, 0xf0, 0x00, 0x00,0x01, 0xb0, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x01, 0x1c, 0x00,0x00, 0x01, 0x3e, 0x00,0x00, 0x03, 0xff, 0x00,0x00, 0x0f, 0xff, 0xe0,0x01, 0x3f, 0xff, 0xc0,0x01, 0xff, 0xff, 0xc0,0x19, 0xff, 0xff, 0xe8,0x7f, 0xff, 0xff, 0xfe,0x3f, 0xff, 0xff, 0xfe,0x1f, 0xc2, 0x07, 0xe0,0x1f, 0x00, 0x01, 0xe0,0x0e, 0x00, 0x00, 0x40,0x00, 0x00, 0x00, 0x00,};//{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x07, 0xf1, 0x80, 0x00, 0xdf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xf1, 0xc0, 0x01, 0xc7, 0xf1, 0xc0, 0x01, 0x87, 0xf1, 0xc0, 0x03, 0x0f, 0xf9, 0x80, 0x03, 0x0f, 0xfb, 0x80, 0x01, 0x8f, 0xff, 0x80, 0x03, 0x9f, 0x79, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00};\nconst uint8_t fireball[] = {0x00, 0x00,0x01, 0x40,0x0a, 0xb0,0x0e, 0xd0,0x00, 0x68,0x53, 0xb4,0x0f, 0x48,0x27, 0x78,0x17, 0xa8,0x27, 0xf0,0x21, 0xd6,0x02, 0xf8,0x20, 0x48,0x06, 0x20,0x01, 0x00,0x00, 0x00};\nconst uint8_t fireball_mask[] = {0x1f, 0x40,0x0f, 0xf0,0x3f, 0xf8,0x1f, 0xfc,0x7f, 0xfd,0x7f, 0xfc,0x7f, 0xfd,0xff, 0xfe,0xff, 0xff,0xff, 0xff,0xff, 0xfe,0xff, 0xfe,0x3f, 0xfe,0x17, 0xf8,0x07, 0xf4,0x01, 0xe0};\nconst uint8_t item[] = {0x1f, 0xf8,0x3f, 0xfc,0x7f, 0xfe,0x7f, 0xfe,0x77, 0xee,0x3f, 0xfc,0x5f, 0xfa,0x2f, 0xf6,0x53, 0xcc,0x3e, 0x7e,0x5e, 0x7c,0x38, 0x1e,0x58, 0x1c,0x3e, 0x7e,0x5e, 0x7e,0x2e, 0xfc,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x0f, 0xfc,0x17, 0xfc,0x22, 0x6c,0x36, 0x44,0x3f, 0xfc,0x1f, 0xfc,0x2b, 0xfc,0x05, 0x54,0x02, 0xa8,0x00, 0x00,0x00, 0x00};\nconst uint8_t item_mask[] = {0x1f, 0xf8,0x3f, 0xfc,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x7f, 0xfe,0x3f, 0xfc,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x0f, 0xfc,0x1f, 0xfc,0x3f, 0xfc,0x3f, 0xfc,0x3f, 0xfc,0x3f, 0xfc,0x3f, 0xfc,0x07, 0xfc,0x03, 0xf8,0x00, 0x00,0x00, 0x00};\n\n//const uint8_t door[] = {0xff, 0xff, 0xff, 0xff,0xb2, 0xbd, 0xcd, 0x5b,0x9a, 0xf4, 0x6d, 0x71,0xff, 0xff, 0xff, 0xff,0x00, 0x00, 0x00, 0x00,0xbf, 0xff, 0xff, 0xfd,0x3f, 0x00, 0xfe, 0xfc,0x3e, 0x00, 0xc6, 0xfc,0xbc, 0xaa, 0xfe, 0xbd,0x39, 0x54, 0xc6, 0xbc,0x32, 0x8e, 0xfe, 0xac,0xb5, 0xfe, 0xc6, 0xad,0x3f, 0xe0, 0xfe, 0xac,0x31, 0xe0, 0xc6, 0xac,0xb3, 0xf4, 0xfe, 0xad,0x3f, 0xe8, 0xc6, 0xac,0x3c, 0xf4, 0xd6, 0xac,0xb8, 0xff, 0xfe, 0xad,0x34, 0xc7, 0xfe, 0xfc,0x38, 0xd6, 0x0e, 0x0c,0xb0, 0xd6, 0x4e, 0x0d,0x3f, 0xd6, 0xaf, 0x5c,0x30, 0x47, 0xff, 0xac,0xb7, 0x57, 0xff, 0xfd,0x3f, 0xc6, 0x0e, 0x0c,0x35, 0x56, 0x40, 0x4c,0xb5, 0x46, 0xaa, 0xad,0x35, 0x56, 0x55, 0x4c,0xff, 0xff, 0xff, 0xff,0xb0, 0x1f, 0xf8, 0x0d,0xd9, 0x30, 0x0c, 0x9b,0xff, 0xe0, 0x07, 0xff};\nconst uint8_t door[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0xe1, 0x8c, 0x00, 0x04, 0x00, 0x7c, 0x03, 0x18, 0x60, 0x08, 0x00, 0x3e, 0x0f, 0xf7, 0xdf, 0x00, 0x1f, 0x00, 0xfe, 0x0f, 0xbe, 0xf8, 0x3e, 0x00, 0x3f, 0x1f, 0xff, 0xdf, 0x00, 0x1f, 0x81, 0xff, 0x0f, 0xff, 0xf8, 0x7e, 0x00, 0x3f, 0x8f, 0xff, 0xdf, 0x00, 0xff, 0xf9, 0xff, 0x1f, 0xff, 0xf8, 0xff, 0x80, 0x3f, 0xc7, 0xff, 0xcc, 0x07, 0xff, 0xfc, 0xff, 0x1f, 0xff, 0xe3, 0xff, 0x80, 0x3f, 0xc7, 0xff, 0xc0, 0x07, 0xff, 0xfc, 0x7f, 0x0f, 0xfe, 0x03, 0xff, 0xc0, 0x3f, 0xc3, 0xf7, 0xc0, 0x07, 0xdf, 0xf8, 0x3e, 0x0f, 0xbe, 0x01, 0xff, 0x80, 0x1f, 0x80, 0xe3, 0x80, 0x07, 0x8f, 0xf8, 0x1e, 0x07, 0x1c, 0x01, 0xff, 0x80, 0x3f, 0xc1, 0xff, 0xc0, 0x0f, 0xff, 0xfc, 0x3f, 0x0f, 0xbe, 0x03, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x1f, 0xf0, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0x81, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xe1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xf3, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0xff, 0x81, 0xff, 0xc0, 0x0f, 0xf0, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0x01, 0xff, 0xc0, 0x0f, 0xf0, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xf0, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x8f, 0xe0, 0xff, 0x81, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xfe, 0x07, 0xe0, 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xfc, 0x07, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x8f, 0xfc, 0x03, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x07, 0xfc, 0x07, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0x9c, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfc, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfc, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0xff, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x1f, 0x80, 0x3f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x3f, 0xc0, 0x1f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x7f, 0xc0, 0x0f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0xff, 0xc0, 0x07, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x01, 0xff, 0xc0, 0x03, 0x8f, 0xc0, 0xc1, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xff, 0xc0, 0xff, 0x80, 0x00, 0x00, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc1, 0xff, 0x80, 0x00, 0x00, 0x01, 0xf3, 0x8e, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0x9c, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0xff, 0xfc, 0x01, 0xff, 0xfe, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc1, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xe3, 0xff, 0xc3, 0xff, 0xff, 0x00, 0x3f, 0xfe, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xf3, 0xff, 0xc1, 0xef, 0xfe, 0x00, 0x3f, 0xfe, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x82, 0x00, 0x00, 0x1f, 0xff, 0x0f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x0f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x8e, 0x0f, 0xf0, 0xff, 0x1f, 0xc1, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x88, 0x0f, 0xf0, 0xff, 0x0f, 0x80, 0xff, 0xff, 0xc1, 0xff, 0xfc, 0x00, 0xff, 0xfe, 0x0f, 0xf0, 0xff, 0x06, 0x00, 0x73, 0xff, 0xc3, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0x03, 0xff, 0xc3, 0xff, 0xff, 0x83, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0x0c, 0x73, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xf0, 0xfe, 0x1f, 0xfe, 0xfb, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfc, 0x0f, 0x9e, 0x73, 0xff, 0x81, 0xf9, 0xf7, 0xe7, 0x9c, 0xff, 0x03, 0xf0, 0xfc, 0x07, 0xfe, 0xfb, 0xc0, 0x00, 0xf0, 0x00, 0x6f, 0xbe, 0xfe, 0x03, 0xf0, 0x3c, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x03, 0xc0, 0x1c, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x03, 0x80, 0x1e, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x07, 0x80, 0x3f, 0x0f, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0x0f, 0xc0, 0x1f, 0x8f, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0x1f, 0x80, 0x1f, 0xc7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0x80, 0x07, 0xc3, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xfc, 0x3e, 0x00, 0x07, 0xc1, 0xfe, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xf7, 0xf8, 0x3e, 0x00, 0x01, 0x00, 0xfc, 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xe7, 0xe3, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00};"
  },
  {
    "path": "compiled/assets_icons.h",
    "content": "#pragma once\n#include <gui/icon.h>\n\n#ifndef _sprites_h\n#define _sprites_h\n\n#define bmp_font_width   24  // in bytes\n#define bmp_font_height  6\n#define bmp_font_width_pxs   192\n#define bmp_font_height_pxs  48\n#define CHAR_MAP         \" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#\"\n#define CHAR_WIDTH       4\n#define CHAR_HEIGHT      6\n\n#define BMP_GUN_WIDTH   32\n#define BMP_GUN_HEIGHT  32\n\n#define BMP_FIRE_WIDTH  24\n#define BMP_FIRE_HEIGHT 20\n\n#define BMP_IMP_WIDTH   32\n#define BMP_IMP_HEIGHT  32\n#define BMP_IMP_COUNT   5\n\n#define BMP_FIREBALL_WIDTH 16\n#define BMP_FIREBALL_HEIGHT 16\n\n#define BMP_DOOR_WIDTH    100\n#define BMP_DOOR_HEIGHT   100\n\n#define BMP_ITEMS_WIDTH   16\n#define BMP_ITEMS_HEIGHT  16\n#define BMP_ITEMS_COUNT   2\n\n#define BMP_LOGO_WIDTH  72\n#define BMP_LOGO_HEIGHT 47\n\n#define GRADIENT_WIDTH  2\n#define GRADIENT_HEIGHT 8\n#define GRADIENT_COUNT  8\n#define GRADIENT_WHITE  7\n#define GRADIENT_BLACK  0\n\n\n\n\n// Inverted icons\nextern const Icon I_fire_inv;\nextern const Icon I_gun_inv;\nextern const Icon I_gun_mask_inv;\nextern const Icon I_logo_inv;\n\n// Fonts\nextern const uint8_t  zero[];  \nextern const uint8_t  one[]; \nextern const uint8_t  two[]; \nextern const uint8_t  three[];  \nextern const uint8_t  four[]; \nextern const uint8_t  five[];\nextern const uint8_t  six[];\nextern const uint8_t  seven[];\nextern const uint8_t  eight[];\nextern const uint8_t  nine[];\nextern const uint8_t  A[];\nextern const uint8_t  B[];\nextern const uint8_t  C[];\nextern const uint8_t  D[];\nextern const uint8_t  E[];\nextern const uint8_t  F[];\nextern const uint8_t  G[];\nextern const uint8_t  H[];\nextern const uint8_t  I[];\nextern const uint8_t  J[];\nextern const uint8_t  K[];\nextern const uint8_t  L[];\nextern const uint8_t  M[];\nextern const uint8_t  N[];\nextern const uint8_t  O[];\nextern const uint8_t  P[];\nextern const uint8_t  Q[];\nextern const uint8_t  R[];\nextern const uint8_t  S[];\nextern const uint8_t  T[];\nextern const uint8_t  U[];\nextern const uint8_t  V[];\nextern const uint8_t  W[];\nextern const uint8_t  X[];\nextern const uint8_t  Y[];\nextern const uint8_t  Z[];\nextern const uint8_t  dot[];\nextern const uint8_t  comma[];\nextern const uint8_t  dash[];\nextern const uint8_t  underscore[];\nextern const uint8_t  bracket_open[];\nextern const uint8_t  bracket_close[];\nextern const uint8_t  cross_left[];\nextern const uint8_t  cross_right[];\nextern const uint8_t  pacman_left[];\nextern const uint8_t  pacman_right[];\nextern const uint8_t  box[];\nextern const uint8_t *char_arr[48];\nextern const uint8_t gradient[];\n//extern const uint8_t gun[] \n//extern const uint8_t gun_mask[] \nextern const uint8_t gun[]; \nextern const uint8_t gun_mask[]; \n\nextern const uint8_t imp_inv[]; \nextern const uint8_t imp_mask_inv[]; \nextern const uint8_t fireball[];\nextern const uint8_t fireball_mask[]; \nextern const uint8_t item[];\nextern const uint8_t item_mask[];\n\nextern const uint8_t door[];\n\n#endif\n"
  },
  {
    "path": "constants.h",
    "content": "#ifndef _constants_h\n#define _constants_h\n#define PB_CONSTEXPR constexpr\n\n#define PI 3.14159265358979323846\n\n// Key pinout\n#define USE_INPUT_PULLUP\n#define K_LEFT              6\n#define K_RIGHT             7\n#define K_UP                8\n#define K_DOWN              3\n#define K_FIRE              10\n\n// SNES Controller\n// uncomment following line to enable snes controller support\n// #define SNES_CONTROLLER\nconst uint8_t DATA_CLOCK   = 11;\nconst uint8_t DATA_LATCH   = 12;\nconst uint8_t DATA_SERIAL  = 13;\n\n// Sound\nconst uint8_t SOUND_PIN   = 9; // do not change, belongs to used timer\n\n// GFX settings\n#define OPTIMIZE_SSD1306                // Optimizations for SSD1366 displays\n\n#define FRAME_TIME          66.666666   // Desired time per frame in ms (66.666666 is ~15 fps)\n#define RES_DIVIDER         2           // Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage\n                                        // Lower will require more process and memory, but looks nicer\n#define Z_RES_DIVIDER       2           // Zbuffer resolution divider. We sacrifice resolution to save memory\n#define DISTANCE_MULTIPLIER 20          // Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care\n                                        // of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH\n#define MAX_RENDER_DEPTH    12\n#define MAX_SPRITE_DEPTH    8\n\n#define ZBUFFER_SIZE        SCREEN_WIDTH / Z_RES_DIVIDER\n\n// Level \n#define LEVEL_WIDTH_BASE    6\n#define LEVEL_WIDTH         (1 << LEVEL_WIDTH_BASE)\n#define LEVEL_HEIGHT        57\n#define LEVEL_SIZE          LEVEL_WIDTH / 2 * LEVEL_HEIGHT\n\n// scenes\n#define INTRO                 0\n#define GAME_PLAY             1\n\n// Game\n#define GUN_TARGET_POS        18\n#define GUN_SHOT_POS          GUN_TARGET_POS + 4\n\n#define ROT_SPEED             .12\n#define MOV_SPEED             .2\n#define MOV_SPEED_INV         5           // 1 / MOV_SPEED\n\n#define JOGGING_SPEED         .005\n#define ENEMY_SPEED           .02\n#define FIREBALL_SPEED        .2\n#define FIREBALL_ANGLES       45          // Num of angles per PI\n\n#define MAX_ENTITIES          10          // Max num of active entities\n#define MAX_STATIC_ENTITIES   28          // Max num of entities in sleep mode\n\n#define MAX_ENTITY_DISTANCE   200         // * DISTANCE_MULTIPLIER\n#define MAX_ENEMY_VIEW        80          // * DISTANCE_MULTIPLIER\n#define ITEM_COLLIDER_DIST    6           // * DISTANCE_MULTIPLIER\n#define ENEMY_COLLIDER_DIST   4           // * DISTANCE_MULTIPLIER\n#define FIREBALL_COLLIDER_DIST 2          // * DISTANCE_MULTIPLIER\n#define ENEMY_MELEE_DIST      6           // * DISTANCE_MULTIPLIER\n#define WALL_COLLIDER_DIST    .2\n\n#define ENEMY_MELEE_DAMAGE    8\n#define ENEMY_FIREBALL_DAMAGE 20\n#define GUN_MAX_DAMAGE        15\n\n// display\nconst uint8_t SCREEN_WIDTH     =  128;\nconst uint8_t SCREEN_HEIGHT    =  64;\nconst uint8_t HALF_WIDTH       =  SCREEN_WIDTH/2;\nconst uint8_t RENDER_HEIGHT    =  56;         // raycaster working height (the rest is for the hud)\nconst uint8_t HALF_HEIGHT      =  SCREEN_HEIGHT/2;\n\n#endif\n"
  },
  {
    "path": "display.h",
    "content": "#include <gui/gui.h>\n#include <furi_hal.h>\n#include <u8g2_glue.h>\n#include \"constants.h\"\n#include \"compiled/assets_icons.h\"\n\n#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))\n\nstatic const uint8_t bit_mask[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };\n\n#define pgm_read_byte(addr) (*(const unsigned char *)(addr))\n#define read_bit(b, n)      b & pgm_read_byte(bit_mask + n) ? 1 : 0\n//#define read_bit(byte, index) (((unsigned)(byte) >> (index)) & 1)\n\nvoid drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas);\nvoid drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas);\nvoid drawSprite(int8_t x, int8_t y, const uint8_t *bitmap, const uint8_t *bitmap_mask, int16_t w, int16_t h, uint8_t sprite, double distance, Canvas* const canvas);\nvoid drawBitmap(int16_t x, int16_t y, const Icon *i, int16_t w, int16_t h, uint16_t color, Canvas* const canvas);\nvoid drawTextSpace(int8_t x, int8_t y, char *txt, uint8_t space, Canvas* const canvas);\nvoid drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas);\nvoid clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas);\nvoid drawGun(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, Canvas* const canvas);\nvoid drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas);\nvoid drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas);\nvoid fadeScreen(uint8_t intensity, bool color, Canvas* const canvas);\nbool getGradientPixel(uint8_t x, uint8_t y, uint8_t i);\ndouble getActualFps();\nvoid fps();\nvoid setupDisplay(Canvas* canvas);\nuint8_t reverse_bits(uint8_t num);\n\n// FPS control\ndouble delta = 1;\nuint32_t lastFrameTime = 0;\nuint8_t zbuffer[128]; /// 128 = screen width & REMOVE WHEN DISPLAY.H IMPLEMENTED\nuint8_t *display_buf = NULL;\n\nvoid drawGun(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, Canvas* const canvas){\n  int16_t byteWidth = (w + 7) / 8;\n  uint8_t byte = 0;\n  for(int16_t j=0; j<h; j++, y++) {\n    for(int16_t i=0; i<w; i++) {\n      if(i & 7) byte <<= 1;\n      else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);\n      if(byte & 0x80) drawPixel(x+i, y, color,false, canvas);\n    }\n  }\n}\n\nvoid drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas){\n\tuint8_t dots = end_y - start_y;\n\tfor(int i = 0; i < dots; i++){\n\t\tcanvas_draw_dot(canvas, x, start_y+i);\n\t}\t\n}\n\nvoid setupDisplay(Canvas* canvas){\n\tmemset(zbuffer, 0xff, 128);\n  display_buf = (uint8_t*)canvas_get_buffer(canvas);\n  //display_buf = u8g2_GetBufferPtr(&canvas->fb);\n}\n\n\nvoid drawBitmap(int16_t x, int16_t y, const Icon *i, int16_t w, int16_t h, uint16_t color, Canvas* const canvas){\n\tcanvas_draw_icon_bitmap(canvas, x, y, w, h, i);\n}\n\nvoid drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas){\n\tchar buf[4];\n\titoa(num, buf, 10);\n\tdrawTextSpace(x,y,buf,1,canvas);\t\n}\n\nvoid drawTextSpace(int8_t x, int8_t y, char *txt, uint8_t space, Canvas* const canvas){\n\tuint8_t pos = x;\n\tuint8_t i = 0;\n\tchar ch;\n\twhile ((ch = txt[i]) != '\\0') {\n    drawChar(pos, y, ch, canvas);\n    i++;\n    pos += CHAR_WIDTH + space;\n\n    // shortcut on end of screen\n    if (pos > SCREEN_WIDTH) return;\n  }\n\n  \n\n}\n\n// Custom drawBitmap method with scale support, mask, zindex and pattern filling\nvoid drawSprite(int8_t x, int8_t y, const uint8_t *bitmap, const uint8_t *bitmap_mask, int16_t w, int16_t h, uint8_t sprite, double distance, Canvas* const canvas){\nuint8_t tw = (double) w / distance;\n  uint8_t th = (double) h / distance;\n  uint8_t byte_width = w / 8;\n  uint8_t pixel_size = fmax(1, (double)1.0 / (double)distance);\n  uint16_t sprite_offset = byte_width * h * sprite;\n\n  bool pixel;\n  bool maskPixel;\n\n  // Don't draw the whole sprite if the anchor is hidden by z buffer\n  // Not checked per pixel for performance reasons\n  if (zbuffer[(int)(fmin(fmax(x, 0), ZBUFFER_SIZE - 1) / Z_RES_DIVIDER)] < distance * DISTANCE_MULTIPLIER) {\n    return;\n  }\n\n  for (uint8_t ty = 0; ty < th; ty += pixel_size) {\n    // Don't draw out of screen\n    if (y + ty < 0 || y + ty >= RENDER_HEIGHT) {\n      continue;\n    }\n\n    uint8_t sy = ty * distance; // The y from the sprite\n\n    for (uint8_t tx = 0; tx < tw; tx += pixel_size) {\n      uint8_t sx = tx * distance; // The x from the sprite\n      uint16_t byte_offset = sprite_offset + sy * byte_width + sx / 8;\n\n      // Don't draw out of screen\n      if (x + tx < 0 || x + tx >= SCREEN_WIDTH) {\n        continue;\n      }\n      \n      maskPixel = read_bit(pgm_read_byte(bitmap_mask + byte_offset), sx % 8);\n\n      if (maskPixel) {\n        pixel = read_bit(pgm_read_byte(bitmap + byte_offset), sx % 8);\n        for (uint8_t ox = 0; ox < pixel_size; ox++) {\n          for (uint8_t oy = 0; oy < pixel_size; oy++) {\n            if(bitmap == imp_inv)\n              drawPixel(x + tx + ox, y + ty + oy, 1, true, canvas);\n            else\n              drawPixel(x + tx + ox, y + ty + oy, pixel, true, canvas);\n          }\n        }\n      }\n    }\n  }\n}\n\n\nvoid drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas) {\n\tif (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= (raycasterViewport ? RENDER_HEIGHT : SCREEN_HEIGHT)){\n\t\treturn;\n\t}\n  if(color)\n    canvas_draw_dot(canvas, x, y);\n  else{\n    canvas_invert_color(canvas);\n    canvas_draw_dot(canvas, x, y);\n    canvas_invert_color(canvas);\n  }\n}\n\nvoid drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas){\n  uint8_t lsb;\n  uint8_t c = 0;\n  while (CHAR_MAP[c] != ch && CHAR_MAP[c] != '\\0') c++;\n  for(uint8_t i = 0; i < 6; i++){\n    //lsb = (char_arr[c][i] >> 4);\n    lsb = reverse_bits(char_arr[c][i]);\n    for (uint8_t n = 0; n < 4; n++){\n      if(CHECK_BIT(lsb, n)){\n        drawPixel(x+n, y+i, true, false, canvas);\n      }    \n    }\n  }\n\n}\n\nvoid clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas){\n\tcanvas_invert_color(canvas);\n\n\tfor(int i = 0; i < w; i++){\n\t\tfor(int j = 0; j < h; j++){\n\t\t\tcanvas_draw_dot(canvas, x+i, y+j);\n\t\t}\n\t}\n\n\tcanvas_invert_color(canvas);\n}\n\nvoid drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas){\n\tfor(int i = 0; i < w; i++){\n\t\tfor(int j = 0; j < h; j++){\n\t\t\tcanvas_draw_dot(canvas, x+i, y+j);\n\t\t}\n\t}\n}\n\nbool getGradientPixel(uint8_t x, uint8_t y, uint8_t i) {\n  if (i == 0) return 0;\n  if (i >= GRADIENT_COUNT - 1) return 1;\n\n  uint8_t index = fmax(0, fmin(GRADIENT_COUNT - 1, i)) * GRADIENT_WIDTH * GRADIENT_HEIGHT // gradient index\n                  + y * GRADIENT_WIDTH % (GRADIENT_WIDTH * GRADIENT_HEIGHT)             // y byte offset\n                  + x / GRADIENT_HEIGHT % GRADIENT_WIDTH;                               // x byte offset\n  //uint8_t *gradient_data = NULL;\n  //furi_hal_compress_icon_decode(icon_get_data(&I_gradient_inv), &gradient_data);\n  // return the bit based on x\n  return read_bit(pgm_read_byte(gradient + index), x % 8);\n}\n\n\n\nvoid fadeScreen(uint8_t intensity, bool color, Canvas* const canvas) {\n  for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {\n    for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {\n      if (getGradientPixel(x, y, intensity)) \n        drawPixel(x, y, color, false, canvas);\n    }\n  }\n}\n\n// Adds a delay to limit play to specified fps\n// Calculates also delta to keep movement consistent in lower framerates\nvoid fps() {\n  while (furi_get_tick() - lastFrameTime < FRAME_TIME);\n  delta = (double)(furi_get_tick() - lastFrameTime) / (double)FRAME_TIME;\n  lastFrameTime = furi_get_tick();\n}\n\ndouble getActualFps() {\n  return 1000 / ((double)FRAME_TIME * (double)delta);\n}\n\n\nuint8_t reverse_bits(uint8_t num)\n{\n    unsigned int NO_OF_BITS = sizeof(num) * 8;\n    uint8_t reverse_num = 0;\n    uint8_t i;\n    for (i = 0; i < NO_OF_BITS; i++) {\n        if ((num & (1 << i)))\n            reverse_num |= 1 << ((NO_OF_BITS - 1) - i);\n    }\n    return reverse_num;\n}"
  },
  {
    "path": "doom.c",
    "content": "#include <furi.h>\n#include <gui/gui.h>\n#include <input/input.h>\n#include <stdlib.h>\n#include <math.h>\n#include <sys/time.h>\n#include \"sound.h\"\n#include \"display.h\"\n#include \"compiled/assets_icons.h\"\n#include \"constants.h\"\n#include \"entities.h\"\n#include \"types.h\"\n#include \"level.h\"\n\n#define SOUND\n\n// Useful macros\n#define swap(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)\n#define sign(a, b) (double) (a > b ? 1 : (b > a ? -1 : 0))\n#define pgm_read_byte(addr) (*(const unsigned char *)(addr))\n\ntypedef enum {\n    EventTypeTick,\n    EventTypeKey,\n} EventType;\n\ntypedef struct {\n    EventType type;\n    InputEvent input;\n} PluginEvent;\n\ntypedef struct {\n    Player player;\n    Entity entity[MAX_ENTITIES];\n    StaticEntity static_entity[MAX_STATIC_ENTITIES];\n    uint8_t num_entities;\n    uint8_t num_static_entities;\n\n    uint8_t scene;\n    uint8_t gun_pos;\n    double jogging;\n    double view_height;\n    bool init;\n    \n\n    bool up;\n    bool down;\n    bool left;\n    bool right;\n    bool fired;\n    bool gun_fired;\n\n    double rot_speed;\n    double old_dir_x;\n    double old_plane_x;\n#ifdef SOUND\n    MusicPlayer* music_instance;\n    bool intro_sound;\n#endif\n} PluginState; \n\n\nCoords translateIntoView(Coords *pos, PluginState* const plugin_state);\nvoid updateHud(Canvas* const canvas, PluginState* const plugin_state);\n// general\n\nbool invert_screen = false;\nuint8_t flash_screen = 0;\n\n// game\n// player and entities\n\n\n\n\nuint8_t getBlockAt(const uint8_t level[], uint8_t x, uint8_t y) {\n  if (x < 0 || x >= LEVEL_WIDTH || y < 0 || y >= LEVEL_HEIGHT) {\n    return E_FLOOR;\n  }\n\n  // y is read in inverse order\n  return pgm_read_byte(level + (((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2))\n         >> (!(x % 2) * 4)       // displace part of wanted bits\n         & 0b1111;               // mask wanted bits\n}\n\n// Finds the player in the map\nvoid initializeLevel(const uint8_t level[], PluginState* const plugin_state) {\n  for (uint8_t y = LEVEL_HEIGHT - 1; y > 0; y--) {\n    for (uint8_t x = 0; x < LEVEL_WIDTH; x++) {\n      uint8_t block = getBlockAt(level, x, y);\n\n      if (block == E_PLAYER) {\n        plugin_state->player = create_player(x, y);\n        return;\n      }\n\n      // todo create other static entities\n    }\n  }\n}\n\nbool isSpawned(UID uid, PluginState* const plugin_state) {\n  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {\n    if (plugin_state->entity[i].uid == uid) return true;\n  }\n\n  return false;\n}\n\nbool isStatic(UID uid, PluginState* const plugin_state) {\n  for (uint8_t i = 0; i < plugin_state->num_static_entities; i++) {\n    if (plugin_state->static_entity[i].uid == uid) return true;\n  }\n\n  return false;\n}\n\nvoid spawnEntity(uint8_t type, uint8_t x, uint8_t y, PluginState* const plugin_state) {\n  // Limit the number of spawned entities\n  if (plugin_state->num_entities >= MAX_ENTITIES) {\n    return;\n  }\n\n  // todo: read static entity status\n  \n  switch (type) {\n    case E_ENEMY:\n      plugin_state->entity[plugin_state->num_entities] = create_enemy(x, y);\n      plugin_state->num_entities++;\n      break;\n\n    case E_KEY:\n      plugin_state->entity[plugin_state->num_entities] = create_key(x, y);\n      plugin_state->num_entities++;\n      break;\n\n    case E_MEDIKIT:\n      plugin_state->entity[plugin_state->num_entities] = create_medikit(x, y);\n      plugin_state->num_entities++;\n      break;\n  }\n}\n\nvoid spawnFireball(double x, double y, PluginState* const plugin_state) {\n  // Limit the number of spawned entities\n  if (plugin_state->num_entities >= MAX_ENTITIES) {\n    return;\n  }\n\n  UID uid = create_uid(E_FIREBALL, x, y);\n  // Remove if already exists, don't throw anything. Not the best, but shouldn't happen too often\n  if (isSpawned(uid, plugin_state)) return;\n\n  // Calculate direction. 32 angles\n  int16_t dir = FIREBALL_ANGLES + atan2(y - plugin_state->player.pos.y, x - plugin_state->player.pos.x) / (double)PI * FIREBALL_ANGLES;\n  if (dir < 0) dir += FIREBALL_ANGLES * 2;\n  plugin_state->entity[plugin_state->num_entities] = create_fireball(x, y, dir);\n  plugin_state->num_entities++;\n}\n\nvoid removeEntity(UID uid, PluginState* const plugin_state) {\n  uint8_t i = 0;\n  bool found = false;\n\n  while (i < plugin_state->num_entities) {\n    if (!found && plugin_state->entity[i].uid == uid) {\n      // todo: doze it\n      found = true;\n      plugin_state->num_entities--;\n    }\n\n    // displace entities\n    if (found) {\n      plugin_state->entity[i] = plugin_state->entity[i + 1];\n    }\n\n    i++;\n  }\n}\n\nvoid removeStaticEntity(UID uid, PluginState* const plugin_state) {\n  uint8_t i = 0;\n  bool found = false;\n\n  while (i < plugin_state->num_static_entities) {\n    if (!found && plugin_state->static_entity[i].uid == uid) {\n      found = true;\n      plugin_state->num_static_entities--;\n    }\n\n    // displace entities\n    if (found) {\n      plugin_state->static_entity[i] = plugin_state->static_entity[i + 1];\n    }\n\n    i++;\n  }\n}\n\nUID detectCollision(const uint8_t level[], Coords *pos, double relative_x, double relative_y, bool only_walls, PluginState* const plugin_state) {\n  // Wall collision\n  uint8_t round_x = (int)pos->x + (int)relative_x;\n  uint8_t round_y = (int)pos->y + (int)relative_y;\n  uint8_t block = getBlockAt(level, round_x, round_y);\n\n  if (block == E_WALL) {\n    //playSound(hit_wall_snd, HIT_WALL_SND_LEN);\n    return create_uid(block, round_x, round_y);\n  }\n\n  if (only_walls) {\n    return UID_null;\n  }\n\n  // Entity collision\n  for (uint8_t i=0; i < plugin_state->num_entities; i++) {\n    // Don't collide with itself\n    if (&(plugin_state->entity[i].pos) == pos) {\n      continue;\n    }\n\n    uint8_t type = uid_get_type(plugin_state->entity[i].uid);\n\n    // Only ALIVE enemy collision\n    if (type != E_ENEMY || plugin_state->entity[i].state == S_DEAD || plugin_state->entity[i].state == S_HIDDEN) {\n      continue;\n    }\n\n    Coords new_coords = { plugin_state->entity[i].pos.x - relative_x, plugin_state->entity[i].pos.y - relative_y };\n    uint8_t distance = coords_distance(pos, &new_coords);\n\n    // Check distance and if it's getting closer\n    if (distance < ENEMY_COLLIDER_DIST && distance < plugin_state->entity[i].distance) {\n      return plugin_state->entity[i].uid;\n    }\n  }\n\n  return UID_null;\n}\n\n// Shoot\nvoid fire(PluginState* const plugin_state) {\n  //playSound(shoot_snd, SHOOT_SND_LEN);\n\n  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {\n    // Shoot only ALIVE enemies\n    if (uid_get_type(plugin_state->entity[i].uid) != E_ENEMY || plugin_state->entity[i].state == S_DEAD || plugin_state->entity[i].state == S_HIDDEN) {\n      continue;\n    }\n\n    Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state);\n    if (fabs(transform.x) < 20 && transform.y > 0) {\n      uint8_t damage = (double) fmin(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabs(transform.x) * plugin_state->entity[i].distance) / 5);\n      if (damage > 0) {\n        plugin_state->entity[i].health = fmax(0, plugin_state->entity[i].health - damage);\n        plugin_state->entity[i].state = S_HIT;\n        plugin_state->entity[i].timer = 4;\n      }\n    }\n  }\n}\n\nUID updatePosition(const uint8_t level[], Coords *pos, double relative_x, double relative_y, bool only_walls, PluginState* const plugin_state) {\n  UID collide_x = detectCollision(level, pos, relative_x, 0, only_walls, plugin_state);\n  UID collide_y = detectCollision(level, pos, 0, relative_y, only_walls, plugin_state);\n\n  if (!collide_x) pos->x += relative_x;\n  if (!collide_y) pos->y += relative_y;\n\n  return collide_x || collide_y || UID_null;\n}\n\nvoid updateEntities(const uint8_t level[], Canvas* const canvas, PluginState* const plugin_state) {\n  uint8_t i = 0;\n  while (i < plugin_state->num_entities) {\n    // update distance\n    plugin_state->entity[i].distance = coords_distance(&(plugin_state->player.pos), &(plugin_state->entity[i].pos));\n\n    // Run the timer. Works with actual frames.\n    // Todo: use delta here. But needs double type and more memory\n    if (plugin_state->entity[i].timer > 0) plugin_state->entity[i].timer--;\n\n    // too far away. put it in doze mode\n    if (plugin_state->entity[i].distance > MAX_ENTITY_DISTANCE) {\n      removeEntity(plugin_state->entity[i].uid, plugin_state);\n      // don't increase 'i', since current one has been removed\n      continue;\n    }\n\n    // bypass render if hidden\n    if (plugin_state->entity[i].state == S_HIDDEN) {\n      i++;\n      continue;\n    }\n\n    uint8_t type = uid_get_type(plugin_state->entity[i].uid);\n\n    switch (type) {\n      case E_ENEMY: {\n          // Enemy \"IA\"\n          if (plugin_state->entity[i].health == 0) {\n            if (plugin_state->entity[i].state != S_DEAD) {\n              plugin_state->entity[i].state = S_DEAD;\n              plugin_state->entity[i].timer = 6;\n            }\n          } else  if (plugin_state->entity[i].state == S_HIT) {\n            if (plugin_state->entity[i].timer == 0) {\n              // Back to alert state\n              plugin_state->entity[i].state = S_ALERT;\n              plugin_state->entity[i].timer = 40;     // delay next fireball thrown\n            }\n          } else if (plugin_state->entity[i].state == S_FIRING) {\n            if (plugin_state->entity[i].timer == 0) {\n              // Back to alert state\n              plugin_state->entity[i].state = S_ALERT;\n              plugin_state->entity[i].timer = 40;     // delay next fireball throwm\n            }\n          } else {\n            // ALERT STATE\n            if (plugin_state->entity[i].distance > ENEMY_MELEE_DIST && plugin_state->entity[i].distance < MAX_ENEMY_VIEW) {\n              if (plugin_state->entity[i].state != S_ALERT) {\n                plugin_state->entity[i].state = S_ALERT;\n                plugin_state->entity[i].timer = 20;   // used to throw fireballs\n              } else {\n                if (plugin_state->entity[i].timer == 0) {\n                  // Throw a fireball\n                  spawnFireball(plugin_state->entity[i].pos.x, plugin_state->entity[i].pos.y, plugin_state);\n                  plugin_state->entity[i].state = S_FIRING;\n                  plugin_state->entity[i].timer = 6;\n                } else {\n                  // move towards to the player.\n                  updatePosition(\n                    level,\n                    &(plugin_state->entity[i].pos),\n                    sign(plugin_state->player.pos.x, plugin_state->entity[i].pos.x) * (double)ENEMY_SPEED * 1, // NOT SURE (delta)\n                    sign(plugin_state->player.pos.y, plugin_state->entity[i].pos.y) * (double)ENEMY_SPEED * 1, // NOT SURE (delta)\n                    true,\n                    plugin_state\n                  );\n                }\n              }\n            } else if (plugin_state->entity[i].distance <= ENEMY_MELEE_DIST) {\n              if (plugin_state->entity[i].state != S_MELEE) {\n                // Preparing the melee attack\n                plugin_state->entity[i].state = S_MELEE;\n                plugin_state->entity[i].timer = 10;\n              } else if (plugin_state->entity[i].timer == 0) {\n                // Melee attack\n                plugin_state->player.health = fmax(0, plugin_state->player.health - ENEMY_MELEE_DAMAGE);\n                plugin_state->entity[i].timer = 14;\n                flash_screen = 1;\n                updateHud(canvas, plugin_state);\n              }\n            } else {\n              // stand\n              plugin_state->entity[i].state = S_STAND;\n            }\n          }\n          break;\n        }\n\n      case E_FIREBALL: {\n          if (plugin_state->entity[i].distance < FIREBALL_COLLIDER_DIST) {\n            // Hit the player and disappear\n            plugin_state->player.health = fmax(0, plugin_state->player.health - ENEMY_FIREBALL_DAMAGE);\n            flash_screen = 1;\n            updateHud(canvas, plugin_state);\n            removeEntity(plugin_state->entity[i].uid, plugin_state);\n            continue; // continue in the loop\n          } else {\n            // Move. Only collide with walls.\n            // Note: using health to store the angle of the movement\n            UID collided = updatePosition(\n              level,\n              &(plugin_state->entity[i].pos),\n              cos((double) plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * (double)FIREBALL_SPEED,\n              sin((double) plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * (double)FIREBALL_SPEED,\n              true,\n              plugin_state\n            );\n\n            if (collided) {\n              removeEntity(plugin_state->entity[i].uid, plugin_state);\n              continue; // continue in the entity check loop\n            }\n          }\n          break;\n        }\n\n      case E_MEDIKIT: {\n          if (plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) {\n            // pickup\n            //playSound(medkit_snd, MEDKIT_SND_LEN);\n            plugin_state->entity[i].state = S_HIDDEN;\n            plugin_state->player.health = fmin(100, plugin_state->player.health + 50);\n            updateHud(canvas, plugin_state);\n            flash_screen = 1;\n          }\n          break;\n        }\n\n      case E_KEY: {\n          if (plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) {\n            // pickup\n            //playSound(get_key_snd, GET_KEY_SND_LEN);\n            plugin_state->entity[i].state = S_HIDDEN;\n            plugin_state->player.keys++;\n            updateHud(canvas, plugin_state);\n            flash_screen = 1;\n          }\n          break;\n        }\n    }\n\n    i++;\n  }\n}\n\n// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html\nvoid renderMap(const uint8_t level[], double view_height, Canvas* const canvas, PluginState* const plugin_state) {\n  UID last_uid = 0; // NOT SURE ?\n\n  for (uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) {\n    double camera_x = 2 * (double) x / SCREEN_WIDTH - 1;\n    double ray_x = plugin_state->player.dir.x + plugin_state->player.plane.x * camera_x;\n    double ray_y = plugin_state->player.dir.y + plugin_state->player.plane.y * camera_x;\n    uint8_t map_x = (uint8_t)plugin_state->player.pos.x;\n    uint8_t map_y = (uint8_t)plugin_state->player.pos.y;\n    Coords map_coords = { plugin_state->player.pos.x, plugin_state->player.pos.y };\n    double delta_x = fabs(1 / ray_x);\n    double delta_y = fabs(1 / ray_y);\n\n    int8_t step_x; \n    int8_t step_y;\n    double side_x;\n    double side_y;\n\n    if (ray_x < 0) {\n      step_x = -1;\n      side_x = (plugin_state->player.pos.x - map_x) * delta_x;\n    } else {\n      step_x = 1;\n      side_x = (map_x + (double)1.0 - plugin_state->player.pos.x) * delta_x;\n    }\n\n    if (ray_y < 0) {\n      step_y = -1;\n      side_y = (plugin_state->player.pos.y - map_y) * delta_y;\n    } else {\n      step_y = 1;\n      side_y = (map_y + (double)1.0 - plugin_state->player.pos.y) * delta_y;\n    }\n\n    // Wall detection\n    uint8_t depth = 0;\n    bool hit = 0;\n    bool side; \n    while (!hit && depth < MAX_RENDER_DEPTH) {\n      if (side_x < side_y) {\n        side_x += delta_x;\n        map_x += step_x;\n        side = 0;\n      } else {\n        side_y += delta_y;\n        map_y += step_y;\n        side = 1;\n      }\n\n      uint8_t block = getBlockAt(level, map_x, map_y);\n\n      if (block == E_WALL) {\n        hit = 1;\n      } else {\n        // Spawning entities here, as soon they are visible for the\n        // player. Not the best place, but would be a very performance\n        // cost scan for them in another loop\n        if (block == E_ENEMY || (block & 0b00001000) /* all collectable items */) {\n          // Check that it's close to the player\n          if (coords_distance(&(plugin_state->player.pos), &map_coords) < MAX_ENTITY_DISTANCE) {\n            UID uid = create_uid(block, map_x, map_y);\n            if (last_uid != uid && !isSpawned(uid, plugin_state)) {\n              spawnEntity(block, map_x, map_y, plugin_state);\n              last_uid = uid;\n            }\n          }\n        }\n      }\n\n      depth++;\n    }\n\n    if (hit) {\n      double distance;\n      \n      if (side == 0) {\n        distance = fmax(1, (map_x - plugin_state->player.pos.x + (1 - step_x) / 2) / ray_x);\n      } else {\n        distance = fmax(1, (map_y - plugin_state->player.pos.y + (1 - step_y) / 2) / ray_y);\n      }\n\n      // store zbuffer value for the column\n      zbuffer[x / Z_RES_DIVIDER] = fmin(distance * DISTANCE_MULTIPLIER, 255);\n\n      // rendered line height\n      uint8_t line_height = RENDER_HEIGHT / distance;\n\n      drawVLine(\n        x,\n        view_height / distance - line_height / 2 + RENDER_HEIGHT / 2,\n        view_height / distance + line_height / 2 + RENDER_HEIGHT / 2,\n        GRADIENT_COUNT - (int)distance / MAX_RENDER_DEPTH * GRADIENT_COUNT - side * 2,\n        canvas\n      );\n    }\n  }\n}\n\n// Sort entities from far to close\nuint8_t sortEntities(PluginState* const plugin_state) {\n  uint8_t gap = plugin_state->num_entities;\n  bool swapped = false;\n  while (gap > 1 || swapped) {\n    //shrink factor 1.3\n    gap = (gap * 10) / 13;\n    if (gap == 9 || gap == 10) gap = 11;\n    if (gap < 1) gap = 1;\n    swapped = false;\n    for (uint8_t i = 0; i < plugin_state->num_entities - gap; i++)\n    {\n      uint8_t j = i + gap;\n      if (plugin_state->entity[i].distance < plugin_state->entity[j].distance)\n      {\n        swap(plugin_state->entity[i], plugin_state->entity[j]);\n        swapped = true;\n      }\n    }\n  }\n  return swapped;\n}\n\nCoords translateIntoView(Coords *pos, PluginState* const plugin_state) {\n  //translate sprite position to relative to camera\n  double sprite_x = pos->x - plugin_state->player.pos.x;\n  double sprite_y = pos->y - plugin_state->player.pos.y;\n\n  //required for correct matrix multiplication\n  double inv_det = ((double)1.0 / ((double)plugin_state->player.plane.x * (double)plugin_state->player.dir.y - (double)plugin_state->player.dir.x * (double)plugin_state->player.plane.y));\n  double transform_x = inv_det * (plugin_state->player.dir.y * sprite_x - plugin_state->player.dir.x * sprite_y);\n  double transform_y = inv_det * (- plugin_state->player.plane.y * sprite_x + plugin_state->player.plane.x * sprite_y); // Z in screen\n  Coords res = {transform_x, transform_y};\n  return res;\n}\n\n\n\n\nvoid renderEntities(double view_height, Canvas* const canvas, PluginState* const plugin_state) {\n  sortEntities(plugin_state);\n\n  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {\n    if (plugin_state->entity[i].state == S_HIDDEN) continue;\n\n    Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state);\n\n    // don´t render if behind the player or too far away\n    if (transform.y <= (double)0.1 || transform.y > MAX_SPRITE_DEPTH) {\n      continue;\n    }\n\n    int16_t sprite_screen_x = HALF_WIDTH * ((double)1.0 + transform.x / transform.y);\n    int8_t sprite_screen_y = RENDER_HEIGHT / 2 + view_height / transform.y;\n    uint8_t type = uid_get_type(plugin_state->entity[i].uid);\n\n    // don´t try to render if outside of screen\n    // doing this pre-shortcut due int16 -> int8 conversion makes out-of-screen\n    // values fit into the screen space\n    if (sprite_screen_x < - HALF_WIDTH || sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH) {\n      continue;\n    }\n\n    switch (type) {\n      case E_ENEMY: {\n          uint8_t sprite;\n          if (plugin_state->entity[i].state == S_ALERT) {\n            // walking\n            sprite = ((int)furi_get_tick() / 500) % 2;\n          } else if (plugin_state->entity[i].state == S_FIRING) {\n            // fireball\n            sprite = 2;\n          } else if (plugin_state->entity[i].state == S_HIT) {\n            // hit\n            sprite = 3;\n          } else if (plugin_state->entity[i].state == S_MELEE) {\n            // melee atack\n            sprite = plugin_state->entity[i].timer > 10 ? 2 : 1;\n          } else if (plugin_state->entity[i].state == S_DEAD) {\n            // dying\n            sprite = plugin_state->entity[i].timer > 0 ? 3 : 4;\n          } else {\n            // stand\n            sprite = 0;\n          }\n\n          drawSprite(\n            sprite_screen_x - BMP_IMP_WIDTH * (double).5 / transform.y,\n            sprite_screen_y - 8 / transform.y,\n            imp_inv,\n            imp_mask_inv,\n            BMP_IMP_WIDTH,\n            BMP_IMP_HEIGHT,\n            sprite,\n            transform.y,\n            canvas\n          );\n          break;\n        }\n\n      case E_FIREBALL: {\n          drawSprite(\n            sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y,\n            sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y,\n            fireball,\n            fireball_mask,\n            BMP_FIREBALL_WIDTH,\n            BMP_FIREBALL_HEIGHT,\n            0,\n            transform.y,\n            canvas\n          );\n          break;\n        }\n\n      case E_MEDIKIT: {\n          drawSprite(\n            sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y,\n            sprite_screen_y + 5 / transform.y,\n            item,\n            item_mask,\n            BMP_ITEMS_WIDTH,\n            BMP_ITEMS_HEIGHT,\n            0,\n            transform.y,\n            canvas\n          );\n          break;\n        }\n\n      case E_KEY: {\n          drawSprite(\n            sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y,\n            sprite_screen_y + 5 / transform.y,\n            item,\n            item_mask,\n            BMP_ITEMS_WIDTH,\n            BMP_ITEMS_HEIGHT,\n            1,\n            transform.y,\n            canvas\n          );\n          break;\n        }\n    }\n  }\n}\n\nvoid renderGun(uint8_t gun_pos, double amount_jogging, Canvas* const canvas) {\n  // jogging\n  char x = 48 + sin((double) furi_get_tick() * (double)JOGGING_SPEED) * 10 * amount_jogging;\n  char y = RENDER_HEIGHT - gun_pos + fabs(cos((double) furi_get_tick() * (double)JOGGING_SPEED)) * 8 * amount_jogging;\n\n  if (gun_pos > GUN_SHOT_POS - 2) {\n    // Gun fire\n    drawBitmap(x + 6, y - 11, &I_fire_inv, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1, canvas);\n  }\n\n  // Don't draw over the hud!\n  uint8_t clip_height = fmax(0, fmin(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y);\n\n  // Draw the gun (black mask + actual sprite).\n  drawBitmap(x, y, &I_gun_mask_inv, BMP_GUN_WIDTH, clip_height, 0, canvas);\n  drawBitmap(x, y, &I_gun_inv, BMP_GUN_WIDTH, clip_height, 1, canvas);\n  //drawGun(x,y,gun_mask, BMP_GUN_WIDTH, clip_height, 0, canvas);\n  //drawGun(x,y,gun, BMP_GUN_WIDTH, clip_height, 1, canvas);\n}\n\n// Only needed first time\nvoid renderHud(Canvas* const canvas, PluginState* plugin_state) {\n  drawTextSpace(2, 58, \"{}\", 0, canvas);        // Health symbol\n  drawTextSpace(40, 58, \"[]\", 0, canvas);       // Keys symbol\n  updateHud(canvas, plugin_state);\n}\n\n// Render values for the HUD\nvoid updateHud(Canvas* const canvas, PluginState* plugin_state) {\n  clearRect(12, 58, 15, 6, canvas);\n  clearRect(50, 58, 15, 6, canvas);\n  drawText(12, 58, plugin_state->player.health, canvas);\n  drawText(50, 58, plugin_state->player.keys, canvas);\n}\n\n\n\n// Debug stats\nvoid renderStats(Canvas* const canvas, PluginState* plugin_state) {\n  clearRect(58, 58, 70, 6, canvas);\n  drawText(114, 58, (int)getActualFps(), canvas);\n  drawText(82, 58, plugin_state->num_entities, canvas);\n  // drawText(94, 58, freeMemory());\n}\n\n// Intro screen\nvoid loopIntro(Canvas* const canvas) {\n  canvas_draw_icon(canvas, (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, &I_logo_inv);\n  drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, \"PRESS FIRE\", 1, canvas);\n}\n\n\n\nstatic void render_callback(Canvas* const canvas, void* ctx) {\n    PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);\n    if(plugin_state == NULL) {\n        return;\n    }\n    if(plugin_state->init)\n      setupDisplay(canvas);\n    \n    canvas_set_font(canvas, FontPrimary);\n    \n\n    switch(plugin_state->scene){\n      case INTRO:{\n        loopIntro(canvas);\n        break;\n      }\n      case GAME_PLAY:{\n        updateEntities(sto_level_1, canvas, plugin_state);\n\n        renderGun(plugin_state->gun_pos,plugin_state->jogging, canvas); \n        renderMap(sto_level_1, plugin_state->view_height, canvas, plugin_state);\n        \n        renderEntities(plugin_state->view_height, canvas, plugin_state);\n        \n\n        renderHud(canvas, plugin_state);\n        updateHud(canvas, plugin_state);\n        renderStats(canvas, plugin_state);\n        break;\n      }\n    }\n    release_mutex((ValueMutex*)ctx, plugin_state);\n}\n\nstatic void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {\n    furi_assert(event_queue); \n\n    PluginEvent event = {.type = EventTypeKey, .input = *input_event};\n    furi_message_queue_put(event_queue, &event, 0);\n}\n\n\nstatic void doom_state_init(PluginState* const plugin_state) {\n    plugin_state->num_entities = 0;\n    plugin_state->num_static_entities = 0;\n\n    plugin_state->scene = INTRO;\n    plugin_state->gun_pos = 0;\n    plugin_state->view_height = 0;\n    plugin_state->init = true;\n    \n\n    plugin_state->up = false;\n    plugin_state->down = false;\n    plugin_state->left = false;\n    plugin_state->right = false;\n    plugin_state->fired = false;\n    plugin_state->gun_fired = false;\n#ifdef SOUND\n    \n    plugin_state->music_instance = malloc(sizeof(MusicPlayer));\n    plugin_state->music_instance->model = malloc(sizeof(MusicPlayerModel));\n    memset(plugin_state->music_instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);\n    memset(plugin_state->music_instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);\n    plugin_state->music_instance->model->volume = 2;\n    \n    plugin_state->music_instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);\n    //plugin_state->music_instance->view_port = view_port_alloc();\n    \n    plugin_state->music_instance->worker = music_player_worker_alloc();\n    //music_player_worker_set_volume(plugin_state->music_instance->worker, 0.75);\n    music_player_worker_set_volume(plugin_state->music_instance->worker, MUSIC_PLAYER_VOLUMES[plugin_state->music_instance->model->volume]);\n    plugin_state->intro_sound = true;\n    //init_sound(plugin_state->music_instance);\n#endif\n} \n\nstatic void doom_game_update_timer_callback(FuriMessageQueue* event_queue) {\n    furi_assert(event_queue);\n\n    PluginEvent event = {.type = EventTypeTick};\n    furi_message_queue_put(event_queue, &event, 0);\n}\n\n\n\nstatic void doom_game_tick(PluginState* const plugin_state){\n  if(plugin_state->scene == GAME_PLAY){\n    fps();\n    memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8));\n    //player is alive\n    if(plugin_state->player.health > 0){\n      if(plugin_state->up){\n        plugin_state->player.velocity += ((double)MOV_SPEED - plugin_state->player.velocity) * (double).4;\n        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;\n        //plugin_state->up = false;\n      }else if(plugin_state->down){\n        plugin_state->player.velocity += (- (double)MOV_SPEED - plugin_state->player.velocity) * (double).4;\n        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;\n        //plugin_state->down = false;\n      }else {\n        plugin_state->player.velocity *= (double).5;\n        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;\n      }\n\n      if(plugin_state->right){\n        plugin_state->rot_speed = (double)ROT_SPEED * delta;\n        plugin_state->old_dir_x = plugin_state->player.dir.x;\n        plugin_state->player.dir.x = plugin_state->player.dir.x * cos(-(plugin_state->rot_speed)) - plugin_state->player.dir.y * sin(-(plugin_state->rot_speed));\n        plugin_state->player.dir.y = plugin_state->old_dir_x * sin(-(plugin_state->rot_speed)) + plugin_state->player.dir.y * cos(-(plugin_state->rot_speed));\n        plugin_state->old_plane_x = plugin_state->player.plane.x;\n        plugin_state->player.plane.x = plugin_state->player.plane.x * cos(-(plugin_state->rot_speed)) - plugin_state->player.plane.y * sin(-(plugin_state->rot_speed));\n        plugin_state->player.plane.y = plugin_state->old_plane_x * sin(-(plugin_state->rot_speed)) + plugin_state->player.plane.y * cos(-(plugin_state->rot_speed));\n\n        //plugin_state->right = false;\n      }else if(plugin_state->left){\n        plugin_state->rot_speed = (double)ROT_SPEED * delta;\n        plugin_state->old_dir_x = plugin_state->player.dir.x;\n        plugin_state->player.dir.x = plugin_state->player.dir.x * cos(plugin_state->rot_speed) - plugin_state->player.dir.y * sin(plugin_state->rot_speed);\n        plugin_state->player.dir.y = plugin_state->old_dir_x * sin(plugin_state->rot_speed) + plugin_state->player.dir.y * cos(plugin_state->rot_speed);\n        plugin_state->old_plane_x = plugin_state->player.plane.x;\n        plugin_state->player.plane.x = plugin_state->player.plane.x * cos(plugin_state->rot_speed) - plugin_state->player.plane.y * sin(plugin_state->rot_speed);\n        plugin_state->player.plane.y = plugin_state->old_plane_x * sin(plugin_state->rot_speed) + plugin_state->player.plane.y * cos(plugin_state->rot_speed);\n        //plugin_state->left = false;\n      }\n      plugin_state->view_height = fabs(sin((double) furi_get_tick() * (double)JOGGING_SPEED)) * 6 * plugin_state->jogging;\n\n      if (plugin_state->gun_pos > GUN_TARGET_POS) {\n      // Right after fire\n        plugin_state->gun_pos -= 1;\n      }else if(plugin_state->gun_pos < GUN_TARGET_POS){\n        plugin_state->gun_pos += 2;\n      }else if(!plugin_state->gun_fired && plugin_state->fired){\n        //furi_hal_speaker_start(20480 / 10, 0.45f);\n/*#ifdef SOUND\n        music_player_worker_start(plugin_state->music_instance->worker);\n#endif*/\n        plugin_state->gun_pos = GUN_SHOT_POS;\n        plugin_state->gun_fired = true;\n        plugin_state->fired = false;\n        fire(plugin_state);\n\n      }else if(plugin_state->gun_fired && !plugin_state->fired){\n        //furi_hal_speaker_stop();\n        plugin_state->gun_fired = false;\n        \n/*#ifdef SOUND\n        music_player_worker_stop(plugin_state->music_instance->worker);\n#endif*/\n      }\n    }else{\n      // Player is dead\n      if(plugin_state->view_height > -10) plugin_state->view_height--;\n      if(plugin_state->gun_pos > 1) plugin_state->gun_pos -=2;\n    }\n\n    if(fabs(plugin_state->player.velocity) > (double)0.003){\n      updatePosition(sto_level_1, &(plugin_state->player.pos), plugin_state->player.dir.x * plugin_state->player.velocity * delta, plugin_state->player.dir.y * plugin_state->player.velocity * delta, false, plugin_state);\n    }else{\n      plugin_state->player.velocity = 0;\n    }\n  }\n}\n\nint32_t doom_app() {\n    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));\n    PluginState* plugin_state = malloc(sizeof(PluginState));\n    doom_state_init(plugin_state);\n    ValueMutex state_mutex; \n    if (!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) {\n        FURI_LOG_E(\"Doom_game\", \"cannot create mutex\\r\\n\");\n        free(plugin_state); \n        return 255;\n    }\n    FuriTimer* timer = furi_timer_alloc(doom_game_update_timer_callback, FuriTimerTypePeriodic, event_queue);\n    furi_timer_start(timer, furi_kernel_get_tick_frequency()/ 12);\n    // Set system callbacks\n    ViewPort* view_port = view_port_alloc(); \n    view_port_draw_callback_set(view_port, render_callback, &state_mutex);\n    view_port_input_callback_set(view_port, input_callback, event_queue);\n \n    // Open GUI and register view_port\n    Gui* gui = furi_record_open(\"gui\"); \n    gui_add_view_port(gui, view_port, GuiLayerFullscreen); \n\n    // GAMEPLAY VARS\n    bool gun_fired = false;\n    \n    \n    \n    //double jogging;\n    uint8_t fade = GRADIENT_COUNT - 1;\n    //////////////////////////////////\n    if(display_buf != NULL) \n      plugin_state->init = false;\n\n    PluginEvent event;\n#ifdef SOUND\n    music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro);\n    music_player_worker_start(plugin_state->music_instance->worker);\n#endif\n    for(bool processing = true; processing;) { \n\t      FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);\n        PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex);\n#ifdef SOUND\n        furi_check(furi_mutex_acquire(plugin_state->music_instance->model_mutex, FuriWaitForever) == FuriStatusOk);\n#endif\n        if(event_status == FuriStatusOk) {\n          if(event.type == EventTypeTick){\n            doom_game_tick(plugin_state);\n          }\n          plugin_state->fired = false;\n\n\n\n            // press events\n            if(event.type == EventTypeKey) {\n                if(event.input.type == InputTypePress) {\n\n                  if(plugin_state->scene == INTRO && event.input.key == InputKeyOk){\n                    plugin_state->scene = GAME_PLAY;\n                    initializeLevel(sto_level_1, plugin_state);\n#ifdef SOUND\n                    furi_mutex_release(plugin_state->music_instance->model_mutex);\n                    music_player_worker_stop(plugin_state->music_instance->worker);\n                    plugin_state->intro_sound = false;\n#endif\n                  }\n\n                  //While playing game\n                  if(plugin_state->scene == GAME_PLAY){\n                    \n                    // If the player is alive\n                    if (plugin_state->player.health > 0) {\n                      //Player speed\n                      if(event.input.key == InputKeyUp){\n                        plugin_state->up = true;\n                      }else if (event.input.key == InputKeyDown) {\n                        plugin_state->down = true; \n                      }\n                      // Player rotation\n                      if(event.input.key == InputKeyRight){\n                        plugin_state->right = true;\n                      }else if(event.input.key == InputKeyLeft){\n                        plugin_state->left = true; \n                      }\n                      if(event.input.key == InputKeyOk){\n                        \n\n/*#ifdef SOUND\n                        music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dspistol);\n#endif*/\n                        plugin_state->fired = true;\n                      }\n                    }else{\n                      // Player is dead\n                      if(event.input.key == InputKeyOk)plugin_state->scene = INTRO; \n                    } \n                  }\n                  \n                }\n                if(event.input.type == InputTypeRelease){\n                  if (plugin_state->player.health > 0) {\n                      //Player speed\n                      if(event.input.key == InputKeyUp){\n                        plugin_state->up = false;\n                      }else if (event.input.key == InputKeyDown) {\n                        plugin_state->down = false;\n                      } \n                      // Player rotation\n                      if(event.input.key == InputKeyRight){\n                        plugin_state->right = false;\n                      }else if(event.input.key == InputKeyLeft){\n                        plugin_state->left = false; \n                      }        \n                    }\n                }\n                if(event.input.key == InputKeyBack){\n                  processing = false;\n#ifdef SOUND\n                  if(plugin_state->intro_sound){\n                    furi_mutex_release(plugin_state->music_instance->model_mutex);\n                    music_player_worker_stop(plugin_state->music_instance->worker);\n                  }\n#endif\n                }\n            } \n        } else {\n            FURI_LOG_D(\"Doom_game\", \"osMessageQueue: event timeout\");\n            // event timeout\n        }\n#ifdef SOUND\n        furi_mutex_release(plugin_state->music_instance->model_mutex);\n#endif\n        view_port_update(view_port);\n        release_mutex(&state_mutex, plugin_state);\n    }\n#ifdef SOUND\n    music_player_worker_free(plugin_state->music_instance->worker);\n    furi_mutex_free(plugin_state->music_instance->model_mutex);\n    free(plugin_state->music_instance->model);\n    free(plugin_state->music_instance);\n#endif\n    furi_timer_free(timer);\n    view_port_enabled_set(view_port, false);\n    gui_remove_view_port(gui, view_port);\n    furi_record_close(\"gui\");\n    view_port_free(view_port);\n    furi_message_queue_free(event_queue);\n    return 0;\n}\n"
  },
  {
    "path": "entities.c",
    "content": "#include \"entities.h\"\n\n\n//extern \"C\"\n/*Player create_player(double x, double y){\n\treturn {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0};\n}*/\n\nPlayer create_player(double x, double y){\n  Player p;\n  p.pos = create_coords((double) x + (double)0.5, (double) y + (double)0.5);\n  p.dir = create_coords(1, 0);\n  p.plane = create_coords(0, -0.66);\n  p.velocity = 0;\n  p.health = 100;\n  p.keys = 0;\n  return p;//{create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0};\n}\n\n//extern \"C\"\nEntity create_entity(uint8_t type, uint8_t x,  uint8_t y, uint8_t initialState, uint8_t initialHealth) {\n  UID uid = create_uid(type, x, y);\n  Coords pos = create_coords((double) x + (double).5, (double) y + (double).5);\n  Entity new_entity;// = { uid, pos, initialState, initialHealth, 0, 0 };\n  new_entity.uid = uid;\n  new_entity.pos = pos;\n  new_entity.state = initialState;\n  new_entity.health = initialHealth;\n  new_entity.distance = 0;\n  new_entity.timer = 0;\n  return new_entity;\n}\n\n//extern \"C\"\nStaticEntity crate_static_entity(UID uid, uint8_t x,  uint8_t y, bool active) {\n  StaticEntity ent;\n  ent.uid = uid;\n  ent.x = x;\n  ent.y = y;\n  ent.active = active;\n  return ent;\n}"
  },
  {
    "path": "entities.h",
    "content": "#ifndef _entities_h\n#define _entities_h\n#include <stdint.h>\n#include <stdbool.h>\n#include \"types.h\"\n\n// Shortcuts\n//#define create_player(x, y)   {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100}\n\n#define create_enemy(x, y)            create_entity(E_ENEMY, x, y, S_STAND, 50)\n#define create_medikit(x, y)          create_entity(E_MEDIKIT, x, y, S_STAND, 0)\n#define create_key(x, y)              create_entity(E_KEY, x, y, S_STAND, 0)\n#define create_fireball(x, y, dir)    create_entity(E_FIREBALL, x, y, S_STAND, dir)\n#define create_door(x, y)             create_entity(E_DOOR, x, y, S_STAND, 0)\n\n// entity statuses\n#define S_STAND               0\n#define S_ALERT               1\n#define S_FIRING              2\n#define S_MELEE               3\n#define S_HIT                 4\n#define S_DEAD                5\n#define S_HIDDEN              6\n#define S_OPEN                7\n#define S_CLOSE               8\n\ntypedef struct Player { \n  Coords pos;\n  Coords dir;\n  Coords plane;\n  double velocity;\n  uint8_t health;\n  uint8_t keys;  \n} Player;\n\ntypedef struct Entity {\n  UID uid;\n  Coords pos;\n  uint8_t state;\n  uint8_t health;     // angle for fireballs\n  uint8_t distance;\n  uint8_t timer;\n} Entity;\n\ntypedef struct StaticEntity  { \n  UID uid;\n  uint8_t x;\n  uint8_t y;\n  bool active;\n} StaticEntity;\n\nEntity create_entity(uint8_t type, uint8_t x,  uint8_t y, uint8_t initialState, uint8_t initialHealth);\nStaticEntity create_static_entity(UID uid, uint8_t x,  uint8_t y, bool active);\nPlayer create_player(double x, double y);\n#endif\n\n"
  },
  {
    "path": "level.h",
    "content": "#ifndef _level_h\n#define _level_h\n\n#include \"constants.h\"\n\n/*\n  Based on E1M1 from Wolfenstein 3D\n\n  ################################################################\n  #############################...........########################\n  ######....###################........E..########################\n  ######....########..........#...........#...####################\n  ######.....#######..........L.....E.......M.####################\n  ######.....#######..........#...........#...####################\n  ##################...########...........########################\n  ######.........###...########...........########################\n  ######.........###...#############D#############################\n  ######.........#......E##########...############################\n  ######....E....D...E...##########...############################\n  ######.........#.......##########...############################\n  ######....E....##################...############################\n  #...##.........##################...############################\n  #.K.######D######################...############################\n  #...#####...###############...#E.....K##########################\n  ##D######...###############..####...############################\n  #...#####...###############..####...############################\n  #...#...#...###############..####...############################\n  #...D...#...#####################...############################\n  #...#...#...#####################...############################\n  #...######D#######################L#############################\n  #.E.##.........#################.....#################........##\n  #...##.........############...............############........##\n  #...##...E.....############...............############........##\n  #....#.........############...E.......E....#.........#........##\n  #....L....K....############................D....E....D....E...##\n  #....#.........############................#.........#........##\n  #...##.....E...############...............####....####........##\n  #...##.........############...............#####..#####.....M..##\n  #...##.........#################.....##########..#####........##\n  #...######L#######################D############..###############\n  #...#####...#####################...###########..###############\n  #E.E#####...#####################...###########..###############\n  #...#...#...#####################.E.###########..###############\n  #...D.M.#...#####################...###########..###############\n  #...#...#...#####################...###########..###.#.#.#.#####\n  #...#####...#####################...###########...#.........####\n  #...#####...#####################...###########...D....E..K.####\n  #................##......########...###########...#.........####\n  #....E........E...L...E...X######...################.#.#.#.#####\n  #................##......########...############################\n  #################################...############################\n  #############..#..#..#############L#############################\n  ###########....#..#.########....#...#....#######################\n  #############.....##########.P..D...D....#######################\n  ############################....#...#....#######################\n  ##############..#################...############################\n  ##############..############....#...#....#######################\n  ############################....D...D....#######################\n  ############################....#...#....#######################\n  #################################...############################\n  ############################.............#######################\n  ############################..........EK.#######################\n  ############################.............#######################\n  ################################################################\n*/\n\n/*\n   Same map above built from some regexp replacements using the legend above.\n   Using this way lets me use only 4 bit to store each block\n*/\nconst uint8_t sto_level_1[LEVEL_SIZE] = {\n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x90, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF2, 0x00, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0x4F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0x05, 0x00, 0x00, 0x90, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0xFF, \n  0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x08, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF2, 0x02, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0x40, 0x80, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, \n  0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x40, 0x00, 0x02, 0x00, 0x90, 0xFF, 0xFF, \n  0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, \n  0xF0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00, 0x7F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, \n  0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \n};\n\n#endif\n\n"
  },
  {
    "path": "sound.h",
    "content": "#ifndef sound_h\n#define sound_h\n#include <m-string.h>\n#include <furi.h>\n#include <furi_hal.h>\n#include <stdint.h>\n#include \"../music_player/music_player_worker.h\"\n\n\n//static const char dspistol[] = \"AnyConv:d=,o=,b=120:408,40p,40p,40p,40p,405,40p,40p,40p,405,30p.,30p.,30p.,13p\";\nstatic const char dsintro[] = \"Doom:d=32,o=4,b=56:f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,e5,a#,a#,f5,f#5,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,8e5\";\n//static const char dsgetpow[] = \"dsgetpow:d=,o=,b=120:407,40p,30.6,407,40p,406,40p,407,40p,40p,407,30p.,407\";\n//static const char dsnoway[] = \"dsnoway:d=,o=,b=120:407,30.4\";\n\n#define MUSIC_PLAYER_SEMITONE_HISTORY_SIZE 4\nstatic const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1};\n\ntypedef struct {\n    uint8_t semitone_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE];\n    uint8_t duration_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE];\n\n    uint8_t volume;\n    uint8_t semitone;\n    uint8_t dots;\n    uint8_t duration;\n    float position;\n} MusicPlayerModel;\n\ntypedef struct {\n    MusicPlayerModel* model; \n    MusicPlayerWorker* worker;\n    FuriMutex** model_mutex;\n} MusicPlayer;\n\n\n#endif"
  },
  {
    "path": "types.c",
    "content": "#include \"types.h\"\n\n/*template <class T>\ninline T sq(T value) {\n    return value * value;\n}*/\n\ndouble sq(double val){\n\treturn val * val;\n}\n\n//extern \"C\"\nCoords create_coords(double x, double y) {\n  Coords cord;\n  cord.x = x;\n  cord.y = y;\n  return cord;\n}\n\n//extern \"C\"\nuint8_t coords_distance(Coords* a, Coords* b) {\n  return sqrt(sq(a->x - b->x) + sq(a->y - b->y)) * 20;\n}\n\n//extern \"C\"\nUID create_uid(uint8_t type, uint8_t x, uint8_t y) {\n  return ((y << 6) | x) << 4 | type;\n}\n\n//extern \"C\"\nuint8_t uid_get_type(UID uid) {\n  return uid & 0x0F;\n}\n"
  },
  {
    "path": "types.h",
    "content": "#ifndef _types_h\n#define _types_h\n\n#include <stdint.h>\n#include <math.h>\n//#include \"constants.h\"\n\n#define UID_null  0\n\n// Entity types (legend applies to level.h)\n#define E_FLOOR             0x0   // . (also null)\n#define E_WALL              0xF   // #\n#define E_PLAYER            0x1   // P\n#define E_ENEMY             0x2   // E\n#define E_DOOR              0x4   // D\n#define E_LOCKEDDOOR        0x5   // L\n#define E_EXIT              0x7   // X\n// collectable entities >= 0x8\n#define E_MEDIKIT           0x8   // M\n#define E_KEY               0x9   // K\n#define E_FIREBALL          0xA   // not in map\n\ntypedef uint16_t UID;\ntypedef uint8_t  EType;\n\ntypedef struct Coords {\n  double x;\n  double y;\n}Coords;\n\nUID create_uid(EType type, uint8_t x, uint8_t y);\nEType uid_get_type(UID uid);\nCoords create_coords(double x, double y);\nuint8_t coords_distance(Coords* a, Coords* b);\n\n#endif\n\n"
  }
]