mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-20 11:51:48 +03:00
Merge branch 'Eng1n33r:dev' into feat/brute-helper
This commit is contained in:
commit
31e06da7e7
91
.github/CODEOWNERS
vendored
91
.github/CODEOWNERS
vendored
@ -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
|
85
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
85
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@ -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.
|
||||
|
35
.github/ISSUE_TEMPLATE/02_enhancements.yml
vendored
35
.github/ISSUE_TEMPLATE/02_enhancements.yml
vendored
@ -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.
|
||||
|
41
.github/ISSUE_TEMPLATE/03_feature_request.yml
vendored
41
.github/ISSUE_TEMPLATE/03_feature_request.yml
vendored
@ -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.
|
||||
|
9
.github/ISSUE_TEMPLATE/config.yml
vendored
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user