From 460d989aa7c9168bd50ef170aea339c54b233bdb Mon Sep 17 00:00:00 2001 From: RogueMaster Date: Mon, 24 Oct 2022 16:39:14 -0400 Subject: [PATCH] more for BJ --- applications/plugins/blackjack/common/card.c | 236 ++++++++++++++++++ applications/plugins/blackjack/common/card.h | 100 ++++++++ applications/plugins/blackjack/common/dml.c | 60 +++++ applications/plugins/blackjack/common/dml.h | 112 +++++++++ applications/plugins/blackjack/common/menu.c | 89 +++++++ applications/plugins/blackjack/common/menu.h | 76 ++++++ applications/plugins/blackjack/common/queue.c | 66 +++++ applications/plugins/blackjack/common/queue.h | 64 +++++ 8 files changed, 803 insertions(+) create mode 100644 applications/plugins/blackjack/common/card.c create mode 100644 applications/plugins/blackjack/common/card.h create mode 100644 applications/plugins/blackjack/common/dml.c create mode 100644 applications/plugins/blackjack/common/dml.h create mode 100644 applications/plugins/blackjack/common/menu.c create mode 100644 applications/plugins/blackjack/common/menu.h create mode 100644 applications/plugins/blackjack/common/queue.c create mode 100644 applications/plugins/blackjack/common/queue.h diff --git a/applications/plugins/blackjack/common/card.c b/applications/plugins/blackjack/common/card.c new file mode 100644 index 000000000..3633ba07a --- /dev/null +++ b/applications/plugins/blackjack/common/card.c @@ -0,0 +1,236 @@ +#include "card.h" +#include "dml.h" + +#define CORNER_MARGIN 3 +#define CARD_DRAW_X_START 108 +#define CARD_DRAW_Y_START 38 +#define CARD_DRAW_X_SPACE 10 +#define CARD_DRAW_Y_SPACE 8 +#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 + } + }; + +//region Player card positions +uint8_t playerCardPositions[22][4] = { + //first row + {108, 38}, + {98, 38}, + {88, 38}, + {78, 38}, + {68, 38}, + {58, 38}, + {48, 38}, + {38, 38}, + //second row + {104, 26}, + {94, 26}, + {84, 26}, + {74, 26}, + {64, 26}, + {54, 26}, + {44, 26}, + //third row + {99, 14}, + {89, 14}, + {79, 14}, + {69, 14}, + {59, 14}, + {49, 14}, +}; +//endregion + +bool get_pip_pixel(uint8_t pip, uint8_t x, uint8_t y) { + return pips[pip][x + y * 7]; +} + +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); +} + +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); + } +} + +Vector card_pos_at_index(uint8_t index) { + 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); + + 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; + deck_ptr->deck_count=deck_count; + deck_ptr->cards=malloc(sizeof(Card) * 52 * deck_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 + }; + counter++; + } + } + } +} + +void shuffle_deck(Deck *deck_ptr) { + srand(DWT->CYCCNT); + deck_ptr->index = 0; + int max = deck_ptr->deck_count * 52; + for (int i = 0; i < max; i++) { + int r = i + (rand() % (max - i)); + Card tmp = deck_ptr->cards[i]; + deck_ptr->cards[i] = deck_ptr->cards[r]; + deck_ptr->cards[r] = tmp; + } +} + +uint8_t hand_count(const Card *cards, uint8_t count) { + uint8_t aceCount = 0; + uint8_t score = 0; + + for (uint8_t i = 0; i < count; i++) { + if (cards[i].character == 12) + aceCount++; + else { + if (cards[i].character > 8) + score += 10; + else + score += cards[i].character + 2; + } + } + + for (uint8_t i = 0; i < aceCount; i++) { + 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, + Canvas *const canvas) { + float time = t; + if (extra_margin) { + time += 0.2; + } + + Vector currentPos = quadratic_2d(from, control, to, time); + if (t > 1) { + 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); + } +} diff --git a/applications/plugins/blackjack/common/card.h b/applications/plugins/blackjack/common/card.h new file mode 100644 index 000000000..27b42f0f4 --- /dev/null +++ b/applications/plugins/blackjack/common/card.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include +#include +#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 + +//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 +} Card; + +typedef struct { + uint8_t deck_count; //Number of decks used + Card *cards; //Cards in the deck + int index; //Card index (to know where we at in the deck) +} Deck; +//endregion + + +/** + * Gets card coordinates at the index (range: 0-20). + * + * @param index Index to check 0-20 + * @return Position of the card + */ +Vector card_pos_at_index(uint8_t index); + +/** + * 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 canvas Pointer to Flipper's canvas object + */ +void draw_card_at(int8_t pos_x, int8_t pos_y, uint8_t pip, uint8_t character, Canvas *const canvas); + +/** + * Draws 'count' cards at the bottom right corner + * + * @param cards List of cards + * @param count Count of cards + * @param canvas Pointer to Flipper's canvas object + */ +void draw_deck(const Card *cards, uint8_t count, Canvas *const canvas); + +/** + * Draws card back at a given coordinate (top-left corner) + * + * @param pos_x X coordinate + * @param pos_y Y coordinate + * @param canvas Pointer to Flipper's canvas object + */ +void draw_card_back_at(int8_t pos_x, int8_t pos_y, Canvas *const canvas); + +/** + * Generates the deck + * + * @param deck_ptr Pointer to the deck + * @param deck_count Number of decks + */ +void generate_deck(Deck *deck_ptr, uint8_t deck_count); + +/** + * Shuffles the deck + * + * @param deck_ptr Pointer to the deck + */ +void shuffle_deck(Deck *deck_ptr); + +/** + * Calculates the hand count for blackjack + * + * @param cards List of cards + * @param count Count of cards + * @return Hand value + */ +uint8_t hand_count(const Card *cards, uint8_t count); + +/** + * Draws card animation + * + * @param animatingCard Card to animate + * @param from Starting position + * @param control Quadratic lerp control point + * @param to End point + * @param t Current time (0-1) + * @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, + Canvas *const canvas); \ No newline at end of file diff --git a/applications/plugins/blackjack/common/dml.c b/applications/plugins/blackjack/common/dml.c new file mode 100644 index 000000000..5329a3be0 --- /dev/null +++ b/applications/plugins/blackjack/common/dml.c @@ -0,0 +1,60 @@ +#include "dml.h" +#include + +float lerp(float v0, float v1, float t) { + if (t > 1) return v1; + return (1 - t) * v0 + t * v1; +} + +Vector lerp_2d(Vector start, Vector end, float t) { + return (Vector) { + lerp(start.x, end.x, t), + lerp(start.y, end.y, 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 + ); +} + +Vector vector_add(Vector a, Vector b) { + return (Vector) {a.x + b.x, a.y + b.y}; +} + +Vector vector_sub(Vector a, Vector b) { + return (Vector) {a.x - b.x, a.y - b.y}; +} + +Vector vector_mul_components(Vector a, Vector b) { + return (Vector) {a.x * b.x, a.y * b.y}; +} + +Vector vector_div_components(Vector a, Vector b) { + return (Vector) {a.x / b.x, a.y / b.y}; +} + +Vector vector_normalized(Vector a) { + float length = vector_magnitude(a); + return (Vector) { + a.x / length, + a.y / length + }; +} + +float vector_magnitude(Vector a) { + return sqrt(a.x * a.x + a.y * a.y); +} + +float vector_distance(Vector a, Vector b) { + return vector_magnitude(vector_sub(a, b)); +} + +float vector_dot(Vector a, Vector b) { + Vector _a = vector_normalized(a); + Vector _b = vector_normalized(b); + return _a.x * _b.x + _a.y * _b.y; +} \ No newline at end of file diff --git a/applications/plugins/blackjack/common/dml.h b/applications/plugins/blackjack/common/dml.h new file mode 100644 index 000000000..3f3391d23 --- /dev/null +++ b/applications/plugins/blackjack/common/dml.h @@ -0,0 +1,112 @@ +// +// Doofy's Math library +// + +#pragma once + +typedef struct { + float x; + float y; +} Vector; + +/** + * Lerp function + * + * @param v0 Start value + * @param v1 End value + * @param t Time (0-1 range) + * @return Point between v0-v1 at a given time + */ +float lerp(float v0, float v1, float t); + +/** + * 2D lerp function + * + * @param start Start vector + * @param end End vector + * @param t Time (0-1 range) + * @return 2d Vector between start and end at time + */ +Vector lerp_2d(Vector start, Vector end, float t); + +/** + * Quadratic lerp function + * + * @param start Start vector + * @param control Control point + * @param end End vector + * @param t Time (0-1 range) + * @return 2d Vector at time + */ +Vector quadratic_2d(Vector start, Vector control, Vector end, float t); + +/** + * Add vector components together + * + * @param a First vector + * @param b Second vector + * @return Resulting vector + */ +Vector vector_add(Vector a, Vector b); + +/** + * Subtract vector components together + * + * @param a First vector + * @param b Second vector + * @return Resulting vector + */ +Vector vector_sub(Vector a, Vector b); + +/** + * Multiplying vector components together + * + * @param a First vector + * @param b Second vector + * @return Resulting vector + */ +Vector vector_mul_components(Vector a, Vector b); + +/** + * Dividing vector components + * + * @param a First vector + * @param b Second vector + * @return Resulting vector + */ +Vector vector_div_components(Vector a, Vector b); + +/** + * Calculating Vector length + * + * @param a Direction vector + * @return Length of the vector + */ +float vector_magnitude(Vector a); + +/** + * Get a normalized vector (length of 1) + * + * @param a Direction vector + * @return Normalized vector + */ +Vector vector_normalized(Vector a); + +/** + * Calculate two vector's distance + * + * @param a First vector + * @param b Second vector + * @return Distance between vectors + */ +float vector_distance(Vector a, Vector b); + +/** + * Calculate the dot product of the vectors. + * No need to normalize, it will do it + * + * @param a First vector + * @param b Second vector + * @return value from -1 to 1 + */ +float vector_dot(Vector a, Vector b); diff --git a/applications/plugins/blackjack/common/menu.c b/applications/plugins/blackjack/common/menu.c new file mode 100644 index 000000000..a58b9bba3 --- /dev/null +++ b/applications/plugins/blackjack/common/menu.c @@ -0,0 +1,89 @@ +#include "menu.h" + +void add_menu(Menu *menu, const char *name, void (*callback)(void *)) { + MenuItem *items = menu->items; + + menu->items = malloc(sizeof(MenuItem) * (menu->menu_count + 1)); + for (uint8_t i = 0; i < menu->menu_count; i++) { + menu->items[i] = items[i]; + } + free(items); + + menu->items[menu->menu_count] = (MenuItem) {name, true, callback}; + menu->menu_count++; +} + +void free_menu(Menu *menu) { + free(menu->items); + free(menu); +} + +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); +} + +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); + 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); + if (menu->items[menu->current_menu].enabled) { + FURI_LOG_D("MENU", "Next menu %i", menu->current_menu); + return; + } + } + FURI_LOG_D("MENU", "Not found, setting false"); + menu->enabled = false; +} + +void activate_menu(Menu *menu, void *state) { + if (!menu->enabled) return; + menu->items[menu->current_menu].callback(state); +} + +void render_menu(Menu *menu, Canvas *canvas, uint8_t pos_x, uint8_t pos_y) { + if (!menu->enabled) return; + canvas_set_color(canvas, ColorWhite); + canvas_draw_rbox(canvas, pos_x, pos_y, menu->menu_width + 2, 10, 2); + + uint8_t w = pos_x+menu->menu_width; + uint8_t h = pos_y+10; + uint8_t p1x = pos_x+2; + uint8_t p2x = pos_x+menu->menu_width-2; + uint8_t p1y = pos_y+2; + uint8_t p2y = pos_y+8; + + canvas_set_color(canvas, ColorBlack); + canvas_draw_line(canvas, p1x, pos_y, p2x, pos_y); + canvas_draw_line(canvas, p1x, h, p2x, h); + canvas_draw_line(canvas, pos_x, p1y, pos_x, p2y); + canvas_draw_line(canvas, w, p1y, w, p2y); + canvas_draw_dot(canvas, pos_x+1, pos_y+1); + canvas_draw_dot(canvas, w-1, pos_y+1); + canvas_draw_dot(canvas, w-1, h-1); + canvas_draw_dot(canvas, pos_x+1, h-1); + +// 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, + menu->items[menu->current_menu].name); + //9*5 + int center = pos_x + menu->menu_width / 2; + for(uint8_t i=0;i<4;i++){ + for(int8_t j = -i; j<=i;j++){ + canvas_draw_dot(canvas, center+j, pos_y-4+i); + canvas_draw_dot(canvas, center+j, pos_y+14-i); + } + } + +} \ No newline at end of file diff --git a/applications/plugins/blackjack/common/menu.h b/applications/plugins/blackjack/common/menu.h new file mode 100644 index 000000000..519a7edad --- /dev/null +++ b/applications/plugins/blackjack/common/menu.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +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 +} MenuItem; + +typedef struct { + MenuItem *items; //list of menu items + uint8_t menu_count; //count of menu items (do not change) + uint8_t current_menu; //currently selected menu item + uint8_t menu_width; //width of the menu + bool enabled; //is the menu enabled (it will not render and accept events when disabled) +} Menu; + +/** + * Cleans up the pointers used by the menu + * + * @param menu Pointer of the menu to clean up + */ +void free_menu(Menu *menu); + +/** + * Add a new menu item + * + * @param menu Pointer of the menu + * @param name Name of the menu item + * @param callback Callback called on activation + */ +void add_menu(Menu *menu, const char *name, void (*callback)(void *)); + +/** + * Setting menu item to be enabled/disabled + * + * @param menu Pointer of the menu + * @param index Menu index to set + * @param state Enabled (true), Disabled(false) + */ +void set_menu_state(Menu *menu, uint8_t index, bool state); + +/** + * Moves selection up or down + * + * @param menu Pointer of the menu + * @param direction Direction to move -1 down, 1 up + */ +void move_menu(Menu *menu, int8_t direction); + +/** + * Triggers the current menu callback + * + * @param menu Pointer of the menu + * @param state Usually your application state + */ +void activate_menu(Menu *menu, void *state); + +/** + * Renders the menu at a coordinate (call it in your render function). + * + * Keep in mind that Flipper has a 128x64 pixel screen resolution and the coordinate + * you give is the menu's rectangle top-left corner (arrows not included). + * The rectangle height is 10 px, the arrows have a 4 pixel height. Space needed is 18px. + * The width of the menu can be configured in the menu object. + * + * + * @param menu Pointer of the menu + * @param canvas Flippers Canvas pointer + * @param pos_x X position to draw + * @param pos_y Y position to draw + */ +void render_menu(Menu *menu, Canvas *canvas, uint8_t pos_x, uint8_t pos_y); \ No newline at end of file diff --git a/applications/plugins/blackjack/common/queue.c b/applications/plugins/blackjack/common/queue.c new file mode 100644 index 000000000..36171f3e3 --- /dev/null +++ b/applications/plugins/blackjack/common/queue.c @@ -0,0 +1,66 @@ +#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); +} + +bool run_queue(QueueState *queue_state, void *app_state) { + if (queue_state->current != NULL) { + queue_state->running = true; + if ((furi_get_tick() - queue_state->start) >= queue_state->current->duration) + dequeue(queue_state, app_state); + + return true; + } + return false; +} + +void dequeue(QueueState *queue_state, void *app_state) { + ((QueueItem *) queue_state->current)->callback(app_state); + QueueItem *f = queue_state->current; + queue_state->current = f->next; + free(f); + if (queue_state->current != NULL) { + if (queue_state->current->start != NULL) + queue_state->current->start(app_state); + queue_state->start = furi_get_tick(); + }else{ + queue_state->running = false; + } +} + +void queue_clear(QueueState *queue_state) { + queue_state->running = false; + QueueItem *curr = queue_state->current; + while (curr != NULL) { + QueueItem *f = curr; + curr = curr->next; + free(f); + } +} + +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); + + } else { + next = queue_state->current; + while (next->next != NULL) { next = (QueueItem *) (next->next); } + next->next = malloc(sizeof(QueueItem)); + next = next->next; + } + next->callback = done; + next->render = render; + next->start = start; + next->duration = duration; + next->next = NULL; +} \ No newline at end of file diff --git a/applications/plugins/blackjack/common/queue.h b/applications/plugins/blackjack/common/queue.h new file mode 100644 index 000000000..cf61cc6b5 --- /dev/null +++ b/applications/plugins/blackjack/common/queue.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +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 (*start)(void *state); //Callback when this item is started running + void *next; //Pointer to the next item + uint32_t duration; //duration of the item +} QueueItem; + +typedef struct { + unsigned int start; //current queue item start time + QueueItem *current; //current queue item + bool running; //is the queue running +} QueueState; + +/** + * Enqueue a new item. + * + * @param queue_state The queue state pointer + * @param app_state Your app state + * @param done Callback for dequeue event + * @param start Callback for when the item is activated + * @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); +/** + * Clears all queue items + * + * @param queue_state The queue state pointer + */ +void queue_clear(QueueState *queue_state); + +/** + * Dequeues the active queue item. Usually you don't need to call it directly. + * + * @param queue_state The queue state pointer + * @param app_state Your application state + */ +void dequeue(QueueState *queue_state, void *app_state); + +/** + * Runs the queue logic (place it in your tick function) + * + * @param queue_state The queue state pointer + * @param app_state Your application state + * @return FALSE when there is nothing to run, TRUE otherwise + */ +bool run_queue(QueueState *queue_state, void *app_state); + +/** + * Calls the currently active queue items render callback (if there is any) + * + * @param queue_state The queue state pointer + * @param app_state Your application state + * @param canvas Pointer to Flipper's canvas object + */ +void render_queue(const QueueState *queue_state, const void *app_state, Canvas *const canvas); \ No newline at end of file