main 6cd5da460b93 cached
13 files
101.4 KB
49.1k tokens
62 symbols
1 requests
Download .txt
Repository: p4nic4ttack/doom-flipper-zero
Branch: main
Commit: 6cd5da460b93
Files: 13
Total size: 101.4 KB

Directory structure:
gitextract_bi69kcir/

├── README.md
├── application.fam
├── compiled/
│   ├── assets_icons.c
│   └── assets_icons.h
├── constants.h
├── display.h
├── doom.c
├── entities.c
├── entities.h
├── level.h
├── sound.h
├── types.c
└── types.h

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Doom Flipper Zero edition

 <div style="text-align:center"><img src="assets/intro-screen.png"/></div>

## Will it run Doom?
As 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>
This version is very basic and might be improved over time.

## How to install on Flipper Zero
During 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.
### Modifying the firmware & build options
 * In the `sites/cc.scons` add the following values to the `CCFLAGS` section:
 ```
 ...
"-Wno-unused-parameter",
"-Wno-type-limits",
"-Wno-unused-variable",
...
 ```
 * In `applications/gui/canvas_i.h` comment out the following line:<br>
 `uint8_t* canvas_get_buffer(Canvas* canvas);` --> `//uint8_t* canvas_get_buffer(Canvas* canvas);`

 * In `applications/gui/canvas.h` add the following lines:
 ```
 uint8_t* canvas_get_buffer(Canvas* canvas);
 void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon);
 ```
 * In `applications/gui/canvas.c` add the following function:
 ```
 void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon){
     furi_assert(canvas);
     furi_assert(icon);

     x += canvas->offset_x;
     y += canvas->offset_y;
     uint8_t* icon_data = NULL;
     furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data);
     u8g2_DrawXBM(&canvas->fb, x, y, w, h, icon_data);
 }
 ```

### Installing the plugin in the firmware
 * 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.
 * Make the `applications/meta/application.fam` look like the following:
 ```
 App(
     appid="basic_plugins",
     name="Basic applications for plug-in menu",
     apptype=FlipperAppType.METAPACKAGE,
     provides=[
         ...
         "doom_game",
         ...

     ],
 )
 ```

If all went well the only thing left to do is building the firmware and installing it to the Flipper.

## Screenshots
![Intro screen](assets/screenshot-intro2.jpg)

![Start screen](assets/screenshot-start2.jpg)

![Imp](assets/screenshot-imp2.jpg)

![Medkit](assets/screenshot-medkit2.jpg)


================================================
FILE: application.fam
================================================
App(
    appid="doom_game",
    name="Doom",
    apptype=FlipperAppType.PLUGIN,
    entry_point="doom_app",
    cdefines=["APP_DOOM_GAME"],
    requires=["gui"],
    stack_size=1 * 1024,
    icon="A_Plugins_14",
    order=30,
)


================================================
FILE: compiled/assets_icons.c
================================================
#include "assets_icons.h"

#include <gui/icon_i.h>





// Inverted icons

const 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,};
const uint8_t* const _I_fire_inv[] = {_I_fire_inv_0};

const 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,};
const uint8_t* const _I_gun_inv[] = {_I_gun_inv_0};

const 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,};
const uint8_t* const _I_gun_mask_inv[] = {_I_gun_mask_inv_0};

const 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,};
const uint8_t* const _I_logo_inv[] = {_I_logo_inv_0};

const Icon I_fire_inv = {.width=24,.height=20,.frame_count=1,.frame_rate=0,.frames=_I_fire_inv};
const Icon I_gun_inv = {.width=32,.height=32,.frame_count=1,.frame_rate=0,.frames=_I_gun_inv};
const Icon I_gun_mask_inv = {.width=32,.height=32,.frame_count=1,.frame_rate=0,.frames=_I_gun_mask_inv};
const Icon I_logo_inv = {.width=72,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_logo_inv};

const uint8_t  space[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t  zero[]  = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};
const uint8_t  one[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x70};
const uint8_t  two[] ={0x00, 0x60, 0x90, 0x20, 0x40, 0xf0};
const uint8_t  three[]  = {0x00, 0x60, 0x90, 0x20, 0x90, 0x60};
const uint8_t  four[]  = {0x00, 0x90, 0x90, 0xf0, 0x10, 0x10};
const uint8_t  five[]  = {0x00, 0xf0, 0x80, 0xe0, 0x10, 0xe0};
const uint8_t  six[]  = {0x00, 0x60, 0x80, 0xe0, 0x90, 0x60};
const uint8_t  seven[]  = {0x00, 0xf0, 0x10, 0x10, 0x10, 0x10};
const uint8_t  eight[]  = {0x00, 0x60, 0x90, 0x60, 0x90, 0x60};
const uint8_t  nine[]  = {0x00, 0x60, 0x90, 0x70, 0x10, 0x60};
const uint8_t  A[]  = {0x00, 0x60, 0x90, 0xf0, 0x90, 0x90};
const uint8_t  B[]  = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0xe0};
const uint8_t  C[]  = {0x00, 0x60, 0x90, 0x80, 0x90, 0x60};
const uint8_t  D[]  = {0x00, 0xe0, 0x90, 0x90, 0x90, 0xe0};
const uint8_t  E[]  = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0xf0};
const uint8_t  F[]  = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80};
const uint8_t  G[]  = {0x00, 0x60, 0x80, 0x80, 0x90, 0x60};
const uint8_t  H[]  = {0x00, 0x90, 0x90, 0xf0, 0x90, 0x90};
const uint8_t  I[]  = {0x00, 0x20, 0x20, 0x20, 0x20, 0x20};
const uint8_t  J[]  = {0x00, 0x10, 0x10, 0x10, 0x90, 0x60};
const uint8_t  K[]  = {0x00, 0x90, 0xa0, 0xc0, 0xa0, 0x90};
const uint8_t  L[]  = {0x00, 0x80, 0x80, 0x80, 0x80, 0xf0};
const uint8_t  M[]  = {0x00, 0x90, 0xf0, 0x90, 0x90, 0x90};
const uint8_t  N[]  = {0x00, 0x90, 0xd0, 0xb0, 0x90, 0x90};
const uint8_t  O[]  = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60};
const uint8_t  P[]  = {0x00, 0xe0, 0x90, 0xe0, 0x80, 0x80};
const uint8_t  Q[]  = {0x00, 0x60, 0x90, 0x90, 0xb0, 0x70};
const uint8_t  R[]  = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0x90};
const uint8_t  S[]  = {0x00, 0x60, 0x80, 0x60, 0x10, 0xe0};
const uint8_t  T[]  = {0x00, 0xe0, 0x40, 0x40, 0x40, 0x40};
const uint8_t  U[]  = {0x00, 0x90, 0x90, 0x90, 0x90, 0x60};
const uint8_t  V[]  = {0x00, 0x90, 0x90, 0x90, 0x60, 0x60};
const uint8_t  W[]  = {0x00, 0x90, 0x90, 0x90, 0xf0, 0x90};
const uint8_t  X[]  = {0x00, 0x90, 0x90, 0x60, 0x90, 0x90};
const uint8_t  Y[]  = {0x00, 0x90, 0x90, 0x60, 0x60, 0x60};
const uint8_t  Z[]  = {0x00, 0xf0, 0x10, 0x60, 0x80, 0xf0};
const uint8_t  dot[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0x40};
const uint8_t  comma[]  = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40};
const uint8_t  dash[]  = {0x00, 0x00, 0x00, 0x60, 0x00, 0x00};
const uint8_t  underscore[]  = {0x00, 0x00, 0x00, 0x00, 0x00, 0xf0};
const uint8_t  bracket_open[]  = {0x00, 0x20, 0x40, 0x40, 0x40, 0x20};
const uint8_t  bracket_close[]  = {0x00, 0x40, 0x20, 0x20, 0x20, 0x40};
const uint8_t  cross_left[]  = {0x10, 0x10, 0x70, 0x70, 0x10, 0x10};
const uint8_t  cross_right[]  = {0x80, 0x80, 0xe0, 0xe0, 0x80, 0x80};
const uint8_t  pacman_left[]  = {0x00, 0x30, 0x50, 0x70, 0x70, 0x00};
const uint8_t  pacman_right[]  = {0x00, 0xc0, 0x60, 0xe0, 0xe0, 0xe0};
const uint8_t  box[]  = {0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00};
const 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};
const 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};
//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};
// 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};
const 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};
const 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};

const 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};
const 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};
const 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};
const 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};
const 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};
const 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};

//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};
const 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};

================================================
FILE: compiled/assets_icons.h
================================================
#pragma once
#include <gui/icon.h>

#ifndef _sprites_h
#define _sprites_h

#define bmp_font_width   24  // in bytes
#define bmp_font_height  6
#define bmp_font_width_pxs   192
#define bmp_font_height_pxs  48
#define CHAR_MAP         " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#"
#define CHAR_WIDTH       4
#define CHAR_HEIGHT      6

#define BMP_GUN_WIDTH   32
#define BMP_GUN_HEIGHT  32

#define BMP_FIRE_WIDTH  24
#define BMP_FIRE_HEIGHT 20

#define BMP_IMP_WIDTH   32
#define BMP_IMP_HEIGHT  32
#define BMP_IMP_COUNT   5

#define BMP_FIREBALL_WIDTH 16
#define BMP_FIREBALL_HEIGHT 16

#define BMP_DOOR_WIDTH    100
#define BMP_DOOR_HEIGHT   100

#define BMP_ITEMS_WIDTH   16
#define BMP_ITEMS_HEIGHT  16
#define BMP_ITEMS_COUNT   2

#define BMP_LOGO_WIDTH  72
#define BMP_LOGO_HEIGHT 47

#define GRADIENT_WIDTH  2
#define GRADIENT_HEIGHT 8
#define GRADIENT_COUNT  8
#define GRADIENT_WHITE  7
#define GRADIENT_BLACK  0




// Inverted icons
extern const Icon I_fire_inv;
extern const Icon I_gun_inv;
extern const Icon I_gun_mask_inv;
extern const Icon I_logo_inv;

// Fonts
extern const uint8_t  zero[];  
extern const uint8_t  one[]; 
extern const uint8_t  two[]; 
extern const uint8_t  three[];  
extern const uint8_t  four[]; 
extern const uint8_t  five[];
extern const uint8_t  six[];
extern const uint8_t  seven[];
extern const uint8_t  eight[];
extern const uint8_t  nine[];
extern const uint8_t  A[];
extern const uint8_t  B[];
extern const uint8_t  C[];
extern const uint8_t  D[];
extern const uint8_t  E[];
extern const uint8_t  F[];
extern const uint8_t  G[];
extern const uint8_t  H[];
extern const uint8_t  I[];
extern const uint8_t  J[];
extern const uint8_t  K[];
extern const uint8_t  L[];
extern const uint8_t  M[];
extern const uint8_t  N[];
extern const uint8_t  O[];
extern const uint8_t  P[];
extern const uint8_t  Q[];
extern const uint8_t  R[];
extern const uint8_t  S[];
extern const uint8_t  T[];
extern const uint8_t  U[];
extern const uint8_t  V[];
extern const uint8_t  W[];
extern const uint8_t  X[];
extern const uint8_t  Y[];
extern const uint8_t  Z[];
extern const uint8_t  dot[];
extern const uint8_t  comma[];
extern const uint8_t  dash[];
extern const uint8_t  underscore[];
extern const uint8_t  bracket_open[];
extern const uint8_t  bracket_close[];
extern const uint8_t  cross_left[];
extern const uint8_t  cross_right[];
extern const uint8_t  pacman_left[];
extern const uint8_t  pacman_right[];
extern const uint8_t  box[];
extern const uint8_t *char_arr[48];
extern const uint8_t gradient[];
//extern const uint8_t gun[] 
//extern const uint8_t gun_mask[] 
extern const uint8_t gun[]; 
extern const uint8_t gun_mask[]; 

extern const uint8_t imp_inv[]; 
extern const uint8_t imp_mask_inv[]; 
extern const uint8_t fireball[];
extern const uint8_t fireball_mask[]; 
extern const uint8_t item[];
extern const uint8_t item_mask[];

extern const uint8_t door[];

#endif


================================================
FILE: constants.h
================================================
#ifndef _constants_h
#define _constants_h
#define PB_CONSTEXPR constexpr

#define PI 3.14159265358979323846

// Key pinout
#define USE_INPUT_PULLUP
#define K_LEFT              6
#define K_RIGHT             7
#define K_UP                8
#define K_DOWN              3
#define K_FIRE              10

// SNES Controller
// uncomment following line to enable snes controller support
// #define SNES_CONTROLLER
const uint8_t DATA_CLOCK   = 11;
const uint8_t DATA_LATCH   = 12;
const uint8_t DATA_SERIAL  = 13;

// Sound
const uint8_t SOUND_PIN   = 9; // do not change, belongs to used timer

// GFX settings
#define OPTIMIZE_SSD1306                // Optimizations for SSD1366 displays

#define FRAME_TIME          66.666666   // Desired time per frame in ms (66.666666 is ~15 fps)
#define RES_DIVIDER         2           // Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage
                                        // Lower will require more process and memory, but looks nicer
#define Z_RES_DIVIDER       2           // Zbuffer resolution divider. We sacrifice resolution to save memory
#define DISTANCE_MULTIPLIER 20          // Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care
                                        // of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH
#define MAX_RENDER_DEPTH    12
#define MAX_SPRITE_DEPTH    8

#define ZBUFFER_SIZE        SCREEN_WIDTH / Z_RES_DIVIDER

// Level 
#define LEVEL_WIDTH_BASE    6
#define LEVEL_WIDTH         (1 << LEVEL_WIDTH_BASE)
#define LEVEL_HEIGHT        57
#define LEVEL_SIZE          LEVEL_WIDTH / 2 * LEVEL_HEIGHT

// scenes
#define INTRO                 0
#define GAME_PLAY             1

// Game
#define GUN_TARGET_POS        18
#define GUN_SHOT_POS          GUN_TARGET_POS + 4

#define ROT_SPEED             .12
#define MOV_SPEED             .2
#define MOV_SPEED_INV         5           // 1 / MOV_SPEED

#define JOGGING_SPEED         .005
#define ENEMY_SPEED           .02
#define FIREBALL_SPEED        .2
#define FIREBALL_ANGLES       45          // Num of angles per PI

#define MAX_ENTITIES          10          // Max num of active entities
#define MAX_STATIC_ENTITIES   28          // Max num of entities in sleep mode

#define MAX_ENTITY_DISTANCE   200         // * DISTANCE_MULTIPLIER
#define MAX_ENEMY_VIEW        80          // * DISTANCE_MULTIPLIER
#define ITEM_COLLIDER_DIST    6           // * DISTANCE_MULTIPLIER
#define ENEMY_COLLIDER_DIST   4           // * DISTANCE_MULTIPLIER
#define FIREBALL_COLLIDER_DIST 2          // * DISTANCE_MULTIPLIER
#define ENEMY_MELEE_DIST      6           // * DISTANCE_MULTIPLIER
#define WALL_COLLIDER_DIST    .2

#define ENEMY_MELEE_DAMAGE    8
#define ENEMY_FIREBALL_DAMAGE 20
#define GUN_MAX_DAMAGE        15

// display
const uint8_t SCREEN_WIDTH     =  128;
const uint8_t SCREEN_HEIGHT    =  64;
const uint8_t HALF_WIDTH       =  SCREEN_WIDTH/2;
const uint8_t RENDER_HEIGHT    =  56;         // raycaster working height (the rest is for the hud)
const uint8_t HALF_HEIGHT      =  SCREEN_HEIGHT/2;

#endif


================================================
FILE: display.h
================================================
#include <gui/gui.h>
#include <furi_hal.h>
#include <u8g2_glue.h>
#include "constants.h"
#include "compiled/assets_icons.h"

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

static const uint8_t bit_mask[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };

#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define read_bit(b, n)      b & pgm_read_byte(bit_mask + n) ? 1 : 0
//#define read_bit(byte, index) (((unsigned)(byte) >> (index)) & 1)

void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas);
void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas);
void 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);
void drawBitmap(int16_t x, int16_t y, const Icon *i, int16_t w, int16_t h, uint16_t color, Canvas* const canvas);
void drawTextSpace(int8_t x, int8_t y, char *txt, uint8_t space, Canvas* const canvas);
void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas);
void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas);
void drawGun(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, Canvas* const canvas);
void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas);
void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas);
void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas);
bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i);
double getActualFps();
void fps();
void setupDisplay(Canvas* canvas);
uint8_t reverse_bits(uint8_t num);

// FPS control
double delta = 1;
uint32_t lastFrameTime = 0;
uint8_t zbuffer[128]; /// 128 = screen width & REMOVE WHEN DISPLAY.H IMPLEMENTED
uint8_t *display_buf = NULL;

void drawGun(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, Canvas* const canvas){
  int16_t byteWidth = (w + 7) / 8;
  uint8_t byte = 0;
  for(int16_t j=0; j<h; j++, y++) {
    for(int16_t i=0; i<w; i++) {
      if(i & 7) byte <<= 1;
      else      byte   = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
      if(byte & 0x80) drawPixel(x+i, y, color,false, canvas);
    }
  }
}

void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas){
	uint8_t dots = end_y - start_y;
	for(int i = 0; i < dots; i++){
		canvas_draw_dot(canvas, x, start_y+i);
	}	
}

void setupDisplay(Canvas* canvas){
	memset(zbuffer, 0xff, 128);
  display_buf = (uint8_t*)canvas_get_buffer(canvas);
  //display_buf = u8g2_GetBufferPtr(&canvas->fb);
}


void drawBitmap(int16_t x, int16_t y, const Icon *i, int16_t w, int16_t h, uint16_t color, Canvas* const canvas){
	canvas_draw_icon_bitmap(canvas, x, y, w, h, i);
}

void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas){
	char buf[4];
	itoa(num, buf, 10);
	drawTextSpace(x,y,buf,1,canvas);	
}

void drawTextSpace(int8_t x, int8_t y, char *txt, uint8_t space, Canvas* const canvas){
	uint8_t pos = x;
	uint8_t i = 0;
	char ch;
	while ((ch = txt[i]) != '\0') {
    drawChar(pos, y, ch, canvas);
    i++;
    pos += CHAR_WIDTH + space;

    // shortcut on end of screen
    if (pos > SCREEN_WIDTH) return;
  }

  

}

// Custom drawBitmap method with scale support, mask, zindex and pattern filling
void 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){
uint8_t tw = (double) w / distance;
  uint8_t th = (double) h / distance;
  uint8_t byte_width = w / 8;
  uint8_t pixel_size = fmax(1, (double)1.0 / (double)distance);
  uint16_t sprite_offset = byte_width * h * sprite;

  bool pixel;
  bool maskPixel;

  // Don't draw the whole sprite if the anchor is hidden by z buffer
  // Not checked per pixel for performance reasons
  if (zbuffer[(int)(fmin(fmax(x, 0), ZBUFFER_SIZE - 1) / Z_RES_DIVIDER)] < distance * DISTANCE_MULTIPLIER) {
    return;
  }

  for (uint8_t ty = 0; ty < th; ty += pixel_size) {
    // Don't draw out of screen
    if (y + ty < 0 || y + ty >= RENDER_HEIGHT) {
      continue;
    }

    uint8_t sy = ty * distance; // The y from the sprite

    for (uint8_t tx = 0; tx < tw; tx += pixel_size) {
      uint8_t sx = tx * distance; // The x from the sprite
      uint16_t byte_offset = sprite_offset + sy * byte_width + sx / 8;

      // Don't draw out of screen
      if (x + tx < 0 || x + tx >= SCREEN_WIDTH) {
        continue;
      }
      
      maskPixel = read_bit(pgm_read_byte(bitmap_mask + byte_offset), sx % 8);

      if (maskPixel) {
        pixel = read_bit(pgm_read_byte(bitmap + byte_offset), sx % 8);
        for (uint8_t ox = 0; ox < pixel_size; ox++) {
          for (uint8_t oy = 0; oy < pixel_size; oy++) {
            if(bitmap == imp_inv)
              drawPixel(x + tx + ox, y + ty + oy, 1, true, canvas);
            else
              drawPixel(x + tx + ox, y + ty + oy, pixel, true, canvas);
          }
        }
      }
    }
  }
}


void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas) {
	if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= (raycasterViewport ? RENDER_HEIGHT : SCREEN_HEIGHT)){
		return;
	}
  if(color)
    canvas_draw_dot(canvas, x, y);
  else{
    canvas_invert_color(canvas);
    canvas_draw_dot(canvas, x, y);
    canvas_invert_color(canvas);
  }
}

void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas){
  uint8_t lsb;
  uint8_t c = 0;
  while (CHAR_MAP[c] != ch && CHAR_MAP[c] != '\0') c++;
  for(uint8_t i = 0; i < 6; i++){
    //lsb = (char_arr[c][i] >> 4);
    lsb = reverse_bits(char_arr[c][i]);
    for (uint8_t n = 0; n < 4; n++){
      if(CHECK_BIT(lsb, n)){
        drawPixel(x+n, y+i, true, false, canvas);
      }    
    }
  }

}

void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas){
	canvas_invert_color(canvas);

	for(int i = 0; i < w; i++){
		for(int j = 0; j < h; j++){
			canvas_draw_dot(canvas, x+i, y+j);
		}
	}

	canvas_invert_color(canvas);
}

void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas){
	for(int i = 0; i < w; i++){
		for(int j = 0; j < h; j++){
			canvas_draw_dot(canvas, x+i, y+j);
		}
	}
}

bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i) {
  if (i == 0) return 0;
  if (i >= GRADIENT_COUNT - 1) return 1;

  uint8_t index = fmax(0, fmin(GRADIENT_COUNT - 1, i)) * GRADIENT_WIDTH * GRADIENT_HEIGHT // gradient index
                  + y * GRADIENT_WIDTH % (GRADIENT_WIDTH * GRADIENT_HEIGHT)             // y byte offset
                  + x / GRADIENT_HEIGHT % GRADIENT_WIDTH;                               // x byte offset
  //uint8_t *gradient_data = NULL;
  //furi_hal_compress_icon_decode(icon_get_data(&I_gradient_inv), &gradient_data);
  // return the bit based on x
  return read_bit(pgm_read_byte(gradient + index), x % 8);
}



void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas) {
  for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
    for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
      if (getGradientPixel(x, y, intensity)) 
        drawPixel(x, y, color, false, canvas);
    }
  }
}

// Adds a delay to limit play to specified fps
// Calculates also delta to keep movement consistent in lower framerates
void fps() {
  while (furi_get_tick() - lastFrameTime < FRAME_TIME);
  delta = (double)(furi_get_tick() - lastFrameTime) / (double)FRAME_TIME;
  lastFrameTime = furi_get_tick();
}

double getActualFps() {
  return 1000 / ((double)FRAME_TIME * (double)delta);
}


uint8_t reverse_bits(uint8_t num)
{
    unsigned int NO_OF_BITS = sizeof(num) * 8;
    uint8_t reverse_num = 0;
    uint8_t i;
    for (i = 0; i < NO_OF_BITS; i++) {
        if ((num & (1 << i)))
            reverse_num |= 1 << ((NO_OF_BITS - 1) - i);
    }
    return reverse_num;
}

================================================
FILE: doom.c
================================================
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include "sound.h"
#include "display.h"
#include "compiled/assets_icons.h"
#include "constants.h"
#include "entities.h"
#include "types.h"
#include "level.h"

#define SOUND

// Useful macros
#define swap(a, b) do { typeof(a) temp = a; a = b; b = temp; } while (0)
#define sign(a, b) (double) (a > b ? 1 : (b > a ? -1 : 0))
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))

typedef enum {
    EventTypeTick,
    EventTypeKey,
} EventType;

typedef struct {
    EventType type;
    InputEvent input;
} PluginEvent;

typedef struct {
    Player player;
    Entity entity[MAX_ENTITIES];
    StaticEntity static_entity[MAX_STATIC_ENTITIES];
    uint8_t num_entities;
    uint8_t num_static_entities;

    uint8_t scene;
    uint8_t gun_pos;
    double jogging;
    double view_height;
    bool init;
    

    bool up;
    bool down;
    bool left;
    bool right;
    bool fired;
    bool gun_fired;

    double rot_speed;
    double old_dir_x;
    double old_plane_x;
#ifdef SOUND
    MusicPlayer* music_instance;
    bool intro_sound;
#endif
} PluginState; 


Coords translateIntoView(Coords *pos, PluginState* const plugin_state);
void updateHud(Canvas* const canvas, PluginState* const plugin_state);
// general

bool invert_screen = false;
uint8_t flash_screen = 0;

// game
// player and entities




uint8_t getBlockAt(const uint8_t level[], uint8_t x, uint8_t y) {
  if (x < 0 || x >= LEVEL_WIDTH || y < 0 || y >= LEVEL_HEIGHT) {
    return E_FLOOR;
  }

  // y is read in inverse order
  return pgm_read_byte(level + (((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2))
         >> (!(x % 2) * 4)       // displace part of wanted bits
         & 0b1111;               // mask wanted bits
}

// Finds the player in the map
void initializeLevel(const uint8_t level[], PluginState* const plugin_state) {
  for (uint8_t y = LEVEL_HEIGHT - 1; y > 0; y--) {
    for (uint8_t x = 0; x < LEVEL_WIDTH; x++) {
      uint8_t block = getBlockAt(level, x, y);

      if (block == E_PLAYER) {
        plugin_state->player = create_player(x, y);
        return;
      }

      // todo create other static entities
    }
  }
}

bool isSpawned(UID uid, PluginState* const plugin_state) {
  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {
    if (plugin_state->entity[i].uid == uid) return true;
  }

  return false;
}

bool isStatic(UID uid, PluginState* const plugin_state) {
  for (uint8_t i = 0; i < plugin_state->num_static_entities; i++) {
    if (plugin_state->static_entity[i].uid == uid) return true;
  }

  return false;
}

void spawnEntity(uint8_t type, uint8_t x, uint8_t y, PluginState* const plugin_state) {
  // Limit the number of spawned entities
  if (plugin_state->num_entities >= MAX_ENTITIES) {
    return;
  }

  // todo: read static entity status
  
  switch (type) {
    case E_ENEMY:
      plugin_state->entity[plugin_state->num_entities] = create_enemy(x, y);
      plugin_state->num_entities++;
      break;

    case E_KEY:
      plugin_state->entity[plugin_state->num_entities] = create_key(x, y);
      plugin_state->num_entities++;
      break;

    case E_MEDIKIT:
      plugin_state->entity[plugin_state->num_entities] = create_medikit(x, y);
      plugin_state->num_entities++;
      break;
  }
}

void spawnFireball(double x, double y, PluginState* const plugin_state) {
  // Limit the number of spawned entities
  if (plugin_state->num_entities >= MAX_ENTITIES) {
    return;
  }

  UID uid = create_uid(E_FIREBALL, x, y);
  // Remove if already exists, don't throw anything. Not the best, but shouldn't happen too often
  if (isSpawned(uid, plugin_state)) return;

  // Calculate direction. 32 angles
  int16_t dir = FIREBALL_ANGLES + atan2(y - plugin_state->player.pos.y, x - plugin_state->player.pos.x) / (double)PI * FIREBALL_ANGLES;
  if (dir < 0) dir += FIREBALL_ANGLES * 2;
  plugin_state->entity[plugin_state->num_entities] = create_fireball(x, y, dir);
  plugin_state->num_entities++;
}

void removeEntity(UID uid, PluginState* const plugin_state) {
  uint8_t i = 0;
  bool found = false;

  while (i < plugin_state->num_entities) {
    if (!found && plugin_state->entity[i].uid == uid) {
      // todo: doze it
      found = true;
      plugin_state->num_entities--;
    }

    // displace entities
    if (found) {
      plugin_state->entity[i] = plugin_state->entity[i + 1];
    }

    i++;
  }
}

void removeStaticEntity(UID uid, PluginState* const plugin_state) {
  uint8_t i = 0;
  bool found = false;

  while (i < plugin_state->num_static_entities) {
    if (!found && plugin_state->static_entity[i].uid == uid) {
      found = true;
      plugin_state->num_static_entities--;
    }

    // displace entities
    if (found) {
      plugin_state->static_entity[i] = plugin_state->static_entity[i + 1];
    }

    i++;
  }
}

UID detectCollision(const uint8_t level[], Coords *pos, double relative_x, double relative_y, bool only_walls, PluginState* const plugin_state) {
  // Wall collision
  uint8_t round_x = (int)pos->x + (int)relative_x;
  uint8_t round_y = (int)pos->y + (int)relative_y;
  uint8_t block = getBlockAt(level, round_x, round_y);

  if (block == E_WALL) {
    //playSound(hit_wall_snd, HIT_WALL_SND_LEN);
    return create_uid(block, round_x, round_y);
  }

  if (only_walls) {
    return UID_null;
  }

  // Entity collision
  for (uint8_t i=0; i < plugin_state->num_entities; i++) {
    // Don't collide with itself
    if (&(plugin_state->entity[i].pos) == pos) {
      continue;
    }

    uint8_t type = uid_get_type(plugin_state->entity[i].uid);

    // Only ALIVE enemy collision
    if (type != E_ENEMY || plugin_state->entity[i].state == S_DEAD || plugin_state->entity[i].state == S_HIDDEN) {
      continue;
    }

    Coords new_coords = { plugin_state->entity[i].pos.x - relative_x, plugin_state->entity[i].pos.y - relative_y };
    uint8_t distance = coords_distance(pos, &new_coords);

    // Check distance and if it's getting closer
    if (distance < ENEMY_COLLIDER_DIST && distance < plugin_state->entity[i].distance) {
      return plugin_state->entity[i].uid;
    }
  }

  return UID_null;
}

// Shoot
void fire(PluginState* const plugin_state) {
  //playSound(shoot_snd, SHOOT_SND_LEN);

  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {
    // Shoot only ALIVE enemies
    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) {
      continue;
    }

    Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state);
    if (fabs(transform.x) < 20 && transform.y > 0) {
      uint8_t damage = (double) fmin(GUN_MAX_DAMAGE, GUN_MAX_DAMAGE / (fabs(transform.x) * plugin_state->entity[i].distance) / 5);
      if (damage > 0) {
        plugin_state->entity[i].health = fmax(0, plugin_state->entity[i].health - damage);
        plugin_state->entity[i].state = S_HIT;
        plugin_state->entity[i].timer = 4;
      }
    }
  }
}

UID updatePosition(const uint8_t level[], Coords *pos, double relative_x, double relative_y, bool only_walls, PluginState* const plugin_state) {
  UID collide_x = detectCollision(level, pos, relative_x, 0, only_walls, plugin_state);
  UID collide_y = detectCollision(level, pos, 0, relative_y, only_walls, plugin_state);

  if (!collide_x) pos->x += relative_x;
  if (!collide_y) pos->y += relative_y;

  return collide_x || collide_y || UID_null;
}

void updateEntities(const uint8_t level[], Canvas* const canvas, PluginState* const plugin_state) {
  uint8_t i = 0;
  while (i < plugin_state->num_entities) {
    // update distance
    plugin_state->entity[i].distance = coords_distance(&(plugin_state->player.pos), &(plugin_state->entity[i].pos));

    // Run the timer. Works with actual frames.
    // Todo: use delta here. But needs double type and more memory
    if (plugin_state->entity[i].timer > 0) plugin_state->entity[i].timer--;

    // too far away. put it in doze mode
    if (plugin_state->entity[i].distance > MAX_ENTITY_DISTANCE) {
      removeEntity(plugin_state->entity[i].uid, plugin_state);
      // don't increase 'i', since current one has been removed
      continue;
    }

    // bypass render if hidden
    if (plugin_state->entity[i].state == S_HIDDEN) {
      i++;
      continue;
    }

    uint8_t type = uid_get_type(plugin_state->entity[i].uid);

    switch (type) {
      case E_ENEMY: {
          // Enemy "IA"
          if (plugin_state->entity[i].health == 0) {
            if (plugin_state->entity[i].state != S_DEAD) {
              plugin_state->entity[i].state = S_DEAD;
              plugin_state->entity[i].timer = 6;
            }
          } else  if (plugin_state->entity[i].state == S_HIT) {
            if (plugin_state->entity[i].timer == 0) {
              // Back to alert state
              plugin_state->entity[i].state = S_ALERT;
              plugin_state->entity[i].timer = 40;     // delay next fireball thrown
            }
          } else if (plugin_state->entity[i].state == S_FIRING) {
            if (plugin_state->entity[i].timer == 0) {
              // Back to alert state
              plugin_state->entity[i].state = S_ALERT;
              plugin_state->entity[i].timer = 40;     // delay next fireball throwm
            }
          } else {
            // ALERT STATE
            if (plugin_state->entity[i].distance > ENEMY_MELEE_DIST && plugin_state->entity[i].distance < MAX_ENEMY_VIEW) {
              if (plugin_state->entity[i].state != S_ALERT) {
                plugin_state->entity[i].state = S_ALERT;
                plugin_state->entity[i].timer = 20;   // used to throw fireballs
              } else {
                if (plugin_state->entity[i].timer == 0) {
                  // Throw a fireball
                  spawnFireball(plugin_state->entity[i].pos.x, plugin_state->entity[i].pos.y, plugin_state);
                  plugin_state->entity[i].state = S_FIRING;
                  plugin_state->entity[i].timer = 6;
                } else {
                  // move towards to the player.
                  updatePosition(
                    level,
                    &(plugin_state->entity[i].pos),
                    sign(plugin_state->player.pos.x, plugin_state->entity[i].pos.x) * (double)ENEMY_SPEED * 1, // NOT SURE (delta)
                    sign(plugin_state->player.pos.y, plugin_state->entity[i].pos.y) * (double)ENEMY_SPEED * 1, // NOT SURE (delta)
                    true,
                    plugin_state
                  );
                }
              }
            } else if (plugin_state->entity[i].distance <= ENEMY_MELEE_DIST) {
              if (plugin_state->entity[i].state != S_MELEE) {
                // Preparing the melee attack
                plugin_state->entity[i].state = S_MELEE;
                plugin_state->entity[i].timer = 10;
              } else if (plugin_state->entity[i].timer == 0) {
                // Melee attack
                plugin_state->player.health = fmax(0, plugin_state->player.health - ENEMY_MELEE_DAMAGE);
                plugin_state->entity[i].timer = 14;
                flash_screen = 1;
                updateHud(canvas, plugin_state);
              }
            } else {
              // stand
              plugin_state->entity[i].state = S_STAND;
            }
          }
          break;
        }

      case E_FIREBALL: {
          if (plugin_state->entity[i].distance < FIREBALL_COLLIDER_DIST) {
            // Hit the player and disappear
            plugin_state->player.health = fmax(0, plugin_state->player.health - ENEMY_FIREBALL_DAMAGE);
            flash_screen = 1;
            updateHud(canvas, plugin_state);
            removeEntity(plugin_state->entity[i].uid, plugin_state);
            continue; // continue in the loop
          } else {
            // Move. Only collide with walls.
            // Note: using health to store the angle of the movement
            UID collided = updatePosition(
              level,
              &(plugin_state->entity[i].pos),
              cos((double) plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * (double)FIREBALL_SPEED,
              sin((double) plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * (double)FIREBALL_SPEED,
              true,
              plugin_state
            );

            if (collided) {
              removeEntity(plugin_state->entity[i].uid, plugin_state);
              continue; // continue in the entity check loop
            }
          }
          break;
        }

      case E_MEDIKIT: {
          if (plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) {
            // pickup
            //playSound(medkit_snd, MEDKIT_SND_LEN);
            plugin_state->entity[i].state = S_HIDDEN;
            plugin_state->player.health = fmin(100, plugin_state->player.health + 50);
            updateHud(canvas, plugin_state);
            flash_screen = 1;
          }
          break;
        }

      case E_KEY: {
          if (plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) {
            // pickup
            //playSound(get_key_snd, GET_KEY_SND_LEN);
            plugin_state->entity[i].state = S_HIDDEN;
            plugin_state->player.keys++;
            updateHud(canvas, plugin_state);
            flash_screen = 1;
          }
          break;
        }
    }

    i++;
  }
}

// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html
void renderMap(const uint8_t level[], double view_height, Canvas* const canvas, PluginState* const plugin_state) {
  UID last_uid = 0; // NOT SURE ?

  for (uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) {
    double camera_x = 2 * (double) x / SCREEN_WIDTH - 1;
    double ray_x = plugin_state->player.dir.x + plugin_state->player.plane.x * camera_x;
    double ray_y = plugin_state->player.dir.y + plugin_state->player.plane.y * camera_x;
    uint8_t map_x = (uint8_t)plugin_state->player.pos.x;
    uint8_t map_y = (uint8_t)plugin_state->player.pos.y;
    Coords map_coords = { plugin_state->player.pos.x, plugin_state->player.pos.y };
    double delta_x = fabs(1 / ray_x);
    double delta_y = fabs(1 / ray_y);

    int8_t step_x; 
    int8_t step_y;
    double side_x;
    double side_y;

    if (ray_x < 0) {
      step_x = -1;
      side_x = (plugin_state->player.pos.x - map_x) * delta_x;
    } else {
      step_x = 1;
      side_x = (map_x + (double)1.0 - plugin_state->player.pos.x) * delta_x;
    }

    if (ray_y < 0) {
      step_y = -1;
      side_y = (plugin_state->player.pos.y - map_y) * delta_y;
    } else {
      step_y = 1;
      side_y = (map_y + (double)1.0 - plugin_state->player.pos.y) * delta_y;
    }

    // Wall detection
    uint8_t depth = 0;
    bool hit = 0;
    bool side; 
    while (!hit && depth < MAX_RENDER_DEPTH) {
      if (side_x < side_y) {
        side_x += delta_x;
        map_x += step_x;
        side = 0;
      } else {
        side_y += delta_y;
        map_y += step_y;
        side = 1;
      }

      uint8_t block = getBlockAt(level, map_x, map_y);

      if (block == E_WALL) {
        hit = 1;
      } else {
        // Spawning entities here, as soon they are visible for the
        // player. Not the best place, but would be a very performance
        // cost scan for them in another loop
        if (block == E_ENEMY || (block & 0b00001000) /* all collectable items */) {
          // Check that it's close to the player
          if (coords_distance(&(plugin_state->player.pos), &map_coords) < MAX_ENTITY_DISTANCE) {
            UID uid = create_uid(block, map_x, map_y);
            if (last_uid != uid && !isSpawned(uid, plugin_state)) {
              spawnEntity(block, map_x, map_y, plugin_state);
              last_uid = uid;
            }
          }
        }
      }

      depth++;
    }

    if (hit) {
      double distance;
      
      if (side == 0) {
        distance = fmax(1, (map_x - plugin_state->player.pos.x + (1 - step_x) / 2) / ray_x);
      } else {
        distance = fmax(1, (map_y - plugin_state->player.pos.y + (1 - step_y) / 2) / ray_y);
      }

      // store zbuffer value for the column
      zbuffer[x / Z_RES_DIVIDER] = fmin(distance * DISTANCE_MULTIPLIER, 255);

      // rendered line height
      uint8_t line_height = RENDER_HEIGHT / distance;

      drawVLine(
        x,
        view_height / distance - line_height / 2 + RENDER_HEIGHT / 2,
        view_height / distance + line_height / 2 + RENDER_HEIGHT / 2,
        GRADIENT_COUNT - (int)distance / MAX_RENDER_DEPTH * GRADIENT_COUNT - side * 2,
        canvas
      );
    }
  }
}

// Sort entities from far to close
uint8_t sortEntities(PluginState* const plugin_state) {
  uint8_t gap = plugin_state->num_entities;
  bool swapped = false;
  while (gap > 1 || swapped) {
    //shrink factor 1.3
    gap = (gap * 10) / 13;
    if (gap == 9 || gap == 10) gap = 11;
    if (gap < 1) gap = 1;
    swapped = false;
    for (uint8_t i = 0; i < plugin_state->num_entities - gap; i++)
    {
      uint8_t j = i + gap;
      if (plugin_state->entity[i].distance < plugin_state->entity[j].distance)
      {
        swap(plugin_state->entity[i], plugin_state->entity[j]);
        swapped = true;
      }
    }
  }
  return swapped;
}

Coords translateIntoView(Coords *pos, PluginState* const plugin_state) {
  //translate sprite position to relative to camera
  double sprite_x = pos->x - plugin_state->player.pos.x;
  double sprite_y = pos->y - plugin_state->player.pos.y;

  //required for correct matrix multiplication
  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));
  double transform_x = inv_det * (plugin_state->player.dir.y * sprite_x - plugin_state->player.dir.x * sprite_y);
  double transform_y = inv_det * (- plugin_state->player.plane.y * sprite_x + plugin_state->player.plane.x * sprite_y); // Z in screen
  Coords res = {transform_x, transform_y};
  return res;
}




void renderEntities(double view_height, Canvas* const canvas, PluginState* const plugin_state) {
  sortEntities(plugin_state);

  for (uint8_t i = 0; i < plugin_state->num_entities; i++) {
    if (plugin_state->entity[i].state == S_HIDDEN) continue;

    Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state);

    // don´t render if behind the player or too far away
    if (transform.y <= (double)0.1 || transform.y > MAX_SPRITE_DEPTH) {
      continue;
    }

    int16_t sprite_screen_x = HALF_WIDTH * ((double)1.0 + transform.x / transform.y);
    int8_t sprite_screen_y = RENDER_HEIGHT / 2 + view_height / transform.y;
    uint8_t type = uid_get_type(plugin_state->entity[i].uid);

    // don´t try to render if outside of screen
    // doing this pre-shortcut due int16 -> int8 conversion makes out-of-screen
    // values fit into the screen space
    if (sprite_screen_x < - HALF_WIDTH || sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH) {
      continue;
    }

    switch (type) {
      case E_ENEMY: {
          uint8_t sprite;
          if (plugin_state->entity[i].state == S_ALERT) {
            // walking
            sprite = ((int)furi_get_tick() / 500) % 2;
          } else if (plugin_state->entity[i].state == S_FIRING) {
            // fireball
            sprite = 2;
          } else if (plugin_state->entity[i].state == S_HIT) {
            // hit
            sprite = 3;
          } else if (plugin_state->entity[i].state == S_MELEE) {
            // melee atack
            sprite = plugin_state->entity[i].timer > 10 ? 2 : 1;
          } else if (plugin_state->entity[i].state == S_DEAD) {
            // dying
            sprite = plugin_state->entity[i].timer > 0 ? 3 : 4;
          } else {
            // stand
            sprite = 0;
          }

          drawSprite(
            sprite_screen_x - BMP_IMP_WIDTH * (double).5 / transform.y,
            sprite_screen_y - 8 / transform.y,
            imp_inv,
            imp_mask_inv,
            BMP_IMP_WIDTH,
            BMP_IMP_HEIGHT,
            sprite,
            transform.y,
            canvas
          );
          break;
        }

      case E_FIREBALL: {
          drawSprite(
            sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y,
            sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y,
            fireball,
            fireball_mask,
            BMP_FIREBALL_WIDTH,
            BMP_FIREBALL_HEIGHT,
            0,
            transform.y,
            canvas
          );
          break;
        }

      case E_MEDIKIT: {
          drawSprite(
            sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y,
            sprite_screen_y + 5 / transform.y,
            item,
            item_mask,
            BMP_ITEMS_WIDTH,
            BMP_ITEMS_HEIGHT,
            0,
            transform.y,
            canvas
          );
          break;
        }

      case E_KEY: {
          drawSprite(
            sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y,
            sprite_screen_y + 5 / transform.y,
            item,
            item_mask,
            BMP_ITEMS_WIDTH,
            BMP_ITEMS_HEIGHT,
            1,
            transform.y,
            canvas
          );
          break;
        }
    }
  }
}

void renderGun(uint8_t gun_pos, double amount_jogging, Canvas* const canvas) {
  // jogging
  char x = 48 + sin((double) furi_get_tick() * (double)JOGGING_SPEED) * 10 * amount_jogging;
  char y = RENDER_HEIGHT - gun_pos + fabs(cos((double) furi_get_tick() * (double)JOGGING_SPEED)) * 8 * amount_jogging;

  if (gun_pos > GUN_SHOT_POS - 2) {
    // Gun fire
    drawBitmap(x + 6, y - 11, &I_fire_inv, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1, canvas);
  }

  // Don't draw over the hud!
  uint8_t clip_height = fmax(0, fmin(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y);

  // Draw the gun (black mask + actual sprite).
  drawBitmap(x, y, &I_gun_mask_inv, BMP_GUN_WIDTH, clip_height, 0, canvas);
  drawBitmap(x, y, &I_gun_inv, BMP_GUN_WIDTH, clip_height, 1, canvas);
  //drawGun(x,y,gun_mask, BMP_GUN_WIDTH, clip_height, 0, canvas);
  //drawGun(x,y,gun, BMP_GUN_WIDTH, clip_height, 1, canvas);
}

// Only needed first time
void renderHud(Canvas* const canvas, PluginState* plugin_state) {
  drawTextSpace(2, 58, "{}", 0, canvas);        // Health symbol
  drawTextSpace(40, 58, "[]", 0, canvas);       // Keys symbol
  updateHud(canvas, plugin_state);
}

// Render values for the HUD
void updateHud(Canvas* const canvas, PluginState* plugin_state) {
  clearRect(12, 58, 15, 6, canvas);
  clearRect(50, 58, 15, 6, canvas);
  drawText(12, 58, plugin_state->player.health, canvas);
  drawText(50, 58, plugin_state->player.keys, canvas);
}



// Debug stats
void renderStats(Canvas* const canvas, PluginState* plugin_state) {
  clearRect(58, 58, 70, 6, canvas);
  drawText(114, 58, (int)getActualFps(), canvas);
  drawText(82, 58, plugin_state->num_entities, canvas);
  // drawText(94, 58, freeMemory());
}

// Intro screen
void loopIntro(Canvas* const canvas) {
  canvas_draw_icon(canvas, (SCREEN_WIDTH - BMP_LOGO_WIDTH) / 2, (SCREEN_HEIGHT - BMP_LOGO_HEIGHT) / 3, &I_logo_inv);
  drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, "PRESS FIRE", 1, canvas);
}



static void render_callback(Canvas* const canvas, void* ctx) {
    PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
    if(plugin_state == NULL) {
        return;
    }
    if(plugin_state->init)
      setupDisplay(canvas);
    
    canvas_set_font(canvas, FontPrimary);
    

    switch(plugin_state->scene){
      case INTRO:{
        loopIntro(canvas);
        break;
      }
      case GAME_PLAY:{
        updateEntities(sto_level_1, canvas, plugin_state);

        renderGun(plugin_state->gun_pos,plugin_state->jogging, canvas); 
        renderMap(sto_level_1, plugin_state->view_height, canvas, plugin_state);
        
        renderEntities(plugin_state->view_height, canvas, plugin_state);
        

        renderHud(canvas, plugin_state);
        updateHud(canvas, plugin_state);
        renderStats(canvas, plugin_state);
        break;
      }
    }
    release_mutex((ValueMutex*)ctx, plugin_state);
}

static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
    furi_assert(event_queue); 

    PluginEvent event = {.type = EventTypeKey, .input = *input_event};
    furi_message_queue_put(event_queue, &event, 0);
}


static void doom_state_init(PluginState* const plugin_state) {
    plugin_state->num_entities = 0;
    plugin_state->num_static_entities = 0;

    plugin_state->scene = INTRO;
    plugin_state->gun_pos = 0;
    plugin_state->view_height = 0;
    plugin_state->init = true;
    

    plugin_state->up = false;
    plugin_state->down = false;
    plugin_state->left = false;
    plugin_state->right = false;
    plugin_state->fired = false;
    plugin_state->gun_fired = false;
#ifdef SOUND
    
    plugin_state->music_instance = malloc(sizeof(MusicPlayer));
    plugin_state->music_instance->model = malloc(sizeof(MusicPlayerModel));
    memset(plugin_state->music_instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
    memset(plugin_state->music_instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
    plugin_state->music_instance->model->volume = 2;
    
    plugin_state->music_instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
    //plugin_state->music_instance->view_port = view_port_alloc();
    
    plugin_state->music_instance->worker = music_player_worker_alloc();
    //music_player_worker_set_volume(plugin_state->music_instance->worker, 0.75);
    music_player_worker_set_volume(plugin_state->music_instance->worker, MUSIC_PLAYER_VOLUMES[plugin_state->music_instance->model->volume]);
    plugin_state->intro_sound = true;
    //init_sound(plugin_state->music_instance);
#endif
} 

static void doom_game_update_timer_callback(FuriMessageQueue* event_queue) {
    furi_assert(event_queue);

    PluginEvent event = {.type = EventTypeTick};
    furi_message_queue_put(event_queue, &event, 0);
}



static void doom_game_tick(PluginState* const plugin_state){
  if(plugin_state->scene == GAME_PLAY){
    fps();
    memset(display_buf, 0, SCREEN_WIDTH * (RENDER_HEIGHT / 8));
    //player is alive
    if(plugin_state->player.health > 0){
      if(plugin_state->up){
        plugin_state->player.velocity += ((double)MOV_SPEED - plugin_state->player.velocity) * (double).4;
        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;
        //plugin_state->up = false;
      }else if(plugin_state->down){
        plugin_state->player.velocity += (- (double)MOV_SPEED - plugin_state->player.velocity) * (double).4;
        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;
        //plugin_state->down = false;
      }else {
        plugin_state->player.velocity *= (double).5;
        plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV;
      }

      if(plugin_state->right){
        plugin_state->rot_speed = (double)ROT_SPEED * delta;
        plugin_state->old_dir_x = plugin_state->player.dir.x;
        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));
        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));
        plugin_state->old_plane_x = plugin_state->player.plane.x;
        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));
        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));

        //plugin_state->right = false;
      }else if(plugin_state->left){
        plugin_state->rot_speed = (double)ROT_SPEED * delta;
        plugin_state->old_dir_x = plugin_state->player.dir.x;
        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);
        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);
        plugin_state->old_plane_x = plugin_state->player.plane.x;
        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);
        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);
        //plugin_state->left = false;
      }
      plugin_state->view_height = fabs(sin((double) furi_get_tick() * (double)JOGGING_SPEED)) * 6 * plugin_state->jogging;

      if (plugin_state->gun_pos > GUN_TARGET_POS) {
      // Right after fire
        plugin_state->gun_pos -= 1;
      }else if(plugin_state->gun_pos < GUN_TARGET_POS){
        plugin_state->gun_pos += 2;
      }else if(!plugin_state->gun_fired && plugin_state->fired){
        //furi_hal_speaker_start(20480 / 10, 0.45f);
/*#ifdef SOUND
        music_player_worker_start(plugin_state->music_instance->worker);
#endif*/
        plugin_state->gun_pos = GUN_SHOT_POS;
        plugin_state->gun_fired = true;
        plugin_state->fired = false;
        fire(plugin_state);

      }else if(plugin_state->gun_fired && !plugin_state->fired){
        //furi_hal_speaker_stop();
        plugin_state->gun_fired = false;
        
/*#ifdef SOUND
        music_player_worker_stop(plugin_state->music_instance->worker);
#endif*/
      }
    }else{
      // Player is dead
      if(plugin_state->view_height > -10) plugin_state->view_height--;
      if(plugin_state->gun_pos > 1) plugin_state->gun_pos -=2;
    }

    if(fabs(plugin_state->player.velocity) > (double)0.003){
      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);
    }else{
      plugin_state->player.velocity = 0;
    }
  }
}

int32_t doom_app() {
    FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
    PluginState* plugin_state = malloc(sizeof(PluginState));
    doom_state_init(plugin_state);
    ValueMutex state_mutex; 
    if (!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) {
        FURI_LOG_E("Doom_game", "cannot create mutex\r\n");
        free(plugin_state); 
        return 255;
    }
    FuriTimer* timer = furi_timer_alloc(doom_game_update_timer_callback, FuriTimerTypePeriodic, event_queue);
    furi_timer_start(timer, furi_kernel_get_tick_frequency()/ 12);
    // Set system callbacks
    ViewPort* view_port = view_port_alloc(); 
    view_port_draw_callback_set(view_port, render_callback, &state_mutex);
    view_port_input_callback_set(view_port, input_callback, event_queue);
 
    // Open GUI and register view_port
    Gui* gui = furi_record_open("gui"); 
    gui_add_view_port(gui, view_port, GuiLayerFullscreen); 

    // GAMEPLAY VARS
    bool gun_fired = false;
    
    
    
    //double jogging;
    uint8_t fade = GRADIENT_COUNT - 1;
    //////////////////////////////////
    if(display_buf != NULL) 
      plugin_state->init = false;

    PluginEvent event;
#ifdef SOUND
    music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro);
    music_player_worker_start(plugin_state->music_instance->worker);
#endif
    for(bool processing = true; processing;) { 
	      FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
        PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex);
#ifdef SOUND
        furi_check(furi_mutex_acquire(plugin_state->music_instance->model_mutex, FuriWaitForever) == FuriStatusOk);
#endif
        if(event_status == FuriStatusOk) {
          if(event.type == EventTypeTick){
            doom_game_tick(plugin_state);
          }
          plugin_state->fired = false;



            // press events
            if(event.type == EventTypeKey) {
                if(event.input.type == InputTypePress) {

                  if(plugin_state->scene == INTRO && event.input.key == InputKeyOk){
                    plugin_state->scene = GAME_PLAY;
                    initializeLevel(sto_level_1, plugin_state);
#ifdef SOUND
                    furi_mutex_release(plugin_state->music_instance->model_mutex);
                    music_player_worker_stop(plugin_state->music_instance->worker);
                    plugin_state->intro_sound = false;
#endif
                  }

                  //While playing game
                  if(plugin_state->scene == GAME_PLAY){
                    
                    // If the player is alive
                    if (plugin_state->player.health > 0) {
                      //Player speed
                      if(event.input.key == InputKeyUp){
                        plugin_state->up = true;
                      }else if (event.input.key == InputKeyDown) {
                        plugin_state->down = true; 
                      }
                      // Player rotation
                      if(event.input.key == InputKeyRight){
                        plugin_state->right = true;
                      }else if(event.input.key == InputKeyLeft){
                        plugin_state->left = true; 
                      }
                      if(event.input.key == InputKeyOk){
                        

/*#ifdef SOUND
                        music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dspistol);
#endif*/
                        plugin_state->fired = true;
                      }
                    }else{
                      // Player is dead
                      if(event.input.key == InputKeyOk)plugin_state->scene = INTRO; 
                    } 
                  }
                  
                }
                if(event.input.type == InputTypeRelease){
                  if (plugin_state->player.health > 0) {
                      //Player speed
                      if(event.input.key == InputKeyUp){
                        plugin_state->up = false;
                      }else if (event.input.key == InputKeyDown) {
                        plugin_state->down = false;
                      } 
                      // Player rotation
                      if(event.input.key == InputKeyRight){
                        plugin_state->right = false;
                      }else if(event.input.key == InputKeyLeft){
                        plugin_state->left = false; 
                      }        
                    }
                }
                if(event.input.key == InputKeyBack){
                  processing = false;
#ifdef SOUND
                  if(plugin_state->intro_sound){
                    furi_mutex_release(plugin_state->music_instance->model_mutex);
                    music_player_worker_stop(plugin_state->music_instance->worker);
                  }
#endif
                }
            } 
        } else {
            FURI_LOG_D("Doom_game", "osMessageQueue: event timeout");
            // event timeout
        }
#ifdef SOUND
        furi_mutex_release(plugin_state->music_instance->model_mutex);
#endif
        view_port_update(view_port);
        release_mutex(&state_mutex, plugin_state);
    }
#ifdef SOUND
    music_player_worker_free(plugin_state->music_instance->worker);
    furi_mutex_free(plugin_state->music_instance->model_mutex);
    free(plugin_state->music_instance->model);
    free(plugin_state->music_instance);
#endif
    furi_timer_free(timer);
    view_port_enabled_set(view_port, false);
    gui_remove_view_port(gui, view_port);
    furi_record_close("gui");
    view_port_free(view_port);
    furi_message_queue_free(event_queue);
    return 0;
}


================================================
FILE: entities.c
================================================
#include "entities.h"


//extern "C"
/*Player create_player(double x, double y){
	return {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0};
}*/

Player create_player(double x, double y){
  Player p;
  p.pos = create_coords((double) x + (double)0.5, (double) y + (double)0.5);
  p.dir = create_coords(1, 0);
  p.plane = create_coords(0, -0.66);
  p.velocity = 0;
  p.health = 100;
  p.keys = 0;
  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};
}

//extern "C"
Entity create_entity(uint8_t type, uint8_t x,  uint8_t y, uint8_t initialState, uint8_t initialHealth) {
  UID uid = create_uid(type, x, y);
  Coords pos = create_coords((double) x + (double).5, (double) y + (double).5);
  Entity new_entity;// = { uid, pos, initialState, initialHealth, 0, 0 };
  new_entity.uid = uid;
  new_entity.pos = pos;
  new_entity.state = initialState;
  new_entity.health = initialHealth;
  new_entity.distance = 0;
  new_entity.timer = 0;
  return new_entity;
}

//extern "C"
StaticEntity crate_static_entity(UID uid, uint8_t x,  uint8_t y, bool active) {
  StaticEntity ent;
  ent.uid = uid;
  ent.x = x;
  ent.y = y;
  ent.active = active;
  return ent;
}

================================================
FILE: entities.h
================================================
#ifndef _entities_h
#define _entities_h
#include <stdint.h>
#include <stdbool.h>
#include "types.h"

// Shortcuts
//#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}

#define create_enemy(x, y)            create_entity(E_ENEMY, x, y, S_STAND, 50)
#define create_medikit(x, y)          create_entity(E_MEDIKIT, x, y, S_STAND, 0)
#define create_key(x, y)              create_entity(E_KEY, x, y, S_STAND, 0)
#define create_fireball(x, y, dir)    create_entity(E_FIREBALL, x, y, S_STAND, dir)
#define create_door(x, y)             create_entity(E_DOOR, x, y, S_STAND, 0)

// entity statuses
#define S_STAND               0
#define S_ALERT               1
#define S_FIRING              2
#define S_MELEE               3
#define S_HIT                 4
#define S_DEAD                5
#define S_HIDDEN              6
#define S_OPEN                7
#define S_CLOSE               8

typedef struct Player { 
  Coords pos;
  Coords dir;
  Coords plane;
  double velocity;
  uint8_t health;
  uint8_t keys;  
} Player;

typedef struct Entity {
  UID uid;
  Coords pos;
  uint8_t state;
  uint8_t health;     // angle for fireballs
  uint8_t distance;
  uint8_t timer;
} Entity;

typedef struct StaticEntity  { 
  UID uid;
  uint8_t x;
  uint8_t y;
  bool active;
} StaticEntity;

Entity create_entity(uint8_t type, uint8_t x,  uint8_t y, uint8_t initialState, uint8_t initialHealth);
StaticEntity create_static_entity(UID uid, uint8_t x,  uint8_t y, bool active);
Player create_player(double x, double y);
#endif



================================================
FILE: level.h
================================================
#ifndef _level_h
#define _level_h

#include "constants.h"

/*
  Based on E1M1 from Wolfenstein 3D

  ################################################################
  #############################...........########################
  ######....###################........E..########################
  ######....########..........#...........#...####################
  ######.....#######..........L.....E.......M.####################
  ######.....#######..........#...........#...####################
  ##################...########...........########################
  ######.........###...########...........########################
  ######.........###...#############D#############################
  ######.........#......E##########...############################
  ######....E....D...E...##########...############################
  ######.........#.......##########...############################
  ######....E....##################...############################
  #...##.........##################...############################
  #.K.######D######################...############################
  #...#####...###############...#E.....K##########################
  ##D######...###############..####...############################
  #...#####...###############..####...############################
  #...#...#...###############..####...############################
  #...D...#...#####################...############################
  #...#...#...#####################...############################
  #...######D#######################L#############################
  #.E.##.........#################.....#################........##
  #...##.........############...............############........##
  #...##...E.....############...............############........##
  #....#.........############...E.......E....#.........#........##
  #....L....K....############................D....E....D....E...##
  #....#.........############................#.........#........##
  #...##.....E...############...............####....####........##
  #...##.........############...............#####..#####.....M..##
  #...##.........#################.....##########..#####........##
  #...######L#######################D############..###############
  #...#####...#####################...###########..###############
  #E.E#####...#####################...###########..###############
  #...#...#...#####################.E.###########..###############
  #...D.M.#...#####################...###########..###############
  #...#...#...#####################...###########..###.#.#.#.#####
  #...#####...#####################...###########...#.........####
  #...#####...#####################...###########...D....E..K.####
  #................##......########...###########...#.........####
  #....E........E...L...E...X######...################.#.#.#.#####
  #................##......########...############################
  #################################...############################
  #############..#..#..#############L#############################
  ###########....#..#.########....#...#....#######################
  #############.....##########.P..D...D....#######################
  ############################....#...#....#######################
  ##############..#################...############################
  ##############..############....#...#....#######################
  ############################....D...D....#######################
  ############################....#...#....#######################
  #################################...############################
  ############################.............#######################
  ############################..........EK.#######################
  ############################.............#######################
  ################################################################
*/

/*
   Same map above built from some regexp replacements using the legend above.
   Using this way lets me use only 4 bit to store each block
*/
const uint8_t sto_level_1[LEVEL_SIZE] = {
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
  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, 
};

#endif



================================================
FILE: sound.h
================================================
#ifndef sound_h
#define sound_h
#include <m-string.h>
#include <furi.h>
#include <furi_hal.h>
#include <stdint.h>
#include "../music_player/music_player_worker.h"


//static const char dspistol[] = "AnyConv:d=,o=,b=120:408,40p,40p,40p,40p,405,40p,40p,40p,405,30p.,30p.,30p.,13p";
static 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";
//static const char dsgetpow[] = "dsgetpow:d=,o=,b=120:407,40p,30.6,407,40p,406,40p,407,40p,40p,407,30p.,407";
//static const char dsnoway[] = "dsnoway:d=,o=,b=120:407,30.4";

#define MUSIC_PLAYER_SEMITONE_HISTORY_SIZE 4
static const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1};

typedef struct {
    uint8_t semitone_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE];
    uint8_t duration_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE];

    uint8_t volume;
    uint8_t semitone;
    uint8_t dots;
    uint8_t duration;
    float position;
} MusicPlayerModel;

typedef struct {
    MusicPlayerModel* model; 
    MusicPlayerWorker* worker;
    FuriMutex** model_mutex;
} MusicPlayer;


#endif

================================================
FILE: types.c
================================================
#include "types.h"

/*template <class T>
inline T sq(T value) {
    return value * value;
}*/

double sq(double val){
	return val * val;
}

//extern "C"
Coords create_coords(double x, double y) {
  Coords cord;
  cord.x = x;
  cord.y = y;
  return cord;
}

//extern "C"
uint8_t coords_distance(Coords* a, Coords* b) {
  return sqrt(sq(a->x - b->x) + sq(a->y - b->y)) * 20;
}

//extern "C"
UID create_uid(uint8_t type, uint8_t x, uint8_t y) {
  return ((y << 6) | x) << 4 | type;
}

//extern "C"
uint8_t uid_get_type(UID uid) {
  return uid & 0x0F;
}


================================================
FILE: types.h
================================================
#ifndef _types_h
#define _types_h

#include <stdint.h>
#include <math.h>
//#include "constants.h"

#define UID_null  0

// Entity types (legend applies to level.h)
#define E_FLOOR             0x0   // . (also null)
#define E_WALL              0xF   // #
#define E_PLAYER            0x1   // P
#define E_ENEMY             0x2   // E
#define E_DOOR              0x4   // D
#define E_LOCKEDDOOR        0x5   // L
#define E_EXIT              0x7   // X
// collectable entities >= 0x8
#define E_MEDIKIT           0x8   // M
#define E_KEY               0x9   // K
#define E_FIREBALL          0xA   // not in map

typedef uint16_t UID;
typedef uint8_t  EType;

typedef struct Coords {
  double x;
  double y;
}Coords;

UID create_uid(EType type, uint8_t x, uint8_t y);
EType uid_get_type(UID uid);
Coords create_coords(double x, double y);
uint8_t coords_distance(Coords* a, Coords* b);

#endif

Download .txt
gitextract_bi69kcir/

├── README.md
├── application.fam
├── compiled/
│   ├── assets_icons.c
│   └── assets_icons.h
├── constants.h
├── display.h
├── doom.c
├── entities.c
├── entities.h
├── level.h
├── sound.h
├── types.c
└── types.h
Download .txt
SYMBOL INDEX (62 symbols across 7 files)

FILE: display.h
  function drawGun (line 38) | void drawGun(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int...
  function drawVLine (line 50) | void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensit...
  function setupDisplay (line 57) | void setupDisplay(Canvas* canvas){
  function drawBitmap (line 64) | void drawBitmap(int16_t x, int16_t y, const Icon *i, int16_t w, int16_t ...
  function drawText (line 68) | void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas){
  function drawTextSpace (line 74) | void drawTextSpace(int8_t x, int8_t y, char *txt, uint8_t space, Canvas*...
  function drawSprite (line 92) | void drawSprite(int8_t x, int8_t y, const uint8_t *bitmap, const uint8_t...
  function drawPixel (line 143) | void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, C...
  function drawChar (line 156) | void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas){
  function clearRect (line 172) | void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const...
  function drawRect (line 184) | void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const ...
  function getGradientPixel (line 192) | bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i) {
  function fadeScreen (line 207) | void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas) {
  function fps (line 218) | void fps() {
  function getActualFps (line 224) | double getActualFps() {
  function reverse_bits (line 229) | uint8_t reverse_bits(uint8_t num)

FILE: doom.c
  type EventType (line 22) | typedef enum {
  type PluginEvent (line 27) | typedef struct {
  type PluginState (line 32) | typedef struct {
  function getBlockAt (line 76) | uint8_t getBlockAt(const uint8_t level[], uint8_t x, uint8_t y) {
  function initializeLevel (line 88) | void initializeLevel(const uint8_t level[], PluginState* const plugin_st...
  function isSpawned (line 103) | bool isSpawned(UID uid, PluginState* const plugin_state) {
  function isStatic (line 111) | bool isStatic(UID uid, PluginState* const plugin_state) {
  function spawnEntity (line 119) | void spawnEntity(uint8_t type, uint8_t x, uint8_t y, PluginState* const ...
  function spawnFireball (line 145) | void spawnFireball(double x, double y, PluginState* const plugin_state) {
  function removeEntity (line 162) | void removeEntity(UID uid, PluginState* const plugin_state) {
  function removeStaticEntity (line 182) | void removeStaticEntity(UID uid, PluginState* const plugin_state) {
  function UID (line 201) | UID detectCollision(const uint8_t level[], Coords *pos, double relative_...
  function fire (line 243) | void fire(PluginState* const plugin_state) {
  function UID (line 264) | UID updatePosition(const uint8_t level[], Coords *pos, double relative_x...
  function updateEntities (line 274) | void updateEntities(const uint8_t level[], Canvas* const canvas, PluginS...
  function renderMap (line 421) | void renderMap(const uint8_t level[], double view_height, Canvas* const ...
  function sortEntities (line 520) | uint8_t sortEntities(PluginState* const plugin_state) {
  function Coords (line 542) | Coords translateIntoView(Coords *pos, PluginState* const plugin_state) {
  function renderEntities (line 558) | void renderEntities(double view_height, Canvas* const canvas, PluginStat...
  function renderGun (line 667) | void renderGun(uint8_t gun_pos, double amount_jogging, Canvas* const can...
  function renderHud (line 688) | void renderHud(Canvas* const canvas, PluginState* plugin_state) {
  function updateHud (line 695) | void updateHud(Canvas* const canvas, PluginState* plugin_state) {
  function renderStats (line 705) | void renderStats(Canvas* const canvas, PluginState* plugin_state) {
  function loopIntro (line 713) | void loopIntro(Canvas* const canvas) {
  function render_callback (line 720) | static void render_callback(Canvas* const canvas, void* ctx) {
  function input_callback (line 754) | static void input_callback(InputEvent* input_event, FuriMessageQueue* ev...
  function doom_state_init (line 762) | static void doom_state_init(PluginState* const plugin_state) {
  function doom_game_update_timer_callback (line 797) | static void doom_game_update_timer_callback(FuriMessageQueue* event_queu...
  function doom_game_tick (line 806) | static void doom_game_tick(PluginState* const plugin_state){
  function doom_app (line 884) | int32_t doom_app() {

FILE: entities.c
  function Player (line 9) | Player create_player(double x, double y){
  function Entity (line 21) | Entity create_entity(uint8_t type, uint8_t x,  uint8_t y, uint8_t initia...
  function StaticEntity (line 35) | StaticEntity crate_static_entity(UID uid, uint8_t x,  uint8_t y, bool ac...

FILE: entities.h
  type Player (line 27) | typedef struct Player {
  type Entity (line 36) | typedef struct Entity {
  type StaticEntity (line 45) | typedef struct StaticEntity  {

FILE: sound.h
  type MusicPlayerModel (line 18) | typedef struct {
  type MusicPlayer (line 29) | typedef struct {

FILE: types.c
  function sq (line 8) | double sq(double val){
  function Coords (line 13) | Coords create_coords(double x, double y) {
  function coords_distance (line 21) | uint8_t coords_distance(Coords* a, Coords* b) {
  function UID (line 26) | UID create_uid(uint8_t type, uint8_t x, uint8_t y) {
  function uid_get_type (line 31) | uint8_t uid_get_type(UID uid) {

FILE: types.h
  type UID (line 23) | typedef uint16_t UID;
  type EType (line 24) | typedef uint8_t  EType;
  type Coords (line 26) | typedef struct Coords {
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (106K chars).
[
  {
    "path": "README.md",
    "chars": 2691,
    "preview": "# Doom Flipper Zero edition\n\n <div style=\"text-align:center\"><img src=\"assets/intro-screen.png\"/></div>\n\n## Will it run "
  },
  {
    "path": "application.fam",
    "chars": 228,
    "preview": "App(\n    appid=\"doom_game\",\n    name=\"Doom\",\n    apptype=FlipperAppType.PLUGIN,\n    entry_point=\"doom_app\",\n    cdefines"
  },
  {
    "path": "compiled/assets_icons.c",
    "chars": 30051,
    "preview": "#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,0x"
  },
  {
    "path": "compiled/assets_icons.h",
    "chars": 2911,
    "preview": "#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#def"
  },
  {
    "path": "constants.h",
    "chars": 3145,
    "preview": "#ifndef _constants_h\n#define _constants_h\n#define PB_CONSTEXPR constexpr\n\n#define PI 3.14159265358979323846\n\n// Key pino"
  },
  {
    "path": "display.h",
    "chars": 7848,
    "preview": "#include <gui/gui.h>\n#include <furi_hal.h>\n#include <u8g2_glue.h>\n#include \"constants.h\"\n#include \"compiled/assets_icons"
  },
  {
    "path": "doom.c",
    "chars": 36171,
    "preview": "#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"
  },
  {
    "path": "entities.c",
    "chars": 1308,
    "preview": "#include \"entities.h\"\n\n\n//extern \"C\"\n/*Player create_player(double x, double y){\n\treturn {create_coords((double) x + (do"
  },
  {
    "path": "entities.h",
    "chars": 1607,
    "preview": "#ifndef _entities_h\n#define _entities_h\n#include <stdint.h>\n#include <stdbool.h>\n#include \"types.h\"\n\n// Shortcuts\n//#def"
  },
  {
    "path": "level.h",
    "chars": 15169,
    "preview": "#ifndef _level_h\n#define _level_h\n\n#include \"constants.h\"\n\n/*\n  Based on E1M1 from Wolfenstein 3D\n\n  ###################"
  },
  {
    "path": "sound.h",
    "chars": 1257,
    "preview": "#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#inclu"
  },
  {
    "path": "types.c",
    "chars": 550,
    "preview": "#include \"types.h\"\n\n/*template <class T>\ninline T sq(T value) {\n    return value * value;\n}*/\n\ndouble sq(double val){\n\tr"
  },
  {
    "path": "types.h",
    "chars": 889,
    "preview": "#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"
  }
]

About this extraction

This page contains the full source code of the p4nic4ttack/doom-flipper-zero GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (101.4 KB), approximately 49.1k tokens, and a symbol index with 62 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!