Merge branch 'Eng1n33r:dev' into feat/brute-helper

This commit is contained in:
Daniel 2022-08-07 15:37:51 +02:00 committed by GitHub
commit 31e06da7e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 521 additions and 513 deletions

91
.github/CODEOWNERS vendored
View File

@ -1,91 +0,0 @@
# Who owns all the fish by default
* @skotopes @DrZlo13 @hedger
# Apps
/applications/about/ @skotopes @DrZlo13 @hedger
/applications/accessor/ @skotopes @DrZlo13 @hedger
/applications/archive/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/bad_usb/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/bt/ @skotopes @DrZlo13 @hedger @gornekich
/applications/cli/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/crypto/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/debug_tools/ @skotopes @DrZlo13 @hedger
/applications/desktop/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/dialogs/ @skotopes @DrZlo13 @hedger
/applications/dolphin/ @skotopes @DrZlo13 @hedger
/applications/gpio/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/gui/ @skotopes @DrZlo13 @hedger
/applications/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/infrared_monitor/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/input/ @skotopes @DrZlo13 @hedger
/applications/lfrfid/ @skotopes @DrZlo13 @hedger
/applications/lfrfid_debug/ @skotopes @DrZlo13 @hedger
/applications/loader/ @skotopes @DrZlo13 @hedger
/applications/music_player/ @skotopes @DrZlo13 @hedger
/applications/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/applications/notification/ @skotopes @DrZlo13 @hedger
/applications/power/ @skotopes @DrZlo13 @hedger
/applications/rpc/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/snake_game/ @skotopes @DrZlo13 @hedger
/applications/storage/ @skotopes @DrZlo13 @hedger
/applications/storage_settings/ @skotopes @DrZlo13 @hedger
/applications/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
/applications/system/ @skotopes @DrZlo13 @hedger
/applications/u2f/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/unit_tests/ @skotopes @DrZlo13 @hedger
/applications/updater/ @skotopes @DrZlo13 @hedger
# Assets
/assets/ @skotopes @DrZlo13 @hedger
# Furi Core
/furi/ @skotopes @DrZlo13 @hedger
# Debug tools and plugins
/debug/ @skotopes @DrZlo13 @hedger
# Docker
/docker/ @skotopes @DrZlo13 @hedger @aprosvetova
/docker-compose.yml @skotopes @DrZlo13 @hedger @aprosvetova
# Documentation
/documentation/ @skotopes @DrZlo13 @hedger @aprosvetova
# Firmware targets
/firmware/ @skotopes @DrZlo13 @hedger
# Lib
/lib/FreeRTOS-Kernel/ @skotopes @DrZlo13 @hedger
/lib/FreeRTOS-glue/ @skotopes @DrZlo13 @hedger
/lib/ST25RFAL002/ @skotopes @DrZlo13 @hedger @gornekich
/lib/STM32CubeWB/ @skotopes @DrZlo13 @hedger @gornekich
/lib/app-scened-template/ @skotopes @DrZlo13 @hedger
/lib/callback-connector/ @skotopes @DrZlo13 @hedger
/lib/digital_signal/ @skotopes @DrZlo13 @hedger @gornekich
/lib/drivers/ @skotopes @DrZlo13 @hedger
/lib/fatfs/ @skotopes @DrZlo13 @hedger
/lib/flipper_format/ @skotopes @DrZlo13 @hedger
/lib/fnv1a-hash/ @skotopes @DrZlo13 @hedger
/lib/heatshrink/ @skotopes @DrZlo13 @hedger
/lib/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
/lib/libusb_stm32/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/littlefs/ @skotopes @DrZlo13 @hedger
/lib/lfs_config.h @skotopes @DrZlo13 @hedger
/lib/micro-ecc/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/microtar/ @skotopes @DrZlo13 @hedger
/lib/mlib/ @skotopes @DrZlo13 @hedger
/lib/nanopb/ @skotopes @DrZlo13 @hedger
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/lib/one_wire/ @skotopes @DrZlo13 @hedger
/lib/qrcode/ @skotopes @DrZlo13 @hedger
/lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
/lib/toolbox/ @skotopes @DrZlo13 @hedger
/lib/u8g2/ @skotopes @DrZlo13 @hedger
/lib/update_util/ @skotopes @DrZlo13 @hedger
# Make tools
/make/ @skotopes @DrZlo13 @hedger @aprosvetova
# Helper scripts
/scripts/ @skotopes @DrZlo13 @hedger

View File

@ -1,46 +1,45 @@
name: Bug report
description: File a bug reports regarding the firmware.
labels: ['bug']
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Flipper Zero firmware.
If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
- type: textarea
id: description
attributes:
label: Describe the bug.
description: "A clear and concise description of what the bug is."
validations:
required: true
- type: textarea
id: repro
attributes:
label: Reproduction
description: "How can this bug be reproduced?"
placeholder: |
1. Switch on...
2. Press button '....'
3. Wait for the moon phase
4. It burns
validations:
required: true
- type: input
id: target
attributes:
label: Target
description: Specify the target
# Target seems to be largely ignored by outside sources.
- type: textarea
id: logs
attributes:
label: Logs
description: Attach your debug logs here
render: Text
# Avoid rendering as Markdown here.
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any issues related to the Flipper Zero unleashed firmware.
- type: textarea
id: description
attributes:
label: Describe the bug.
description: "A clear and concise description of what the bug is."
validations:
required: true
- type: textarea
id: repro
attributes:
label: Reproduction
description: "How can this bug be reproduced?"
placeholder: |
1. Switch on...
2. Press button '....'
3. Wait for the moon phase
4. It burns
validations:
required: true
- type: input
id: target
attributes:
label: Target
description: Specify the target
# Target seems to be largely ignored by outside sources.
- type: textarea
id: logs
attributes:
label: Logs
description: Attach your debug logs here
render: Text
# Avoid rendering as Markdown here.
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.

View File

@ -1,21 +1,20 @@
name: Enhancements
description: Suggest improvements for any existing functionality within the firmware.
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue. This template is meant for feature requests and improvements to already existing functionality.
If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
- type: textarea
id: proposal
attributes:
label: "Describe the enhancement you're suggesting."
description: |
Feel free to describe in as much detail as you wish.
validations:
required: true
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue. This template is meant for feature requests and improvements to already existing functionality.
- type: textarea
id: proposal
attributes:
label: "Describe the enhancement you're suggesting."
description: |
Feel free to describe in as much detail as you wish.
validations:
required: true
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.

View File

@ -1,24 +1,23 @@
name: Feature Request
description: For feature requests regarding the firmware.
labels: ['feature request']
labels: ["feature request"]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions.
If you require help with the Flipper zero and its firmware, we ask that you join [our forum](https://forum.flipperzero.one)
- type: textarea
id: proposal
attributes:
label: "Description of the feature you're suggesting."
description: |
Please describe your feature request in as many details as possible.
- Describe what it should do.
- Note whetever it is to extend existing functionality or introduce new functionality.
validations:
required: true
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out an issue, this template is meant for any feature suggestions.
- type: textarea
id: proposal
attributes:
label: "Description of the feature you're suggesting."
description: |
Please describe your feature request in as many details as possible.
- Describe what it should do.
- Note whetever it is to extend existing functionality or introduce new functionality.
validations:
required: true
- type: textarea
id: anything-else
attributes:
label: Anything else?
description: Let us know if you have anything else to share.

View File

@ -1,5 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Need help?
url: https://forum.flipperzero.one
about: For any question regarding on how to use the Flipper Zero and its firmware.
- name: Telegram
url: https://t.me/flipperzero_unofficial
about: Unofficial Telegram chat
- name: Discord
url: https://discord.gg/58D6E8BtTU
about: Unofficial Discord Community

View File

@ -5,6 +5,6 @@ App(
entry_point="arkanoid_game_app",
cdefines=["APP_ARKANOID_GAME"],
requires=["gui"],
stack_size=1 * 1024,
stack_size=4 * 1024,
order=30,
)

View File

@ -3,61 +3,53 @@
#include <input/input.h>
#include <stdlib.h>
#include <gui/view.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#define TAG "Arkanoid"
unsigned int COLUMNS = 13; //Columns of bricks
unsigned int ROWS = 4; //Rows of bricks
int dx = -1; //Initial movement of ball
int dy = -1; //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
bool paused = false; //If the game has been paused
int xPaddle; //X position of paddle
bool isHit[4][13]; //Array of if bricks are hit or not
bool bounced = false; //Used to fix double bounce glitch
int lives = 3; //Amount of lives
int level = 1; //Current level
unsigned int score = 0; //Score for the game
unsigned int brickCount; //Amount of bricks hit
int pad, pad2, pad3; //Button press buffer used to stop pause repeating
int oldpad, oldpad2, oldpad3;
char text[16]; //General string buffer
bool start = false; //If in menu or in game
bool initialDraw = false; //If the inital draw has happened
char initials[3]; //Initials used in high score
//Ball Bounds used in collision detection
int leftBall;
int rightBall;
int topBall;
int bottomBall;
//Brick Bounds used in collision detection
int leftBrick;
int rightBrick;
int topBrick;
int bottomBrick;
int tick;
#define FLIPPER_LCD_WIDTH 128
#define FLIPPER_LCD_HEIGHT 64
typedef enum { EventTypeTick, EventTypeKey } EventType;
typedef enum { DirectionUp, DirectionRight, DirectionDown, DirectionLeft } Direction;
typedef enum { GameStatePlaying, GameStateGameOver } GameState;
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 x;
int y;
} Point;
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 {
GameState game_state;
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
} ArkanoidState;
typedef struct {
@ -65,134 +57,128 @@ typedef struct {
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) {
int number = min + rand() % (max - min);
return number;
}
void intro(Canvas* canvas) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 46, 0, "Arkanoid");
//arduboy.tunes.tone(987, 160);
//delay(160);
//arduboy.tunes.tone(1318, 400);
//delay(2000);
}
void move_ball(Canvas* canvas) {
tick++;
if(released) {
void move_ball(Canvas* canvas, ArkanoidState* st) {
st->tick++;
if(st->ball_state.released) {
//Move ball
if(abs(dx) == 2) {
xb += dx / 2;
if(abs(st->ball_state.dx) == 2) {
st->ball_state.xb += st->ball_state.dx / 2;
// 2x speed is really 1.5 speed
if(tick % 2 == 0) xb += dx / 2;
if(st->tick % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2;
} else {
xb += dx;
st->ball_state.xb += st->ball_state.dx;
}
yb = yb + dy;
st->ball_state.yb = st->ball_state.yb + st->ball_state.dy;
//Set bounds
leftBall = xb;
rightBall = xb + 2;
topBall = yb;
bottomBall = yb + 2;
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(yb <= 0) {
yb = 2;
dy = -dy;
// arduboy.tunes.tone(523, 250);
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(yb >= FLIPPER_LCD_HEIGHT) {
canvas_draw_frame(canvas, xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
xPaddle = 54;
yb = 60;
released = false;
lives--;
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--;
snprintf(text, sizeof(text), "LIVES:%u", lives);
canvas_draw_str(canvas, 0, 90, text);
// arduboy.tunes.tone(175, 250);
if(rand_range(0, 2) == 0) {
dx = 1;
st->ball_state.dx = 1;
} else {
dx = -1;
st->ball_state.dx = -1;
}
}
//Bounce off left side
if(xb <= 0) {
xb = 2;
dx = -dx;
// arduboy.tunes.tone(523, 250);
if(st->ball_state.xb <= 0) {
st->ball_state.xb = 2;
st->ball_state.dx = -st->ball_state.dx;
}
//Bounce off right side
if(xb >= FLIPPER_LCD_WIDTH - 2) {
xb = FLIPPER_LCD_WIDTH - 4;
dx = -dx;
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(xb + 1 >= xPaddle && xb <= xPaddle + 12 && yb + 2 >= FLIPPER_LCD_HEIGHT - 1 &&
yb <= FLIPPER_LCD_HEIGHT) {
dy = -dy;
dx = ((xb - (xPaddle + 6)) / 3); //Applies spin on the ball
// prevent straight bounce
if(dx == 0) {
dx = (rand_range(0, 2) == 1) ? 1 : -1;
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;
}
// arduboy.tunes.tone(200, 250);
}
//Bounce off Bricks
for(unsigned int row = 0; row < ROWS; row++) {
for(unsigned int column = 0; column < COLUMNS; column++) {
if(!isHit[row][column]) {
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
leftBrick = 10 * column;
rightBrick = 10 * column + 10;
topBrick = 6 * row + 1;
bottomBrick = 6 * row + 7;
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(topBall <= bottomBrick && bottomBall >= topBrick &&
leftBall <= rightBrick && rightBall >= leftBrick) {
// Draw score
score += (level * 10);
snprintf(text, sizeof(text), "SCORE:%u", score);
canvas_draw_str(canvas, 80, 90, text);
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);
brickCount++;
isHit[row][column] = true;
st->brickCount++;
st->brick_state.isHit[row][column] = true;
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
//Vertical collision
if(bottomBall > bottomBrick || topBall < topBrick) {
if(st->ball_state.bottomBall > st->brick_state.bottomBrick ||
st->ball_state.topBall < st->brick_state.topBrick) {
//Only bounce once each ball move
if(!bounced) {
dy = -dy;
yb += dy;
bounced = true;
// arduboy.tunes.tone(261, 250);
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(leftBall < leftBrick || rightBall > rightBrick) {
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(!bounced) {
dx = -dx;
xb += dx;
bounced = true;
// arduboy.tunes.tone(261, 250);
if(!st->bounced) {
st->ball_state.dx = -st->ball_state.dx;
st->ball_state.xb += st->ball_state.dx;
st->bounced = true;
}
}
}
@ -201,104 +187,156 @@ void move_ball(Canvas* canvas) {
}
//Reset Bounce
bounced = false;
st->bounced = false;
} else {
//Ball follows paddle
xb = xPaddle + 5;
st->ball_state.xb = st->xPaddle + 5;
}
}
void draw_lives(Canvas* canvas) {
snprintf(text, sizeof(text), "LIVES:%u", lives);
canvas_draw_str(canvas, 0, 90, text);
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_ball(Canvas* canvas) {
canvas_draw_dot(canvas, xb, yb);
canvas_draw_dot(canvas, xb + 1, yb);
canvas_draw_dot(canvas, xb, yb + 1);
canvas_draw_dot(canvas, xb + 1, yb + 1);
move_ball(canvas);
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_paddle(Canvas* canvas) {
canvas_draw_frame(canvas, xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
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 reset_level(Canvas* canvas) {
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, xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
//Undraw ball
canvas_draw_dot(canvas, xb, yb);
canvas_draw_dot(canvas, xb + 1, yb);
canvas_draw_dot(canvas, xb, yb + 1);
canvas_draw_dot(canvas, xb + 1, yb + 1);
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
xPaddle = 54;
yb = 60;
brickCount = 0;
released = false;
arkanoid_state->xPaddle = 54;
arkanoid_state->ball_state.yb = 60;
arkanoid_state->brickCount = 0;
arkanoid_state->ball_state.released = false;
// Reset all brick hit states
for(unsigned int row = 0; row < ROWS; row++) {
for(unsigned int column = 0; column < COLUMNS; column++) {
isHit[row][column] = false;
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* const arkanoid_state) {
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->game_state = GameStatePlaying;
arkanoid_state->COLUMNS = 13;
arkanoid_state->ROWS = 4;
arkanoid_state->ball_state.dx = -1;
arkanoid_state->ball_state.dy = -1;
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
initialDraw = false;
arkanoid_state->initialDraw = false;
}
static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
const ArkanoidState* arkanoid_state = acquire_mutex((ValueMutex*)ctx, 25);
ArkanoidState* arkanoid_state = acquire_mutex((ValueMutex*)ctx, 25);
if(arkanoid_state == NULL) {
return;
}
//Initial level draw
if(!initialDraw) {
initialDraw = true;
if(!arkanoid_state->initialDraw) {
arkanoid_state->initialDraw = true;
// Set default font for text
canvas_set_font(canvas, FontPrimary);
canvas_set_font(canvas, FontSecondary);
//Draws the new level
reset_level(canvas);
reset_level(canvas, arkanoid_state);
}
//Draws new bricks and resets their values
for(unsigned int row = 0; row < ROWS; row++) {
for(unsigned int column = 0; column < COLUMNS; column++) {
if(!isHit[row][column]) {
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(lives > 0) {
draw_paddle(canvas);
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);
draw_ball(canvas);
if(brickCount == ROWS * COLUMNS) {
level++;
reset_level(canvas);
if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) {
arkanoid_state->level++;
reset_level(canvas, arkanoid_state);
}
} else {
reset_level(canvas);
initialDraw = false;
start = false;
lives = 3;
score = 0;
reset_level(canvas, arkanoid_state);
arkanoid_state->initialDraw = false;
arkanoid_state->lives = 3;
arkanoid_state->score = 0;
}
release_mutex((ValueMutex*)ctx, arkanoid_state);
@ -320,6 +358,7 @@ static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) {
int32_t arkanoid_game_app(void* p) {
UNUSED(p);
int32_t return_code = 0;
// Set random seed from interrupts
srand(DWT->CYCCNT);
@ -331,8 +370,8 @@ int32_t arkanoid_game_app(void* p) {
ValueMutex state_mutex;
if(!init_mutex(&state_mutex, arkanoid_state, sizeof(ArkanoidState))) {
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
free(arkanoid_state);
return 255;
return_code = 255;
goto free_and_exit;
}
// Set system callbacks
@ -345,7 +384,7 @@ int32_t arkanoid_game_app(void* p) {
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22);
// Open GUI and register view_port
Gui* gui = furi_record_open("gui");
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
GameEvent event;
@ -363,13 +402,13 @@ int32_t arkanoid_game_app(void* p) {
processing = false;
break;
case InputKeyRight:
if(xPaddle < FLIPPER_LCD_WIDTH - 12) {
xPaddle += 8;
if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) {
arkanoid_state->xPaddle += 8;
}
break;
case InputKeyLeft:
if(xPaddle > 0) {
xPaddle -= 8;
if(arkanoid_state->xPaddle > 0) {
arkanoid_state->xPaddle -= 8;
}
break;
case InputKeyUp:
@ -378,38 +417,40 @@ int32_t arkanoid_game_app(void* p) {
break;
case InputKeyOk:
//Release ball if FIRE pressed
released = true;
arkanoid_state->ball_state.released = true;
//Apply random direction to ball on release
if(rand_range(0, 2) == 0) {
dx = 1;
arkanoid_state->ball_state.dx = 1;
} else {
dx = -1;
arkanoid_state->ball_state.dx = -1;
}
//Makes sure the ball heads upwards
dy = -1;
arkanoid_state->ball_state.dy = -1;
break;
}
}
}
} else {
// Event timeout
FURI_LOG_D(TAG, "osMessageQueue: Event timeout");
FURI_LOG_D(TAG, "furi_message_queue: Event timeout");
}
view_port_update(view_port);
release_mutex(&state_mutex, arkanoid_state);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close("gui");
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_NOTIFICATION);
view_port_free(view_port);
furi_message_queue_free(event_queue);
delete_mutex(&state_mutex);
free(arkanoid_state);
return 0;
}
free_and_exit:
free(arkanoid_state);
furi_message_queue_free(event_queue);
return return_code;
}

View File

@ -61,6 +61,15 @@ typedef struct {
InputEvent input;
} SnakeEvent;
static const NotificationSequence sequence_short_vibro_and_sound = {
&message_vibro_on,
&message_note_c5,
&message_delay_50,
&message_sound_off,
&message_vibro_off,
NULL,
};
static void snake_game_render_callback(Canvas* const canvas, void* ctx) {
const SnakeState* snake_state = acquire_mutex((ValueMutex*)ctx, 25);
if(snake_state == NULL) {
@ -238,7 +247,7 @@ static void snake_game_move_snake(SnakeState* const snake_state, Point const nex
snake_state->points[0] = next_step;
}
static void snake_game_process_game_step(SnakeState* const snake_state) {
static void snake_game_process_game_step(SnakeState* const snake_state, NotificationApp* notify) {
if(snake_state->state == GameStateGameOver) {
return;
}
@ -273,10 +282,8 @@ static void snake_game_process_game_step(SnakeState* const snake_state) {
bool eatFruit = (next_step.x == snake_state->fruit.x) && (next_step.y == snake_state->fruit.y);
if(eatFruit) {
NotificationApp* notification = furi_record_open("notification");
notification_message(notification, &sequence_single_vibro);
notification_message(notification, &sequence_blink_white_100);
furi_record_close("notification");
notification_message(notify, &sequence_short_vibro_and_sound);
//notification_message(notify, &sequence_blink_white_100);
snake_state->len++;
if(snake_state->len >= MAX_SNAKE_LEN) {
@ -320,6 +327,8 @@ int32_t snake_game_app(void* p) {
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
SnakeEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
@ -354,7 +363,7 @@ int32_t snake_game_app(void* p) {
}
}
} else if(event.type == EventTypeTick) {
snake_game_process_game_step(snake_state);
snake_game_process_game_step(snake_state, notification);
}
} else {
// event timeout
@ -368,6 +377,7 @@ int32_t snake_game_app(void* p) {
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);
delete_mutex(&state_mutex);

View File

@ -5,6 +5,6 @@ App(
entry_point="tetris_game_app",
cdefines=["APP_TETRIS_GAME"],
requires=["gui"],
stack_size=1 * 1024,
stack_size=2 * 1024,
order=20,
)

View File

@ -6,33 +6,28 @@
#define TAG "TicTacToe"
uint8_t selBoxX;
uint8_t selBoxY;
uint8_t selX = 2;
uint8_t selY = 2;
uint16_t scoreX;
uint16_t scoreO;
char player = 'X';
char field[3][3];
bool fieldx[3][3];
const uint8_t coords[3] = {6, 27, 48};
bool button_state = false;
typedef enum { EventTypeTick, EventTypeKey } EventType;
typedef enum { DirectionUp, DirectionRight, DirectionDown, DirectionLeft } Direction;
typedef enum { GameStatePlaying, GameStateGameOver } GameState;
typedef struct {
GameState game_state;
FuriTimer* timer;
uint8_t selBoxX;
uint8_t selBoxY;
uint8_t selX;
uint8_t selY;
uint16_t scoreX;
uint16_t scoreO;
char player;
char field[3][3];
bool fieldx[3][3];
uint8_t coords[3];
bool button_state;
} TicTacToeState;
typedef struct {
@ -49,15 +44,15 @@ void drawCircle(Canvas* const canvas, uint8_t x, uint8_t y) {
canvas_draw_circle(canvas, x + 4, y + 5, 5);
}
void player_switch() {
if(player == 'O') {
player = 'X';
} else if(player == 'X') {
player = 'O';
void player_switch(TicTacToeState* ts) {
if(ts->player == 'O') {
ts->player = 'X';
} else if(ts->player == 'X') {
ts->player = 'O';
}
}
void tictactoe_draw(Canvas* canvas) {
void tictactoe_draw(Canvas* canvas, TicTacToeState* ts) {
// Draws the game field
canvas_draw_frame(canvas, 0, 0, 64, 64); // frame
canvas_draw_line(canvas, 0, 21, 63, 21); // horizontal line
@ -68,34 +63,34 @@ void tictactoe_draw(Canvas* canvas) {
// Draws the game field elements (X or O)
for(uint8_t i = 0; i <= 2; i++) {
for(uint8_t j = 0; j <= 2; j++) {
if(field[i][j] == 'O') {
drawCircle(canvas, coords[i], coords[j]);
} else if(field[i][j] == 'X') {
drawCross(canvas, coords[i], coords[j]);
if(ts->field[i][j] == 'O') {
drawCircle(canvas, ts->coords[i], ts->coords[j]);
} else if(ts->field[i][j] == 'X') {
drawCross(canvas, ts->coords[i], ts->coords[j]);
}
}
}
// Draws the selection box
if(selX == 1) {
selBoxX = 1;
} else if(selX == 2) {
selBoxX = 22;
} else if(selX == 3) {
selBoxX = 43;
if(ts->selX == 1) {
ts->selBoxX = 1;
} else if(ts->selX == 2) {
ts->selBoxX = 22;
} else if(ts->selX == 3) {
ts->selBoxX = 43;
}
if(selY == 1) {
selBoxY = 1;
} else if(selY == 2) {
selBoxY = 22;
} else if(selY == 3) {
selBoxY = 43;
if(ts->selY == 1) {
ts->selBoxY = 1;
} else if(ts->selY == 2) {
ts->selBoxY = 22;
} else if(ts->selY == 3) {
ts->selBoxY = 43;
}
canvas_set_color(canvas, ColorBlack);
canvas_draw_frame(canvas, selBoxX, selBoxY, 20, 20);
canvas_draw_frame(canvas, selBoxX + 1, selBoxY + 1, 18, 18);
canvas_draw_frame(canvas, ts->selBoxX, ts->selBoxY, 20, 20);
canvas_draw_frame(canvas, ts->selBoxX + 1, ts->selBoxY + 1, 18, 18);
// Draws the sidebar
canvas_set_font(canvas, FontPrimary);
@ -103,105 +98,112 @@ void tictactoe_draw(Canvas* canvas) {
canvas_draw_str(canvas, 75, 24, "X:");
char scoreXBuffer[10];
snprintf(scoreXBuffer, sizeof(scoreXBuffer), "%d", scoreX);
snprintf(scoreXBuffer, sizeof(scoreXBuffer), "%d", ts->scoreX);
canvas_draw_str(canvas, 88, 24, scoreXBuffer);
canvas_draw_str(canvas, 75, 35, "O:");
char scoreOBuffer[10];
snprintf(scoreOBuffer, sizeof(scoreOBuffer), "%d", scoreO);
snprintf(scoreOBuffer, sizeof(scoreOBuffer), "%d", ts->scoreO);
canvas_draw_str(canvas, 88, 35, scoreOBuffer);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 75, 46, "Player:");
if(player == 'X') {
if(ts->player == 'X') {
drawCross(canvas, 93, 50);
} else if(player == 'O') {
} else if(ts->player == 'O') {
drawCircle(canvas, 93, 50);
}
}
void clear_game_field() {
void clear_game_field(TicTacToeState* ts) {
// Clears the game field arrays
for(uint8_t i = 0; i <= 2; i++) {
for(uint8_t j = 0; j <= 2; j++) {
field[i][j] = ' ';
fieldx[i][j] = false;
ts->field[i][j] = ' ';
ts->fieldx[i][j] = false;
}
}
selX = 2; // Centers the selection box on X axis
selY = 2; // Centers the selection box on Y axis
ts->selX = 2; // Centers the selection box on X axis
ts->selY = 2; // Centers the selection box on Y axis
}
void reset_game_data() {
scoreO = 0;
scoreX = 0;
player = 'X';
void reset_game_data(TicTacToeState* ts) {
ts->scoreO = 0;
ts->scoreX = 0;
ts->player = 'X';
}
void draw_win(Canvas* canvas, char player) {
void draw_win(Canvas* canvas, char player, TicTacToeState* ts) {
// Handles the score table
if(player == 'X') {
scoreX++;
ts->scoreX++;
} else if(player == 'O') {
scoreO++;
ts->scoreO++;
}
// Switches the players
player_switch();
player_switch(ts);
// Draws the board with players switched
tictactoe_draw(canvas);
tictactoe_draw(canvas, ts);
// Clear the game field
clear_game_field();
clear_game_field(ts);
// Draw the new board
tictactoe_draw(canvas);
tictactoe_draw(canvas, ts);
}
static void tictactoe_state_init(TicTacToeState* const tictactoe_state) {
static void tictactoe_state_init(TicTacToeState* tictactoe_state) {
// Set the initial game state
tictactoe_state->game_state = GameStatePlaying;
tictactoe_state->selX = 2;
tictactoe_state->selY = 2;
tictactoe_state->player = 'X';
tictactoe_state->coords[0] = 6;
tictactoe_state->coords[1] = 27;
tictactoe_state->coords[2] = 48;
tictactoe_state->button_state = false;
clear_game_field();
clear_game_field(tictactoe_state);
reset_game_data();
reset_game_data(tictactoe_state);
}
static void tictactoe_draw_callback(Canvas* const canvas, void* ctx) {
const TicTacToeState* tictactoe_state = acquire_mutex((ValueMutex*)ctx, 25);
if(tictactoe_state == NULL) {
TicTacToeState* ticst = acquire_mutex((ValueMutex*)ctx, 25);
if(ticst == NULL) {
return;
}
if(selX > 3) {
selX = 3;
} else if(selX < 1) {
selX = 1;
if(ticst->selX > 3) {
ticst->selX = 3;
} else if(ticst->selX < 1) {
ticst->selX = 1;
}
if(selY > 3) {
selY = 3;
} else if(selY < 1) {
selY = 1;
if(ticst->selY > 3) {
ticst->selY = 3;
} else if(ticst->selY < 1) {
ticst->selY = 1;
}
// Assigns the game field elements their value (X or O) when the OK button is pressed
if(button_state) {
button_state = false;
if(ticst->button_state) {
ticst->button_state = false;
for(uint8_t i = 0; i <= 2; i++) {
for(uint8_t j = 0; j <= 2; j++) {
if((selX == i + 1) && (selY == j + 1) && (fieldx[i][j] == false)) {
if(player == 'X') {
field[i][j] = 'X';
fieldx[i][j] = true;
player_switch();
} else if(player == 'O') {
field[i][j] = 'O';
fieldx[i][j] = true;
player_switch();
if((ticst->selX == i + 1) && (ticst->selY == j + 1) &&
(ticst->fieldx[i][j] == false)) {
if(ticst->player == 'X') {
ticst->field[i][j] = 'X';
ticst->fieldx[i][j] = true;
player_switch(ticst);
} else if(ticst->player == 'O') {
ticst->field[i][j] = 'O';
ticst->fieldx[i][j] = true;
player_switch(ticst);
}
}
}
@ -209,48 +211,80 @@ static void tictactoe_draw_callback(Canvas* const canvas, void* ctx) {
}
// Checks the game field for winning combinations
if((field[0][0] == 'X') && (field[1][0] == 'X') && (field[2][0] == 'X')) {
draw_win(canvas, 'X');
} else if((field[0][1] == 'X') && (field[1][1] == 'X') && (field[2][1] == 'X')) {
draw_win(canvas, 'X');
} else if((field[0][2] == 'X') && (field[1][2] == 'X') && (field[2][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[0][0] == 'X') && (field[0][1] == 'X') && (field[0][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[1][0] == 'X') && (field[1][1] == 'X') && (field[1][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[2][0] == 'X') && (field[2][1] == 'X') && (field[2][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[0][0] == 'X') && (field[1][1] == 'X') && (field[2][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[2][0] == 'X') && (field[1][1] == 'X') && (field[0][2] == 'X')) {
draw_win(canvas, 'X');
} else if((field[0][0] == 'O') && (field[1][0] == 'O') && (field[2][0] == 'O')) {
draw_win(canvas, 'O');
} else if((field[0][1] == 'O') && (field[1][1] == 'O') && (field[2][1] == 'O')) {
draw_win(canvas, 'O');
} else if((field[0][2] == 'O') && (field[1][2] == 'O') && (field[2][2] == 'O')) {
draw_win(canvas, 'O');
} else if((field[0][0] == 'O') && (field[0][1] == 'O') && (field[0][2] == 'O')) {
draw_win(canvas, 'O');
} else if((field[1][0] == 'O') && (field[1][1] == 'O') && (field[1][2] == 'O')) {
draw_win(canvas, 'O');
} else if((field[2][0] == 'O') && (field[2][1] == 'O') && (field[2][2] == 'O')) {
draw_win(canvas, 'O');
} else if((field[0][0] == 'O') && (field[1][1] == 'O') && (field[2][2] == 'O')) {
draw_win(canvas, 'O');
} else if((field[2][0] == 'O') && (field[1][1] == 'O') && (field[0][2] == 'O')) {
draw_win(canvas, 'O');
if((ticst->field[0][0] == 'X') && (ticst->field[1][0] == 'X') && (ticst->field[2][0] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(fieldx[0][0] == true) && (fieldx[0][1] == true) && (fieldx[0][2] == true) &&
(fieldx[1][0] == true) && (fieldx[1][1] == true) && (fieldx[1][2] == true) &&
(fieldx[2][0] == true) && (fieldx[2][1] == true) && (fieldx[2][2] == true)) {
draw_win(canvas, 'T');
(ticst->field[0][1] == 'X') && (ticst->field[1][1] == 'X') &&
(ticst->field[2][1] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[0][2] == 'X') && (ticst->field[1][2] == 'X') &&
(ticst->field[2][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[0][0] == 'X') && (ticst->field[0][1] == 'X') &&
(ticst->field[0][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[1][0] == 'X') && (ticst->field[1][1] == 'X') &&
(ticst->field[1][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[2][0] == 'X') && (ticst->field[2][1] == 'X') &&
(ticst->field[2][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[0][0] == 'X') && (ticst->field[1][1] == 'X') &&
(ticst->field[2][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[2][0] == 'X') && (ticst->field[1][1] == 'X') &&
(ticst->field[0][2] == 'X')) {
draw_win(canvas, 'X', ticst);
} else if(
(ticst->field[0][0] == 'O') && (ticst->field[1][0] == 'O') &&
(ticst->field[2][0] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[0][1] == 'O') && (ticst->field[1][1] == 'O') &&
(ticst->field[2][1] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[0][2] == 'O') && (ticst->field[1][2] == 'O') &&
(ticst->field[2][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[0][0] == 'O') && (ticst->field[0][1] == 'O') &&
(ticst->field[0][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[1][0] == 'O') && (ticst->field[1][1] == 'O') &&
(ticst->field[1][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[2][0] == 'O') && (ticst->field[2][1] == 'O') &&
(ticst->field[2][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[0][0] == 'O') && (ticst->field[1][1] == 'O') &&
(ticst->field[2][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->field[2][0] == 'O') && (ticst->field[1][1] == 'O') &&
(ticst->field[0][2] == 'O')) {
draw_win(canvas, 'O', ticst);
} else if(
(ticst->fieldx[0][0] == true) && (ticst->fieldx[0][1] == true) &&
(ticst->fieldx[0][2] == true) && (ticst->fieldx[1][0] == true) &&
(ticst->fieldx[1][1] == true) && (ticst->fieldx[1][2] == true) &&
(ticst->fieldx[2][0] == true) && (ticst->fieldx[2][1] == true) &&
(ticst->fieldx[2][2] == true)) {
draw_win(canvas, 'T', ticst);
}
tictactoe_draw(canvas);
tictactoe_draw(canvas, ticst);
release_mutex((ValueMutex*)ctx, tictactoe_state);
release_mutex((ValueMutex*)ctx, ticst);
}
static void tictactoe_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
@ -310,26 +344,26 @@ int32_t tictactoe_game_app(void* p) {
processing = false;
break;
case InputKeyRight:
selX++;
tictactoe_state->selX++;
break;
case InputKeyLeft:
selX--;
tictactoe_state->selX--;
break;
case InputKeyUp:
selY--;
tictactoe_state->selY--;
break;
case InputKeyDown:
selY++;
tictactoe_state->selY++;
break;
case InputKeyOk:
button_state = true;
tictactoe_state->button_state = true;
break;
}
}
}
} else {
// Event timeout
FURI_LOG_D(TAG, "osMessageQueue: Event timeout");
FURI_LOG_D(TAG, "furi_message_queue: Event timeout");
}
view_port_update(view_port);

View File

@ -11,6 +11,20 @@
<br>
<br>
## With Web Updater
- Be sure you updated to latest official release before, and verify that microSD card is installed
- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest)
- Connect your device and select `Install via Web Updater`
after that on web updater page - press `Connect` button
- Press `Install` button
- And wait, if all flashed successfully - you will have all needed assets pre installed
- Done
<br>
<br>
## With offline update on flipper
### **Replace (CURRENT VERSION) with version that you downloaded from releases**
@ -59,7 +73,7 @@ then select **`flipper-z-f7-full-(CURRENT VERSION).dfu`**
<br>
# After install:
- ### If you installed using .dfu - unpack files from archive `sd-card-(CURRENT VERSION).zip` to your microSD card
<br>
- ## [Read instructions how to use plugins and more](https://github.com/Eng1n33r/flipperzero-firmware#instructions)
- ## [How To: Configure UniversalRF Remix App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/UniRFRemix.md)