diff --git a/applications/plugins/heap_defence_game/application.fam b/applications/plugins/heap_defence_game/application.fam new file mode 100644 index 000000000..b132531d1 --- /dev/null +++ b/applications/plugins/heap_defence_game/application.fam @@ -0,0 +1,11 @@ +App( + appid="heap_defence", + name="Heap Defence", + apptype=FlipperAppType.EXTERNAL, + entry_point="heap_defence_app", + requires=["gui"], + stack_size=1 * 1024, + fap_category="Games", + fap_icon="box.png", + fap_icon_assets="assets_images", +) diff --git a/applications/plugins/heap_defence_game/assets_images/Background_128x64.png b/applications/plugins/heap_defence_game/assets_images/Background_128x64.png new file mode 100644 index 000000000..a7eb1326f Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Background_128x64.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box1_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box1_10x10.png new file mode 100644 index 000000000..d168f9511 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box1_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box2_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box2_10x10.png new file mode 100644 index 000000000..e3bbb48e7 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box2_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box3_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box3_10x10.png new file mode 100644 index 000000000..e20e75b00 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box3_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box4_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box4_10x10.png new file mode 100644 index 000000000..98d134104 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box4_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box5_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box5_10x10.png new file mode 100644 index 000000000..f8dbf339f Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box5_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box6p_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box6p_10x10.png new file mode 100644 index 000000000..da50f8c86 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box6p_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box7p_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box7p_10x10.png new file mode 100644 index 000000000..efcd2ac0c Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box7p_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Box8p_10x10.png b/applications/plugins/heap_defence_game/assets_images/Box8p_10x10.png new file mode 100644 index 000000000..57ca46e9c Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Box8p_10x10.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Game_over_128x64.png b/applications/plugins/heap_defence_game/assets_images/Game_over_128x64.png new file mode 100644 index 000000000..d4837e635 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Game_over_128x64.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png new file mode 100644 index 000000000..d4837e635 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png new file mode 100644 index 000000000..a88122d90 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png new file mode 100644 index 000000000..02fa41df0 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png new file mode 100644 index 000000000..d0c63d484 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png new file mode 100644 index 000000000..1c2756fdb Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png new file mode 100644 index 000000000..313fd6961 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png new file mode 100644 index 000000000..cf854656c Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate new file mode 100644 index 000000000..b8626c4cf --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate @@ -0,0 +1 @@ +4 diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png new file mode 100644 index 000000000..104a779c9 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png new file mode 100644 index 000000000..afc4a932f Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate @@ -0,0 +1 @@ +2 diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png new file mode 100644 index 000000000..58c2ef68d Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png new file mode 100644 index 000000000..afee3ec83 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate @@ -0,0 +1 @@ +2 diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png new file mode 100644 index 000000000..e8bb70be6 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png new file mode 100644 index 000000000..d7dd740f7 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png new file mode 100644 index 000000000..a8a9fe7e7 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png new file mode 100644 index 000000000..d7dd740f7 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate @@ -0,0 +1 @@ +2 diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png new file mode 100644 index 000000000..fc2150343 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png new file mode 100644 index 000000000..9a03083a0 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png new file mode 100644 index 000000000..5c2911fbc Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png new file mode 100644 index 000000000..9a03083a0 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate @@ -0,0 +1 @@ +2 diff --git a/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_01.png b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_01.png new file mode 100644 index 000000000..7fd2f8627 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_01.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_02.png b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_02.png new file mode 100644 index 000000000..32fc98b74 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_02.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_03.png b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_03.png new file mode 100644 index 000000000..e7beb004d Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_03.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_04.png b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_04.png new file mode 100644 index 000000000..32fc98b74 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_04.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_rate b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_rate new file mode 100644 index 000000000..00750edc0 --- /dev/null +++ b/applications/plugins/heap_defence_game/assets_images/HD_start_128x64/frame_rate @@ -0,0 +1 @@ +3 diff --git a/applications/plugins/heap_defence_game/assets_images/Person4_1_10x20.png b/applications/plugins/heap_defence_game/assets_images/Person4_1_10x20.png new file mode 100644 index 000000000..104a779c9 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Person4_1_10x20.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Person4_2_10x20.png b/applications/plugins/heap_defence_game/assets_images/Person4_2_10x20.png new file mode 100644 index 000000000..afc4a932f Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Person4_2_10x20.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Person5_1_10x20.png b/applications/plugins/heap_defence_game/assets_images/Person5_1_10x20.png new file mode 100644 index 000000000..58c2ef68d Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Person5_1_10x20.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Person5_2_10x20.png b/applications/plugins/heap_defence_game/assets_images/Person5_2_10x20.png new file mode 100644 index 000000000..afee3ec83 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Person5_2_10x20.png differ diff --git a/applications/plugins/heap_defence_game/assets_images/Start_128x64.png b/applications/plugins/heap_defence_game/assets_images/Start_128x64.png new file mode 100644 index 000000000..32fc98b74 Binary files /dev/null and b/applications/plugins/heap_defence_game/assets_images/Start_128x64.png differ diff --git a/applications/plugins/heap_defence_game/box.png b/applications/plugins/heap_defence_game/box.png new file mode 100644 index 000000000..9ad9b3900 Binary files /dev/null and b/applications/plugins/heap_defence_game/box.png differ diff --git a/applications/plugins/heap_defence_game/heap_defence.c b/applications/plugins/heap_defence_game/heap_defence.c new file mode 100644 index 000000000..c4375bafe --- /dev/null +++ b/applications/plugins/heap_defence_game/heap_defence.c @@ -0,0 +1,593 @@ +// +// Created by moh on 30.11.2021. +// +// Ported to latest firmware by @xMasterX - 18 Oct 2022 +// + +#include + +#include "hede_assets.h" +#include "heap_defence_icons.h" + +#include +#include +#include +#include +#include +#include + +#define Y_FIELD_SIZE 6 +#define Y_LAST (Y_FIELD_SIZE - 1) +#define X_FIELD_SIZE 12 +#define X_LAST (X_FIELD_SIZE - 1) + +#define DRAW_X_OFFSET 4 + +#define TAG "HeDe" + +#define BOX_HEIGHT 10 +#define BOX_WIDTH 10 +#define TIMER_UPDATE_FREQ 8 +#define BOX_GENERATION_RATE 15 + +static IconAnimation* BOX_DESTROYED; +static const Icon* boxes[] = { + (Icon*)&A_HD_BoxDestroyed_10x10, + &I_Box1_10x10, + &I_Box2_10x10, + &I_Box3_10x10, + &I_Box4_10x10, + &I_Box5_10x10}; + +static uint8_t BOX_TEXTURE_COUNT = sizeof(boxes) / sizeof(Icon*); + +typedef enum { + AnimationGameOver = 0, + AnimationPause, + AnimationLeft, + AnimationRight, +} Animations; + +static IconAnimation* animations[4]; + +typedef u_int8_t byte; + +typedef enum { + GameStatusVibro = 1 << 0, + GameStatusInProgress = 1 << 1, +} GameStatuses; + +typedef struct { + uint8_t x; + uint8_t y; +} Position; + +typedef enum { PlayerRising = 1, PlayerFalling = -1, PlayerNothing = 0 } PlayerStates; + +typedef struct { + Position p; + int8_t x_direction; + int8_t j_tick; + int8_t h_tick; + int8_t states; + bool right_frame; +} Person; + +typedef struct { + uint8_t offset : 4; + uint8_t box_id : 3; + uint8_t exists : 1; +} Box; + +static const uint8_t ROW_BYTE_SIZE = sizeof(Box) * X_FIELD_SIZE; + +typedef struct { + Box** field; + Person* person; + Animations animation; + GameStatuses game_status; +} GameState; + +typedef Box** Field; + +typedef enum { EventGameTick, EventKeyPress } EventType; + +typedef struct { + EventType type; + InputEvent input; +} GameEvent; + +/** + * #Construct / Destroy + */ + +static void game_reset_field_and_player(GameState* game) { + ///Reset field + bzero(game->field[0], X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); + + ///Reset person + bzero(game->person, sizeof(Person)); + game->person->p.x = X_FIELD_SIZE / 2; + game->person->p.y = Y_LAST; +} + +static GameState* allocGameState() { + GameState* game = malloc(sizeof(GameState)); + + game->person = malloc(sizeof(Person)); + + game->field = malloc(Y_FIELD_SIZE * sizeof(Box*)); + game->field[0] = malloc(X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); + for(int y = 1; y < Y_FIELD_SIZE; ++y) { + game->field[y] = game->field[0] + (y * X_FIELD_SIZE); + } + game_reset_field_and_player(game); + + game->game_status = GameStatusInProgress; + return game; +} + +static void game_destroy(GameState* game) { + furi_assert(game); + free(game->field[0]); + free(game->field); + free(game); +} + +static void assets_load() { + /// Init animations + animations[AnimationPause] = icon_animation_alloc(&A_HD_start_128x64); + animations[AnimationGameOver] = icon_animation_alloc(&A_HD_game_over_128x64); + animations[AnimationLeft] = icon_animation_alloc(&A_HD_person_left_10x20); + animations[AnimationRight] = icon_animation_alloc(&A_HD_person_right_10x20); + + BOX_DESTROYED = icon_animation_alloc(&A_HD_BoxDestroyed_10x10); + + icon_animation_start(animations[AnimationLeft]); + icon_animation_start(animations[AnimationRight]); +} + +static void assets_clear() { + for(int i = 0; i < 4; ++i) { + icon_animation_stop(animations[i]); + icon_animation_free(animations[i]); + } + icon_animation_free(BOX_DESTROYED); +} + +/** + * Box utils + */ + +static inline bool is_empty(Box* box) { + return !box->exists; +} + +static inline bool has_dropped(Box* box) { + return box->offset == 0; +} + +static Box* get_upper_box(Field field, Position current) { + return (&field[current.y - 1][current.x]); +} + +static Box* get_lower_box(Field field, Position current) { + return (&field[current.y + 1][current.x]); +} + +static Box* get_next_box(Field field, Position current, int x_direction) { + return (&field[current.y][current.x + x_direction]); +} + +static inline void decrement_y_offset_to_zero(Box* n) { + if(n->offset) --n->offset; +} + +static inline void heap_swap(Box* first, Box* second) { + Box temp = *first; + + *first = *second; + *second = temp; +} + +/** + * #Box logic + */ + +static void generate_box(GameState const* game) { + furi_assert(game); + + static byte tick_count = BOX_GENERATION_RATE; + if(tick_count++ != BOX_GENERATION_RATE) { + return; + } + tick_count = 0; + + int x_offset = rand() % X_FIELD_SIZE; + while(game->field[1][x_offset].exists) { + x_offset = rand() % X_FIELD_SIZE; + } + + game->field[1][x_offset].exists = true; + game->field[1][x_offset].offset = BOX_HEIGHT; + game->field[1][x_offset].box_id = (rand() % (BOX_TEXTURE_COUNT - 1)) + 1; +} + +static void drop_box(GameState* game) { + furi_assert(game); + + for(int y = Y_LAST; y > 0; y--) { + for(int x = 0; x < X_FIELD_SIZE; x++) { + Box* current_box = game->field[y] + x; + Box* upper_box = game->field[y - 1] + x; + + if(y == Y_LAST) { + decrement_y_offset_to_zero(current_box); + } + + decrement_y_offset_to_zero(upper_box); + + if(is_empty(current_box) && !is_empty(upper_box) && has_dropped(upper_box)) { + upper_box->offset = BOX_HEIGHT; + heap_swap(current_box, upper_box); + } + } + } +} + +static bool clear_rows(Box** field) { + for(int x = 0; x < X_FIELD_SIZE; ++x) { + if(is_empty(field[Y_LAST] + x) || !has_dropped(field[Y_LAST] + x)) { + return false; + } + } + + memset(field[Y_LAST], 128, ROW_BYTE_SIZE); + return true; +} + +/** + * Input Handling + */ + +static inline bool on_ground(Person* person, Field field) { + return person->p.y == Y_LAST || field[person->p.y + 1][person->p.x].exists; +} + +static void handle_key_presses(Person* person, InputEvent* input, GameState* game) { + switch(input->key) { + case InputKeyUp: + if(person->states == PlayerNothing && on_ground(person, game->field)) { + person->states = PlayerRising; + person->j_tick = 0; + } + break; + case InputKeyLeft: + person->right_frame = false; + if(person->h_tick == 0) { + person->h_tick = 1; + person->x_direction = -1; + } + break; + case InputKeyRight: + person->right_frame = true; + if(person->h_tick == 0) { + person->h_tick = 1; + person->x_direction = 1; + } + break; + case InputKeyOk: + game->game_status &= ~GameStatusInProgress; + game->animation = AnimationPause; + icon_animation_start(animations[AnimationPause]); + default: + break; + } +} + +/** + * #Person logic + */ + +static inline bool ground_box_check(Field field, Position new_position) { + Box* lower_box = get_lower_box(field, new_position); + + bool ground_box_dropped = + (new_position.y == Y_LAST || //Eсли мы и так в самом низу + is_empty(lower_box) || // Ecли снизу пустота + has_dropped(lower_box)); //Eсли бокс снизу допадал + return ground_box_dropped; +} + +static inline bool is_movable(Field field, Position box_pos, int x_direction) { + //TODO::Moжет и не двух, предположение + bool out_of_bounds = box_pos.x == 0 || box_pos.x == X_LAST; + if(out_of_bounds) return false; + bool box_on_top = box_pos.y < 1 || get_upper_box(field, box_pos)->exists; + if(box_on_top) return false; + bool has_next_box = get_next_box(field, box_pos, x_direction)->exists; + if(has_next_box) return false; + + return true; +} + +static bool horizontal_move(Person* person, Field field) { + Position new_position = person->p; + + if(!person->x_direction) return false; + + new_position.x += person->x_direction; + + bool on_edge_column = new_position.x > X_LAST; + if(on_edge_column) return false; + + if(is_empty(&field[new_position.y][new_position.x])) { + bool ground_box_dropped = ground_box_check(field, new_position); + if(ground_box_dropped) { + person->p = new_position; + return true; + } + } else if(is_movable(field, new_position, person->x_direction)) { + *get_next_box(field, new_position, person->x_direction) = + field[new_position.y][new_position.x]; + + field[new_position.y][new_position.x] = (Box){0}; + person->p = new_position; + return true; + } + return false; +} + +void hd_person_set_state(Person* person, PlayerStates state) { + person->states = state; + person->j_tick = 0; +} + +static void person_move(Person* person, Field field) { + /// Left-right logic + FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); + + if(person->states == PlayerNothing) { + if(!on_ground(person, field)) { + hd_person_set_state(person, PlayerFalling); + } + } else if(person->states == PlayerRising) { + if(person->j_tick++ == 0) { + person->p.y--; + } else if(person->j_tick == 6) { + hd_person_set_state(person, PlayerNothing); + } + + /// Destroy upper box + get_upper_box(field, person->p)->box_id = 0; + field[person->p.y][person->p.x].box_id = 0; + + } else if(person->states == PlayerFalling) { + if(person->j_tick++ == 0) { + if(on_ground(person, field)) { // TODO: Test the bugfix + hd_person_set_state(person, PlayerNothing); + } else { + person->p.y++; + } + } else if(person->j_tick == 5) { + if(on_ground(person, field)) { + hd_person_set_state(person, PlayerNothing); + } else { + hd_person_set_state(person, PlayerFalling); + } + } + } + + switch(person->h_tick) { + case 0: + break; + case 1: + person->h_tick++; + FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); + bool moved = horizontal_move(person, field); + if(!moved) { + person->h_tick = 0; + person->x_direction = 0; + } + break; + case 5: + FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); + person->h_tick = 0; + person->x_direction = 0; + break; + default: + FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); + person->h_tick++; + } +} + +static inline bool is_person_dead(Person* person, Box** field) { + return get_upper_box(field, person->p)->box_id != 0; +} + +/** + * #Callback + */ + +static void draw_box(Canvas* canvas, Box* box, int x, int y) { + if(is_empty(box)) { + return; + } + byte y_screen = y * BOX_HEIGHT - box->offset; + byte x_screen = x * BOX_WIDTH + DRAW_X_OFFSET; + + if(box->box_id == 0) { + canvas_set_bitmap_mode(canvas, true); + icon_animation_start(BOX_DESTROYED); + canvas_draw_icon_animation(canvas, x_screen, y_screen, BOX_DESTROYED); + if(icon_animation_is_last_frame(BOX_DESTROYED)) { + *box = (Box){0}; + icon_animation_stop(BOX_DESTROYED); + } + canvas_set_bitmap_mode(canvas, false); + } else { + canvas_draw_icon(canvas, x_screen, y_screen, boxes[box->box_id]); + } +} + +static void heap_defense_render_callback(Canvas* const canvas, void* mutex) { + furi_assert(mutex); + + const GameState* game = acquire_mutex((ValueMutex*)mutex, 25); + + ///Draw GameOver or Pause + if(!(game->game_status & GameStatusInProgress)) { + FURI_LOG_W(TAG, "[DAED_DRAW]func: [%s] line: %d ", __FUNCTION__, __LINE__); + + canvas_draw_icon_animation(canvas, 0, 0, animations[game->animation]); + release_mutex((ValueMutex*)mutex, game); + return; + } + + ///Draw field + canvas_draw_icon(canvas, 0, 0, &I_Background_128x64); + + ///Draw Person + const Person* person = game->person; + IconAnimation* player_animation = person->right_frame ? animations[AnimationRight] : + animations[AnimationLeft]; + + uint8_t x_screen = person->p.x * BOX_WIDTH + DRAW_X_OFFSET; + if(person->h_tick && person->h_tick != 1) { + if(person->right_frame) { + x_screen += (person->h_tick) * 2 - BOX_WIDTH; + } else { + x_screen -= (person->h_tick) * 2 - BOX_WIDTH; + } + } + + uint8_t y_screen = (person->p.y - 1) * BOX_HEIGHT; + if(person->j_tick) { + if(person->states == PlayerRising) { + y_screen += BOX_HEIGHT - (person->j_tick) * 2; + } else if(person->states == PlayerFalling) { + y_screen -= BOX_HEIGHT - (person->j_tick) * 2; + } + } + + canvas_draw_icon_animation(canvas, x_screen, y_screen, player_animation); + + ///Draw Boxes + canvas_set_color(canvas, ColorBlack); + for(int y = 1; y < Y_FIELD_SIZE; ++y) { + for(int x = 0; x < X_FIELD_SIZE; ++x) { + draw_box(canvas, &(game->field[y][x]), x, y); + } + } + + release_mutex((ValueMutex*)mutex, game); +} + +static void heap_defense_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { + if(input_event->type != InputTypePress && input_event->type != InputTypeLong) return; + + furi_assert(event_queue); + GameEvent event = {.type = EventKeyPress, .input = *input_event}; + furi_message_queue_put(event_queue, &event, FuriWaitForever); +} + +static void heap_defense_timer_callback(FuriMessageQueue* event_queue) { + furi_assert(event_queue); + + GameEvent event = {.type = EventGameTick, .input = {0}}; + furi_message_queue_put(event_queue, &event, 0); +} + +int32_t heap_defence_app(void* p) { + UNUSED(p); + srand(DWT->CYCCNT); + + //FURI_LOG_W(TAG, "Heap defence start %d", __LINE__); + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); + GameState* game = allocGameState(); + + ValueMutex state_mutex; + if(!init_mutex(&state_mutex, game, sizeof(GameState))) { + game_destroy(game); + return 1; + } + + assets_load(); + ViewPort* view_port = view_port_alloc(); + view_port_draw_callback_set(view_port, heap_defense_render_callback, &state_mutex); + view_port_input_callback_set(view_port, heap_defense_input_callback, event_queue); + + FuriTimer* timer = + furi_timer_alloc(heap_defense_timer_callback, FuriTimerTypePeriodic, event_queue); + furi_timer_start(timer, furi_kernel_get_tick_frequency() / TIMER_UPDATE_FREQ); + + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + NotificationApp* notification = furi_record_open("notification"); + + memset(game->field[Y_LAST], 128, ROW_BYTE_SIZE); + game->person->p.y -= 2; + game->game_status = 0; + game->animation = AnimationPause; + + GameEvent event = {0}; + while(event.input.key != InputKeyBack) { + if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) { + continue; + } + + game = (GameState*)acquire_mutex_block(&state_mutex); + + //unset vibration + if(game->game_status & GameStatusVibro) { + notification_message(notification, &sequence_reset_vibro); + game->game_status &= ~GameStatusVibro; + icon_animation_stop(BOX_DESTROYED); + memset(game->field[Y_LAST], 0, ROW_BYTE_SIZE); + } + + if(!(game->game_status & GameStatusInProgress)) { + if(event.type == EventKeyPress && event.input.key == InputKeyOk) { + game->game_status |= GameStatusInProgress; + icon_animation_stop(animations[game->animation]); + } + + } else if(event.type == EventKeyPress) { + handle_key_presses(game->person, &(event.input), game); + } else { // EventGameTick + + drop_box(game); + generate_box(game); + if(clear_rows(game->field)) { + notification_message(notification, &sequence_set_vibro_on); + icon_animation_start(BOX_DESTROYED); + game->game_status |= GameStatusVibro; + } + person_move(game->person, game->field); + + if(is_person_dead(game->person, game->field)) { + game->game_status &= ~GameStatusInProgress; + game->animation = AnimationGameOver; + icon_animation_start(animations[AnimationGameOver]); + game_reset_field_and_player(game); + notification_message(notification, &sequence_error); + } + } + release_mutex(&state_mutex, game); + view_port_update(view_port); + } + + furi_timer_free(timer); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_record_close("gui"); + furi_record_close("notification"); + furi_message_queue_free(event_queue); + assets_clear(); + delete_mutex(&state_mutex); + game_destroy(game); + + return 0; +} diff --git a/applications/plugins/heap_defence_game/hede_assets.c b/applications/plugins/heap_defence_game/hede_assets.c new file mode 100644 index 000000000..ec8b933b9 --- /dev/null +++ b/applications/plugins/heap_defence_game/hede_assets.c @@ -0,0 +1,11 @@ +// +// Created by user on 15.12.2021. +// +#include "hede_assets.h" +#include + +const uint8_t _A_HD_BoxDestroyed_10x10_0[] = {0x01,0x00,0x10,0x00,0x00,0x1d,0xa2,0x01,0xc8,0x80,0x6d,0x20,0x15,0x08,0x06,0x72,0x01,0x48,0x07,0xa0,}; +const uint8_t _A_HD_BoxDestroyed_10x10_1[] = {0x00,0x00,0x00,0x28,0x01,0x4A,0x00,0xA8,0x01,0x84,0x00,0x22,0x00,0x88,0x00,0x58,0x01,0x22,0x00,0x00,0x00,}; +const uint8_t _A_HD_BoxDestroyed_10x10_2[] = {0x00,0x00,0x00,0x08,0x01,0x42,0x00,0x09,0x01,0x00,0x02,0x02,0x00,0x01,0x02,0x00,0x01,0x21,0x00,0x42,0x02,}; +const uint8_t *_A_HD_BoxDestroyed_10x10[] = {_A_HD_BoxDestroyed_10x10_0,_A_HD_BoxDestroyed_10x10_1,_A_HD_BoxDestroyed_10x10_2}; +const Icon A_HD_BoxDestroyed_10x10 = {.width=10,.height=10,.frame_count=3,.frame_rate=4,.frames=_A_HD_BoxDestroyed_10x10}; \ No newline at end of file diff --git a/applications/plugins/heap_defence_game/hede_assets.h b/applications/plugins/heap_defence_game/hede_assets.h new file mode 100644 index 000000000..3bcabc59f --- /dev/null +++ b/applications/plugins/heap_defence_game/hede_assets.h @@ -0,0 +1,11 @@ +// +// Created by user on 15.12.2021. +// + +#ifndef HEDE_ASSETS_H +#define HEDE_ASSETS_H +#include + +extern const Icon A_HD_BoxDestroyed_10x10; + +#endif