From 1e36565b943ed1758539344df1db66078270b924 Mon Sep 17 00:00:00 2001 From: Felix Pankratz Date: Fri, 23 Sep 2022 16:59:38 +0200 Subject: [PATCH] game over + win screen --- .assets.h.swp | Bin 12288 -> 0 bytes assets/tile_0.png | Bin 148 -> 130 bytes assets/tile_1.png | Bin 155 -> 152 bytes assets/tile_2.png | Bin 164 -> 164 bytes assets/tile_3.png | Bin 162 -> 166 bytes assets/tile_4.png | Bin 162 -> 164 bytes assets/tile_5.png | Bin 164 -> 167 bytes assets/tile_6.png | Bin 173 -> 164 bytes assets/tile_7.png | Bin 168 -> 165 bytes assets/tile_8.png | Bin 166 -> 161 bytes minesweeper.c | 115 ++++++++++++++++++++++++++++++++++++++-------- 11 files changed, 95 insertions(+), 20 deletions(-) delete mode 100644 .assets.h.swp diff --git a/.assets.h.swp b/.assets.h.swp deleted file mode 100644 index 3566dca0bfa835a4d8030e4f28c444a977aa662e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&%}T>S5C`z7dKE=qV6{hW($cV^IR3ve5Z<0E7Cd|-84~TS5J?`@|NrUv|C876 zJf0`DpsFJv009U<00Izz00bZa0SG_<0ucCFKyY+!yWMS`J$L?Gbw2Eqv3v(U5T(wn v=UZWQqWm%o62+I~Lw~5Pxx5kw;+~qJiui_ny(3ooI<~_5tv=SFjk){gTe~DWM4f1;-EJ delta 82 zcmZo-oWeN4)B6wu1K%M=Q4OyK1_lOAPZ!4!jo{>zgoGdbEDl`421Z6k29Kt+GO20w l3iEKWDy)CN)YH?$!>}NTLqLi5QWH=UgQu&X%Q~loCIFAi7H9wf diff --git a/assets/tile_1.png b/assets/tile_1.png index e887fa9ad57c2a4459cf77b5c82d1ae4544baac1..588d77c2ad3b7d00413646b5316eca6e3f7b9f33 100644 GIT binary patch delta 98 zcmbQuID>J5BnKM<1H%#iecclkHT(}TFz_8>6xHx*01E1Qx;Tbt1SkLDXW^+}5T4S; z?B?dC!OavPvcS8Ep^GVJTVg~bU&aE4tFk;i3<8c^JVni+&OnU}p00i_>zopr0OOz; Af&c&j delta 101 zcmbQiIGb^TBnJ}%1A}+2=ADU(8bOB{82An|9?xHq0u(gxba4!k2v1H)Nci#pzx@Ok zwjPHDovt&fO#u!JBCVSaFeo;rDL66lPS9&SytAi=;XoHZ_tT(YL7-j+Pgg&ebxsLQ E0C-6ujQ{`u diff --git a/assets/tile_2.png b/assets/tile_2.png index 423d097c53d006136b07243e7c9afc51c2db0258..9c1c590131adc294d658bcb17ad7ca13ea27538e 100644 GIT binary patch delta 110 zcmZ3&xP)6xHx*018@qx;Tbt1SkLDXW^+}5T25j zkdo4poYHWWWrETSgF7rS46cl4xKf-0?=Vbq*eWzWe23=A)$B}9x*uc`tX O!rS%_n-N2+gp`}FbD6Vov00f3rjvD`|mor Q=l}o!07*qoM6N<$f-{>bkpKVy diff --git a/assets/tile_3.png b/assets/tile_3.png index f6d678446fed0560f69d10e0de2abcd3c16882fc..a229d01f5adc4e5cbac38b4c2fa1f26a30128abe 100644 GIT binary patch delta 112 zcmZ3)xQuavBnKM<1H%#iecclkHDV7jFz_8>6xHx*018@rx;Tbt1SkLDXW^+}5T25j zkdo4poYHWWWrETSgF7rS46cl4xKf-0MH*BbByP$Um@9BA&2~62n}>%Xqf?%Z{rsD9 PpfL=du6{1-oD!M<3f~~< delta 108 zcmZ3+xQKCrBnJ}%1A}+2=ADU(8j*(?82An|9?xHq0u(g&ba4!k2v1H)Nci#pzx@Ok zwjKutK~^ILrvldiPKyTZ)TR%Hj85!FOb)pn)bKey(X!yci4z6xHx*018@qx;Tbt1SkLDXW^+}5T25j zkdo4}DS$DCk!OMSk$?ui0FeVF%Cnim8H%*e>^<>L?JSpo!&g&gW(M0k0z4OLg{y&v OFnGH9xvX72BO@jT_On6){12FC0gYhr MboFyt=akR{05BUN=l}o! diff --git a/assets/tile_5.png b/assets/tile_5.png index 22fad623f915bde27c43ef8e4b16dcee2c86f95a..2c8f03c3d1459486d34484d6221fc74548321ebb 100644 GIT binary patch delta 113 zcmZ3&xSVl6xHx*01Dc8x;Tbt1SkLDXW^+}h+$M# zR*qm`OZYY8fQm>1OQHl@fJlRnqdDhlX@{v$p8QV delta 110 zcmZ3^xP)xP)&U2EHSVQ?>b|85kHWJzX3_G=h`=@U!q#FbGd!V|H_MGjL-oU{&Cp zkf_kJhT|xUgu}L}71|CAvqd%bHFzpSJ06(L!^7~;Mvg=B%8O>8Aq<|belF{r5}E)q CCLBlr delta 107 zcmV-x0F?iv0j&X$No2wR01m2EHSVQ?>b|85kI>JY5_^G=h`=@U!q#FvKt_D=SAZuqFJOaX>|& zfh9pg@_^_ACJ8QwFvZzTix^^sSUff}#hNn%0mF|tncsbXuAT*&!r~j1taPm|25LwEC2ui07*qo IM6N<$f(9WZVE_OC diff --git a/assets/tile_8.png b/assets/tile_8.png index 2e59014a553b8e080b3998a707eb08fe73e8607e..cebbe5389bd0eee1f538e4d66f5886e2a228b94c 100644 GIT binary patch delta 95 zcmZ3+xR7yzXT%W(2EHSVQ?>b|85kJMJY5_^G=h`=@U!q#FbGd!V|H_MGjL-oU{&Cp zkf_kJhT|yL43gTe~DWM4fyRI2& delta 100 zcmV-q0Gt1z0j2?vNnOGK01m #include +#include #include "assets.h" @@ -13,7 +14,7 @@ #define TILE_WIDTH 8 #define TILE_HEIGHT 8 -#define MINECOUNT 27 +#define MINECOUNT 12 typedef enum { EventTypeTick, @@ -51,6 +52,9 @@ typedef struct { int cursor_x; int cursor_y; bool game_started; + int mines_left; + int fields_cleared; + bool showing_dialog; } Minesweeper; static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { @@ -65,6 +69,10 @@ static void render_callback(Canvas* const canvas, void* ctx) { if (minesweeper_state == NULL) { return; } + if (minesweeper_state->showing_dialog) { + release_mutex((ValueMutex*)ctx, minesweeper_state); + return; + } canvas_set_font(canvas, FontPrimary); for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { for (int x = 0; x < PLAYFIELD_WIDTH; x++) { @@ -191,6 +199,12 @@ static void render_callback(Canvas* const canvas, void* ctx) { static void setup_playfield(Minesweeper* minesweeper_state) { int mines_left = MINECOUNT; + for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { + for (int x = 0; x < PLAYFIELD_WIDTH; x++){ + minesweeper_state->minefield[x][y] = FieldEmpty; + minesweeper_state->playfield[x][y] = TileTypeUncleared; + } + } while(mines_left > 0) { int rand_x = rand() % PLAYFIELD_WIDTH; int rand_y = rand() % PLAYFIELD_HEIGHT; @@ -200,6 +214,8 @@ static void setup_playfield(Minesweeper* minesweeper_state) { minesweeper_state->minefield[rand_x][rand_y] = FieldMine; mines_left--; } + minesweeper_state->mines_left = MINECOUNT; + minesweeper_state->fields_cleared = 0; } } @@ -211,24 +227,65 @@ static void place_flag(Minesweeper* minesweeper_state) { } } -static void game_lost() { - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - notification_message(notifications, &sequence_set_vibro_on); - furi_delay_ms(200); - notification_message(notifications, &sequence_reset_vibro); - furi_record_close(RECORD_NOTIFICATION); +static bool game_lost(Minesweeper* minesweeper_state) { + // returns true if the player wants to restart, otherwise false + minesweeper_state->showing_dialog = true; + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS); + + DialogMessage* message = dialog_message_alloc(); + const char* header_text = "Game Over"; + const char* message_text = "You hit a mine!"; + + dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); + dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, NULL, "Play again", NULL); + // TODO: create icon + dialog_message_set_icon(message, NULL, 72, 17); + + notification_message(notifications, &sequence_set_vibro_on); + furi_delay_ms(200); + notification_message(notifications, &sequence_reset_vibro); + + DialogMessageButton choice = dialog_message_show(dialogs, message); + dialog_message_free(message); + minesweeper_state->showing_dialog = false; + furi_record_close(RECORD_NOTIFICATION); + + return choice == DialogMessageButtonCenter; +} + +static bool game_won(Minesweeper* minesweeper_state) { + NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); + DialogsApp *dialogs = furi_record_open(RECORD_DIALOGS); + + DialogMessage* message = dialog_message_alloc(); + const char* header_text = "Game won!"; + const char* message_text = "You cleared the minefield!"; + + dialog_message_set_header(message, header_text, 64, 3, AlignCenter, AlignTop); + dialog_message_set_text(message, message_text, 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, NULL, "Play again", NULL); + // TODO: create icon + dialog_message_set_icon(message, NULL, 72, 17); + + DialogMessageButton choice = dialog_message_show(dialogs, message); + dialog_message_free(message); + minesweeper_state->showing_dialog = false; + notification_message(notifications, &sequence_reset_vibro); + furi_record_close(RECORD_NOTIFICATION); + return choice == DialogMessageButtonCenter; } -static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) { +static bool play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y) { if (minesweeper_state->playfield[cursor_x][cursor_y] != TileTypeUncleared) { // we're on an already uncovered field - return; + return true; } if (minesweeper_state->minefield[cursor_x][cursor_y] == FieldMine) { // TODO: player loses! minesweeper_state->playfield[cursor_x][cursor_y] = TileTypeMine; - game_lost(); - return; + return false; } else { // get number of surrounding mines. int hint = 0; @@ -248,6 +305,7 @@ static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y } // 〜( ̄▽ ̄〜) don't judge me (〜 ̄▽ ̄)〜 minesweeper_state->playfield[cursor_x][cursor_y] = hint; + minesweeper_state->fields_cleared++; FURI_LOG_D("Minesweeper", "Setting %d,%d to %d", cursor_x, cursor_y, hint); if (hint == 0) { // auto open surrounding fields. @@ -264,16 +322,17 @@ static void play_move(Minesweeper* minesweeper_state, int cursor_x, int cursor_y } } } + return true; } } -static void minesweeper_state_init(Minesweeper* const plugin_state) { - plugin_state->cursor_x = plugin_state->cursor_y = 0; - plugin_state->game_started = false; +static void minesweeper_state_init(Minesweeper* const minesweeper_state) { + minesweeper_state->cursor_x = minesweeper_state->cursor_y = 0; + minesweeper_state->game_started = false; + minesweeper_state->showing_dialog = false; for (int y = 0; y < PLAYFIELD_HEIGHT; y++) { for (int x = 0; x < PLAYFIELD_WIDTH; x++){ - plugin_state->minefield[x][y] = FieldEmpty; - plugin_state->playfield[x][y] = TileTypeUncleared; + minesweeper_state->playfield[x][y] = TileTypeUncleared; } } } @@ -342,10 +401,26 @@ int32_t minesweeper_app(void* p) { setup_playfield(minesweeper_state); minesweeper_state->game_started = true; } - play_move( - minesweeper_state, - minesweeper_state->cursor_x, - minesweeper_state->cursor_y); + if (!play_move(minesweeper_state, minesweeper_state->cursor_x, minesweeper_state->cursor_y)) { + // ooops. looks like we hit a mine! + if (game_lost(minesweeper_state)) { + // player wants to restart. + setup_playfield(minesweeper_state); + } else { + // player wants to exit :( + processing = false; + } + } else { + // check win condition. + if (minesweeper_state->fields_cleared == (PLAYFIELD_HEIGHT*PLAYFIELD_WIDTH) - MINECOUNT){ + if (game_won(minesweeper_state)) { + //player wants to restart + setup_playfield(minesweeper_state); + } else { + processing = false; + } + } + } break; case InputKeyBack: // Exit the plugin