17 more apps done, 14 to go

This commit is contained in:
Willy-JL
2023-11-16 05:14:05 +00:00
parent 6fe1238a64
commit d74fa7bf52
218 changed files with 0 additions and 20726 deletions

View File

@@ -1,13 +0,0 @@
App(
appid="arkanoid",
name="Arkanoid",
apptype=FlipperAppType.EXTERNAL,
entry_point="arkanoid_game_app",
requires=["gui"],
stack_size=1 * 1024,
fap_icon="arkanoid_10px.png",
fap_category="Games",
fap_author="@xMasterX & @gotnull",
fap_version="1.0",
fap_description="Arkanoid Game",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,479 +0,0 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <gui/view.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <dolphin/dolphin.h>
#define TAG "Arkanoid"
#define FLIPPER_LCD_WIDTH 128
#define FLIPPER_LCD_HEIGHT 64
#define MAX_SPEED 3
typedef enum { EventTypeTick, EventTypeKey } EventType;
typedef struct {
//Brick Bounds used in collision detection
int leftBrick;
int rightBrick;
int topBrick;
int bottomBrick;
bool isHit[4][13]; //Array of if bricks are hit or not
} BrickState;
typedef struct {
int dx; //Initial movement of ball
int dy; //Initial movement of ball
int xb; //Balls starting possition
int yb; //Balls starting possition
bool released; //If the ball has been released by the player
//Ball Bounds used in collision detection
int leftBall;
int rightBall;
int topBall;
int bottomBall;
} BallState;
typedef struct {
FuriMutex* mutex;
BallState ball_state;
BrickState brick_state;
NotificationApp* notify;
unsigned int COLUMNS; //Columns of bricks
unsigned int ROWS; //Rows of bricks
bool initialDraw; //If the inital draw has happened
int xPaddle; //X position of paddle
char text[16]; //General string buffer
bool bounced; //Used to fix double bounce glitch
int lives; //Amount of lives
int level; //Current level
unsigned int score; //Score for the game
unsigned int brickCount; //Amount of bricks hit
int tick; //Tick counter
bool gameStarted; // Did the game start?
int speed; // Ball speed
} ArkanoidState;
typedef struct {
EventType type;
InputEvent input;
} GameEvent;
static const NotificationSequence sequence_short_sound = {
&message_note_c5,
&message_delay_50,
&message_sound_off,
NULL,
};
// generate number in range [min,max)
int rand_range(int min, int max) {
return min + rand() % (max - min);
}
void move_ball(Canvas* canvas, ArkanoidState* st) {
st->tick++;
int current_speed = abs(st->speed - 1 - MAX_SPEED);
if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) {
return;
}
if(st->ball_state.released) {
//Move ball
if(abs(st->ball_state.dx) == 2) {
st->ball_state.xb += st->ball_state.dx / 2;
// 2x speed is really 1.5 speed
if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2;
} else {
st->ball_state.xb += st->ball_state.dx;
}
st->ball_state.yb = st->ball_state.yb + st->ball_state.dy;
//Set bounds
st->ball_state.leftBall = st->ball_state.xb;
st->ball_state.rightBall = st->ball_state.xb + 2;
st->ball_state.topBall = st->ball_state.yb;
st->ball_state.bottomBall = st->ball_state.yb + 2;
//Bounce off top edge
if(st->ball_state.yb <= 0) {
st->ball_state.yb = 2;
st->ball_state.dy = -st->ball_state.dy;
}
//Lose a life if bottom edge hit
if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) {
canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
st->xPaddle = 54;
st->ball_state.yb = 60;
st->ball_state.released = false;
st->lives--;
st->gameStarted = false;
if(rand_range(0, 2) == 0) {
st->ball_state.dx = 1;
} else {
st->ball_state.dx = -1;
}
}
//Bounce off left side
if(st->ball_state.xb <= 0) {
st->ball_state.xb = 2;
st->ball_state.dx = -st->ball_state.dx;
}
//Bounce off right side
if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) {
st->ball_state.xb = FLIPPER_LCD_WIDTH - 4;
st->ball_state.dx = -st->ball_state.dx;
// arduboy.tunes.tone(523, 250);
}
//Bounce off paddle
if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 &&
st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 &&
st->ball_state.yb <= FLIPPER_LCD_HEIGHT) {
st->ball_state.dy = -st->ball_state.dy;
st->ball_state.dx =
((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball
// prevent straight bounce, but not prevent roguuemaster from stealing
if(st->ball_state.dx == 0) {
st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1;
}
}
//Bounce off Bricks
for(unsigned int row = 0; row < st->ROWS; row++) {
for(unsigned int column = 0; column < st->COLUMNS; column++) {
if(!st->brick_state.isHit[row][column]) {
//Sets Brick bounds
st->brick_state.leftBrick = 10 * column;
st->brick_state.rightBrick = 10 * column + 10;
st->brick_state.topBrick = 6 * row + 1;
st->brick_state.bottomBrick = 6 * row + 7;
//If A collison has occured
if(st->ball_state.topBall <= st->brick_state.bottomBrick &&
st->ball_state.bottomBall >= st->brick_state.topBrick &&
st->ball_state.leftBall <= st->brick_state.rightBrick &&
st->ball_state.rightBall >= st->brick_state.leftBrick) {
st->score += st->level;
// Blink led when we hit some brick
notification_message(st->notify, &sequence_short_sound);
//notification_message(st->notify, &sequence_blink_white_100);
st->brickCount++;
st->brick_state.isHit[row][column] = true;
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
//Vertical collision
if(st->ball_state.bottomBall > st->brick_state.bottomBrick ||
st->ball_state.topBall < st->brick_state.topBrick) {
//Only bounce once each ball move
if(!st->bounced) {
st->ball_state.dy = -st->ball_state.dy;
st->ball_state.yb += st->ball_state.dy;
st->bounced = true;
}
}
//Hoizontal collision
if(st->ball_state.leftBall < st->brick_state.leftBrick ||
st->ball_state.rightBall > st->brick_state.rightBrick) {
//Only bounce once brick each ball move
if(!st->bounced) {
st->ball_state.dx = -st->ball_state.dx;
st->ball_state.xb += st->ball_state.dx;
st->bounced = true;
}
}
}
}
}
}
//Reset Bounce
st->bounced = false;
} else {
//Ball follows paddle
st->ball_state.xb = st->xPaddle + 5;
}
}
void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) {
if(arkanoid_state->lives == 3) {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16);
} else if(arkanoid_state->lives == 2) {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
} else {
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
}
}
void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) {
snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score);
canvas_draw_str_aligned(
canvas,
FLIPPER_LCD_WIDTH - 2,
FLIPPER_LCD_HEIGHT - 6,
AlignRight,
AlignBottom,
arkanoid_state->text);
}
void draw_ball(Canvas* canvas, ArkanoidState* ast) {
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb);
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb);
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1);
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1);
move_ball(canvas, ast);
}
void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) {
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
}
void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) {
//Undraw paddle
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
//Undraw ball
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1);
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1);
//Alter various variables to reset the game
arkanoid_state->xPaddle = 54;
arkanoid_state->ball_state.yb = 60;
arkanoid_state->brickCount = 0;
arkanoid_state->ball_state.released = false;
arkanoid_state->gameStarted = false;
// Reset all brick hit states
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
arkanoid_state->brick_state.isHit[row][column] = false;
}
}
}
static void arkanoid_state_init(ArkanoidState* arkanoid_state) {
// Init notification
arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION);
// Set the initial game state
arkanoid_state->COLUMNS = 13;
arkanoid_state->ROWS = 4;
arkanoid_state->ball_state.dx = -1;
arkanoid_state->ball_state.dy = -1;
arkanoid_state->speed = 2;
arkanoid_state->bounced = false;
arkanoid_state->lives = 3;
arkanoid_state->level = 1;
arkanoid_state->score = 0;
arkanoid_state->COLUMNS = 13;
arkanoid_state->COLUMNS = 13;
// Reset initial state
arkanoid_state->initialDraw = false;
arkanoid_state->gameStarted = false;
}
static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
ArkanoidState* arkanoid_state = ctx;
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
//Initial level draw
if(!arkanoid_state->initialDraw) {
arkanoid_state->initialDraw = true;
// Set default font for text
canvas_set_font(canvas, FontSecondary);
//Draws the new level
reset_level(canvas, arkanoid_state);
}
//Draws new bricks and resets their values
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
if(!arkanoid_state->brick_state.isHit[row][column]) {
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
}
}
}
if(arkanoid_state->lives > 0) {
draw_paddle(canvas, arkanoid_state);
draw_ball(canvas, arkanoid_state);
draw_score(canvas, arkanoid_state);
draw_lives(canvas, arkanoid_state);
if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) {
arkanoid_state->level++;
reset_level(canvas, arkanoid_state);
}
} else {
reset_level(canvas, arkanoid_state);
arkanoid_state->initialDraw = false;
arkanoid_state->lives = 3;
arkanoid_state->score = 0;
}
furi_mutex_release(arkanoid_state->mutex);
}
static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeTick};
furi_message_queue_put(event_queue, &event, 0);
}
int32_t arkanoid_game_app(void* p) {
UNUSED(p);
int32_t return_code = 0;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState));
arkanoid_state_init(arkanoid_state);
arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!arkanoid_state->mutex) {
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
return_code = 255;
goto free_and_exit;
}
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state);
view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue);
FuriTimer* timer =
furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// Key events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress || event.input.type == InputTypeLong ||
event.input.type == InputTypeRepeat) {
switch(event.input.key) {
case InputKeyBack:
processing = false;
break;
case InputKeyRight:
if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) {
arkanoid_state->xPaddle += 8;
}
break;
case InputKeyLeft:
if(arkanoid_state->xPaddle > 0) {
arkanoid_state->xPaddle -= 8;
}
break;
case InputKeyUp:
if(arkanoid_state->speed < MAX_SPEED) {
arkanoid_state->speed++;
}
break;
case InputKeyDown:
if(arkanoid_state->speed > 1) {
arkanoid_state->speed--;
}
break;
case InputKeyOk:
if(arkanoid_state->gameStarted == false) {
//Release ball if FIRE pressed
arkanoid_state->ball_state.released = true;
//Apply random direction to ball on release
if(rand_range(0, 2) == 0) {
arkanoid_state->ball_state.dx = 1;
} else {
arkanoid_state->ball_state.dx = -1;
}
//Makes sure the ball heads upwards
arkanoid_state->ball_state.dy = -1;
//start the game flag
arkanoid_state->gameStarted = true;
}
break;
default:
break;
}
}
}
}
view_port_update(view_port);
furi_mutex_release(arkanoid_state->mutex);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
view_port_free(view_port);
furi_mutex_free(arkanoid_state->mutex);
free_and_exit:
free(arkanoid_state);
furi_message_queue_free(event_queue);
return return_code;
}

View File

@@ -1,15 +0,0 @@
App(
appid="calculator",
name="Calculator",
apptype=FlipperAppType.EXTERNAL,
entry_point="calculator_app",
cdefines=["APP_CALCULATOR"],
requires=["gui"],
stack_size=1 * 1024,
fap_icon="calcIcon.png",
fap_category="Tools",
fap_author="@n-o-T-I-n-s-a-n-e",
fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e",
fap_version="1.0",
fap_description="Calculator, that can calculate simple expressions",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,458 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <stdbool.h> // Header-file for boolean data-type.
#include <string.h> // Header-file for string functions.
#include "tinyexpr.h" // Header-file for the TinyExpr library.
#include <stdio.h>
#include <stdlib.h>
const short MAX_TEXT_LENGTH = 20;
typedef struct {
short x;
short y;
} selectedPosition;
typedef struct {
FuriMutex* mutex;
selectedPosition position;
//string with the inputted calculator text
char text[20];
short textLength;
char log[20];
} Calculator;
char getKeyAtPosition(short x, short y) {
if(x == 0 && y == 0) {
return 'C';
}
if(x == 1 && y == 0) {
return '<';
}
if(x == 2 && y == 0) {
return '%';
}
if(x == 3 && y == 0) {
return '/';
}
if(x == 0 && y == 1) {
return '1';
}
if(x == 1 && y == 1) {
return '2';
}
if(x == 2 && y == 1) {
return '3';
}
if(x == 3 && y == 1) {
return '*';
}
if(x == 0 && y == 2) {
return '4';
}
if(x == 1 && y == 2) {
return '5';
}
if(x == 2 && y == 2) {
return '6';
}
if(x == 3 && y == 2) {
return '-';
}
if(x == 0 && y == 3) {
return '7';
}
if(x == 1 && y == 3) {
return '8';
}
if(x == 2 && y == 3) {
return '9';
}
if(x == 3 && y == 3) {
return '+';
}
if(x == 0 && y == 4) {
return '(';
}
if(x == 1 && y == 4) {
return '0';
}
if(x == 2 && y == 4) {
return '.';
}
if(x == 3 && y == 4) {
return '=';
}
return ' ';
}
short calculateStringWidth(const char* str, short lenght) {
/* widths:
1 = 2
2, 3, 4, 5, 6, 7, 8, 9, 0, X, -, +, . = = 5
%, / = 7
S = 5
(, ) = 3
*/
short width = 0;
for(short i = 0; i < lenght; i++) {
switch(str[i]) {
case '1':
width += 2;
break;
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
case '*':
case '-':
case '+':
case '.':
width += 5;
break;
case '%':
case '/':
width += 7;
break;
case 'S':
width += 5;
break;
case '(':
case ')':
width += 3;
break;
default:
break;
}
width += 1;
}
return width;
}
void generate_calculator_layout(Canvas* canvas) {
//draw dotted lines
for(int i = 0; i <= 64; i++) {
if(i % 2 == 0) {
canvas_draw_dot(canvas, i, 14);
canvas_draw_dot(canvas, i, 33);
}
if(i % 2 == 1) {
canvas_draw_dot(canvas, i, 15);
canvas_draw_dot(canvas, i, 34);
}
}
//draw horizontal lines
canvas_draw_box(canvas, 0, 41, 64, 2);
canvas_draw_box(canvas, 0, 57, 64, 2);
canvas_draw_box(canvas, 0, 73, 64, 2);
canvas_draw_box(canvas, 0, 89, 64, 2);
canvas_draw_box(canvas, 0, 105, 64, 2);
canvas_draw_box(canvas, 0, 121, 64, 2);
//draw vertical lines
canvas_draw_box(canvas, 0, 43, 1, 80);
canvas_draw_box(canvas, 15, 43, 2, 80);
canvas_draw_box(canvas, 31, 43, 2, 80);
canvas_draw_box(canvas, 47, 43, 2, 80);
canvas_draw_box(canvas, 63, 43, 1, 80);
//draw buttons
//row 1 (C, ;, %, ÷)
canvas_draw_str(canvas, 5, 54, "C");
canvas_draw_str(canvas, 19, 54, " <-");
canvas_draw_str(canvas, 35, 54, " %");
canvas_draw_str(canvas, 51, 54, " /");
//row 2 (1, 2, 3, X)
canvas_draw_str(canvas, 5, 70, " 1");
canvas_draw_str(canvas, 19, 70, " 2");
canvas_draw_str(canvas, 35, 70, " 3");
canvas_draw_str(canvas, 51, 70, " X");
//row 3 (4, 5, 6, -)
canvas_draw_str(canvas, 5, 86, " 4");
canvas_draw_str(canvas, 19, 86, " 5");
canvas_draw_str(canvas, 35, 86, " 6");
canvas_draw_str(canvas, 51, 86, " -");
//row 4 (7, 8, 9, +)
canvas_draw_str(canvas, 5, 102, " 7");
canvas_draw_str(canvas, 19, 102, " 8");
canvas_draw_str(canvas, 35, 102, " 9");
canvas_draw_str(canvas, 51, 102, " +");
//row 5 (+/-, 0, ., =)
canvas_draw_str(canvas, 3, 118, "( )");
canvas_draw_str(canvas, 19, 118, " 0");
canvas_draw_str(canvas, 35, 118, " .");
canvas_draw_str(canvas, 51, 118, " =");
}
void calculator_draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
const Calculator* calculator_state = ctx;
furi_mutex_acquire(calculator_state->mutex, FuriWaitForever);
canvas_clear(canvas);
//show selected button
short startX = 1;
short startY = 43;
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(
canvas,
startX + (calculator_state->position.x) * 16,
(startY) + (calculator_state->position.y) * 16,
16,
16);
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(
canvas,
startX + (calculator_state->position.x) * 16 + 2,
(startY) + (calculator_state->position.y) * 16 + 2,
10,
10);
canvas_set_color(canvas, ColorBlack);
generate_calculator_layout(canvas);
//draw text
short stringWidth = calculateStringWidth(calculator_state->text, calculator_state->textLength);
short startingPosition = 5;
if(stringWidth > 60) {
startingPosition += 60 - (stringWidth + 5);
}
canvas_set_color(canvas, ColorBlack);
canvas_draw_str(canvas, startingPosition, 28, calculator_state->text);
//canvas_draw_str(canvas, 10, 10, calculator_state->log);
//draw cursor
canvas_draw_box(canvas, stringWidth + 5, 29, 5, 1);
furi_mutex_release(calculator_state->mutex);
}
void calculator_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
void calculate(Calculator* calculator_state) {
double result;
result = te_interp(calculator_state->text, 0);
calculator_state->textLength = 0;
calculator_state->text[0] = '\0';
// sprintf(calculator_state->text, "%f", result);
//invert sign if negative
if(result < 0) {
calculator_state->text[calculator_state->textLength++] = '-';
result = -result;
}
//get numbers before and after decimal
int beforeDecimal = result;
int afterDecimal = (result - beforeDecimal) * 100;
char beforeDecimalString[10];
char afterDecimalString[10];
int i = 0;
//parse to a string
while(beforeDecimal > 0) {
beforeDecimalString[i++] = beforeDecimal % 10 + '0';
beforeDecimal /= 10;
}
// invert string
for(int j = 0; j < i / 2; j++) {
char temp = beforeDecimalString[j];
beforeDecimalString[j] = beforeDecimalString[i - j - 1];
beforeDecimalString[i - j - 1] = temp;
}
//add it to the answer
for(int j = 0; j < i; j++) {
calculator_state->text[calculator_state->textLength++] = beforeDecimalString[j];
}
i = 0;
if(afterDecimal > 0) {
while(afterDecimal > 0) {
afterDecimalString[i++] = afterDecimal % 10 + '0';
afterDecimal /= 10;
}
// invert string
for(int j = 0; j < i / 2; j++) {
char temp = afterDecimalString[j];
afterDecimalString[j] = afterDecimalString[i - j - 1];
afterDecimalString[i - j - 1] = temp;
}
//add decimal point
calculator_state->text[calculator_state->textLength++] = '.';
//add numbers after decimal
for(int j = 0; j < i; j++) {
calculator_state->text[calculator_state->textLength++] = afterDecimalString[j];
}
}
calculator_state->text[calculator_state->textLength] = '\0';
}
int32_t calculator_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
Calculator* calculator_state = malloc(sizeof(Calculator));
calculator_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!calculator_state->mutex) {
//FURI_LOG_E("calculator", "cannot create mutex\r\n");
free(calculator_state);
return -1;
}
// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, calculator_draw_callback, calculator_state);
view_port_input_callback_set(view_port, calculator_input_callback, event_queue);
view_port_set_orientation(view_port, ViewPortOrientationVertical);
// Register view port in GUI
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
//NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
InputEvent event;
while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
//break out of the loop if the back key is pressed
if(event.type == InputTypeShort && event.key == InputKeyBack) {
break;
}
if(event.type == InputTypeShort) {
switch(event.key) {
case InputKeyUp:
if(calculator_state->position.y > 0) {
calculator_state->position.y--;
}
break;
case InputKeyDown:
if(calculator_state->position.y < 4) {
calculator_state->position.y++;
}
break;
case InputKeyLeft:
if(calculator_state->position.x > 0) {
calculator_state->position.x--;
}
break;
case InputKeyRight:
if(calculator_state->position.x < 3) {
calculator_state->position.x++;
}
break;
case InputKeyOk: {
//add the selected button to the text
//char* text = calculator_state->text;
// short* textLength = &calculator_state->textLength;
char key =
getKeyAtPosition(calculator_state->position.x, calculator_state->position.y);
switch(key) {
case 'C':
while(calculator_state->textLength > 0) {
calculator_state->text[calculator_state->textLength--] = '\0';
}
calculator_state->text[0] = '\0';
calculator_state->log[2] = key;
break;
case '<':
calculator_state->log[2] = key;
if(calculator_state->textLength > 0) {
calculator_state->text[--calculator_state->textLength] = '\0';
} else {
calculator_state->text[0] = '\0';
}
break;
case '=':
calculator_state->log[2] = key;
calculate(calculator_state);
break;
case '%':
case '/':
case '*':
case '-':
case '+':
case '.':
case '(':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
if(calculator_state->textLength < MAX_TEXT_LENGTH) {
calculator_state->text[calculator_state->textLength++] = key;
calculator_state->text[calculator_state->textLength] = '\0';
}
//calculator_state->log[1] = calculator_state->text[*textLength];
break;
default:
break;
}
}
default:
break;
}
view_port_update(view_port);
}
if(event.type == InputTypeLong) {
switch(event.key) {
case InputKeyOk:
if(calculator_state->position.x == 0 && calculator_state->position.y == 4) {
if(calculator_state->textLength < MAX_TEXT_LENGTH) {
calculator_state->text[calculator_state->textLength++] = ')';
calculator_state->text[calculator_state->textLength] = '\0';
}
view_port_update(view_port);
}
break;
default:
break;
}
}
}
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_mutex_free(calculator_state->mutex);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_GUI);
free(calculator_state);
return 0;
}

View File

@@ -1,786 +0,0 @@
// SPDX-License-Identifier: Zlib
/*
* TINYEXPR - Tiny recursive descent parser and evaluation engine in C
*
* Copyright (c) 2015-2020 Lewis Van Winkle
*
* http://CodePlea.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/* COMPILE TIME OPTIONS */
/* Exponentiation associativity:
For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
/* #define TE_POW_FROM_RIGHT */
/* Logarithms
For log = base 10 log do nothing
For log = natural log uncomment the next line. */
/* #define TE_NAT_LOG */
#include "tinyexpr.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#ifndef NAN
#define NAN (0.0 / 0.0)
#endif
#ifndef INFINITY
#define INFINITY (1.0 / 0.0)
#endif
typedef double (*te_fun2)(double, double);
enum {
TOK_NULL = TE_CLOSURE7 + 1,
TOK_ERROR,
TOK_END,
TOK_SEP,
TOK_OPEN,
TOK_CLOSE,
TOK_NUMBER,
TOK_VARIABLE,
TOK_INFIX
};
enum { TE_CONSTANT = 1 };
typedef struct state {
const char* start;
const char* next;
int type;
union {
double value;
const double* bound;
const void* function;
};
void* context;
const te_variable* lookup;
int lookup_len;
} state;
#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F)
#define IS_PURE(TYPE) (((TYPE)&TE_FLAG_PURE) != 0)
#define IS_FUNCTION(TYPE) (((TYPE)&TE_FUNCTION0) != 0)
#define IS_CLOSURE(TYPE) (((TYPE)&TE_CLOSURE0) != 0)
#define ARITY(TYPE) (((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE)&0x00000007) : 0)
#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__})
static te_expr* new_expr(const int type, const te_expr* parameters[]) {
const int arity = ARITY(type);
const int psize = sizeof(void*) * arity;
const int size =
(sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0);
te_expr* ret = malloc(size);
memset(ret, 0, size);
if(arity && parameters) {
memcpy(ret->parameters, parameters, psize);
}
ret->type = type;
ret->bound = 0;
return ret;
}
void te_free_parameters(te_expr* n) {
if(!n) return;
switch(TYPE_MASK(n->type)) {
case TE_FUNCTION7:
case TE_CLOSURE7:
te_free(n->parameters[6]); /* Falls through. */
case TE_FUNCTION6:
case TE_CLOSURE6:
te_free(n->parameters[5]); /* Falls through. */
case TE_FUNCTION5:
case TE_CLOSURE5:
te_free(n->parameters[4]); /* Falls through. */
case TE_FUNCTION4:
case TE_CLOSURE4:
te_free(n->parameters[3]); /* Falls through. */
case TE_FUNCTION3:
case TE_CLOSURE3:
te_free(n->parameters[2]); /* Falls through. */
case TE_FUNCTION2:
case TE_CLOSURE2:
te_free(n->parameters[1]); /* Falls through. */
case TE_FUNCTION1:
case TE_CLOSURE1:
te_free(n->parameters[0]);
}
}
void te_free(te_expr* n) {
if(!n) return;
te_free_parameters(n);
free(n);
}
static double pi(void) {
return 3.14159265358979323846;
}
static double e(void) {
return 2.71828182845904523536;
}
static double fac(double a) { /* simplest version of fac */
if(a < (double)0.0) return NAN;
if(a > UINT_MAX) return INFINITY;
unsigned int ua = (unsigned int)(a);
unsigned long int result = 1, i;
for(i = 1; i <= ua; i++) {
if(i > ULONG_MAX / result) return INFINITY;
result *= i;
}
return (double)result;
}
static double ncr(double n, double r) {
if(n < (double)0.0 || r < (double)0.0 || n < r) return NAN;
if(n > UINT_MAX || r > UINT_MAX) return INFINITY;
unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i;
unsigned long int result = 1;
if(ur > un / 2) ur = un - ur;
for(i = 1; i <= ur; i++) {
if(result > ULONG_MAX / (un - ur + i)) return INFINITY;
result *= un - ur + i;
result /= i;
}
return result;
}
static double npr(double n, double r) {
return ncr(n, r) * fac(r);
}
#ifdef _MSC_VER
#pragma function(ceil)
#pragma function(floor)
#endif
static const te_variable functions[] = {
/* must be in alphabetical order */
{"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0},
{"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#ifdef TE_NAT_LOG
{"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#else
{"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#endif
{"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0},
{"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{0, 0, 0, 0}};
static const te_variable* find_builtin(const char* name, int len) {
int imin = 0;
int imax = sizeof(functions) / sizeof(te_variable) - 2;
/*Binary search.*/
while(imax >= imin) {
const int i = (imin + ((imax - imin) / 2));
int c = strncmp(name, functions[i].name, len);
if(!c) c = '\0' - functions[i].name[len];
if(c == 0) {
return functions + i;
} else if(c > 0) {
imin = i + 1;
} else {
imax = i - 1;
}
}
return 0;
}
static const te_variable* find_lookup(const state* s, const char* name, int len) {
int iters;
const te_variable* var;
if(!s->lookup) return 0;
for(var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
if(strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
return var;
}
}
return 0;
}
static double add(double a, double b) {
return a + b;
}
static double sub(double a, double b) {
return a - b;
}
static double mul(double a, double b) {
return a * b;
}
static double divide(double a, double b) {
return a / b;
}
static double negate(double a) {
return -a;
}
static double comma(double a, double b) {
(void)a;
return b;
}
void next_token(state* s) {
s->type = TOK_NULL;
do {
if(!*s->next) {
s->type = TOK_END;
return;
}
/* Try reading a number. */
if((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
s->value = strtof(s->next, (char**)&s->next);
s->type = TOK_NUMBER;
} else {
/* Look for a variable or builtin function call. */
if(isalpha((int)s->next[0])) {
const char* start;
start = s->next;
while(isalpha((int)s->next[0]) || isdigit((int)s->next[0]) || (s->next[0] == '_'))
s->next++;
const te_variable* var = find_lookup(s, start, s->next - start);
if(!var) var = find_builtin(start, s->next - start);
if(!var) {
s->type = TOK_ERROR;
} else {
switch(TYPE_MASK(var->type)) {
case TE_VARIABLE:
s->type = TOK_VARIABLE;
s->bound = var->address;
break;
case TE_CLOSURE0:
case TE_CLOSURE1:
case TE_CLOSURE2:
case TE_CLOSURE3: /* Falls through. */
case TE_CLOSURE4:
case TE_CLOSURE5:
case TE_CLOSURE6:
case TE_CLOSURE7: /* Falls through. */
s->context = var->context; /* Falls through. */
case TE_FUNCTION0:
case TE_FUNCTION1:
case TE_FUNCTION2:
case TE_FUNCTION3: /* Falls through. */
case TE_FUNCTION4:
case TE_FUNCTION5:
case TE_FUNCTION6:
case TE_FUNCTION7: /* Falls through. */
s->type = var->type;
s->function = var->address;
break;
}
}
} else {
/* Look for an operator or special character. */
switch(s->next++[0]) {
case '+':
s->type = TOK_INFIX;
s->function = add;
break;
case '-':
s->type = TOK_INFIX;
s->function = sub;
break;
case '*':
s->type = TOK_INFIX;
s->function = mul;
break;
case '/':
s->type = TOK_INFIX;
s->function = divide;
break;
case '^':
s->type = TOK_INFIX;
s->function = pow;
break;
case '%':
s->type = TOK_INFIX;
s->function = fmod;
break;
case '(':
s->type = TOK_OPEN;
break;
case ')':
s->type = TOK_CLOSE;
break;
case ',':
s->type = TOK_SEP;
break;
case ' ':
case '\t':
case '\n':
case '\r':
break;
default:
s->type = TOK_ERROR;
break;
}
}
}
} while(s->type == TOK_NULL);
}
static te_expr* list(state* s);
static te_expr* expr(state* s);
static te_expr* power(state* s);
static te_expr* base(state* s) {
/* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
te_expr* ret;
int arity;
switch(TYPE_MASK(s->type)) {
case TOK_NUMBER:
ret = new_expr(TE_CONSTANT, 0);
ret->value = s->value;
next_token(s);
break;
case TOK_VARIABLE:
ret = new_expr(TE_VARIABLE, 0);
ret->bound = s->bound;
next_token(s);
break;
case TE_FUNCTION0:
case TE_CLOSURE0:
ret = new_expr(s->type, 0);
ret->function = s->function;
if(IS_CLOSURE(s->type)) ret->parameters[0] = s->context;
next_token(s);
if(s->type == TOK_OPEN) {
next_token(s);
if(s->type != TOK_CLOSE) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
}
break;
case TE_FUNCTION1:
case TE_CLOSURE1:
ret = new_expr(s->type, 0);
ret->function = s->function;
if(IS_CLOSURE(s->type)) ret->parameters[1] = s->context;
next_token(s);
ret->parameters[0] = power(s);
break;
case TE_FUNCTION2:
case TE_FUNCTION3:
case TE_FUNCTION4:
case TE_FUNCTION5:
case TE_FUNCTION6:
case TE_FUNCTION7:
case TE_CLOSURE2:
case TE_CLOSURE3:
case TE_CLOSURE4:
case TE_CLOSURE5:
case TE_CLOSURE6:
case TE_CLOSURE7:
arity = ARITY(s->type);
ret = new_expr(s->type, 0);
ret->function = s->function;
if(IS_CLOSURE(s->type)) ret->parameters[arity] = s->context;
next_token(s);
if(s->type != TOK_OPEN) {
s->type = TOK_ERROR;
} else {
int i;
for(i = 0; i < arity; i++) {
next_token(s);
ret->parameters[i] = expr(s);
if(s->type != TOK_SEP) {
break;
}
}
if(s->type != TOK_CLOSE || i != arity - 1) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
}
break;
case TOK_OPEN:
next_token(s);
ret = list(s);
if(s->type != TOK_CLOSE) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
break;
default:
ret = new_expr(0, 0);
s->type = TOK_ERROR;
ret->value = NAN;
break;
}
return ret;
}
static te_expr* power(state* s) {
/* <power> = {("-" | "+")} <base> */
int sign = 1;
while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
if(s->function == sub) sign = -sign;
next_token(s);
}
te_expr* ret;
if(sign == 1) {
ret = base(s);
} else {
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
ret->function = negate;
}
return ret;
}
#ifdef TE_POW_FROM_RIGHT
static te_expr* factor(state* s) {
/* <factor> = <power> {"^" <power>} */
te_expr* ret = power(s);
int neg = 0;
if(ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
te_expr* se = ret->parameters[0];
free(ret);
ret = se;
neg = 1;
}
te_expr* insertion = 0;
while(s->type == TOK_INFIX && (s->function == pow)) {
te_fun2 t = s->function;
next_token(s);
if(insertion) {
/* Make exponentiation go right-to-left. */
te_expr* insert =
NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
insert->function = t;
insertion->parameters[1] = insert;
insertion = insert;
} else {
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
ret->function = t;
insertion = ret;
}
}
if(neg) {
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
ret->function = negate;
}
return ret;
}
#else
static te_expr* factor(state* s) {
/* <factor> = <power> {"^" <power>} */
te_expr* ret = power(s);
while(s->type == TOK_INFIX && (s->function == pow)) {
te_fun2 t = s->function;
next_token(s);
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
ret->function = t;
}
return ret;
}
#endif
static te_expr* term(state* s) {
/* <term> = <factor> {("*" | "/" | "%") <factor>} */
te_expr* ret = factor(s);
while(s->type == TOK_INFIX &&
(s->function == mul || s->function == divide || s->function == fmod)) {
te_fun2 t = s->function;
next_token(s);
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
ret->function = t;
}
return ret;
}
static te_expr* expr(state* s) {
/* <expr> = <term> {("+" | "-") <term>} */
te_expr* ret = term(s);
while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
te_fun2 t = s->function;
next_token(s);
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
ret->function = t;
}
return ret;
}
static te_expr* list(state* s) {
/* <list> = <expr> {"," <expr>} */
te_expr* ret = expr(s);
while(s->type == TOK_SEP) {
next_token(s);
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
ret->function = comma;
}
return ret;
}
#define TE_FUN(...) ((double (*)(__VA_ARGS__))n->function)
#define M(e) te_eval(n->parameters[e])
double te_eval(const te_expr* n) {
if(!n) return NAN;
switch(TYPE_MASK(n->type)) {
case TE_CONSTANT:
return n->value;
case TE_VARIABLE:
return *n->bound;
case TE_FUNCTION0:
case TE_FUNCTION1:
case TE_FUNCTION2:
case TE_FUNCTION3:
case TE_FUNCTION4:
case TE_FUNCTION5:
case TE_FUNCTION6:
case TE_FUNCTION7:
switch(ARITY(n->type)) {
case 0:
return TE_FUN(void)();
case 1:
return TE_FUN(double)(M(0));
case 2:
return TE_FUN(double, double)(M(0), M(1));
case 3:
return TE_FUN(double, double, double)(M(0), M(1), M(2));
case 4:
return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3));
case 5:
return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4));
case 6:
return TE_FUN(double, double, double, double, double, double)(
M(0), M(1), M(2), M(3), M(4), M(5));
case 7:
return TE_FUN(double, double, double, double, double, double, double)(
M(0), M(1), M(2), M(3), M(4), M(5), M(6));
default:
return NAN;
}
case TE_CLOSURE0:
case TE_CLOSURE1:
case TE_CLOSURE2:
case TE_CLOSURE3:
case TE_CLOSURE4:
case TE_CLOSURE5:
case TE_CLOSURE6:
case TE_CLOSURE7:
switch(ARITY(n->type)) {
case 0:
return TE_FUN(void*)(n->parameters[0]);
case 1:
return TE_FUN(void*, double)(n->parameters[1], M(0));
case 2:
return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1));
case 3:
return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2));
case 4:
return TE_FUN(void*, double, double, double, double)(
n->parameters[4], M(0), M(1), M(2), M(3));
case 5:
return TE_FUN(void*, double, double, double, double, double)(
n->parameters[5], M(0), M(1), M(2), M(3), M(4));
case 6:
return TE_FUN(void*, double, double, double, double, double, double)(
n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5));
case 7:
return TE_FUN(void*, double, double, double, double, double, double, double)(
n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6));
default:
return NAN;
}
default:
return NAN;
}
}
#undef TE_FUN
#undef M
static void optimize(te_expr* n) {
/* Evaluates as much as possible. */
if(n->type == TE_CONSTANT) return;
if(n->type == TE_VARIABLE) return;
/* Only optimize out functions flagged as pure. */
if(IS_PURE(n->type)) {
const int arity = ARITY(n->type);
int known = 1;
int i;
for(i = 0; i < arity; ++i) {
optimize(n->parameters[i]);
if(((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) {
known = 0;
}
}
if(known) {
const double value = te_eval(n);
te_free_parameters(n);
n->type = TE_CONSTANT;
n->value = value;
}
}
}
te_expr*
te_compile(const char* expression, const te_variable* variables, int var_count, int* error) {
state s;
s.start = s.next = expression;
s.lookup = variables;
s.lookup_len = var_count;
next_token(&s);
te_expr* root = list(&s);
if(s.type != TOK_END) {
te_free(root);
if(error) {
*error = (s.next - s.start);
if(*error == 0) *error = 1;
}
return 0;
} else {
optimize(root);
if(error) *error = 0;
return root;
}
}
double te_interp(const char* expression, int* error) {
te_expr* n = te_compile(expression, 0, 0, error);
double ret;
if(n) {
ret = te_eval(n);
te_free(n);
} else {
ret = NAN;
}
return ret;
}
static void pn(const te_expr* n, int depth) {
int i, arity;
printf("%*s", depth, "");
switch(TYPE_MASK(n->type)) {
case TE_CONSTANT:
printf("%f\n", n->value);
break;
case TE_VARIABLE:
printf("bound %p\n", n->bound);
break;
case TE_FUNCTION0:
case TE_FUNCTION1:
case TE_FUNCTION2:
case TE_FUNCTION3:
case TE_FUNCTION4:
case TE_FUNCTION5:
case TE_FUNCTION6:
case TE_FUNCTION7:
case TE_CLOSURE0:
case TE_CLOSURE1:
case TE_CLOSURE2:
case TE_CLOSURE3:
case TE_CLOSURE4:
case TE_CLOSURE5:
case TE_CLOSURE6:
case TE_CLOSURE7:
arity = ARITY(n->type);
printf("f%d", arity);
for(i = 0; i < arity; i++) {
printf(" %p", n->parameters[i]);
}
printf("\n");
for(i = 0; i < arity; i++) {
pn(n->parameters[i], depth + 1);
}
break;
}
}
void te_print(const te_expr* n) {
pn(n, 0);
}

View File

@@ -1,97 +0,0 @@
// SPDX-License-Identifier: Zlib
/*
* TINYEXPR - Tiny recursive descent parser and evaluation engine in C
*
* Copyright (c) 2015-2020 Lewis Van Winkle
*
* http://CodePlea.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TINYEXPR_H
#define TINYEXPR_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct te_expr {
int type;
union {
double value;
const double* bound;
const void* function;
};
void* parameters[1];
} te_expr;
enum {
TE_VARIABLE = 0,
TE_FUNCTION0 = 8,
TE_FUNCTION1,
TE_FUNCTION2,
TE_FUNCTION3,
TE_FUNCTION4,
TE_FUNCTION5,
TE_FUNCTION6,
TE_FUNCTION7,
TE_CLOSURE0 = 16,
TE_CLOSURE1,
TE_CLOSURE2,
TE_CLOSURE3,
TE_CLOSURE4,
TE_CLOSURE5,
TE_CLOSURE6,
TE_CLOSURE7,
TE_FLAG_PURE = 32
};
typedef struct te_variable {
const char* name;
const void* address;
int type;
void* context;
} te_variable;
/* Parses the input expression, evaluates it, and frees it. */
/* Returns NaN on error. */
double te_interp(const char* expression, int* error);
/* Parses the input expression and binds variables. */
/* Returns NULL on error. */
te_expr*
te_compile(const char* expression, const te_variable* variables, int var_count, int* error);
/* Evaluates the expression. */
double te_eval(const te_expr* n);
/* Prints debugging information on the syntax tree. */
void te_print(const te_expr* n);
/* Frees the expression. */
/* This is safe to call on NULL pointers. */
void te_free(te_expr* n);
#ifdef __cplusplus
}
#endif
#endif /*TINYEXPR_H*/

View File

@@ -1,17 +0,0 @@
App(
appid="doom",
name="DOOM",
apptype=FlipperAppType.EXTERNAL,
entry_point="doom_app",
requires=[
"gui",
"music_player",
],
stack_size=4 * 1024,
fap_icon="doom_10px.png",
fap_category="Games",
fap_icon_assets="assets",
fap_author="@xMasterX & @Svarich & @hedger (original code by @p4nic4ttack)",
fap_version="1.0",
fap_description="Will it run Doom?",
)

View File

@@ -1,331 +0,0 @@
#include "assets.h"
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};

View File

@@ -1,108 +0,0 @@
#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 128
#define BMP_LOGO_HEIGHT 64
#define GRADIENT_WIDTH 2
#define GRADIENT_HEIGHT 8
#define GRADIENT_COUNT 8
#define GRADIENT_WHITE 7
#define GRADIENT_BLACK 0
// 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 847 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -1,91 +0,0 @@
#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 20
// 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

View File

@@ -1,281 +0,0 @@
#include <gui/gui.h>
#include <furi_hal.h>
#include "constants.h"
#include "doom_icons.h"
#include <assets_icons.h>
#include "assets.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();
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
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) {
UNUSED(intensity);
uint8_t dots = end_y - start_y;
for(int i = 0; i < dots; i++) {
canvas_draw_dot(canvas, x, start_y + i);
}
}
void drawBitmap(
int16_t x,
int16_t y,
const Icon* i,
int16_t w,
int16_t h,
uint16_t color,
Canvas* const canvas) {
UNUSED(w);
UNUSED(h);
if(!color) {
canvas_invert_color(canvas);
}
canvas_draw_icon(canvas, x, y, i);
if(!color) {
canvas_invert_color(canvas);
}
}
void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas) {
char buf[4];
snprintf(buf, 4, "%d", num);
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 diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,504 +0,0 @@
#include "doom_music_player_worker.h"
#include <furi_hal.h>
#include <furi.h>
#include <storage/storage.h>
#include <lib/flipper_format/flipper_format.h>
#include <m-array.h>
#define TAG "MusicPlayerWorker"
#define MUSIC_PLAYER_FILETYPE "Flipper Music Format"
#define MUSIC_PLAYER_VERSION 0
#define SEMITONE_PAUSE 0xFF
#define NOTE_C4 261.63f
#define NOTE_C4_SEMITONE (4.0f * 12.0f)
#define TWO_POW_TWELTH_ROOT 1.059463094359f
typedef struct {
uint8_t semitone;
uint8_t duration;
uint8_t dots;
} NoteBlock;
ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST);
struct MusicPlayerWorker {
FuriThread* thread;
bool should_work;
MusicPlayerWorkerCallback callback;
void* callback_context;
float volume;
uint32_t bpm;
uint32_t duration;
uint32_t octave;
NoteBlockArray_t notes;
};
static int32_t music_player_worker_thread_callback(void* context) {
furi_assert(context);
MusicPlayerWorker* instance = context;
NoteBlockArray_it_t it;
NoteBlockArray_it(it, instance->notes);
if(furi_hal_speaker_acquire(1000)) {
while(instance->should_work) {
if(NoteBlockArray_end_p(it)) {
NoteBlockArray_it(it, instance->notes);
furi_delay_ms(10);
} else {
NoteBlock* note_block = NoteBlockArray_ref(it);
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm /
note_block->duration;
uint32_t dots = note_block->dots;
while(dots > 0) {
duration += duration / 2;
dots--;
}
uint32_t next_tick = furi_get_tick() + duration;
float volume = instance->volume;
if(instance->callback) {
instance->callback(
note_block->semitone,
note_block->dots,
note_block->duration,
0.0,
instance->callback_context);
}
furi_hal_speaker_stop();
furi_hal_speaker_start(frequency, volume);
while(instance->should_work && furi_get_tick() < next_tick) {
volume *= 0.9945679;
furi_hal_speaker_set_volume(volume);
furi_delay_ms(2);
}
NoteBlockArray_next(it);
}
}
furi_hal_speaker_stop();
furi_hal_speaker_release();
} else {
FURI_LOG_E(TAG, "Speaker system is busy with another process.");
}
return 0;
}
MusicPlayerWorker* music_player_worker_alloc() {
MusicPlayerWorker* instance = malloc(sizeof(MusicPlayerWorker));
NoteBlockArray_init(instance->notes);
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "MusicPlayerWorker");
furi_thread_set_stack_size(instance->thread, 1024);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, music_player_worker_thread_callback);
instance->volume = 1.0f;
return instance;
}
void music_player_worker_free(MusicPlayerWorker* instance) {
furi_assert(instance);
furi_thread_free(instance->thread);
NoteBlockArray_clear(instance->notes);
free(instance);
}
static bool is_digit(const char c) {
return isdigit(c) != 0;
}
static bool is_letter(const char c) {
return islower(c) != 0 || isupper(c) != 0;
}
static bool is_space(const char c) {
return c == ' ' || c == '\t';
}
static size_t extract_number(const char* string, uint32_t* number) {
size_t ret = 0;
while(is_digit(*string)) {
*number *= 10;
*number += (*string - '0');
string++;
ret++;
}
return ret;
}
static size_t extract_dots(const char* string, uint32_t* number) {
size_t ret = 0;
while(*string == '.') {
*number += 1;
string++;
ret++;
}
return ret;
}
static size_t extract_char(const char* string, char* symbol) {
if(is_letter(*string)) {
*symbol = *string;
return 1;
} else {
return 0;
}
}
static size_t extract_sharp(const char* string, char* symbol) {
if(*string == '#' || *string == '_') {
*symbol = '#';
return 1;
} else {
return 0;
}
}
static size_t skip_till(const char* string, const char symbol) {
size_t ret = 0;
while(*string != '\0' && *string != symbol) {
string++;
ret++;
}
if(*string != symbol) {
ret = 0;
}
return ret;
}
static bool music_player_worker_add_note(
MusicPlayerWorker* instance,
uint8_t semitone,
uint8_t duration,
uint8_t dots) {
NoteBlock note_block;
note_block.semitone = semitone;
note_block.duration = duration;
note_block.dots = dots;
NoteBlockArray_push_back(instance->notes, note_block);
return true;
}
static int8_t note_to_semitone(const char note) {
switch(note) {
case 'C':
return 0;
// C#
case 'D':
return 2;
// D#
case 'E':
return 4;
case 'F':
return 5;
// F#
case 'G':
return 7;
// G#
case 'A':
return 9;
// A#
case 'B':
return 11;
default:
return 0;
}
}
static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const char* string) {
const char* cursor = string;
bool result = true;
while(*cursor != '\0') {
if(!is_space(*cursor)) {
uint32_t duration = 0;
char note_char = '\0';
char sharp_char = '\0';
uint32_t octave = 0;
uint32_t dots = 0;
// Parsing
cursor += extract_number(cursor, &duration);
cursor += extract_char(cursor, &note_char);
cursor += extract_sharp(cursor, &sharp_char);
cursor += extract_number(cursor, &octave);
cursor += extract_dots(cursor, &dots);
// Post processing
note_char = toupper(note_char);
if(!duration) {
duration = instance->duration;
}
if(!octave) {
octave = instance->octave;
}
// Validation
bool is_valid = true;
is_valid &= (duration >= 1 && duration <= 128);
is_valid &= ((note_char >= 'A' && note_char <= 'G') || note_char == 'P');
is_valid &= (sharp_char == '#' || sharp_char == '\0');
is_valid &= (octave <= 16);
is_valid &= (dots <= 16);
if(!is_valid) {
FURI_LOG_E(
TAG,
"Invalid note: %lu%c%c%lu.%lu",
duration,
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots);
result = false;
break;
}
// Note to semitones
uint8_t semitone = 0;
if(note_char == 'P') {
semitone = SEMITONE_PAUSE;
} else {
semitone += octave * 12;
semitone += note_to_semitone(note_char);
semitone += sharp_char == '#' ? 1 : 0;
}
if(music_player_worker_add_note(instance, semitone, duration, dots)) {
FURI_LOG_D(
TAG,
"Added note: %c%c%lu.%lu = %u %lu",
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots,
semitone,
duration);
} else {
FURI_LOG_E(
TAG,
"Invalid note: %c%c%lu.%lu = %u %lu",
note_char == '\0' ? '_' : note_char,
sharp_char == '\0' ? '_' : sharp_char,
octave,
dots,
semitone,
duration);
}
cursor += skip_till(cursor, ',');
}
if(*cursor != '\0') cursor++;
}
return result;
}
bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool ret = false;
if(strcasestr(file_path, ".fmf")) {
ret = music_player_worker_load_fmf_from_file(instance, file_path);
} else {
ret = music_player_worker_load_rtttl_from_file(instance, file_path);
}
return ret;
}
bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool result = false;
FuriString* temp_str;
temp_str = furi_string_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* file = flipper_format_file_alloc(storage);
do {
if(!flipper_format_file_open_existing(file, file_path)) break;
uint32_t version = 0;
if(!flipper_format_read_header(file, temp_str, &version)) break;
if(furi_string_cmp_str(temp_str, MUSIC_PLAYER_FILETYPE) ||
(version != MUSIC_PLAYER_VERSION)) {
FURI_LOG_E(TAG, "Incorrect file format or version");
break;
}
if(!flipper_format_read_uint32(file, "BPM", &instance->bpm, 1)) {
FURI_LOG_E(TAG, "BPM is missing");
break;
}
if(!flipper_format_read_uint32(file, "Duration", &instance->duration, 1)) {
FURI_LOG_E(TAG, "Duration is missing");
break;
}
if(!flipper_format_read_uint32(file, "Octave", &instance->octave, 1)) {
FURI_LOG_E(TAG, "Octave is missing");
break;
}
if(!flipper_format_read_string(file, "Notes", temp_str)) {
FURI_LOG_E(TAG, "Notes is missing");
break;
}
if(!music_player_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) {
break;
}
result = true;
} while(false);
furi_record_close(RECORD_STORAGE);
flipper_format_free(file);
furi_string_free(temp_str);
return result;
}
bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path) {
furi_assert(instance);
furi_assert(file_path);
bool result = false;
FuriString* content;
content = furi_string_alloc();
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
do {
if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_E(TAG, "Unable to open file");
break;
};
uint16_t ret = 0;
do {
uint8_t buffer[65] = {0};
ret = storage_file_read(file, buffer, sizeof(buffer) - 1);
for(size_t i = 0; i < ret; i++) {
furi_string_push_back(content, buffer[i]);
}
} while(ret > 0);
furi_string_trim(content);
if(!furi_string_size(content)) {
FURI_LOG_E(TAG, "Empty file");
break;
}
if(!music_player_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) {
FURI_LOG_E(TAG, "Invalid file content");
break;
}
result = true;
} while(0);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
furi_string_free(content);
return result;
}
bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string) {
furi_assert(instance);
const char* cursor = string;
// Skip name
cursor += skip_till(cursor, ':');
if(*cursor != ':') {
return false;
}
// Duration
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->duration);
// Octave
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->octave);
// BPM
cursor += skip_till(cursor, '=');
if(*cursor != '=') {
return false;
}
cursor++;
cursor += extract_number(cursor, &instance->bpm);
// Notes
cursor += skip_till(cursor, ':');
if(*cursor != ':') {
return false;
}
cursor++;
if(!music_player_worker_parse_notes(instance, cursor)) {
return false;
}
return true;
}
void music_player_worker_set_callback(
MusicPlayerWorker* instance,
MusicPlayerWorkerCallback callback,
void* context) {
furi_assert(instance);
instance->callback = callback;
instance->callback_context = context;
}
void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume) {
furi_assert(instance);
instance->volume = volume;
}
void music_player_worker_start(MusicPlayerWorker* instance) {
furi_assert(instance);
furi_assert(instance->should_work == false);
instance->should_work = true;
furi_thread_start(instance->thread);
}
void music_player_worker_stop(MusicPlayerWorker* instance) {
furi_assert(instance);
furi_assert(instance->should_work == true);
instance->should_work = false;
furi_thread_join(instance->thread);
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*MusicPlayerWorkerCallback)(
uint8_t semitone,
uint8_t dots,
uint8_t duration,
float position,
void* context);
typedef struct MusicPlayerWorker MusicPlayerWorker;
MusicPlayerWorker* music_player_worker_alloc();
void music_player_worker_free(MusicPlayerWorker* instance);
bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path);
bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path);
bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path);
bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string);
void music_player_worker_set_callback(
MusicPlayerWorker* instance,
MusicPlayerWorkerCallback callback,
void* context);
void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume);
void music_player_worker_start(MusicPlayerWorker* instance);
void music_player_worker_stop(MusicPlayerWorker* instance);
#ifdef __cplusplus
}
#endif

View File

@@ -1,42 +0,0 @@
#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;
}

View File

@@ -1,56 +0,0 @@
#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

View File

@@ -1,188 +0,0 @@
#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

View File

@@ -1,34 +0,0 @@
#ifndef sound_h
#define sound_h
#include <furi.h>
#include <furi_hal.h>
#include <stdint.h>
#include "doom_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

View File

@@ -1,33 +0,0 @@
#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;
}

View File

@@ -1,36 +0,0 @@
#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

View File

@@ -1,14 +0,0 @@
App(
appid="flappy_bird",
name="Flappy Bird",
apptype=FlipperAppType.EXTERNAL,
entry_point="flappy_game_app",
requires=["gui"],
stack_size=4 * 1024,
fap_icon="flappy_10px.png",
fap_category="Games",
fap_icon_assets="assets",
fap_author="@DroomOne & @xMasterX",
fap_version="1.0",
fap_description="Flappy Bird Game",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,379 +0,0 @@
#include <stdlib.h>
#include "flappy_bird_icons.h"
#include <assets_icons.h>
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <dolphin/dolphin.h>
#define TAG "Flappy"
#define DEBUG false
#define FLAPPY_BIRD_HEIGHT 15
#define FLAPPY_BIRD_WIDTH 10
#define FLAPPY_PILAR_MAX 6
#define FLAPPY_PILAR_DIST 35
#define FLAPPY_GAB_HEIGHT 25
#define FLAPPY_GAB_WIDTH 10
#define FLAPPY_GRAVITY_JUMP -1.1
#define FLAPPY_GRAVITY_TICK 0.15
#define FLIPPER_LCD_WIDTH 128
#define FLIPPER_LCD_HEIGHT 64
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef enum { BirdState0 = 0, BirdState1, BirdState2, BirdStateMAX } BirdState;
const Icon* bird_states[BirdStateMAX] = {
&I_bird_01,
&I_bird_02,
&I_bird_03,
};
typedef struct {
int x;
int y;
} POINT;
typedef struct {
float gravity;
POINT point;
} BIRD;
typedef struct {
POINT point;
int height;
int visible;
bool passed;
} PILAR;
typedef enum {
GameStateLife,
GameStateGameOver,
} State;
typedef struct {
BIRD bird;
int points;
int pilars_count;
PILAR pilars[FLAPPY_PILAR_MAX];
bool debug;
State state;
FuriMutex* mutex;
} GameState;
typedef struct {
EventType type;
InputEvent input;
} GameEvent;
typedef enum {
DirectionUp,
DirectionRight,
DirectionDown,
DirectionLeft,
} Direction;
static void flappy_game_random_pilar(GameState* const game_state) {
PILAR pilar;
pilar.passed = false;
pilar.visible = 1;
pilar.height = random() % (FLIPPER_LCD_HEIGHT - FLAPPY_GAB_HEIGHT) + 1;
pilar.point.y = 0;
pilar.point.x = FLIPPER_LCD_WIDTH + FLAPPY_GAB_WIDTH + 1;
game_state->pilars_count++;
game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX] = pilar;
}
static void flappy_game_state_init(GameState* const game_state) {
BIRD bird;
bird.gravity = 0.0f;
bird.point.x = 15;
bird.point.y = 32;
game_state->debug = DEBUG;
game_state->bird = bird;
game_state->pilars_count = 0;
game_state->points = 0;
game_state->state = GameStateLife;
memset(game_state->pilars, 0, sizeof(game_state->pilars));
flappy_game_random_pilar(game_state);
}
static void flappy_game_state_free(GameState* const game_state) {
free(game_state);
}
static void flappy_game_tick(GameState* const game_state) {
if(game_state->state == GameStateLife) {
if(!game_state->debug) {
game_state->bird.gravity += FLAPPY_GRAVITY_TICK;
game_state->bird.point.y += game_state->bird.gravity;
}
// Checking the location of the last respawned pilar.
PILAR* pilar = &game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX];
if(pilar->point.x == (FLIPPER_LCD_WIDTH - FLAPPY_PILAR_DIST))
flappy_game_random_pilar(game_state);
// Updating the position/status of the pilars (visiblity, posotion, game points)
// | | | | |
// | | | | |
// |__| | |__|
// _____X | X_____
// | | | | | // [Pos + Width of pilar] >= [Bird Pos]
// |_____| | |_____|
// X <----> | X <->
// Bird Pos + Lenght of the bird] >= [Pilar]
for(int i = 0; i < FLAPPY_PILAR_MAX; i++) {
PILAR* pilar = &game_state->pilars[i];
if(pilar != NULL && pilar->visible && game_state->state == GameStateLife) {
pilar->point.x--;
if(game_state->bird.point.x >= pilar->point.x + FLAPPY_GAB_WIDTH &&
pilar->passed == false) {
pilar->passed = true;
game_state->points++;
}
if(pilar->point.x < -FLAPPY_GAB_WIDTH) pilar->visible = 0;
if(game_state->bird.point.y <= 0 - FLAPPY_BIRD_WIDTH) {
game_state->bird.point.y = 64;
}
if(game_state->bird.point.y > 64 - FLAPPY_BIRD_WIDTH) {
game_state->bird.point.y = FLIPPER_LCD_HEIGHT - FLAPPY_BIRD_WIDTH;
}
// Bird inbetween pipes
if((game_state->bird.point.x + FLAPPY_BIRD_HEIGHT >= pilar->point.x) &&
(game_state->bird.point.x <= pilar->point.x + FLAPPY_GAB_WIDTH)) {
// Bird below Bottom Pipe
if(game_state->bird.point.y + FLAPPY_BIRD_WIDTH - 2 >=
pilar->height + FLAPPY_GAB_HEIGHT) {
game_state->state = GameStateGameOver;
break;
}
// Bird above Upper Pipe
if(game_state->bird.point.y < pilar->height) {
game_state->state = GameStateGameOver;
break;
}
}
}
}
}
}
static void flappy_game_flap(GameState* const game_state) {
game_state->bird.gravity = FLAPPY_GRAVITY_JUMP;
}
static void flappy_game_render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
const GameState* game_state = ctx;
furi_mutex_acquire(game_state->mutex, FuriWaitForever);
canvas_draw_frame(canvas, 0, 0, 128, 64);
if(game_state->state == GameStateLife) {
// Pilars
for(int i = 0; i < FLAPPY_PILAR_MAX; i++) {
const PILAR* pilar = &game_state->pilars[i];
if(pilar != NULL && pilar->visible == 1) {
canvas_draw_frame(
canvas, pilar->point.x, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height);
canvas_draw_frame(
canvas, pilar->point.x + 1, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height);
canvas_draw_frame(
canvas,
pilar->point.x + 2,
pilar->point.y,
FLAPPY_GAB_WIDTH - 1,
pilar->height);
canvas_draw_frame(
canvas,
pilar->point.x,
pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT,
FLAPPY_GAB_WIDTH,
FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT);
canvas_draw_frame(
canvas,
pilar->point.x + 1,
pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT,
FLAPPY_GAB_WIDTH - 1,
FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT);
canvas_draw_frame(
canvas,
pilar->point.x + 2,
pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT,
FLAPPY_GAB_WIDTH - 1,
FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT);
}
}
// Switch animation
BirdState bird_state = BirdState1;
if(game_state->bird.gravity < -0.5)
bird_state = BirdState0;
else if(game_state->bird.gravity > 0.5)
bird_state = BirdState2;
canvas_draw_icon(
canvas, game_state->bird.point.x, game_state->bird.point.y, bird_states[bird_state]);
canvas_set_font(canvas, FontSecondary);
char buffer[12];
snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points);
canvas_draw_str_aligned(canvas, 100, 12, AlignCenter, AlignBottom, buffer);
if(game_state->debug) {
char coordinates[20];
snprintf(coordinates, sizeof(coordinates), "Y: %u", game_state->bird.point.y);
canvas_draw_str_aligned(canvas, 1, 12, AlignCenter, AlignBottom, coordinates);
}
}
if(game_state->state == GameStateGameOver) {
// Screen is 128x64 px
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 34, 20, 62, 24);
canvas_set_color(canvas, ColorBlack);
canvas_draw_frame(canvas, 34, 20, 62, 24);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 37, 31, "Game Over");
canvas_set_font(canvas, FontSecondary);
char buffer[12];
snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points);
canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer);
}
furi_mutex_release(game_state->mutex);
}
static void flappy_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void flappy_game_update_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event = {.type = EventTypeTick};
furi_message_queue_put(event_queue, &event, 0);
}
int32_t flappy_game_app(void* p) {
UNUSED(p);
int32_t return_code = 0;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
GameState* game_state = malloc(sizeof(GameState));
flappy_game_state_init(game_state);
game_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!game_state->mutex) {
FURI_LOG_E(TAG, "cannot create mutex\r\n");
return_code = 255;
goto free_and_exit;
}
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, flappy_game_render_callback, game_state);
view_port_input_callback_set(view_port, flappy_game_input_callback, event_queue);
FuriTimer* timer =
furi_timer_alloc(flappy_game_update_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 25);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
// Call dolphin deed on game start
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(game_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress) {
switch(event.input.key) {
case InputKeyUp:
if(game_state->state == GameStateLife) {
flappy_game_flap(game_state);
}
break;
case InputKeyDown:
break;
case InputKeyRight:
break;
case InputKeyLeft:
break;
case InputKeyOk:
if(game_state->state == GameStateGameOver) {
flappy_game_state_init(game_state);
}
if(game_state->state == GameStateLife) {
flappy_game_flap(game_state);
}
break;
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
} else if(event.type == EventTypeTick) {
flappy_game_tick(game_state);
}
}
view_port_update(view_port);
furi_mutex_release(game_state->mutex);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
furi_mutex_free(game_state->mutex);
free_and_exit:
flappy_game_state_free(game_state);
furi_message_queue_free(event_queue);
return return_code;
}

View File

@@ -1,15 +0,0 @@
App(
appid="gameoflife",
name="Game of Life",
apptype=FlipperAppType.EXTERNAL,
entry_point="game_of_life_app",
cdefines=["APP_GAMEOFLIFE_GAME"],
requires=["gui"],
stack_size=2 * 1024,
fap_icon="golIcon.png",
fap_category="Games",
fap_author="@tgxn (original by @itsyourbedtime)",
fap_weburl="https://github.com/tgxn/flipperzero-firmware/blob/dev/applications/game_of_life/game_of_life.c",
fap_version="1.0",
fap_description="Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.",
)

View File

@@ -1,164 +0,0 @@
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} AppEvent;
typedef struct {
bool revive;
int evo;
FuriMutex* mutex;
} State;
unsigned char new[TOTAL_PIXELS] = {};
unsigned char old[TOTAL_PIXELS] = {};
unsigned char* fields[] = {new, old};
int current = 0;
int next = 1;
unsigned char get_cell(int x, int y) {
if(x <= 0 || x >= SCREEN_WIDTH) return 0;
if(y <= 0 || y >= SCREEN_HEIGHT) return 0;
int pix = (y * SCREEN_WIDTH) + x;
return fields[current][pix];
}
int count_neightbors(int x, int y) {
return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) +
get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) +
get_cell(x, y + 1);
}
static void update_field(State* state) {
if(state->revive) {
for(int i = 0; i < TOTAL_PIXELS; ++i) {
if((random() % 100) == 1) {
fields[current][i] = 1;
}
state->revive = false;
}
}
for(int i = 0; i < TOTAL_PIXELS; ++i) {
int x = i % SCREEN_WIDTH;
int y = (int)(i / SCREEN_WIDTH);
int v = get_cell(x, y);
int n = count_neightbors(x, y);
if(v && n == 3) {
++state->evo;
} else if(v && (n < 2 || n > 3)) {
++state->evo;
v = 0;
} else if(!v && n == 3) {
++state->evo;
v = 1;
}
fields[next][i] = v;
}
next ^= current;
current ^= next;
next ^= current;
if(state->evo < TOTAL_PIXELS) {
state->revive = true;
state->evo = 0;
}
}
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
AppEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, 0);
}
static void render_callback(Canvas* canvas, void* ctx) {
//furi_assert(ctx);
State* state = ctx;
furi_mutex_acquire(state->mutex, FuriWaitForever);
canvas_clear(canvas);
for(int i = 0; i < TOTAL_PIXELS; ++i) {
int x = i % SCREEN_WIDTH;
int y = (int)(i / SCREEN_WIDTH);
if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y);
}
furi_mutex_release(state->mutex);
}
int32_t game_of_life_app(void* p) {
UNUSED(p);
srand(DWT->CYCCNT);
FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent));
furi_check(event_queue);
State* _state = malloc(sizeof(State));
_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!_state->mutex) {
printf("cannot create mutex\r\n");
furi_message_queue_free(event_queue);
free(_state);
return 255;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, _state);
view_port_input_callback_set(view_port, input_callback, event_queue);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
AppEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
furi_mutex_acquire(_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk && event.type == EventTypeKey &&
event.input.type == InputTypePress) {
if(event.input.key == InputKeyBack) {
// furiac_exit(NULL);
processing = false;
furi_mutex_release(_state->mutex);
break;
}
}
update_field(_state);
view_port_update(view_port);
furi_mutex_release(_state->mutex);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(_state->mutex);
free(_state);
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,15 +0,0 @@
App(
appid="hc_sr04",
name="[HC-SR] Dist. Sensor",
apptype=FlipperAppType.EXTERNAL,
entry_point="hc_sr04_app",
requires=[
"gui",
],
stack_size=2 * 1024,
fap_icon="dist_sensor10px.png",
fap_category="GPIO",
fap_author="@xMasterX (first implementation by @Sanqui)",
fap_version="1.0",
fap_description="HC-SR(04) Distance sensor reader",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 B

View File

@@ -1,275 +0,0 @@
// insired by
// https://github.com/esphome/esphome/blob/ac0d921413c3884752193fe568fa82853f0f99e9/esphome/components/ultrasonic/ultrasonic_sensor.cpp
// Ported and modified by @xMasterX
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_power.h>
#include <furi_hal_console.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <gui/elements.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} PluginEvent;
typedef struct {
FuriMutex* mutex;
NotificationApp* notification;
bool have_5v;
bool measurement_made;
uint32_t echo; // us
float distance; // meters
} PluginState;
const NotificationSequence sequence_done = {
&message_display_backlight_on,
&message_green_255,
&message_note_c5,
&message_delay_50,
&message_sound_off,
NULL,
};
static void render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
const PluginState* plugin_state = ctx;
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
// border around the edge of the screen
// canvas_draw_frame(canvas, 0, 0, 128, 64);
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(
canvas, 64, 2, AlignCenter, AlignTop, "HC-SR04 Ultrasonic\nDistance Sensor");
canvas_set_font(canvas, FontSecondary);
if(!plugin_state->have_5v) {
elements_multiline_text_aligned(
canvas,
4,
28,
AlignLeft,
AlignTop,
"5V on GPIO must be\nenabled, or USB must\nbe connected.");
} else {
if(!plugin_state->measurement_made) {
elements_multiline_text_aligned(
canvas, 64, 28, AlignCenter, AlignTop, "Press OK button to measure");
elements_multiline_text_aligned(
canvas, 64, 40, AlignCenter, AlignTop, "13/TX -> Trig\n14/RX -> Echo");
} else {
elements_multiline_text_aligned(canvas, 4, 28, AlignLeft, AlignTop, "Readout:");
FuriString* str_buf;
str_buf = furi_string_alloc();
furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo);
canvas_draw_str_aligned(
canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf));
furi_string_printf(str_buf, "Distance: %02f m", (double)plugin_state->distance);
canvas_draw_str_aligned(
canvas, 8, 48, AlignLeft, AlignTop, furi_string_get_cstr(str_buf));
furi_string_free(str_buf);
}
}
furi_mutex_release(plugin_state->mutex);
}
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, FuriWaitForever);
}
static void hc_sr04_state_init(PluginState* const plugin_state) {
plugin_state->echo = -1;
plugin_state->distance = -1;
plugin_state->measurement_made = false;
furi_hal_power_suppress_charge_enter();
plugin_state->have_5v = false;
if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) {
plugin_state->have_5v = true;
} else {
furi_hal_power_enable_otg();
plugin_state->have_5v = true;
}
}
float hc_sr04_us_to_m(uint32_t us) {
//speed of sound for 20°C, 50% relative humidity
//331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404
const float speed_sound_m_per_s = 344.04f;
const float time_s = us / 1e6f;
const float total_dist = time_s * speed_sound_m_per_s;
return total_dist / 2.0f;
}
static void hc_sr04_measure(PluginState* const plugin_state) {
//plugin_state->echo = 1;
//return;
if(!plugin_state->have_5v) {
if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) {
plugin_state->have_5v = true;
} else {
return;
}
}
//furi_hal_light_set(LightRed, 0xFF);
notification_message(plugin_state->notification, &sequence_blink_start_yellow);
const uint32_t timeout_ms = 2000;
// Pin 13 / TX -> Trig
furi_hal_gpio_write(&gpio_usart_tx, false);
furi_hal_gpio_init(&gpio_usart_tx, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
// Pin 14 / RX -> Echo
furi_hal_gpio_write(&gpio_usart_rx, false);
furi_hal_gpio_init(&gpio_usart_rx, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
//FURI_CRITICAL_ENTER();
// 10 ms pulse on TX
furi_hal_gpio_write(&gpio_usart_tx, true);
furi_delay_ms(10);
furi_hal_gpio_write(&gpio_usart_tx, false);
const uint32_t start = furi_get_tick();
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
;
while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx))
;
const uint32_t pulse_start = DWT->CYCCNT;
while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx))
;
const uint32_t pulse_end = DWT->CYCCNT;
//FURI_CRITICAL_EXIT();
plugin_state->echo =
(pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond();
plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo);
plugin_state->measurement_made = true;
//furi_hal_light_set(LightRed, 0x00);
notification_message(plugin_state->notification, &sequence_blink_stop);
notification_message(plugin_state->notification, &sequence_done);
}
int32_t hc_sr04_app() {
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState));
hc_sr04_state_init(plugin_state);
furi_hal_console_disable();
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!plugin_state->mutex) {
FURI_LOG_E("hc_sr04", "cannot create mutex\r\n");
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
furi_hal_console_enable();
furi_hal_power_suppress_charge_exit();
furi_message_queue_free(event_queue);
free(plugin_state);
return 255;
}
plugin_state->notification = furi_record_open(RECORD_NOTIFICATION);
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, plugin_state);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey) {
if(event.input.type == InputTypePress) {
switch(event.input.key) {
case InputKeyUp:
case InputKeyDown:
case InputKeyRight:
case InputKeyLeft:
break;
case InputKeyOk:
hc_sr04_measure(plugin_state);
break;
case InputKeyBack:
processing = false;
break;
default:
break;
}
}
}
}
view_port_update(view_port);
furi_mutex_release(plugin_state->mutex);
}
if(furi_hal_power_is_otg_enabled()) {
furi_hal_power_disable_otg();
}
furi_hal_power_suppress_charge_exit();
// Return TX / RX back to usart mode
furi_hal_gpio_init_ex(
&gpio_usart_tx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
furi_hal_gpio_init_ex(
&gpio_usart_rx,
GpioModeAltFunctionPushPull,
GpioPullUp,
GpioSpeedVeryHigh,
GpioAltFn7USART1);
furi_hal_console_enable();
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(plugin_state->mutex);
free(plugin_state);
return 0;
}

View File

@@ -1,14 +0,0 @@
App(
appid="heap_defence",
name="Heap Defence",
apptype=FlipperAppType.EXTERNAL,
entry_point="heap_defence_app",
requires=["gui"],
stack_size=1 * 1024,
fap_category="Games",
fap_icon="box.png",
fap_icon_assets="assets_images",
fap_author="@xMasterX (original implementation by @wquinoa & @Vedmein)",
fap_version="1.0",
fap_description="Heap Defence game from hackathon (aka Stack Attack)",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

View File

@@ -1,598 +0,0 @@
//
// Created by moh on 30.11.2021.
//
// Ported to latest firmware by @xMasterX - 18 Oct 2022
//
#include <string.h>
#include "hede_assets.h"
#include "heap_defence_icons.h"
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <dolphin/dolphin.h>
#define Y_FIELD_SIZE 6
#define Y_LAST (Y_FIELD_SIZE - 1)
#define X_FIELD_SIZE 12
#define X_LAST (X_FIELD_SIZE - 1)
#define DRAW_X_OFFSET 4
#define TAG "HeDe"
#define BOX_HEIGHT 10
#define BOX_WIDTH 10
#define TIMER_UPDATE_FREQ 8
#define BOX_GENERATION_RATE 15
static IconAnimation* BOX_DESTROYED;
static const Icon* boxes[] = {
(Icon*)&A_HD_BoxDestroyed_10x10,
&I_Box1_10x10,
&I_Box2_10x10,
&I_Box3_10x10,
&I_Box4_10x10,
&I_Box5_10x10};
static uint8_t BOX_TEXTURE_COUNT = sizeof(boxes) / sizeof(Icon*);
typedef enum {
AnimationGameOver = 0,
AnimationPause,
AnimationLeft,
AnimationRight,
} Animations;
static IconAnimation* animations[4];
typedef u_int8_t byte;
typedef enum {
GameStatusVibro = 1 << 0,
GameStatusInProgress = 1 << 1,
} GameStatuses;
typedef struct {
uint8_t x;
uint8_t y;
} Position;
typedef enum { PlayerRising = 1, PlayerFalling = -1, PlayerNothing = 0 } PlayerStates;
typedef struct {
Position p;
int8_t x_direction;
int8_t j_tick;
int8_t h_tick;
int8_t states;
bool right_frame;
} Person;
typedef struct {
uint8_t offset : 4;
uint8_t box_id : 3;
uint8_t exists : 1;
} Box;
static const uint8_t ROW_BYTE_SIZE = sizeof(Box) * X_FIELD_SIZE;
typedef struct {
Box** field;
Person* person;
Animations animation;
GameStatuses game_status;
FuriMutex* mutex;
} GameState;
typedef Box** Field;
typedef enum { EventGameTick, EventKeyPress } EventType;
typedef struct {
EventType type;
InputEvent input;
} GameEvent;
/**
* #Construct / Destroy
*/
static void game_reset_field_and_player(GameState* game) {
///Reset field
bzero(game->field[0], X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box));
///Reset person
bzero(game->person, sizeof(Person));
game->person->p.x = X_FIELD_SIZE / 2;
game->person->p.y = Y_LAST;
}
static GameState* allocGameState() {
GameState* game = malloc(sizeof(GameState));
game->person = malloc(sizeof(Person));
game->field = malloc(Y_FIELD_SIZE * sizeof(Box*));
game->field[0] = malloc(X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box));
for(int y = 1; y < Y_FIELD_SIZE; ++y) {
game->field[y] = game->field[0] + (y * X_FIELD_SIZE);
}
game_reset_field_and_player(game);
game->game_status = GameStatusInProgress;
return game;
}
static void game_destroy(GameState* game) {
furi_assert(game);
free(game->field[0]);
free(game->field);
free(game);
}
static void assets_load() {
/// Init animations
animations[AnimationPause] = icon_animation_alloc(&A_HD_start_128x64);
animations[AnimationGameOver] = icon_animation_alloc(&A_HD_game_over_128x64);
animations[AnimationLeft] = icon_animation_alloc(&A_HD_person_left_10x20);
animations[AnimationRight] = icon_animation_alloc(&A_HD_person_right_10x20);
BOX_DESTROYED = icon_animation_alloc(&A_HD_BoxDestroyed_10x10);
icon_animation_start(animations[AnimationLeft]);
icon_animation_start(animations[AnimationRight]);
}
static void assets_clear() {
for(int i = 0; i < 4; ++i) {
icon_animation_stop(animations[i]);
icon_animation_free(animations[i]);
}
icon_animation_free(BOX_DESTROYED);
}
/**
* Box utils
*/
static inline bool is_empty(Box* box) {
return !box->exists;
}
static inline bool has_dropped(Box* box) {
return box->offset == 0;
}
static Box* get_upper_box(Field field, Position current) {
return (&field[current.y - 1][current.x]);
}
static Box* get_lower_box(Field field, Position current) {
return (&field[current.y + 1][current.x]);
}
static Box* get_next_box(Field field, Position current, int x_direction) {
return (&field[current.y][current.x + x_direction]);
}
static inline void decrement_y_offset_to_zero(Box* n) {
if(n->offset) --n->offset;
}
static inline void heap_swap(Box* first, Box* second) {
Box temp = *first;
*first = *second;
*second = temp;
}
/**
* #Box logic
*/
static void generate_box(GameState const* game) {
furi_assert(game);
static byte tick_count = BOX_GENERATION_RATE;
if(tick_count++ != BOX_GENERATION_RATE) {
return;
}
tick_count = 0;
int x_offset = rand() % X_FIELD_SIZE;
while(game->field[1][x_offset].exists) {
x_offset = rand() % X_FIELD_SIZE;
}
game->field[1][x_offset].exists = true;
game->field[1][x_offset].offset = BOX_HEIGHT;
game->field[1][x_offset].box_id = (rand() % (BOX_TEXTURE_COUNT - 1)) + 1;
}
static void drop_box(GameState* game) {
furi_assert(game);
for(int y = Y_LAST; y > 0; y--) {
for(int x = 0; x < X_FIELD_SIZE; x++) {
Box* current_box = game->field[y] + x;
Box* upper_box = game->field[y - 1] + x;
if(y == Y_LAST) {
decrement_y_offset_to_zero(current_box);
}
decrement_y_offset_to_zero(upper_box);
if(is_empty(current_box) && !is_empty(upper_box) && has_dropped(upper_box)) {
upper_box->offset = BOX_HEIGHT;
heap_swap(current_box, upper_box);
}
}
}
}
static bool clear_rows(Box** field) {
for(int x = 0; x < X_FIELD_SIZE; ++x) {
if(is_empty(field[Y_LAST] + x) || !has_dropped(field[Y_LAST] + x)) {
return false;
}
}
memset(field[Y_LAST], 128, ROW_BYTE_SIZE);
return true;
}
/**
* Input Handling
*/
static inline bool on_ground(Person* person, Field field) {
return person->p.y == Y_LAST || field[person->p.y + 1][person->p.x].exists;
}
static void handle_key_presses(Person* person, InputEvent* input, GameState* game) {
switch(input->key) {
case InputKeyUp:
if(person->states == PlayerNothing && on_ground(person, game->field)) {
person->states = PlayerRising;
person->j_tick = 0;
}
break;
case InputKeyLeft:
person->right_frame = false;
if(person->h_tick == 0) {
person->h_tick = 1;
person->x_direction = -1;
}
break;
case InputKeyRight:
person->right_frame = true;
if(person->h_tick == 0) {
person->h_tick = 1;
person->x_direction = 1;
}
break;
case InputKeyOk:
game->game_status &= ~GameStatusInProgress;
game->animation = AnimationPause;
icon_animation_start(animations[AnimationPause]);
default:
break;
}
}
/**
* #Person logic
*/
static inline bool ground_box_check(Field field, Position new_position) {
Box* lower_box = get_lower_box(field, new_position);
bool ground_box_dropped =
(new_position.y == Y_LAST || //Eсли мы и так в самом низу
is_empty(lower_box) || // Ecли снизу пустота
has_dropped(lower_box)); //Eсли бокс снизу допадал
return ground_box_dropped;
}
static inline bool is_movable(Field field, Position box_pos, int x_direction) {
//TODO::Moжет и не двух, предположение
bool out_of_bounds = box_pos.x == 0 || box_pos.x == X_LAST;
if(out_of_bounds) return false;
bool box_on_top = box_pos.y < 1 || get_upper_box(field, box_pos)->exists;
if(box_on_top) return false;
bool has_next_box = get_next_box(field, box_pos, x_direction)->exists;
if(has_next_box) return false;
return true;
}
static bool horizontal_move(Person* person, Field field) {
Position new_position = person->p;
if(!person->x_direction) return false;
new_position.x += person->x_direction;
bool on_edge_column = new_position.x > X_LAST;
if(on_edge_column) return false;
if(is_empty(&field[new_position.y][new_position.x])) {
bool ground_box_dropped = ground_box_check(field, new_position);
if(ground_box_dropped) {
person->p = new_position;
return true;
}
} else if(is_movable(field, new_position, person->x_direction)) {
*get_next_box(field, new_position, person->x_direction) =
field[new_position.y][new_position.x];
field[new_position.y][new_position.x] = (Box){0};
person->p = new_position;
return true;
}
return false;
}
void hd_person_set_state(Person* person, PlayerStates state) {
person->states = state;
person->j_tick = 0;
}
static void person_move(Person* person, Field field) {
/// Left-right logic
FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__);
if(person->states == PlayerNothing) {
if(!on_ground(person, field)) {
hd_person_set_state(person, PlayerFalling);
}
} else if(person->states == PlayerRising) {
if(person->j_tick++ == 0) {
person->p.y--;
} else if(person->j_tick == 6) {
hd_person_set_state(person, PlayerNothing);
}
/// Destroy upper box
get_upper_box(field, person->p)->box_id = 0;
field[person->p.y][person->p.x].box_id = 0;
} else if(person->states == PlayerFalling) {
if(person->j_tick++ == 0) {
if(on_ground(person, field)) { // TODO: Test the bugfix
hd_person_set_state(person, PlayerNothing);
} else {
person->p.y++;
}
} else if(person->j_tick == 5) {
if(on_ground(person, field)) {
hd_person_set_state(person, PlayerNothing);
} else {
hd_person_set_state(person, PlayerFalling);
}
}
}
switch(person->h_tick) {
case 0:
break;
case 1:
person->h_tick++;
FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__);
bool moved = horizontal_move(person, field);
if(!moved) {
person->h_tick = 0;
person->x_direction = 0;
}
break;
case 5:
FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__);
person->h_tick = 0;
person->x_direction = 0;
break;
default:
FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__);
person->h_tick++;
}
}
static inline bool is_person_dead(Person* person, Box** field) {
return get_upper_box(field, person->p)->box_id != 0;
}
/**
* #Callback
*/
static void draw_box(Canvas* canvas, Box* box, int x, int y) {
if(is_empty(box)) {
return;
}
byte y_screen = y * BOX_HEIGHT - box->offset;
byte x_screen = x * BOX_WIDTH + DRAW_X_OFFSET;
if(box->box_id == 0) {
canvas_set_bitmap_mode(canvas, true);
icon_animation_start(BOX_DESTROYED);
canvas_draw_icon_animation(canvas, x_screen, y_screen, BOX_DESTROYED);
if(icon_animation_is_last_frame(BOX_DESTROYED)) {
*box = (Box){0};
icon_animation_stop(BOX_DESTROYED);
}
canvas_set_bitmap_mode(canvas, false);
} else {
canvas_draw_icon(canvas, x_screen, y_screen, boxes[box->box_id]);
}
}
static void heap_defense_render_callback(Canvas* const canvas, void* mutex) {
furi_assert(mutex);
const GameState* game = mutex;
furi_mutex_acquire(game->mutex, FuriWaitForever);
///Draw GameOver or Pause
if(!(game->game_status & GameStatusInProgress)) {
FURI_LOG_W(TAG, "[DAED_DRAW]func: [%s] line: %d ", __FUNCTION__, __LINE__);
canvas_draw_icon_animation(canvas, 0, 0, animations[game->animation]);
furi_mutex_release(game->mutex);
return;
}
///Draw field
canvas_draw_icon(canvas, 0, 0, &I_Background_128x64);
///Draw Person
const Person* person = game->person;
IconAnimation* player_animation = person->right_frame ? animations[AnimationRight] :
animations[AnimationLeft];
uint8_t x_screen = person->p.x * BOX_WIDTH + DRAW_X_OFFSET;
if(person->h_tick && person->h_tick != 1) {
if(person->right_frame) {
x_screen += (person->h_tick) * 2 - BOX_WIDTH;
} else {
x_screen -= (person->h_tick) * 2 - BOX_WIDTH;
}
}
uint8_t y_screen = (person->p.y - 1) * BOX_HEIGHT;
if(person->j_tick) {
if(person->states == PlayerRising) {
y_screen += BOX_HEIGHT - (person->j_tick) * 2;
} else if(person->states == PlayerFalling) {
y_screen -= BOX_HEIGHT - (person->j_tick) * 2;
}
}
canvas_draw_icon_animation(canvas, x_screen, y_screen, player_animation);
///Draw Boxes
canvas_set_color(canvas, ColorBlack);
for(int y = 1; y < Y_FIELD_SIZE; ++y) {
for(int x = 0; x < X_FIELD_SIZE; ++x) {
draw_box(canvas, &(game->field[y][x]), x, y);
}
}
furi_mutex_release(game->mutex);
}
static void heap_defense_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
if(input_event->type != InputTypePress && input_event->type != InputTypeLong) return;
furi_assert(event_queue);
GameEvent event = {.type = EventKeyPress, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void heap_defense_timer_callback(FuriMessageQueue* event_queue) {
furi_assert(event_queue);
GameEvent event;
event.type = EventGameTick;
event.input = (InputEvent){0};
furi_message_queue_put(event_queue, &event, 0);
}
int32_t heap_defence_app(void* p) {
UNUSED(p);
//FURI_LOG_W(TAG, "Heap defence start %d", __LINE__);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
GameState* game = allocGameState();
game->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!game->mutex) {
game_destroy(game);
return 1;
}
assets_load();
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, heap_defense_render_callback, game);
view_port_input_callback_set(view_port, heap_defense_input_callback, event_queue);
FuriTimer* timer =
furi_timer_alloc(heap_defense_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / TIMER_UPDATE_FREQ);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
memset(game->field[Y_LAST], 128, ROW_BYTE_SIZE);
game->person->p.y -= 2;
game->game_status = 0;
game->animation = AnimationPause;
// Call dolphin deed on game start
dolphin_deed(DolphinDeedPluginGameStart);
GameEvent event = {0};
while(event.input.key != InputKeyBack) {
if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) {
continue;
}
furi_mutex_acquire(game->mutex, FuriWaitForever);
//unset vibration
if(game->game_status & GameStatusVibro) {
notification_message(notification, &sequence_reset_vibro);
game->game_status &= ~GameStatusVibro;
icon_animation_stop(BOX_DESTROYED);
memset(game->field[Y_LAST], 0, ROW_BYTE_SIZE);
}
if(!(game->game_status & GameStatusInProgress)) {
if(event.type == EventKeyPress && event.input.key == InputKeyOk) {
game->game_status |= GameStatusInProgress;
icon_animation_stop(animations[game->animation]);
}
} else if(event.type == EventKeyPress) {
handle_key_presses(game->person, &(event.input), game);
} else { // EventGameTick
drop_box(game);
generate_box(game);
if(clear_rows(game->field)) {
notification_message(notification, &sequence_set_vibro_on);
icon_animation_start(BOX_DESTROYED);
game->game_status |= GameStatusVibro;
}
person_move(game->person, game->field);
if(is_person_dead(game->person, game->field)) {
game->game_status &= ~GameStatusInProgress;
game->animation = AnimationGameOver;
icon_animation_start(animations[AnimationGameOver]);
game_reset_field_and_player(game);
notification_message(notification, &sequence_error);
}
}
furi_mutex_release(game->mutex);
view_port_update(view_port);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
furi_message_queue_free(event_queue);
assets_clear();
furi_mutex_free(game->mutex);
game_destroy(game);
return 0;
}

View File

@@ -1,28 +0,0 @@
//
// Created by user on 15.12.2021.
//
#include "hede_assets.h"
#include <gui/icon_i.h>
const uint8_t _A_HD_BoxDestroyed_10x10_0[] = {
0x01, 0x00, 0x10, 0x00, 0x00, 0x1d, 0xa2, 0x01, 0xc8, 0x80,
0x6d, 0x20, 0x15, 0x08, 0x06, 0x72, 0x01, 0x48, 0x07, 0xa0,
};
const uint8_t _A_HD_BoxDestroyed_10x10_1[] = {
0x00, 0x00, 0x00, 0x28, 0x01, 0x4A, 0x00, 0xA8, 0x01, 0x84, 0x00,
0x22, 0x00, 0x88, 0x00, 0x58, 0x01, 0x22, 0x00, 0x00, 0x00,
};
const uint8_t _A_HD_BoxDestroyed_10x10_2[] = {
0x00, 0x00, 0x00, 0x08, 0x01, 0x42, 0x00, 0x09, 0x01, 0x00, 0x02,
0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x21, 0x00, 0x42, 0x02,
};
const uint8_t* _A_HD_BoxDestroyed_10x10[] = {
_A_HD_BoxDestroyed_10x10_0,
_A_HD_BoxDestroyed_10x10_1,
_A_HD_BoxDestroyed_10x10_2};
const Icon A_HD_BoxDestroyed_10x10 = {
.width = 10,
.height = 10,
.frame_count = 3,
.frame_rate = 4,
.frames = _A_HD_BoxDestroyed_10x10};

View File

@@ -1,11 +0,0 @@
//
// Created by user on 15.12.2021.
//
#ifndef HEDE_ASSETS_H
#define HEDE_ASSETS_H
#include <gui/icon.h>
extern const Icon A_HD_BoxDestroyed_10x10;
#endif

View File

@@ -1,13 +0,0 @@
App(
appid="ir_scope",
name="IR Scope",
apptype=FlipperAppType.EXTERNAL,
entry_point="ir_scope_app",
requires=["gui"],
stack_size=2 * 1024,
fap_icon="ir_scope.png",
fap_category="Infrared",
fap_author="@kallanreed",
fap_version="1.2",
fap_description="App allows to see incoming IR signals.",
)

View File

@@ -1,184 +0,0 @@
// Author: github.com/kallanreed
#include <furi.h>
#include <furi_hal.h>
#include <infrared.h>
#include <infrared_worker.h>
#include <furi_hal_infrared.h>
#include <gui/gui.h>
#define TAG "IR Scope"
#define COLS 128
#define ROWS 8
typedef struct {
bool autoscale;
uint16_t us_per_sample;
size_t timings_cnt;
uint32_t* timings;
uint32_t timings_sum;
FuriMutex* mutex;
} IRScopeState;
static void state_set_autoscale(IRScopeState* state) {
if(state->autoscale) state->us_per_sample = state->timings_sum / (ROWS * COLS);
}
static void canvas_draw_str_outline(Canvas* canvas, int x, int y, const char* str) {
canvas_set_color(canvas, ColorWhite);
for(int y1 = -1; y1 <= 1; ++y1)
for(int x1 = -1; x1 <= 1; ++x1) canvas_draw_str(canvas, x + x1, y + y1, str);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str(canvas, x, y, str);
}
static void render_callback(Canvas* canvas, void* ctx) {
const IRScopeState* state = (IRScopeState*)ctx;
furi_mutex_acquire(state->mutex, FuriWaitForever);
canvas_clear(canvas);
canvas_draw_frame(canvas, 0, 0, 128, 64);
// Draw the signal chart.
bool on = false;
bool done = false;
size_t ix = 0;
int timing_cols = -1; // Count of columns used to draw the current timing
for(size_t row = 0; row < ROWS && !done; ++row) {
for(size_t col = 0; col < COLS && !done; ++col) {
done = ix >= state->timings_cnt;
if(!done && timing_cols < 0) {
timing_cols = state->timings[ix] / state->us_per_sample;
on = !on;
}
if(timing_cols == 0) ++ix;
int y = row * 8 + 7;
canvas_draw_line(canvas, col, y, col, y - (on ? 5 : 0));
--timing_cols;
}
}
canvas_set_font(canvas, FontSecondary);
if(state->autoscale)
canvas_draw_str_outline(canvas, 100, 64, "Auto");
else {
char buf[20];
snprintf(buf, sizeof(buf), "%uus", state->us_per_sample);
canvas_draw_str_outline(canvas, 100, 64, buf);
}
furi_mutex_release(state->mutex);
}
static void input_callback(InputEvent* input_event, void* ctx) {
FuriMessageQueue* event_queue = ctx;
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
static void ir_received_callback(void* ctx, InfraredWorkerSignal* signal) {
furi_check(signal);
IRScopeState* state = (IRScopeState*)ctx;
furi_mutex_acquire(state->mutex, FuriWaitForever);
const uint32_t* timings;
infrared_worker_get_raw_signal(signal, &timings, &state->timings_cnt);
if(state->timings) {
free(state->timings);
state->timings_sum = 0;
}
state->timings = malloc(state->timings_cnt * sizeof(uint32_t));
// Copy and sum.
for(size_t i = 0; i < state->timings_cnt; ++i) {
state->timings[i] = timings[i];
state->timings_sum += timings[i];
}
state_set_autoscale(state);
furi_mutex_release(state->mutex);
}
int32_t ir_scope_app(void* p) {
UNUSED(p);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
furi_check(event_queue);
if(furi_hal_infrared_is_busy()) {
FURI_LOG_E(TAG, "Infrared is busy.");
return -1;
}
IRScopeState state = {
.autoscale = false, .us_per_sample = 200, .timings = NULL, .timings_cnt = 0, .mutex = NULL};
state.mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!state.mutex) {
FURI_LOG_E(TAG, "Cannot create mutex.");
return -1;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, &state);
view_port_input_callback_set(view_port, input_callback, event_queue);
Gui* gui = furi_record_open("gui");
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
InfraredWorker* worker = infrared_worker_alloc();
infrared_worker_rx_enable_signal_decoding(worker, false);
infrared_worker_rx_enable_blink_on_receiving(worker, true);
infrared_worker_rx_set_received_signal_callback(worker, ir_received_callback, &state);
infrared_worker_rx_start(worker);
InputEvent event;
bool processing = true;
while(processing) {
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
if(event.type == InputTypeRelease) {
furi_mutex_acquire(state.mutex, FuriWaitForever);
if(event.key == InputKeyBack) {
processing = false;
} else if(event.key == InputKeyUp) {
state.us_per_sample = MIN(1000, state.us_per_sample + 25);
state.autoscale = false;
} else if(event.key == InputKeyDown) {
state.us_per_sample = MAX(25, state.us_per_sample - 25);
state.autoscale = false;
} else if(event.key == InputKeyOk) {
state.autoscale = !state.autoscale;
if(state.autoscale)
state_set_autoscale(&state);
else
state.us_per_sample = 200;
}
furi_mutex_release(state.mutex);
}
}
view_port_update(view_port);
}
// Clean up.
infrared_worker_rx_stop(worker);
infrared_worker_free(worker);
if(state.timings) free(state.timings);
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);
furi_mutex_free(state.mutex);
return 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

Some files were not shown because too many files have changed in this diff Show More