blackjack upd

This commit is contained in:
RogueMaster
2022-11-17 23:37:29 -05:00
parent b32612b1c9
commit 7c09807aeb
17 changed files with 1145 additions and 758 deletions

View File

@@ -1,10 +1,10 @@
App(
appid="BlackJack",
name="BlackJack",
appid="blackjack",
name="Blackjack",
apptype=FlipperAppType.EXTERNAL,
entry_point="blackjack_app",
cdefines=["APP_BLACKJACK"],
requires=["gui","storage"],
requires=["gui","storage","canvas"],
stack_size=2 * 1024,
order=30,
fap_icon="blackjack_10px.png",

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

View File

@@ -3,6 +3,8 @@
#include <stdlib.h>
#include <dolphin/dolphin.h>
#include <dialogs/dialogs.h>
#include <gui/canvas_i.h>
#include <math.h>
#include "util.h"
#include "defines.h"
@@ -12,7 +14,7 @@
#include "util.h"
#include "ui.h"
#include "BlackJack_icons.h"
#include "blackjack_icons.h"
#define DEALER_MAX 17
@@ -21,6 +23,7 @@ void start_round(GameState* game_state);
void init(GameState *game_state);
static void draw_ui(Canvas *const canvas, const GameState *game_state) {
draw_money(canvas, game_state->player_score);
draw_score(canvas, true, hand_count(game_state->player_cards, game_state->player_card_count));
@@ -68,6 +71,7 @@ Card draw_card(GameState* game_state) {
return c;
}
void drawPlayerCard(void *ctx) {
GameState *game_state = ctx;
Card c = draw_card(game_state);
@@ -89,42 +93,48 @@ void drawDealerCard(void* ctx) {
//region queue callbacks
void to_lose_state(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "You lost");
}
void to_bust_state(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Busted!");
}
void to_draw_state(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Draw");
}
void to_dealer_turn(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Dealers turn");
}
void to_win_state(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "You win");
}
void to_start(const void *ctx, Canvas *const canvas) {
const GameState *game_state = ctx;
if(game_state->settings.message_duration == 0) return;
if (game_state->settings.message_duration == 0)
return;
popup_frame(canvas);
elements_multiline_text_aligned(canvas, 64, 22, AlignCenter, AlignCenter, "Round started");
}
@@ -135,6 +145,7 @@ void before_start(void* ctx) {
game_state->player_card_count = 0;
}
void start(void *ctx) {
GameState *game_state = ctx;
start_round(game_state);
@@ -144,12 +155,7 @@ void draw(void* ctx) {
GameState *game_state = ctx;
game_state->player_score += game_state->bet;
game_state->bet = 0;
enqueue(
&(game_state->queue_state),
game_state,
start,
before_start,
to_start,
enqueue(&(game_state->queue_state), game_state, start, before_start, to_start,
game_state->settings.message_duration);
}
@@ -163,15 +169,11 @@ void lose(void* ctx) {
game_state->state = GameStatePlay;
game_state->bet = 0;
if (game_state->player_score >= game_state->settings.round_price) {
enqueue(
&(game_state->queue_state),
game_state,
start,
before_start,
to_start,
enqueue(&(game_state->queue_state), game_state, start, before_start, to_start,
game_state->settings.message_duration);
} else {
enqueue(&(game_state->queue_state), game_state, game_over, NULL, NULL, 0);
enqueue(&(game_state->queue_state), game_state, game_over, NULL, NULL,
0);
}
}
@@ -180,15 +182,11 @@ void win(void* ctx) {
game_state->state = GameStatePlay;
game_state->player_score += game_state->bet * 2;
game_state->bet = 0;
enqueue(
&(game_state->queue_state),
game_state,
start,
before_start,
to_start,
enqueue(&(game_state->queue_state), game_state, start, before_start, to_start,
game_state->settings.message_duration);
}
void dealerTurn(void *ctx) {
GameState *game_state = ctx;
game_state->state = GameStateDealer;
@@ -206,17 +204,21 @@ void dealer_card_animation(const void* ctx, Canvas* const canvas) {
Card animatingCard = game_state->deck.cards[game_state->deck.index];
if (game_state->dealer_card_count > 1) {
Vector end = card_pos_at_index(game_state->dealer_card_count);
draw_card_animation(animatingCard, (Vector){0, 64}, (Vector){0, 32}, end, t, true, canvas);
draw_card_animation(animatingCard,
(Vector) {0, 64},
(Vector) {0, 32},
end,
t,
true,
canvas);
} else {
draw_card_animation(
animatingCard,
draw_card_animation(animatingCard,
(Vector) {32, -CARD_HEIGHT},
(Vector) {64, 32},
(Vector) {2, 2},
t,
false,
canvas);
// draw_deck(game_state->dealer_cards, game_state->dealer_card_count, canvas);
}
}
@@ -224,8 +226,7 @@ void dealer_back_card_animation(const void* ctx, Canvas* const canvas) {
const GameState *game_state = ctx;
float t = animationTime(game_state);
Vector currentPos =
quadratic_2d((Vector){32, -CARD_HEIGHT}, (Vector){64, 32}, (Vector){13, 5}, t);
Vector currentPos = quadratic_2d((Vector) {32, -CARD_HEIGHT}, (Vector) {64, 32}, (Vector) {13, 5}, t);
draw_card_back_at(currentPos.x, currentPos.y, canvas);
}
@@ -236,38 +237,32 @@ void player_card_animation(const void* ctx, Canvas* const canvas) {
Card animatingCard = game_state->deck.cards[game_state->deck.index];
Vector end = card_pos_at_index(game_state->player_card_count);
draw_card_animation(
animatingCard, (Vector){32, -CARD_HEIGHT}, (Vector){0, 32}, end, t, true, canvas);
// draw_deck(game_state->dealer_cards, game_state->player_card_count, canvas);
draw_card_animation(animatingCard,
(Vector) {32, -CARD_HEIGHT},
(Vector) {0, 32},
end,
t,
true,
canvas);
}
//endregion
void player_tick(GameState *game_state) {
uint8_t score = hand_count(game_state->player_cards, game_state->player_card_count);
if ((game_state->doubled && score <= 21) || score == 21) {
enqueue(
&(game_state->queue_state),
game_state,
dealerTurn,
NULL,
to_dealer_turn,
enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn,
game_state->settings.message_duration);
} else if (score > 21) {
enqueue(
&(game_state->queue_state),
game_state,
lose,
NULL,
to_bust_state,
enqueue(&(game_state->queue_state), game_state, lose, NULL, to_bust_state,
game_state->settings.message_duration);
} else {
if(game_state->selectDirection == DirectionUp ||
game_state->selectDirection == DirectionDown) {
if(game_state->selectDirection == DirectionUp || game_state->selectDirection == DirectionDown){
move_menu(game_state->menu, game_state->selectDirection == DirectionUp ? -1 : 1);
}
if (game_state->selectDirection == Select){
activate_menu(game_state->menu, game_state);
}
}
}
@@ -278,37 +273,17 @@ void dealer_tick(GameState* game_state) {
if (dealer_score >= DEALER_MAX) {
if (dealer_score > 21 || dealer_score < player_score) {
enqueue(
&(game_state->queue_state),
game_state,
win,
NULL,
to_win_state,
enqueue(&(game_state->queue_state), game_state, win, NULL, to_win_state,
game_state->settings.message_duration);
} else if (dealer_score > player_score) {
enqueue(
&(game_state->queue_state),
game_state,
lose,
NULL,
to_lose_state,
enqueue(&(game_state->queue_state), game_state, lose, NULL, to_lose_state,
game_state->settings.message_duration);
} else if (dealer_score == player_score) {
enqueue(
&(game_state->queue_state),
game_state,
draw,
NULL,
to_draw_state,
enqueue(&(game_state->queue_state), game_state, draw, NULL, to_draw_state,
game_state->settings.message_duration);
}
} else {
enqueue(
&(game_state->queue_state),
game_state,
drawDealerCard,
NULL,
dealer_card_animation,
enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_card_animation,
game_state->settings.animation_duration);
}
}
@@ -321,8 +296,7 @@ void settings_tick(GameState* game_state) {
game_state->selectedMenu--;
}
if(game_state->selectDirection == DirectionLeft ||
game_state->selectDirection == DirectionRight) {
if (game_state->selectDirection == DirectionLeft || game_state->selectDirection == DirectionRight) {
int nextScore = 0;
switch (game_state->selectedMenu) {
case 0:
@@ -367,6 +341,7 @@ void settings_tick(GameState* game_state) {
break;
}
}
}
void tick(GameState *game_state) {
@@ -387,39 +362,21 @@ void tick(GameState* game_state) {
if (!game_state->started) {
game_state->selectedMenu = 0;
game_state->started = true;
enqueue(
&(game_state->queue_state),
game_state,
drawDealerCard,
NULL,
dealer_back_card_animation,
enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_back_card_animation,
game_state->settings.animation_duration);
enqueue(
&(game_state->queue_state),
game_state,
drawPlayerCard,
NULL,
player_card_animation,
enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation,
game_state->settings.animation_duration);
enqueue(
&(game_state->queue_state),
game_state,
drawDealerCard,
NULL,
dealer_card_animation,
enqueue(&(game_state->queue_state), game_state, drawDealerCard, NULL, dealer_card_animation,
game_state->settings.animation_duration);
enqueue(
&(game_state->queue_state),
game_state,
drawPlayerCard,
NULL,
player_card_animation,
enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation,
game_state->settings.animation_duration);
}
if(!queue_ran) player_tick(game_state);
if (!queue_ran)
player_tick(game_state);
break;
case GameStateDealer:
if(!queue_ran) dealer_tick(game_state);
if (!queue_ran)
dealer_tick(game_state);
break;
case GameStateSettings:
settings_tick(game_state);
@@ -429,6 +386,7 @@ void tick(GameState* game_state) {
}
game_state->selectDirection = None;
}
void start_round(GameState *game_state) {
@@ -482,31 +440,15 @@ void doubleAction(void* state) {
game_state->player_score -= game_state->settings.round_price;
game_state->bet += game_state->settings.round_price;
game_state->doubled = true;
enqueue(
&(game_state->queue_state),
game_state,
drawPlayerCard,
NULL,
player_card_animation,
enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation,
game_state->settings.animation_duration);
game_state->player_cards[game_state->player_card_count] =
game_state->deck.cards[game_state->deck.index];
game_state->player_cards[game_state->player_card_count] = game_state->deck.cards[game_state->deck.index];
uint8_t score = hand_count(game_state->player_cards, game_state->player_card_count + 1);
if (score > 21) {
enqueue(
&(game_state->queue_state),
game_state,
lose,
NULL,
to_bust_state,
enqueue(&(game_state->queue_state), game_state, lose, NULL, to_bust_state,
game_state->settings.message_duration);
} else {
enqueue(
&(game_state->queue_state),
game_state,
dealerTurn,
NULL,
to_dealer_turn,
enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn,
game_state->settings.message_duration);
}
set_menu_state(game_state->menu, 0, false);
@@ -515,22 +457,12 @@ void doubleAction(void* state) {
void hitAction(void *state){
GameState *game_state = state;
enqueue(
&(game_state->queue_state),
game_state,
drawPlayerCard,
NULL,
player_card_animation,
enqueue(&(game_state->queue_state), game_state, drawPlayerCard, NULL, player_card_animation,
game_state->settings.animation_duration);
}
void stayAction(void *state){
GameState *game_state = state;
enqueue(
&(game_state->queue_state),
game_state,
dealerTurn,
NULL,
to_dealer_turn,
enqueue(&(game_state->queue_state), game_state, dealerTurn, NULL, to_dealer_turn,
game_state->settings.message_duration);
}
@@ -548,6 +480,7 @@ int32_t blackjack_app(void* p) {
add_menu(game_state->menu, "Double", doubleAction);
add_menu(game_state->menu, "Hit", hitAction);
add_menu(game_state->menu, "Stay", stayAction);
set_card_graphics(&I_card_graphics);
game_state->state = GameStateStart;
@@ -562,7 +495,8 @@ int32_t blackjack_app(void* p) {
view_port_draw_callback_set(view_port, render_callback, &state_mutex);
view_port_input_callback_set(view_port, input_callback, event_queue);
FuriTimer* timer = furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue);
FuriTimer *timer =
furi_timer_alloc(update_timer_callback, FuriTimerTypePeriodic, event_queue);
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 25);
Gui *gui = furi_record_open("gui");
@@ -575,6 +509,7 @@ int32_t blackjack_app(void* p) {
GameState *localstate = (GameState *) acquire_mutex_block(&state_mutex);
if (event_status == FuriStatusOk) {
if (event.type == EventTypeKey) {
if (event.input.type == InputTypePress) {
switch (event.input.key) {
case InputKeyUp:
@@ -615,6 +550,7 @@ int32_t blackjack_app(void* p) {
release_mutex(&state_mutex, localstate);
}
furi_timer_free(timer);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
@@ -623,6 +559,7 @@ int32_t blackjack_app(void* p) {
delete_mutex(&state_mutex);
free_and_exit:
free(game_state->deck.cards);
free_menu(game_state->menu);
queue_clear(&(game_state->queue_state));
free(game_state);

View File

@@ -1,7 +1,7 @@
#include "card.h"
#include "dml.h"
#include "ui.h"
#define CORNER_MARGIN 3
#define CARD_DRAW_X_START 108
#define CARD_DRAW_Y_START 38
#define CARD_DRAW_X_SPACE 10
@@ -9,21 +9,27 @@
#define CARD_DRAW_X_OFFSET 4
#define CARD_DRAW_FIRST_ROW_LENGTH 7
bool pips[4][49] = {
{//spades
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0},
{
//hearts
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
},
{//diamonds
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
{//clubs
0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}};
uint8_t pips[4][3] = {
{21, 10, 7}, //spades
{7, 10, 7}, //hearts
{0, 10, 7}, //diamonds
{14, 10, 7}, //clubs
};
uint8_t letters[13][3] = {
{0, 0, 5},
{5, 0, 5},
{10, 0, 5},
{15, 0, 5},
{20, 0, 5},
{25, 0, 5},
{30, 0, 5},
{0, 5, 5},
{5, 5, 5},
{10, 5, 5},
{15, 5, 5},
{20, 5, 5},
{25, 5, 5},
};
//region Player card positions
uint8_t playerCardPositions[22][4] = {
@@ -53,99 +59,84 @@ uint8_t playerCardPositions[22][4] = {
{49, 14},
};
//endregion
Icon *card_graphics = NULL;
bool get_pip_pixel(uint8_t pip, uint8_t x, uint8_t y) {
return pips[pip][x + y * 7];
void set_card_graphics(const Icon *graphics) {
card_graphics = (Icon *) graphics;
}
void
draw_card_at_colored(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, bool inverted, Canvas *const canvas) {
DrawMode primary = inverted ? Black : White;
DrawMode secondary = inverted ? White : Black;
draw_rounded_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, primary);
draw_rounded_box_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, Black);
uint8_t *drawInfo = pips[pip];
uint8_t px = drawInfo[0], py = drawInfo[1], s = drawInfo[2];
uint8_t left = pos_x + 2;
uint8_t right = (pos_x + CARD_WIDTH - s - 2);
uint8_t top = pos_y + 2;
uint8_t bottom = (pos_y + CARD_HEIGHT - s - 2);
draw_icon_clip(canvas, card_graphics, right, top, px, py, s, s,
secondary);
draw_icon_clip_flipped(canvas, card_graphics, left, bottom, px, py, s, s,
secondary);
drawInfo = letters[character];
px = drawInfo[0], py = drawInfo[1], s = drawInfo[2];
left = pos_x + 2;
right = (pos_x + CARD_WIDTH - s - 2);
top = pos_y + 2;
bottom = (pos_y + CARD_HEIGHT - s - 2);
draw_icon_clip(canvas, card_graphics, left, top + 1, px, py, s, s,
secondary);
draw_icon_clip_flipped(canvas, card_graphics, right, bottom - 1, px, py, s, s,
secondary);
}
void draw_card_at(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Canvas *const canvas) {
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT);
canvas_set_color(canvas, ColorBlack);
canvas_draw_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT);
uint8_t left = pos_x + CORNER_MARGIN;
uint8_t right = (pos_x + CARD_WIDTH - CORNER_MARGIN - 7);
uint8_t top = pos_y + CORNER_MARGIN;
uint8_t bottom = (pos_y + CARD_HEIGHT - CORNER_MARGIN - 7);
for(uint8_t x = 0; x < 7; x++) {
for(uint8_t y = 0; y < 7; y++) {
if(get_pip_pixel(pip, x, y)) {
canvas_draw_dot(canvas, right + x + 1, top + y);
canvas_draw_dot(canvas, left + x - 1, bottom + y);
}
}
}
canvas_set_font(canvas, FontSecondary);
char drawChar[3];
if(character < 9)
snprintf(drawChar, sizeof(drawChar), "%i", character + 2);
else {
if(character == 9)
snprintf(drawChar, sizeof(drawChar), "J");
else if(character == 10)
snprintf(drawChar, sizeof(drawChar), "Q");
else if(character == 11)
snprintf(drawChar, sizeof(drawChar), "K");
else if(character == 12)
snprintf(drawChar, sizeof(drawChar), "A");
}
canvas_set_font_direction(canvas, CanvasDirectionLeftToRight);
canvas_draw_str_aligned(canvas, left + 2, top + 3, AlignCenter, AlignCenter, drawChar);
canvas_set_font_direction(canvas, CanvasDirectionRightToLeft);
//flipper crashes on non center aligned text when upside down
uint8_t margin = 9;
if(character == 8) //10 needs bigger margin
margin = 12;
canvas_draw_str_aligned(
canvas, right + margin, bottom - 3, AlignCenter, AlignCenter, drawChar);
canvas_set_font_direction(canvas, CanvasDirectionLeftToRight);
draw_card_at_colored(pos_x, pos_y, pip, character, false, canvas);
}
void draw_deck(const Card *cards, uint8_t count, Canvas *const canvas) {
for (int i = count - 1; i >= 0; i--) {
draw_card_at(
playerCardPositions[i][0],
playerCardPositions[i][1],
cards[i].pip,
cards[i].character,
canvas);
draw_card_at(playerCardPositions[i][0], playerCardPositions[i][1], cards[i].pip, cards[i].character, canvas);
}
}
Vector card_pos_at_index(uint8_t index) {
return (Vector){playerCardPositions[index][0], playerCardPositions[index][1]};
return (Vector) {
playerCardPositions[index][0],
playerCardPositions[index][1]
};
}
void draw_card_back_at(int8_t pos_x, int8_t pos_y, Canvas *const canvas) {
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT);
draw_rounded_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, White);
draw_rounded_box_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, Black);
draw_icon_clip(canvas, card_graphics, pos_x + 1, pos_y + 1, 35, 0, 15, 21, Black);
canvas_set_color(canvas, ColorBlack);
canvas_draw_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT);
for(uint8_t x = 0; x < CARD_WIDTH - 2; x++) {
for(uint8_t y = 0; y < CARD_HEIGHT - 2; y++) {
if((x + y) % 2 == 1) {
canvas_draw_dot(canvas, pos_x + x + 1, pos_y + y + 1);
}
}
}
}
void generate_deck(Deck *deck_ptr, uint8_t deck_count) {
uint16_t counter = 0;
if (deck_ptr->cards == NULL) {
deck_ptr->deck_count = deck_count;
deck_ptr->cards = malloc(sizeof(Card) * 52 * deck_count);
deck_ptr->card_count = deck_count * 52;
deck_ptr->cards = malloc(sizeof(Card) * deck_ptr->card_count);
}
for (uint8_t deck = 0; deck < deck_count; deck++) {
for (uint8_t pip = 0; pip < 4; pip++) {
for (uint8_t label = 0; label < 13; label++) {
deck_ptr->cards[counter] = (Card){pip, label};
deck_ptr->cards[counter] = (Card)
{
pip, label, false, false
};
counter++;
}
}
@@ -180,22 +171,14 @@ uint8_t hand_count(const Card* cards, uint8_t count) {
}
for (uint8_t i = 0; i < aceCount; i++) {
if((score + 11) <= 21)
score += 11;
else
score++;
if ((score + 11) <= 21) score += 11;
else score++;
}
return score;
}
void draw_card_animation(
Card animatingCard,
Vector from,
Vector control,
Vector to,
float t,
bool extra_margin,
void draw_card_animation(Card animatingCard, Vector from, Vector control, Vector to, float t, bool extra_margin,
Canvas *const canvas) {
float time = t;
if (extra_margin) {
@@ -204,13 +187,144 @@ void draw_card_animation(
Vector currentPos = quadratic_2d(from, control, to, time);
if (t > 1) {
draw_card_at(
currentPos.x, currentPos.y, animatingCard.pip, animatingCard.character, canvas);
draw_card_at(currentPos.x, currentPos.y, animatingCard.pip,
animatingCard.character, canvas);
} else {
if (t < 0.5)
draw_card_back_at(currentPos.x, currentPos.y, canvas);
else
draw_card_at(
currentPos.x, currentPos.y, animatingCard.pip, animatingCard.character, canvas);
draw_card_at(currentPos.x, currentPos.y, animatingCard.pip,
animatingCard.character, canvas);
}
}
void init_hand(Hand *hand_ptr, uint8_t count) {
hand_ptr->cards = malloc(sizeof(Card) * count);
hand_ptr->index = 0;
hand_ptr->max = count;
}
void free_hand(Hand *hand_ptr) {
FURI_LOG_D("CARD", "Freeing hand");
free(hand_ptr->cards);
}
void add_to_hand(Hand *hand_ptr, Card card) {
FURI_LOG_D("CARD", "Adding to hand");
if (hand_ptr->index < hand_ptr->max) {
hand_ptr->cards[hand_ptr->index] = card;
hand_ptr->index++;
}
}
void draw_card_space(int16_t pos_x, int16_t pos_y, bool highlighted, Canvas *const canvas) {
if (highlighted) {
draw_rounded_box_frame(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, Black);
draw_rounded_box_frame(canvas, pos_x + 2, pos_y + 2, CARD_WIDTH - 4, CARD_HEIGHT - 4, White);
} else {
draw_rounded_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT, Black);
draw_rounded_box_frame(canvas, pos_x + 2, pos_y + 2, CARD_WIDTH - 4, CARD_HEIGHT - 4, White);
}
}
int first_non_flipped_card(Hand hand) {
for (int i = 0; i < hand.index; i++) {
if (!hand.cards[i].flipped) {
return i;
}
}
return hand.index;
}
void draw_hand_column(Hand hand, int16_t pos_x, int16_t pos_y, int8_t highlight, Canvas *const canvas) {
if (hand.index == 0) {
draw_card_space(pos_x, pos_y, highlight > 0, canvas);
if(highlight==0)
draw_rounded_box(canvas, pos_x, pos_y, CARD_WIDTH, CARD_HEIGHT,
Inverse);
return;
}
int loopEnd = hand.index;
int hStart = max(loopEnd-4, 0);
int pos = 0;
int first= first_non_flipped_card(hand);
bool wastop=false;
if(first>=0 && first<=hStart && highlight!=first){
if(first>0){
draw_card_back_at(pos_x, pos_y + pos, canvas);
pos+=4;
hStart++;
wastop=true;
}
draw_card_at_colored(pos_x, pos_y + pos, hand.cards[first].pip, hand.cards[first].character,
false,
canvas);
pos+=8;
hStart++;
}
if(hStart>highlight && highlight>=0){
if(!wastop && first>0){
draw_card_back_at(pos_x, pos_y + pos, canvas);
pos+=4;
hStart++;
}
draw_card_at_colored(pos_x, pos_y + pos, hand.cards[highlight].pip, hand.cards[highlight].character,
true,
canvas);
pos+=8;
hStart++;
}
for (int i = hStart; i < loopEnd; i++, pos+=4) {
if (hand.cards[i].flipped) {
draw_card_back_at(pos_x, pos_y + pos, canvas);
if(i==highlight)
draw_rounded_box(canvas, pos_x+1, pos_y + pos+1, CARD_WIDTH - 2, CARD_HEIGHT - 2,
Inverse);
} else {
draw_card_at_colored(pos_x, pos_y + pos, hand.cards[i].pip, hand.cards[i].character,
(i == highlight),
canvas);
if(i == highlight || i==first) pos+=4;
}
}
}
Card remove_from_deck(uint16_t index, Deck *deck) {
FURI_LOG_D("CARD", "Removing from deck");
Card result = {0, 0, true, false};
if (deck->card_count > 0) {
deck->card_count--;
for (int i = 0, curr_index = 0; i <= deck->card_count; i++) {
if (i != index) {
deck->cards[curr_index] = deck->cards[i];
curr_index++;
} else {
result = deck->cards[i];
}
}
if (deck->index >= 0) {
deck->index--;
}
}
return result;
}
void extract_hand_region(Hand *hand, Hand *to, uint8_t start_index) {
FURI_LOG_D("CARD", "Extracting hand region");
if (start_index >= hand->index) return;
for (uint8_t i = start_index; i < hand->index; i++) {
add_to_hand(to, hand->cards[i]);
}
hand->index = start_index;
}
void add_hand_region(Hand *to, Hand *from) {
FURI_LOG_D("CARD", "Adding hand region");
if ((to->index + from->index) <= to->max) {
for (int i = 0; i < from->index; i++) {
add_to_hand(to, from->cards[i]);
}
}
}

View File

@@ -5,24 +5,35 @@
#include <stdlib.h>
#include "dml.h"
#define CARD_HEIGHT 24
#define CARD_HALF_HEIGHT CARD_HEIGHT / 2
#define CARD_WIDTH 18
#define CARD_HALF_WIDTH CARD_WIDTH / 2
#define CARD_HEIGHT 23
#define CARD_HALF_HEIGHT 11
#define CARD_WIDTH 17
#define CARD_HALF_WIDTH 8
//region types
typedef struct {
uint8_t pip; //Pip index 0:spades, 1:hearths, 2:diamonds, 3:clubs
uint8_t character; //Card letter [0-12], 0 means 2, 12 is Ace
bool disabled;
bool flipped;
} Card;
typedef struct {
uint8_t deck_count; //Number of decks used
Card *cards; //Cards in the deck
int card_count;
int index; //Card index (to know where we at in the deck)
} Deck;
typedef struct {
Card *cards; //Cards in the deck
uint8_t index; //Current index
uint8_t max; //How many cards we want to store
} Hand;
//endregion
void set_card_graphics(const Icon *graphics);
/**
* Gets card coordinates at the index (range: 0-20).
*
@@ -42,6 +53,19 @@ Vector card_pos_at_index(uint8_t index);
*/
void draw_card_at(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Canvas *const canvas);
/**
* Draws card at a given coordinate (top-left corner)
*
* @param pos_x X position
* @param pos_y Y position
* @param pip Pip index 0:spades, 1:hearths, 2:diamonds, 3:clubs
* @param character Letter [0-12] 0 is 2, 12 is A
* @param inverted Invert colors
* @param canvas Pointer to Flipper's canvas object
*/
void
draw_card_at_colored(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, bool inverted, Canvas *const canvas);
/**
* Draws 'count' cards at the bottom right corner
*
@@ -95,11 +119,59 @@ uint8_t hand_count(const Card* cards, uint8_t count);
* @param extra_margin Use extra margin at the end (arrives 0.2 unit before the end so it can stay there a bit)
* @param canvas Pointer to Flipper's canvas object
*/
void draw_card_animation(
Card animatingCard,
Vector from,
Vector control,
Vector to,
float t,
bool extra_margin,
void draw_card_animation(Card animatingCard, Vector from, Vector control, Vector to, float t, bool extra_margin,
Canvas *const canvas);
/**
* Init hand pointer
* @param hand_ptr Pointer to hand
* @param count Number of cards we want to store
*/
void init_hand(Hand *hand_ptr, uint8_t count);
/**
* Free hand resources
* @param hand_ptr Pointer to hand
*/
void free_hand(Hand *hand_ptr);
/**
* Add card to hand
* @param hand_ptr Pointer to hand
* @param card Card to add
*/
void add_to_hand(Hand *hand_ptr, Card card);
/**
* Draw card placement position at coordinate
* @param pos_x X coordinate
* @param pos_y Y coordinate
* @param highlighted Apply highlight effect
* @param canvas Canvas object
*/
void draw_card_space(int16_t pos_x, int16_t pos_y, bool highlighted, Canvas *const canvas);
/**
* Draws a column of card, displaying the last [max_cards] cards on the list
* @param hand Hand object
* @param pos_x X coordinate to draw
* @param pos_y Y coordinate to draw
* @param highlight Index to highlight, negative means no highlight
* @param canvas Canvas object
*/
void
draw_hand_column(Hand hand, int16_t pos_x, int16_t pos_y, int8_t highlight, Canvas *const canvas);
/**
* Removes a card from the deck (Be aware, if you remove the first item, the deck index will be at -1 so you have to handle that)
* @param index Index to remove
* @param deck Deck reference
* @return The removed card
*/
Card remove_from_deck(uint16_t index, Deck *deck);
int first_non_flipped_card(Hand hand);
void extract_hand_region(Hand *hand, Hand *to, uint8_t start_index);
void add_hand_region(Hand *to, Hand *from);

View File

@@ -14,7 +14,11 @@ Vector lerp_2d(Vector start, Vector end, float t) {
}
Vector quadratic_2d(Vector start, Vector control, Vector end, float t) {
return lerp_2d(lerp_2d(start, control, t), lerp_2d(control, end, t), t);
return lerp_2d(
lerp_2d(start, control, t),
lerp_2d(control, end, t),
t
);
}
Vector vector_add(Vector a, Vector b) {
@@ -35,7 +39,10 @@ Vector vector_div_components(Vector a, Vector b) {
Vector vector_normalized(Vector a) {
float length = vector_magnitude(a);
return (Vector){a.x / length, a.y / length};
return (Vector) {
a.x / length,
a.y / length
};
}
float vector_magnitude(Vector a) {

View File

@@ -9,6 +9,10 @@ typedef struct {
float y;
} Vector;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
/**
* Lerp function
*

View File

@@ -22,31 +22,21 @@ void set_menu_state(Menu* menu, uint8_t index, bool state) {
if (menu->menu_count > index) {
menu->items[index].enabled = state;
}
if(!state && menu->current_menu == index) move_menu(menu, 1);
if(!state && menu->current_menu==index)
move_menu(menu, 1);
}
void move_menu(Menu *menu, int8_t direction) {
if (!menu->enabled) return;
int max = menu->menu_count;
for (int8_t i = 0; i < max; i++) {
FURI_LOG_D(
"MENU",
"Iteration %i, current %i, direction %i, state %i",
i,
menu->current_menu,
direction,
menu->items[menu->current_menu].enabled ? 1 : 0);
FURI_LOG_D("MENU", "Iteration %i, current %i, direction %i, state %i", i, menu->current_menu,direction,menu->items[menu->current_menu].enabled?1:0);
if (direction < 0 && menu->current_menu == 0) {
menu->current_menu = menu->menu_count - 1;
} else {
menu->current_menu = (menu->current_menu + direction) % menu->menu_count;
}
FURI_LOG_D(
"MENU",
"After process current %i, direction %i, state %i",
menu->current_menu,
direction,
menu->items[menu->current_menu].enabled ? 1 : 0);
FURI_LOG_D("MENU", "After process current %i, direction %i, state %i", menu->current_menu,direction,menu->items[menu->current_menu].enabled?1:0);
if (menu->items[menu->current_menu].enabled) {
FURI_LOG_D("MENU", "Next menu %i", menu->current_menu);
return;
@@ -85,12 +75,7 @@ void render_menu(Menu* menu, Canvas* canvas, uint8_t pos_x, uint8_t pos_y) {
// canvas_draw_rbox(canvas, pos_x, pos_y, menu->menu_width + 2, 10, 2);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str_aligned(
canvas,
pos_x + menu->menu_width / 2,
pos_y + 6,
AlignCenter,
AlignCenter,
canvas_draw_str_aligned(canvas, pos_x + menu->menu_width / 2, pos_y + 6, AlignCenter, AlignCenter,
menu->items[menu->current_menu].name);
//9*5
int center = pos_x + menu->menu_width / 2;
@@ -100,4 +85,5 @@ void render_menu(Menu* menu, Canvas* canvas, uint8_t pos_x, uint8_t pos_y) {
canvas_draw_dot(canvas, center+j, pos_y+14-i);
}
}
}

View File

@@ -7,8 +7,7 @@ typedef struct {
const char *name; //Name of the menu
bool enabled; //Is the menu item enabled (it will not render, you cannot select it)
void (*callback)(
void* state); //Callback for when the activate_menu is called while this menu is selected
void (*callback)(void *state); //Callback for when the activate_menu is called while this menu is selected
} MenuItem;
typedef struct {

View File

@@ -1,5 +1,6 @@
#include "queue.h"
void render_queue(const QueueState *queue_state, const void *app_state, Canvas *const canvas) {
if (queue_state->current != NULL && queue_state->current->render != NULL)
((QueueItem *) queue_state->current)->render(app_state, canvas);
@@ -22,7 +23,8 @@ void dequeue(QueueState* queue_state, void* app_state) {
queue_state->current = f->next;
free(f);
if (queue_state->current != NULL) {
if(queue_state->current->start != NULL) queue_state->current->start(app_state);
if (queue_state->current->start != NULL)
queue_state->current->start(app_state);
queue_state->start = furi_get_tick();
}else{
queue_state->running = false;
@@ -39,25 +41,20 @@ void queue_clear(QueueState* queue_state) {
}
}
void enqueue(
QueueState* queue_state,
void* app_state,
void (*done)(void* state),
void (*start)(void* state),
void (*render)(const void* state, Canvas* const canvas),
uint32_t duration) {
void enqueue(QueueState *queue_state, void *app_state,
void(*done)(void *state), void(*start)(void *state),
void (*render)(const void *state, Canvas *const canvas), uint32_t duration) {
QueueItem *next;
if (queue_state->current == NULL) {
queue_state->start = furi_get_tick();
queue_state->current = malloc(sizeof(QueueItem));
next = queue_state->current;
if(next->start != NULL) next->start(app_state);
if (next->start != NULL)
next->start(app_state);
} else {
next = queue_state->current;
while(next->next != NULL) {
next = (QueueItem*)(next->next);
}
while (next->next != NULL) { next = (QueueItem *) (next->next); }
next->next = malloc(sizeof(QueueItem));
next = next->next;
}

View File

@@ -5,9 +5,7 @@
typedef struct {
void (*callback)(void *state); //Callback for when the item is dequeued
void (*render)(
const void* state,
Canvas* const canvas); //Callback for the rendering loop while this item is running
void (*render)(const void *state, Canvas *const canvas); //Callback for the rendering loop while this item is running
void (*start)(void *state); //Callback when this item is started running
void *next; //Pointer to the next item
uint32_t duration; //duration of the item
@@ -29,13 +27,9 @@ typedef struct {
* @param render Callback to render loop if needed
* @param duration Length of the item
*/
void enqueue(
QueueState* queue_state,
void* app_state,
void (*done)(void* state),
void (*start)(void* state),
void (*render)(const void* state, Canvas* const canvas),
uint32_t duration);
void enqueue(QueueState *queue_state, void *app_state,
void(*done)(void *state), void(*start)(void *state),
void (*render)(const void *state, Canvas *const canvas), uint32_t duration);
/**
* Clears all queue items
*

View File

@@ -0,0 +1,216 @@
#include "ui.h"
#include <gui/canvas_i.h>
#include <u8g2_glue.h>
#include <gui/icon_animation_i.h>
#include <gui/icon.h>
#include <gui/icon_i.h>
#include <furi_hal.h>
TileMap *tileMap;
uint8_t tileMapCount = 0;
void ui_cleanup() {
if (tileMap != NULL) {
for (uint8_t i = 0; i < tileMapCount; i++) {
if (tileMap[i].data != NULL)
free(tileMap[i].data);
}
free(tileMap);
}
}
void add_new_tilemap(uint8_t *data, unsigned long iconId) {
TileMap *old = tileMap;
tileMapCount++;
tileMap = malloc(sizeof(TileMap) * tileMapCount);
if (tileMapCount > 1) {
for (uint8_t i = 0; i < tileMapCount; i++)
tileMap[i] = old[i];
}
tileMap[tileMapCount - 1] = (TileMap) {data, iconId};
}
uint8_t *get_tilemap(unsigned long icon_id) {
for (uint8_t i = 0; i < tileMapCount; i++) {
if (tileMap[i].iconId == icon_id)
return tileMap[i].data;
}
return NULL;
}
uint32_t pixel_index(uint8_t x, uint8_t y) {
return y * SCREEN_WIDTH + x;
}
bool in_screen(int16_t x, int16_t y) {
return x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT;
}
unsigned flipBit(uint8_t x, uint8_t bit) {
return x ^ (1 << bit);
}
unsigned setBit(uint8_t x, uint8_t bit) {
return x | (1 << bit);
}
unsigned unsetBit(uint8_t x, uint8_t bit) {
return x & ~(1 << bit);
}
bool test_pixel(uint8_t *data, uint8_t x, uint8_t y, uint8_t w) {
uint8_t current_bit = (y % 8);
uint8_t current_row = ((y - current_bit) / 8);
uint8_t current_value = data[current_row * w + x];
return current_value & (1 << current_bit);
}
uint8_t* get_buffer(Canvas *const canvas){
return canvas->fb.tile_buf_ptr;
// return canvas_get_buffer(canvas);
}
uint8_t* make_buffer(){
return malloc(sizeof(uint8_t) * 8 * 128);
}
void clone_buffer(uint8_t* canvas, uint8_t* data){
for(int i=0;i<1024;i++){
data[i]= canvas[i];
}
}
bool read_pixel(Canvas *const canvas, int16_t x, int16_t y) {
if (in_screen(x, y)) {
return test_pixel(get_buffer(canvas), x, y, SCREEN_WIDTH);
}
return false;
}
void set_pixel(Canvas *const canvas, int16_t x, int16_t y, DrawMode draw_mode) {
if (in_screen(x, y)) {
uint8_t current_bit = (y % 8);
uint8_t current_row = ((y - current_bit) / 8);
uint32_t i = pixel_index(x, current_row);
uint8_t* buffer = get_buffer(canvas);
uint8_t current_value = buffer[i];
if (draw_mode == Inverse) {
buffer[i] = flipBit(current_value, current_bit);
} else {
if (draw_mode == White) {
buffer[i] = unsetBit(current_value, current_bit);
} else {
buffer[i] = setBit(current_value, current_bit);
}
}
}
}
void draw_line(Canvas *const canvas, int16_t x1, int16_t y1, int16_t x2, int16_t y2, DrawMode draw_mode) {
for (int16_t x = x2; x >= x1; x--) {
for (int16_t y = y2; y >= y1; y--) {
set_pixel(canvas, x, y, draw_mode);
}
}
}
void draw_rounded_box_frame(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode draw_mode) {
int16_t xMinCorner = x + 1;
int16_t xMax = x + w - 1;
int16_t xMaxCorner = x + w - 2;
int16_t yMinCorner = y + 1;
int16_t yMax = y + h - 1;
int16_t yMaxCorner = y + h - 2;
draw_line(canvas, xMinCorner, y, xMaxCorner, y, draw_mode);
draw_line(canvas, xMinCorner, yMax, xMaxCorner, yMax, draw_mode);
draw_line(canvas, x, yMinCorner, x, yMaxCorner, draw_mode);
draw_line(canvas, xMax, yMinCorner, xMax, yMaxCorner, draw_mode);
}
void draw_rounded_box(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode draw_mode) {
for (int16_t o = w - 2; o >= 1; o--) {
for (int16_t p = h - 2; p >= 1; p--) {
set_pixel(canvas, x + o, y + p, draw_mode);
}
}
draw_rounded_box_frame(canvas, x, y, w, h, draw_mode);
}
void invert_shape(Canvas *const canvas, uint8_t *data, int16_t x, int16_t y, uint8_t w, uint8_t h) {
draw_pixels(canvas, data, x, y, w, h, Inverse);
}
void draw_pixels(Canvas *const canvas, uint8_t *data, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode) {
for (int8_t o = 0; o < w; o++) {
for (int8_t p = 0; p < h; p++) {
if (in_screen(o + x, p + y) && data[p * w + o] == 1)
set_pixel(canvas, o + x, p + y, drawMode);
}
}
}
void draw_rectangle(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode) {
for (int8_t o = 0; o < w; o++) {
for (int8_t p = 0; p < h; p++) {
if (in_screen(o + x, p + y)) {
set_pixel(canvas, o + x, p + y, drawMode);
}
}
}
}
void invert_rectangle(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h) {
draw_rectangle(canvas, x, y, w, h, Inverse);
}
uint8_t *image_data(Canvas *const canvas, const Icon *icon) {
uint8_t *data = malloc(sizeof(uint8_t) * 8 * 128);
uint8_t *screen = canvas->fb.tile_buf_ptr;
canvas->fb.tile_buf_ptr = data;
canvas_draw_icon(canvas, 0, 0, icon);
canvas->fb.tile_buf_ptr = screen;
return data;
}
uint8_t *getOrAddIconData(Canvas *const canvas, const Icon *icon) {
uint8_t *icon_data = get_tilemap((unsigned long) icon);
if (icon_data == NULL) {
icon_data = image_data(canvas, icon);
add_new_tilemap(icon_data, (unsigned long) icon);
}
return icon_data;
}
void draw_icon_clip(Canvas *const canvas, const Icon *icon, int16_t x, int16_t y, uint8_t left, uint8_t top, uint8_t w,
uint8_t h, DrawMode drawMode) {
uint8_t *icon_data = getOrAddIconData(canvas, icon);
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
bool on = test_pixel(icon_data, left + i, top + j, SCREEN_WIDTH);
if (drawMode == Filled) {
set_pixel(canvas, x + i, y + j, on ? Black : White);
} else if (on)
set_pixel(canvas, x + i, y + j, drawMode);
}
}
}
void draw_icon_clip_flipped(Canvas *const canvas, const Icon *icon, int16_t x, int16_t y, uint8_t left, uint8_t top,
uint8_t w,
uint8_t h, DrawMode drawMode) {
uint8_t *icon_data = getOrAddIconData(canvas, icon);
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
bool on = test_pixel(icon_data, left + i, top + j, SCREEN_WIDTH);
if (drawMode == Filled) {
set_pixel(canvas, x + w - i - 1, y + h - j - 1, on ? Black : White);
} else if (on)
set_pixel(canvas, x + w - i - 1, y + h - j - 1, drawMode);
}
}
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include <furi.h>
#include <gui/canvas.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
typedef enum {
Black,
White,
Inverse,
Filled //Currently only for Icon clip drawing
} DrawMode;
// size is the screen size
typedef struct {
uint8_t *data;
unsigned long iconId;
} TileMap;
bool test_pixel(uint8_t *data, uint8_t x, uint8_t y, uint8_t w);
uint8_t *image_data(Canvas *const canvas, const Icon *icon);
uint32_t pixel_index(uint8_t x, uint8_t y);
void draw_icon_clip(Canvas *const canvas, const Icon *icon, int16_t x, int16_t y, uint8_t left, uint8_t top, uint8_t w,
uint8_t h, DrawMode drawMode);
void draw_icon_clip_flipped(Canvas *const canvas, const Icon *icon, int16_t x, int16_t y, uint8_t left, uint8_t top, uint8_t w,
uint8_t h, DrawMode drawMode);
void draw_rounded_box(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode);
void draw_rounded_box_frame(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode);
void draw_rectangle(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode);
void invert_rectangle(Canvas *const canvas, int16_t x, int16_t y, uint8_t w, uint8_t h);
void invert_shape(Canvas *const canvas, uint8_t *data, int16_t x, int16_t y, uint8_t w, uint8_t h);
void draw_pixels(Canvas *const canvas, uint8_t *data, int16_t x, int16_t y, uint8_t w, uint8_t h, DrawMode drawMode);
bool read_pixel(Canvas *const canvas, int16_t x, int16_t y);
void set_pixel(Canvas *const canvas, int16_t x, int16_t y, DrawMode draw_mode);
void draw_line(Canvas *const canvas, int16_t x1, int16_t y1, int16_t x2, int16_t y2, DrawMode draw_mode);
bool in_screen(int16_t x, int16_t y);
void ui_cleanup();
uint8_t* get_buffer(Canvas *const canvas);
uint8_t* make_buffer();
void clone_buffer(uint8_t* canvas, uint8_t* data);

View File

@@ -43,7 +43,15 @@ typedef enum {
GameStateDealer,
} PlayState;
typedef enum { DirectionUp, DirectionRight, DirectionDown, DirectionLeft, Select, None } Direction;
typedef enum {
DirectionUp,
DirectionDown,
DirectionRight,
DirectionLeft,
Select,
Back,
None
} Direction;
typedef struct {
Card player_cards[21];
@@ -66,3 +74,4 @@ typedef struct {
Menu *menu;
unsigned int last_tick;
} GameState;

View File

@@ -6,19 +6,23 @@
#define LINE_HEIGHT 16
#define ITEM_PADDING 4
const char MoneyMul[4] = {'K', 'B', 'T', 'S'};
const char MoneyMul[4] = {
'K', 'B', 'T', 'S'
};
void draw_player_scene(Canvas *const canvas, const GameState *game_state) {
int max_card = game_state->player_card_count;
if(max_card > 0) draw_deck((game_state->player_cards), max_card, canvas);
if (max_card > 0)
draw_deck((game_state->player_cards), max_card, canvas);
if(game_state->dealer_card_count > 0) draw_card_back_at(13, 5, canvas);
if (game_state->dealer_card_count > 0)
draw_card_back_at(13, 5, canvas);
max_card = game_state->dealer_card_count;
if (max_card > 1) {
draw_card_at(
2, 2, game_state->dealer_cards[1].pip, game_state->dealer_cards[1].character, canvas);
draw_card_at(2, 2, game_state->dealer_cards[1].pip, game_state->dealer_cards[1].character,
canvas);
}
}
@@ -35,12 +39,11 @@ void popup_frame(Canvas* const canvas) {
canvas_set_font(canvas, FontSecondary);
}
void draw_play_menu(Canvas *const canvas, const GameState *game_state) {
const char *menus[3] = {"Double", "Hit", "Stay"};
for (uint8_t m = 0; m < 3; m++) {
if(m == 0 &&
(game_state->doubled || game_state->player_score < game_state->settings.round_price))
continue;
if (m == 0 && (game_state->doubled || game_state->player_score < game_state->settings.round_price)) continue;
int y = m * 13 + 25;
canvas_set_color(canvas, ColorBlack);
@@ -65,7 +68,8 @@ void draw_play_menu(Canvas* const canvas, const GameState* game_state) {
void draw_screen(Canvas *const canvas, const bool *points) {
for (uint8_t x = 0; x < 128; x++) {
for (uint8_t y = 0; y < 64; y++) {
if(points[y * 128 + x]) canvas_draw_dot(canvas, x, y);
if (points[y * 128 + x])
canvas_draw_dot(canvas, x, y);
}
}
}
@@ -100,13 +104,8 @@ void draw_money(Canvas* const canvas, uint32_t score) {
canvas_draw_str_aligned(canvas, 126, 2, AlignRight, AlignTop, drawChar);
}
void draw_menu(
Canvas* const canvas,
const char* text,
const char* value,
int8_t y,
bool left_caret,
bool right_caret,
void draw_menu(Canvas *const canvas, const char *text, const char *value, int8_t y, bool left_caret, bool right_caret,
bool selected) {
UNUSED(selected);
if (y < 0 || y >= 64) return;
@@ -118,7 +117,8 @@ void draw_menu(
}
canvas_draw_str_aligned(canvas, 4, y + ITEM_PADDING, AlignLeft, AlignTop, text);
if(left_caret) canvas_draw_str_aligned(canvas, 80, y + ITEM_PADDING, AlignLeft, AlignTop, "<");
if (left_caret)
canvas_draw_str_aligned(canvas, 80, y + ITEM_PADDING, AlignLeft, AlignTop, "<");
canvas_draw_str_aligned(canvas, 100, y + ITEM_PADDING, AlignCenter, AlignTop, value);
if (right_caret)
canvas_draw_str_aligned(canvas, 120, y + ITEM_PADDING, AlignRight, AlignTop, ">");
@@ -136,51 +136,45 @@ void settings_page(Canvas* const canvas, const GameState* gameState) {
int scrollHeight = round(64 / 6.0) + ITEM_PADDING * 2;
int scrollPos = 64 / (6.0 / (gameState->selectedMenu + 1)) - ITEM_PADDING * 2;
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 123, scrollPos, 4, scrollHeight);
canvas_draw_box(canvas, 125, 0, 1, 64);
snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.starting_money);
draw_menu(
canvas,
"Start money",
drawChar,
draw_menu(canvas, "Start money", drawChar,
0 * LINE_HEIGHT + startY,
gameState->settings.starting_money > gameState->settings.round_price,
gameState->settings.starting_money < 400,
gameState->selectedMenu == 0);
gameState->selectedMenu == 0
);
snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.round_price);
draw_menu(
canvas,
"Round price",
drawChar,
draw_menu(canvas, "Round price", drawChar,
1 * LINE_HEIGHT + startY,
gameState->settings.round_price > 10,
gameState->settings.round_price < gameState->settings.starting_money,
gameState->selectedMenu == 1);
gameState->selectedMenu == 1
);
snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.animation_duration);
draw_menu(
canvas,
"Anim. length",
drawChar,
draw_menu(canvas, "Anim. length", drawChar,
2 * LINE_HEIGHT + startY,
gameState->settings.animation_duration > 0,
gameState->settings.animation_duration < 2000,
gameState->selectedMenu == 2);
gameState->selectedMenu == 2
);
snprintf(drawChar, sizeof(drawChar), "%li", gameState->settings.message_duration);
draw_menu(
canvas,
"Popup time",
drawChar,
draw_menu(canvas, "Popup time", drawChar,
3 * LINE_HEIGHT + startY,
gameState->settings.message_duration > 0,
gameState->settings.message_duration < 2000,
gameState->selectedMenu == 3);
gameState->selectedMenu == 3
);
// draw_menu(canvas, "Sound", gameState->settings.sound_effects ? "Yes" : "No",
// 5 * LINE_HEIGHT + startY,
// true,
// true,
// gameState->selectedMenu == 5
// );
}

View File

@@ -8,10 +8,9 @@ void save_settings(Settings settings) {
FlipperFormat *file = flipper_format_file_alloc(storage);
FURI_LOG_D(APP_NAME, "Saving config");
if (flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) {
FURI_LOG_D(
APP_NAME, "Saving %s: %ld", CONF_ANIMATION_DURATION, settings.animation_duration);
flipper_format_update_uint32(
file, CONF_ANIMATION_DURATION, &(settings.animation_duration), 1);
FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_ANIMATION_DURATION, settings.animation_duration);
flipper_format_update_uint32(file, CONF_ANIMATION_DURATION, &(settings.animation_duration), 1);
FURI_LOG_D(APP_NAME, "Saving %s: %ld", CONF_MESSAGE_DURATION, settings.message_duration);
flipper_format_update_uint32(file, CONF_MESSAGE_DURATION, &(settings.message_duration), 1);
@@ -78,7 +77,8 @@ Settings load_settings() {
if (!flipper_format_file_open_existing(file, CONFIG_FILE_PATH)) {
FURI_LOG_E(APP_NAME, "Error opening existing file %s", CONFIG_FILE_PATH);
flipper_format_file_close(file);
} else {
}
else {
uint32_t value;
bool valueBool;
FURI_LOG_D(APP_NAME, "Checking version");