From 41895118bd5a73f5358d60ce89f337bec57f1d4d Mon Sep 17 00:00:00 2001 From: ushastoe <40743392+krolchonok@users.noreply.github.com> Date: Fri, 28 Apr 2023 01:28:40 +0300 Subject: [PATCH 01/23] Update HowToInstall.md 46 version --- documentation/HowToInstall.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index a650d97ee7..abbca0830f 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -23,7 +23,7 @@ after that on web updater page - press `Connect` button - And wait, if all flashed successfully - you will have all needed assets pre installed - Done -![web](https://user-images.githubusercontent.com/40743392/233779040-596ad9a9-87cd-4b19-a831-16fdc678ba35.png) +![web](https://user-images.githubusercontent.com/40743392/235004244-30a59649-fa52-4db0-bf8f-ef5290951aa0.png)
@@ -40,7 +40,7 @@ after that on web updater page - press `Connect` button - Error in ios app will show up, but flipper will be updated successfully - And if all flashed successfully - you will have all needed assets pre installed - Done -![ios](https://user-images.githubusercontent.com/40743392/233779071-10e37af5-a7d9-41d6-81cd-9bb660352b4d.png) +![ios](https://user-images.githubusercontent.com/40743392/235004287-bf739fb9-ca77-4843-a235-4614832e9ae5.png)

@@ -56,7 +56,7 @@ after that on web updater page - press `Connect` button - Wait until update is finished - And if all flashed successfully - you will have all needed assets pre installed - Done -![andro_tgz](https://user-images.githubusercontent.com/40743392/233782806-e81c9634-4694-4faf-88ce-08b89a8b6fa0.png) +![andro_tgz](https://user-images.githubusercontent.com/40743392/235004340-325a97da-7e3d-4821-892c-705f661bfddc.png)

@@ -71,7 +71,7 @@ after that on web updater page - press `Connect` button - Wait until update is finished - And if all flashed successfully - you will have all needed assets pre installed - Done -![androweb](https://user-images.githubusercontent.com/40743392/233782906-1f8f1ebf-c488-4d9f-9a6f-67a4e693cbda.png) +![androweb](https://user-images.githubusercontent.com/40743392/235004374-bef68a66-1b10-4688-a506-8753660c2ebc.png)
@@ -90,7 +90,7 @@ after that on web updater page - press `Connect` button - And wait, if all flashed successfully - you will have all needed assets pre installed - Done -![qflip](https://user-images.githubusercontent.com/40743392/233779331-3f21c662-6e77-42e5-a928-f5441bd85bd4.png) +![qflip](https://user-images.githubusercontent.com/40743392/235004392-8e824589-d0fa-444c-a592-098ff629f8c6.png) @@ -111,7 +111,7 @@ after that on web updater page - press `Connect` button - Update will start, wait for all stages - Done -![manual](https://user-images.githubusercontent.com/40743392/233779363-faf5b35b-e136-4dca-b1fb-15188b26eb6a.png) +![manual](https://user-images.githubusercontent.com/40743392/235004403-cc82a02b-06a3-4cbe-9420-8eb0ad1f4659.png) From b31e955744d329601b087c0099d7c1734f0980cc Mon Sep 17 00:00:00 2001 From: ushastoe <40743392+krolchonok@users.noreply.github.com> Date: Fri, 28 Apr 2023 01:39:58 +0300 Subject: [PATCH 02/23] Update HowToInstall.md --- documentation/HowToInstall.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index abbca0830f..9b762ea112 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -23,7 +23,7 @@ after that on web updater page - press `Connect` button - And wait, if all flashed successfully - you will have all needed assets pre installed - Done -![web](https://user-images.githubusercontent.com/40743392/235004244-30a59649-fa52-4db0-bf8f-ef5290951aa0.png) +![web](https://user-images.githubusercontent.com/40743392/235005830-98ceda39-a143-47ef-ad4d-5489bc3df98b.png)
@@ -40,7 +40,7 @@ after that on web updater page - press `Connect` button - Error in ios app will show up, but flipper will be updated successfully - And if all flashed successfully - you will have all needed assets pre installed - Done -![ios](https://user-images.githubusercontent.com/40743392/235004287-bf739fb9-ca77-4843-a235-4614832e9ae5.png) +![ios](https://user-images.githubusercontent.com/40743392/235005844-bea8f2fd-f50d-41b1-9191-e3842d8658d2.png)

@@ -56,7 +56,8 @@ after that on web updater page - press `Connect` button - Wait until update is finished - And if all flashed successfully - you will have all needed assets pre installed - Done -![andro_tgz](https://user-images.githubusercontent.com/40743392/235004340-325a97da-7e3d-4821-892c-705f661bfddc.png) +![andro_tgz](https://user-images.githubusercontent.com/40743392/235005877-d4f5f73c-241c-4a7b-a51d-b8407983856c.png) +

@@ -71,7 +72,7 @@ after that on web updater page - press `Connect` button - Wait until update is finished - And if all flashed successfully - you will have all needed assets pre installed - Done -![androweb](https://user-images.githubusercontent.com/40743392/235004374-bef68a66-1b10-4688-a506-8753660c2ebc.png) +![androweb](https://user-images.githubusercontent.com/40743392/235005891-19ef6bb6-094f-437d-afcd-75d60921e3c4.png)
@@ -89,8 +90,7 @@ after that on web updater page - press `Connect` button - Update will start - And wait, if all flashed successfully - you will have all needed assets pre installed - Done - -![qflip](https://user-images.githubusercontent.com/40743392/235004392-8e824589-d0fa-444c-a592-098ff629f8c6.png) +![qflip](https://user-images.githubusercontent.com/40743392/235005910-819abd34-65d4-4aaa-a11c-9c28bea737e9.png) @@ -110,8 +110,8 @@ after that on web updater page - press `Connect` button `update/f7-update-(CURRENT VERSION)/update.fuf` - Update will start, wait for all stages - Done +![manual](https://user-images.githubusercontent.com/40743392/235005942-c4debf85-b251-41c1-ad0b-c7bd94b999fb.png) -![manual](https://user-images.githubusercontent.com/40743392/235004403-cc82a02b-06a3-4cbe-9420-8eb0ad1f4659.png) From 7b21dd7082fddf58542e1a06ebcd1a0ad711e845 Mon Sep 17 00:00:00 2001 From: ushastoe <40743392+krolchonok@users.noreply.github.com> Date: Fri, 28 Apr 2023 01:41:03 +0300 Subject: [PATCH 03/23] Update HowToInstall.md --- documentation/HowToInstall.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 9b762ea112..d4dcc3bbcf 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -110,7 +110,8 @@ after that on web updater page - press `Connect` button `update/f7-update-(CURRENT VERSION)/update.fuf` - Update will start, wait for all stages - Done -![manual](https://user-images.githubusercontent.com/40743392/235005942-c4debf85-b251-41c1-ad0b-c7bd94b999fb.png) +![manual](https://user-images.githubusercontent.com/40743392/235006093-5f76f28c-6159-4785-a7ca-a06354dffab6.png) + From c0de75367f7b4209585648a2506aaeec165c0b38 Mon Sep 17 00:00:00 2001 From: ushastoe <40743392+krolchonok@users.noreply.github.com> Date: Fri, 28 Apr 2023 01:43:27 +0300 Subject: [PATCH 04/23] Update HowToInstall.md --- documentation/HowToInstall.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index d4dcc3bbcf..656d4cc4bf 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -110,7 +110,7 @@ after that on web updater page - press `Connect` button `update/f7-update-(CURRENT VERSION)/update.fuf` - Update will start, wait for all stages - Done -![manual](https://user-images.githubusercontent.com/40743392/235006093-5f76f28c-6159-4785-a7ca-a06354dffab6.png) +![manual](https://user-images.githubusercontent.com/40743392/235006410-19eaf58e-2425-4e8e-8ec9-973bda362c47.png) From 96375e8244a1e90bf6359e040677425dbc36968d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Apr 2023 14:00:40 +0300 Subject: [PATCH 05/23] Version instead of branch --- firmware/targets/f7/ble_glue/dev_info_service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/targets/f7/ble_glue/dev_info_service.c b/firmware/targets/f7/ble_glue/dev_info_service.c index 8bdb2eea84..d24058632f 100644 --- a/firmware/targets/f7/ble_glue/dev_info_service.c +++ b/firmware/targets/f7/ble_glue/dev_info_service.c @@ -33,7 +33,7 @@ void dev_info_svc_start() { dev_info_svc->version_string = furi_string_alloc_printf( "%s %s %s %s", version_get_githash(NULL), - version_get_gitbranch(NULL), + version_get_version(NULL), version_get_gitbranchnum(NULL), version_get_builddate(NULL)); snprintf( From e87256e01f3e289c6eb60badd4ae88e190369da5 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Fri, 28 Apr 2023 14:04:16 +0300 Subject: [PATCH 06/23] Update TOTP --- .../services/config/token_info_iterator.c | 16 ++++++-------- .../external/totp/services/hmac/hmac_common.h | 1 - .../external/totp/services/hmac/hmac_sha256.c | 1 + .../external/totp/services/hmac/sha1.c | 8 +++---- .../external/totp/services/hmac/sha256.c | 7 ++----- .../external/totp/services/hmac/sha512.c | 7 ++----- .../totp/services/hmac/sha_pad_buffer.c | 11 ++++++++++ .../totp/services/hmac/sha_pad_buffer.h | 4 ++++ applications/external/totp/types/token_info.c | 21 +++++++++++++++++++ applications/external/totp/types/token_info.h | 12 +++++++++-- 10 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 applications/external/totp/services/hmac/sha_pad_buffer.c create mode 100644 applications/external/totp/services/hmac/sha_pad_buffer.h diff --git a/applications/external/totp/services/config/token_info_iterator.c b/applications/external/totp/services/config/token_info_iterator.c index 9b7dd5550c..f8cd3c64e5 100644 --- a/applications/external/totp/services/config/token_info_iterator.c +++ b/applications/external/totp/services/config/token_info_iterator.c @@ -68,7 +68,9 @@ static bool seek_to_token(size_t token_index, TokenInfoIteratorContext* context) direction = StreamDirectionBackward; } - stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart); + if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) { + return false; + } if(token_index_diff != 0) { long i = 0; @@ -89,10 +91,6 @@ static bool seek_to_token(size_t token_index, TokenInfoIteratorContext* context) context->last_seek_offset = stream_tell(stream); context->last_seek_index = token_index; - } else { - if(!stream_seek(stream, context->last_seek_offset, StreamOffsetFromStart)) { - return false; - } } return true; @@ -495,11 +493,9 @@ bool totp_token_info_iterator_go_to(TokenInfoIteratorContext* context, size_t to } uint32_t temp_data32; - if(flipper_format_read_uint32( - context->config_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &temp_data32, 1) && - temp_data32 <= STEAM) { - tokenInfo->algo = (TokenHashAlgo)temp_data32; - } else { + if(!flipper_format_read_uint32( + context->config_file, TOTP_CONFIG_KEY_TOKEN_ALGO, &temp_data32, 1) || + !token_info_set_algo_from_int(tokenInfo, temp_data32)) { tokenInfo->algo = SHA1; } diff --git a/applications/external/totp/services/hmac/hmac_common.h b/applications/external/totp/services/hmac/hmac_common.h index 0cd56ed999..3499cb800b 100644 --- a/applications/external/totp/services/hmac/hmac_common.h +++ b/applications/external/totp/services/hmac/hmac_common.h @@ -1,5 +1,4 @@ #include -#include "sha256.h" #include "memxor.h" #define IPAD 0x36 diff --git a/applications/external/totp/services/hmac/hmac_sha256.c b/applications/external/totp/services/hmac/hmac_sha256.c index c51f24b4d7..00ac2a177c 100644 --- a/applications/external/totp/services/hmac/hmac_sha256.c +++ b/applications/external/totp/services/hmac/hmac_sha256.c @@ -15,6 +15,7 @@ along with this program. If not, see . */ #include "hmac_sha256.h" +#include "sha256.h" #define GL_HMAC_NAME 256 #define GL_HMAC_BLOCKSIZE 64 diff --git a/applications/external/totp/services/hmac/sha1.c b/applications/external/totp/services/hmac/sha1.c index ecf22fc972..29f22e3c30 100644 --- a/applications/external/totp/services/hmac/sha1.c +++ b/applications/external/totp/services/hmac/sha1.c @@ -27,6 +27,8 @@ #include #include +#include "sha_pad_buffer.h" + #ifdef WORDS_BIGENDIAN #define SWAP(n) (n) #else @@ -34,10 +36,6 @@ #define SWAP(n) swap_uint32(n) #endif -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */}; - /* Take a pointer to a 160 bit block of data (five 32 bit ints) and initialize it to the start constants of the SHA1 algorithm. This must be called before using hash in the call to sha1_hash. */ @@ -87,7 +85,7 @@ void* sha1_finish_ctx(struct sha1_ctx* ctx, void* resbuf) { ctx->buffer[size - 2] = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29)); ctx->buffer[size - 1] = SWAP(ctx->total[0] << 3); - memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes); /* Process last bytes. */ sha1_process_block(ctx->buffer, size * 4, ctx); diff --git a/applications/external/totp/services/hmac/sha256.c b/applications/external/totp/services/hmac/sha256.c index 89ca67c2be..09ba272e74 100644 --- a/applications/external/totp/services/hmac/sha256.c +++ b/applications/external/totp/services/hmac/sha256.c @@ -25,6 +25,7 @@ #include #include +#include "sha_pad_buffer.h" #ifdef WORDS_BIGENDIAN #define SWAP(n) (n) @@ -33,10 +34,6 @@ #define SWAP(n) swap_uint32(n) #endif -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. */ -static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */}; - /* Takes a pointer to a 256 bit block of data (eight 32 bit ints) and initializes it to the start constants of the SHA256 algorithm. This @@ -91,7 +88,7 @@ static void sha256_conclude_ctx(struct sha256_ctx* ctx) { set_uint32((char*)&ctx->buffer[size - 2], SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29))); set_uint32((char*)&ctx->buffer[size - 1], SWAP(ctx->total[0] << 3)); - memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); + sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 4 - bytes); /* Process last bytes. */ sha256_process_block(ctx->buffer, size * 4, ctx); diff --git a/applications/external/totp/services/hmac/sha512.c b/applications/external/totp/services/hmac/sha512.c index b56dd0f2eb..ffe2864fbd 100644 --- a/applications/external/totp/services/hmac/sha512.c +++ b/applications/external/totp/services/hmac/sha512.c @@ -27,13 +27,10 @@ #include #include "byteswap.h" +#include "sha_pad_buffer.h" #define SWAP(n) swap_uint64(n) -/* This array contains the bytes used to pad the buffer to the next - 128-byte boundary. */ -static const unsigned char fillbuf[128] = {0x80, 0 /* , 0, 0, ... */}; - /* Takes a pointer to a 512 bit block of data (eight 64 bit ints) and initializes it to the start constants of the SHA512 algorithm. This @@ -90,7 +87,7 @@ static void sha512_conclude_ctx(struct sha512_ctx* ctx) { SWAP(u64or(u64shl(ctx->total[1], 3), u64shr(ctx->total[0], 61)))); set_uint64((char*)&ctx->buffer[size - 1], SWAP(u64shl(ctx->total[0], 3))); - memcpy(&((char*)ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); + sha_pad_buffer(&((uint8_t*)ctx->buffer)[bytes], (size - 2) * 8 - bytes); /* Process last bytes. */ sha512_process_block(ctx->buffer, size * 8, ctx); diff --git a/applications/external/totp/services/hmac/sha_pad_buffer.c b/applications/external/totp/services/hmac/sha_pad_buffer.c new file mode 100644 index 0000000000..badedbcc7d --- /dev/null +++ b/applications/external/totp/services/hmac/sha_pad_buffer.c @@ -0,0 +1,11 @@ +#include "sha_pad_buffer.h" +#include + +void sha_pad_buffer(uint8_t* buffer, size_t size) { + if(size > 0) { + buffer[0] = 0x80; + if(size > 1) { + memset(&buffer[1], 0, size - 1); + } + } +} \ No newline at end of file diff --git a/applications/external/totp/services/hmac/sha_pad_buffer.h b/applications/external/totp/services/hmac/sha_pad_buffer.h new file mode 100644 index 0000000000..7dba40fa96 --- /dev/null +++ b/applications/external/totp/services/hmac/sha_pad_buffer.h @@ -0,0 +1,4 @@ +#include +#include + +void sha_pad_buffer(uint8_t* buffer, size_t size); \ No newline at end of file diff --git a/applications/external/totp/types/token_info.c b/applications/external/totp/types/token_info.c index 2f108033be..6810d02110 100644 --- a/applications/external/totp/types/token_info.c +++ b/applications/external/totp/types/token_info.c @@ -117,6 +117,27 @@ bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) return false; } +bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code) { + switch(algo_code) { + case SHA1: + token_info->algo = SHA1; + break; + case SHA256: + token_info->algo = SHA256; + break; + case SHA512: + token_info->algo = SHA512; + break; + case STEAM: + token_info->algo = STEAM; + break; + default: + return false; + } + + return true; +} + char* token_info_get_algo_as_cstr(const TokenInfo* token_info) { switch(token_info->algo) { case SHA1: diff --git a/applications/external/totp/types/token_info.h b/applications/external/totp/types/token_info.h index 138ad32b12..0d73dd0615 100644 --- a/applications/external/totp/types/token_info.h +++ b/applications/external/totp/types/token_info.h @@ -168,7 +168,7 @@ void token_info_free(TokenInfo* token_info); /** * @brief Encrypts & sets plain token secret to the given instance of \c TokenInfo * @param token_info instance where secret should be updated - * @param base32_token_secret plain token secret in Base32 format + * @param plain_token_secret plain token secret * @param token_secret_length plain token secret length * @param plain_token_secret_encoding plain token secret encoding * @param iv initialization vecor (IV) to be used for encryption @@ -201,10 +201,18 @@ bool token_info_set_duration_from_int(TokenInfo* token_info, uint8_t duration); * @brief Sets token hashing algorithm from \c str value * @param token_info instance whichs token hashing algorithm should be updated * @param str desired token algorithm - * @return \c true if token hahsing algorithm has been updated; \c false otherwise + * @return \c true if token hashing algorithm has been updated; \c false otherwise */ bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str); +/** + * @brief Sets token hashing algorithm from \c algo_code code + * @param token_info instance whichs token hashing algorithm should be updated + * @param algo_code desired token algorithm code + * @return \c true if token hashing algorithm has been updated; \c false otherwise + */ +bool token_info_set_algo_from_int(TokenInfo* token_info, uint8_t algo_code); + /** * @brief Gets token hahsing algorithm name as C-string * @param token_info instance which token hahsing algorithm name should be returned From 5085a17bcb6fbe74fc8d874ef371aedc45d71d2f Mon Sep 17 00:00:00 2001 From: ushastoe Date: Sat, 29 Apr 2023 18:16:53 +0300 Subject: [PATCH 07/23] HID app refactor --- .../external/hid_app/assets/OutCircles.png | Bin 0 -> 2469 bytes .../hid_app/assets/Pause_icon_9x9.png | Bin 4559 -> 1743 bytes .../hid_app/assets/Pin_back_arrow_10x10.png | Bin 0 -> 4575 bytes .../hid_app/assets/Pressed_Button_19x19.png | Bin 0 -> 1790 bytes .../external/hid_app/assets/S_DOWN.png | Bin 0 -> 1893 bytes .../external/hid_app/assets/S_LEFT.png | Bin 0 -> 1906 bytes .../external/hid_app/assets/S_RIGHT.png | Bin 0 -> 1902 bytes applications/external/hid_app/assets/S_UP.png | Bin 0 -> 1886 bytes .../external/hid_app/assets/Voldwn_6x6.png | Bin 3593 -> 4556 bytes .../external/hid_app/assets/Volup_8x6.png | Bin 3595 -> 4564 bytes .../external/hid_app/views/hid_media.c | 51 +++++++++++------- .../external/hid_app/views/hid_mouse.c | 26 ++++----- .../external/hid_app/views/hid_tiktok.c | 42 ++++++++------- .../external/hid_app/views/hid_ytshorts.c | 33 +++++++----- 14 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 applications/external/hid_app/assets/OutCircles.png create mode 100644 applications/external/hid_app/assets/Pin_back_arrow_10x10.png create mode 100644 applications/external/hid_app/assets/Pressed_Button_19x19.png create mode 100644 applications/external/hid_app/assets/S_DOWN.png create mode 100644 applications/external/hid_app/assets/S_LEFT.png create mode 100644 applications/external/hid_app/assets/S_RIGHT.png create mode 100644 applications/external/hid_app/assets/S_UP.png diff --git a/applications/external/hid_app/assets/OutCircles.png b/applications/external/hid_app/assets/OutCircles.png new file mode 100644 index 0000000000000000000000000000000000000000..f34d2687a6b1c03b312899572ce3dc6c2fb7af13 GIT binary patch literal 2469 zcmcIm32+lt7*6Xzu>~1H$_+b8NG&vlD9qT+?j~JHvLU;rX|*a) zs8AWFWu$-{au?(nK~W9`idGl|vC5${fH*Bh1Um@jC`WypCIu9bVaCjC_U-0--~YY; z|Ni$fJ3DJ+m-s&M8jYrlEz>d%+(&?m>=X;WSFikiIk-I?$b3cCXcD@sSBz%S;$9j} z94tDViqk%Z;Uu4yFbEgq-OM=4h)6K- zWP+4~o+?jba2!5C}jZa*i-+|E7;{iy z6)EVDByY4*+0lp)L1}R)d4lNYr9wGHRTP;ZSXf0c!Juj+f>8*eb6_|q8AH;k7|CE* z8`KVrz_SYb53tdJVQPs<-F;w*7u`jV1GU>3n_pH~KPT8MCK!m)iXzYOdW>dy%7xGb z>qc}2%7D0Vy&Dl&(q$kyo~ML1U0}XN;tJGEsPo%=%S#;KXwN1?=}3-rQ5-_hm>bbk zlpdj7f&rl@N=K8Fo7ItIc$I+d<)8>!hxOjes;c4vBgPqd4%3qeM;ToR##1z6Bv=kH zP;MjPa=Qo&*TK-;xMs;K1?>_KvJ3cmj&Vyt9}D~=`dE*E2K*k?&43-m%@k!&x}r#b zU9&$sYMoeIPzM2K=vL_XB%x{z5qxcQT#TTEV-3JHYj9xK&JoG zT%{}<_zv~u~Z-y?vX z6NR6AF^}is2iD==ef1=Dc<^FSb-!$L82V51-8FBt0Wv^qs@9YvH66}++N+x$?F_>R z%t%?xdYzffz;UZN!%C3DjTns^F{1&)N2G;gdPOiZJZd9B9~~`>yl0<}P6mgEI&43- zz(f1NC-_0lg5X%|-nVX+MiZN2vt&5(ryYHD@0NW~r=P~$X{{v9UJ zdf=towjG;u{Pm3o>7m!thi*)$?)>%1^j6&0!?R;?-?M*ATQTqFhTa`*eRl1AN>_F+ zhE1?-=v8JWvz89&vZ!0x1#O1|302ABk?#AKl-+v&06cZgsxSN1^eF#+&sfv;qQzz< znHt+~PII6`-P}qhXEHM1wzgA!O9eIXo#%5e*vfy~kz^Y@bkYaY2i7E=?e^JAxub8D zY%;Tz&XXNac|V*~J}I6jrZokYjNY=aS4wRoeQa>ogEO5MQ!h1V`p$gZ^~CKh>xtd5 ziNPUPW;o#UDI+&rABkip5^*tj!_hPEZV+wzbH&&U^pa=Hl>QTh^w6I>500v@z0_Ej zI;*;6!K&EmmZhtpthvp(HtYCi)@IEX=GT8wku$J(>#)K7L$}4$8z1$&IpgwL z^Lv}U*LpiIp%u#uD^84ESJqHrxtUw}4oI0O_OR;l3sWd-MV>MdBcL;m5JV#(iu|X&A6Jzl|RhB?A;}_+@tDm{t;n}&l*S8-} z{k)|9o7MrN&Yga44D{82+r#TRUranZF@JsMrmlJ7$o_ra>QpxYS-Y@$_3~vU-yU!( zNrz&$TG6XzdBw%I$a52GoBp~p@k)6u(;8R&$%fv@*_6ZTA1RwP%d%;B-t@l#cgkqJ literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/assets/Pause_icon_9x9.png b/applications/external/hid_app/assets/Pause_icon_9x9.png index d72d712bbaa47429793bddbab0096de8d95045b4..fe16dc03e2629da128e37a7b9e1ccb11b4c92b78 100644 GIT binary patch delta 682 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 diff --git a/applications/external/hid_app/assets/Pin_back_arrow_10x10.png b/applications/external/hid_app/assets/Pin_back_arrow_10x10.png new file mode 100644 index 0000000000000000000000000000000000000000..e7510fd5dc0084fe0f9b6fdeabf969ed3cfd6466 GIT binary patch literal 4575 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 literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/assets/S_LEFT.png b/applications/external/hid_app/assets/S_LEFT.png new file mode 100644 index 0000000000000000000000000000000000000000..13c9f51b4ee428f92a995efb2bb961c76f7dc247 GIT binary patch literal 1906 zcmcIlONbmr819IM7&n_k4$)j}ItL9}(^cI){bDD(voo{qKxSPwgINzks;jDJ+MVg@ zbocDcE(ks_5Qv}=1w|C`D7g3lbt6Pn#GHIU4iUUY52APw)Pq_*uU%!c?!|$getq@* zUw!}ARTmZ)9yoOH*g;8>4pryNOX7T39CshMMf|_-N$17s_Gtd$M3U|}k{$b`mtVP4 zlJ>tI)R)uc+9{Xtb`DeSv0Sem3A7|lP4^;9R#+-~tPz9-<>$*+6gi*;(Meia6;+0McO*{gYY|hISi(CoVU<-DrpHIc zq9#vy(&RVMHh%pNg_Mj7MxD6Tw}%pywOCtlCjyK5`XaX!Go13c&UtIpsl`!6Su=7- zzV}QJQr=BYWQv9ZSQ)3Rpop&N02)BE>kzt{;~M6DPz>ibKMx<$@wa<${2^3|q*|TNn^eqX7B_0uE+6z{I1FBGWP%>gy8Y%bavFC$jN_ z+)_>i$Jk95X^c=4+JJeM2Otq_n0g*Sp3XF%>b{S?5!-`tAU+-3+RmD(qJmMtnMsiW zu#GHXl;Hq}Il?upQOkxpAyn{e)h+QBk87L?cXdUk#PxaH#v(sK8#kC5g^euDf?dpF zK1f9C)`s85X?AXS)e7W(=v+*)tQQoLHJMRm_&C_Xy}jui&~}?lknYm_0W9Hu+Ql&| zHiXmv87}o^;uE~OyY#&^{(qD{w3Re**kEGiRF!NpYPQ4-nxg)@Ut9eiWu_?7oOLr9 z+Axb7V?$2v98n{$6Wuci&>ZLk(=bfnc+3KZVdNd%@Nr((2P#^@7S|}4)*Q5ra>>k> z^ddr)Qn8}xvo>^)4Q&gexoso+GZ_d{cURs=Zd+zYHi)%5yBzNt;%2<>uuxbQi(Td7 zPjpJ`NZo3=Sht_Kwp5(_Se|(F_rG4djxV4W9=iP5ryo?GID4)7?X6ww-I>XmcQzVt zyjuC@aqlB-v+B=0Vq7$@fBh_2x$WxtKi<1~wDacE&z(AY&r=(}{`vOizDvz3Uw!!7 zjg3$6OP^2Qb?(6TvzuQ|p7>(_rK0)bcj@y#9y|Qlk;=p`Hzt0_cExICq5RhD*(d)7 DzvyO% literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/assets/S_RIGHT.png b/applications/external/hid_app/assets/S_RIGHT.png new file mode 100644 index 0000000000000000000000000000000000000000..e0ba2afd1aefe680ef730165fab4c73892d67709 GIT binary patch literal 1902 zcmcIlONbmr7;Z(DWOWf=APd1x=i(zZUHzEut|pT>J2UGJY_FTmglzN>tE;PLnw{=y zyL)$LS49Xx2@>%j9()`k7{r6%B>|PqMK5{~!3TIXiiqe%4CWwK&-Bc$vRU`yKtJcJ z@BixizpgsJxbWE2nFOH2JQ=4e4Ua;zU?vO+V_rR^Z9NWXn_RT2ZQBAqHb(1~lb z6U=QS^u)$Oi)^eATnKW zJf@A(!YA&S+{dx3lwdxm5zujVhlb%8oo0nl@C|6Vrpmm(lip0C70jLAjYC&i#x~*D|K+T452z7W6Je=XZfteTh>wAGZ zj@^vX3`c}E>lKNMDg}XOYo6gNu8Dw7u>}y-Ens<&0*n;uB7QbaI?%<(*BM#Ooyf-z zbL%m}ImT|Q@Q zO`utZ2~0yb05UKFL?dpQdJqv;k;JXKHP&T`!#wV;CW#)geU^ln=O+kpo62$2&eP1< z`7Gvwl(%lZ_&!e1r;EF8APz!jW0GgRB9Xkw)RT(W!4B^2P3Mrd*P)zrm*x*)Df6=) zPH45wo&L{o$u|?9;GhgX zu4z?8Y1FC>RhzLOQY>hhP?_B}axjyjAbEG?1LU@4c4PxzyYt)euE8J1`woq`WeML^ zl9S)|`Hqw}>(!QZ;fGhNlaC(US6}`0`Sz3d9=vqv*(aXsAvST>`Np}AU0+fkzWevX zFMjjx2d8h$e|_Lu$7-I9_J8`-$uB3azVgx^*ALwH-JchJdF>*)F8}n`=9z1ooA3Sn z*8Iec=!rusBo2rlA)$&3ESyk<+5_T%Km~3H4&2I#BEbc?mT}@_7qngWLL|q3Z{GLj zea|zmwHBT~bny5=Nszj6H1pW^gDJbyNoqz50#kA2eH?;ew+ z``!=Q%h|H`f=hU)V#+&A9fq+$OVY`iVT{QN%j6F022n-%{l@2t9MFogWO>kwYpfT{ zZzSx@#zLEHtPqDPGpFQ}Lst-lEW`3J>_@3PtSBR1S6t_hHANmlvXzQb%?rxQUQ4d= zgvpKy0f7+8Wk=P^Ix))rv$6pVLxZ-amw;}&&~T9{7e7UmOQ`QI*5`_1;;y3fvMhEr zZ7>+915@QmSJNHG(V(Fj1`r64u16Ujf+#&PVW_i|Bte`7Jd$%p+~KQPMG;cRa|q)p zZIl*13CFY{jx}9{`J5&|&)XduhEsH!HP%FxLhp{mX?s0p+9FH&YC>3JjYZjsNwK)c zGoJSNU9?SK|3e`q(}MA8(jVDFiN^XY6x^x6>LY!zTT2+uc+%#)Kj~C!Qc*ULs>@F< z1rg7?F@V)^#wv>Fnh78RhTVqHg(VlEXQ1gqIEH#62oz^{Z(vRXe|;}d&vTnm zn&F7BX1$^aQECuSmonSYZ3+P``wSQaQGj*IfNwe2LIe^UnIm0de4Ufk+=+brIJcA& z!7+8yrM_GA_CxQ5MaDO{%u8IoA4zUc!)G>f2 zB7l_;1|8kPfUpjR4)J{hV@2MoTjPD6c$^A%g<48npC=&}`3XYYWm+6{^E3-~F^l;i z6|Gw@zK=8PmEx)&$fMA?nB-ZnC?sz(qe}5O*ulNM=^WDzdQ6b+()=+j<$gB639EL6 z)BhPR?QY^zytcday*2)SlwR0MdN}Gbv2tokJ{c`vV#ZC;{@t&weorz}6=}}9nHDz8 z;_lRtQ#(f#Stc<%B2|V1eNaNE1e^{l1B8&}n8?SLX^vI&gDtK}Fw1k$M)g|Bs+mIx&3d(MU;gs@FOEt_4&2-N>CT<>@ZpDEx@=s3>-NW&_Pq!`m0nlRe|7D<#)WS; z&wuvB)nBWFcOL&GyZ+ZlS2RQU=ITZN=J4weZoGF4x*hA*ADj2z^TW9xXVMvR?izUR dLThDn|C>wR&!;bbcqQKfn~jC~C$lfV`Zrq^TDbrK literal 0 HcmV?d00001 diff --git a/applications/external/hid_app/assets/Voldwn_6x6.png b/applications/external/hid_app/assets/Voldwn_6x6.png index d7a82a2df8262667a9a03419f437ff9b350e645f..ce487b546812e471bfaf380f3849f954e6c757ac 100644 GIT binary patch delta 1123 zcmbtTO=uHA6rSKu+hki0wNyl8*;c9OW@mr0e>T!I2~D7>u|`F_bhERYEF{@=ciUPI zZ51ztg2;NX(z^#iD0-5DMNeYEgI+v|C&g1iyoeAdrm40HDjwdx+4sJA?|bvjEF4-5t8TqR10U(^UlF7U`J~B*Z z(@Bw4M3LsAEC88>6#&ZB%Jqp154FJC2(EJAgCLsVHCje0I0MP3! zKRz>v6MOTcg>=1M$IEk1U(I6I;bbm)07SYQ76Nyd4`9^&U@5#fphO|9LkLMpiLw%_ zbCP+2W@Qy}s=z-Sjf6rSm71q|etOCe)*^=kiRc48k0P&B8#$!M zsj}}oD#JLFZY65FB?jq?Q8B6*<}qxPWm;ILZ2PuXwu2{;-mcbF z`c0PSB_x})E@=v_7=lJCMHHhAN#+$))FoM$f=5JrUxP(1r=E7Ll2y|x!733uPa<74 zZMUlVamuP{C4+HlC5qe{RZZFz+r`uy^Zgvp;v3=Grd7d-Uv5UQLEMTryJalTx80dj zJTSwdM=Gmq{t+_^`gtd-S31k-yGQX*^LvlitB?m58 zHDphFCy%v?>t(H0GEkgiDCQsd|BW)O7Qf~HALKFjXmjKpba2S0?xN^Q_{8+SWro;(PWD#)E8nEcIY` G;`%p^?M_($ delta 269 zcmX@3+$m$x8Q|y6%O%Cdz`(%k>ERLtq}f22gBeI(7m}}HVBm7jbaoE#baqxKD9TUE z%t>WnsJOM!&xA|2!BSNas7$iNHKHUqKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MNkD z0|T?-ZW>Ty2*wnMhfPZdWL2OmPRHz3PuKo=K2Qa`i92328LD!W>&_QnJ0dj1BPl)UP|Nnu^ z&_kE&fRwDKi(^Q|t)v7XNMT@fb2DIEB9SN(BCv=>;Q#|;4TIpasE#Q>g$$mqelF{r G5}E+EnMbPt diff --git a/applications/external/hid_app/assets/Volup_8x6.png b/applications/external/hid_app/assets/Volup_8x6.png index 4b7ec66d65178e808c672576150f5773b04c31a4..ee9045f7fde3e4c5e7104bdee4919d7694e34d7c 100644 GIT binary patch delta 1123 zcmb7D&ubGw6rNz!Hc4BdLZuX0HXtp!*_qAe*Vw2@8k#^;W37sK>2zn3EF{@=ciUPI z{UKh8g2*1U(!W7077rpQ;;jb{ir`5P9z+lXZz9BrX{xP)_3(DyzWLsJ-^};sM*r); z*m7ZPq|@8y1psvBvcuzi?clb*eGmVB&fIAP+DgfM5`eW^zVBo&0N$LQP8aO)k(7|j zq$4OEiAYKi0gzo@i>cmA(n#zj&l0rkcpiYOM*vv74!}1aTKovWGz8$&Bmnp>0KMkw z<1<5iV_#u(B2%x|xqI&Ut9ib3nAwXq0KT4vdBDBZLmaj4u6S<_#Dh@MAcR6R9z;>3 zDbeCFL4k@Q!C|ih{#&tiq!(gduEHGjZOadU0+CG(6E@9>Gdv8Vy$a!cC(G5GfOO%EODt5Vv-tDOek!MYzm4RM8d!Yy+(~$ z`}kn1xK<{$5~B%G7Uf;@Ke(_9VOkyjO8@t%_<#C?eC(Q8JLt>5l#sWHu+-#FF@hLfwFgM=*^?A?|g0Tpl_ffrE)mPWyXf@ IrzWrc08aHw1^@s6 delta 274 zcmcbj+%03#8Q|y6%O%Cdz`(%k>ERLtq&a|?je{9Tp1iGpl7WHCIn&uWz|+}Tp`a)~ zEi)&TfuZ8oMn4lS-3CilL7+0p64!{5;QX|b^2DN42FH~Aq*MjZ+{ElzqZ8JJlaTW+4n z&B!>}h}U59Q(g&n7bi0d0|V#D`utLp@-$N^k%G diff --git a/applications/external/hid_app/views/hid_media.c b/applications/external/hid_app/views/hid_media.c index 468529d56a..0028ac596d 100644 --- a/applications/external/hid_app/views/hid_media.c +++ b/applications/external/hid_app/views/hid_media.c @@ -21,6 +21,7 @@ typedef struct { bool down_pressed; bool ok_pressed; bool connected; + bool back_pressed; HidTransport transport; } HidMediaModel; @@ -55,61 +56,72 @@ static void hid_media_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6); + canvas_draw_icon(canvas, 79, 9, &I_Volup_8x6); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6); + canvas_draw_icon(canvas, 80, 41, &I_Voldwn_6x6); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); - hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 65, 28, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 70, 28, CanvasDirectionRightToLeft); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); - hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 96, 28, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 101, 28, CanvasDirectionLeftToRight); canvas_set_color(canvas, ColorBlack); // Ok if(model->ok_pressed) { - canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); - canvas_draw_line(canvas, 100, 29, 100, 33); - canvas_draw_line(canvas, 102, 29, 102, 33); + hid_media_draw_arrow(canvas, 80, 28, CanvasDirectionLeftToRight); + canvas_draw_line(canvas, 84, 26, 84, 30); + canvas_draw_line(canvas, 86, 26, 86, 30); canvas_set_color(canvas, ColorBlack); // Exit + if(model->back_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 111, 38, &I_Pin_back_arrow_10x10); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); canvas_set_font(canvas, FontSecondary); elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); @@ -135,6 +147,8 @@ static void hid_media_process_press(HidMedia* hid_media, InputEvent* event) { } else if(event->key == InputKeyOk) { model->ok_pressed = true; hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; } }, true); @@ -160,6 +174,8 @@ static void hid_media_process_release(HidMedia* hid_media, InputEvent* event) { } else if(event->key == InputKeyOk) { model->ok_pressed = false; hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; } }, true); @@ -176,12 +192,7 @@ static bool hid_media_input_callback(InputEvent* event, void* context) { } else if(event->type == InputTypeRelease) { hid_media_process_release(hid_media, event); consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_media->hid); - } } - return consumed; } diff --git a/applications/external/hid_app/views/hid_mouse.c b/applications/external/hid_app/views/hid_mouse.c index ca299c4632..75df53dd1f 100644 --- a/applications/external/hid_app/views/hid_mouse.c +++ b/applications/external/hid_app/views/hid_mouse.c @@ -49,66 +49,66 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) { } // Keypad circles - canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); + canvas_draw_icon(canvas, 80, 8, &I_Pin_arrow_up_7x9); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); + canvas_draw_icon(canvas, 80, 40, &I_Pin_arrow_down_7x9); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); + canvas_draw_icon(canvas, 63, 25, &I_Pin_arrow_left_9x7); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); + canvas_draw_icon(canvas, 95, 25, &I_Pin_arrow_right_9x7); canvas_set_color(canvas, ColorBlack); // Ok if(model->left_mouse_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); + canvas_draw_icon(canvas, 79, 24, &I_Left_mouse_icon_9x9); canvas_set_color(canvas, ColorBlack); // Back if(model->right_mouse_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 108, 48, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); + canvas_draw_icon(canvas, 112, 38, &I_Right_mouse_icon_9x9); canvas_set_color(canvas, ColorBlack); } diff --git a/applications/external/hid_app/views/hid_tiktok.c b/applications/external/hid_app/views/hid_tiktok.c index 9b15d812b0..bfa0dbc899 100644 --- a/applications/external/hid_app/views/hid_tiktok.c +++ b/applications/external/hid_app/views/hid_tiktok.c @@ -41,64 +41,68 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); // Keypad circles - canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles); // Pause if(model->back_mouse_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9); + canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9); canvas_set_color(canvas, ColorBlack); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9); + canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9); + canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6); + canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6); + canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6); canvas_set_color(canvas, ColorBlack); // Ok if(model->ok_pressed) { - canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17); - } else { - canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9); + canvas_set_color(canvas, ColorBlack); + // Exit canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); canvas_set_font(canvas, FontSecondary); @@ -187,17 +191,17 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) { consumed = true; } else if(event->key == InputKeyDown) { // Swipe to new video - hid_hal_mouse_scroll(hid_tiktok->hid, 19); + hid_hal_mouse_scroll(hid_tiktok->hid, -19); consumed = true; } else if(event->key == InputKeyUp) { // Swipe to previous video - hid_hal_mouse_scroll(hid_tiktok->hid, -19); + hid_hal_mouse_scroll(hid_tiktok->hid, 19); consumed = true; } else if(event->key == InputKeyBack) { // Pause - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT); - furi_delay_ms(25); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_RIGHT); + hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); consumed = true; } } else if(event->type == InputTypeLong) { diff --git a/applications/external/hid_app/views/hid_ytshorts.c b/applications/external/hid_app/views/hid_ytshorts.c index 44ad02ff05..9be2f853c1 100644 --- a/applications/external/hid_app/views/hid_ytshorts.c +++ b/applications/external/hid_app/views/hid_ytshorts.c @@ -41,70 +41,75 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); // Keypad circles - canvas_draw_icon(canvas, 66, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles); // Pause if(model->back_mouse_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 106, 46, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 108, 48, &I_Pause_icon_9x9); + canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9); canvas_set_color(canvas, ColorBlack); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 83, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 86, 11, &I_Arr_up_7x9); + canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 83, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 86, 44, &I_Arr_dwn_7x9); + canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 67, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 71, 29, &I_Voldwn_6x6); + canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 99, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 101, 29, &I_Volup_8x6); + canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6); canvas_set_color(canvas, ColorBlack); // Ok if(model->ok_pressed) { - canvas_draw_icon(canvas, 81, 23, &I_Like_pressed_17x17); - } else { - canvas_draw_icon(canvas, 84, 27, &I_Like_def_11x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9); + canvas_set_color(canvas, ColorBlack); + // Exit canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); canvas_set_font(canvas, FontSecondary); elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } + static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) { // Set cursor to the phone's left up corner // Delays to guarantee one packet per connection interval From 947dd1b75444696def1cd0f558d3dd05179e5301 Mon Sep 17 00:00:00 2001 From: ushastoe Date: Sat, 29 Apr 2023 18:20:54 +0300 Subject: [PATCH 08/23] Change UP&DOWN swipe --- applications/external/hid_app/views/hid_tiktok.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/external/hid_app/views/hid_tiktok.c b/applications/external/hid_app/views/hid_tiktok.c index bfa0dbc899..4dfbde4eb2 100644 --- a/applications/external/hid_app/views/hid_tiktok.c +++ b/applications/external/hid_app/views/hid_tiktok.c @@ -190,13 +190,13 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) { hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); consumed = true; } else if(event->key == InputKeyDown) { - // Swipe to new video - hid_hal_mouse_scroll(hid_tiktok->hid, -19); - consumed = true; - } else if(event->key == InputKeyUp) { // Swipe to previous video hid_hal_mouse_scroll(hid_tiktok->hid, 19); consumed = true; + } else if(event->key == InputKeyUp) { + // Swipe to new video + hid_hal_mouse_scroll(hid_tiktok->hid, -19); + consumed = true; } else if(event->key == InputKeyBack) { // Pause hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); From b86d155e8e67a866afe37eed44bfd4e1607e8011 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 29 Apr 2023 21:41:09 +0300 Subject: [PATCH 09/23] Remove ko-fi --- .github/FUNDING.yml | 1 - CHANGELOG.md | 1 - ReadMe.md | 1 - 3 files changed, 3 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 6a4a770bf9..9187b07480 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,4 +1,3 @@ -ko_fi: masterx custom: [ "https://boosty.to/mmxdev", diff --git a/CHANGELOG.md b/CHANGELOG.md index f613f6edab..8dfbf46cf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,6 @@ ## Please support development of the project * **Boosty** (patreon alternative): https://boosty.to/mmxdev -* Ko-Fi: https://ko-fi.com/masterx * cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65 * YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209 * USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs` diff --git a/ReadMe.md b/ReadMe.md index 1d42e52a3f..7ba70bc338 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -118,7 +118,6 @@ The amount of work done on this project is huge and we need your support, no mat Also, regarding our releases, every build has and always will be free and open-source. There will be no paywall releases or closed-source apps within the firmware. As long as I am working on this project it will never happen. You can support us by using links or addresses below: * **Boosty** (patreon alternative): https://boosty.to/mmxdev -* Ko-Fi: https://ko-fi.com/masterx * cloudtips (only RU payments accepted): https://pay.cloudtips.ru/p/7b3e9d65 * YooMoney (only RU payments accepted): https://yoomoney.ru/fundraise/XA49mgQLPA0.221209 * USDT(TRC20): `TSXcitMSnWXUFqiUfEXrTVpVewXy2cYhrs` From 512fe8aeada2d38194518e44765e1404d00b5f27 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 30 Apr 2023 14:59:38 +0300 Subject: [PATCH 10/23] Fix readme --- ReadMe.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReadMe.md b/ReadMe.md index 7ba70bc338..1611bed679 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -161,6 +161,7 @@ You can support us by using links or addresses below: - **UART Terminal** [(by cool4uma)](https://github.com/cool4uma/UART_Terminal/tree/main) - **ProtoView** [(by antirez)](https://github.com/antirez/protoview) - **SWD Probe** [(by g3gg0)](https://github.com/g3gg0/flipper-swd_probe) +- IR Scope [(by kallanreed)](https://github.com/DarkFlippers/unleashed-firmware/pull/407) Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/) From a9e47454d5bdf3d08bf77561691e239dacd89660 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 16:17:47 +0300 Subject: [PATCH 11/23] Fix SWD Probe plugin GPIO pins state Reset pins after exit --- applications/external/swd_probe/swd_probe_app.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/applications/external/swd_probe/swd_probe_app.c b/applications/external/swd_probe/swd_probe_app.c index 02cbf8a87e..e8846b9e2d 100644 --- a/applications/external/swd_probe/swd_probe_app.c +++ b/applications/external/swd_probe/swd_probe_app.c @@ -3166,6 +3166,11 @@ int32_t swd_probe_app_main(void* p) { furi_message_queue_free(app->event_queue); furi_mutex_free(app->gui_mutex); furi_mutex_free(app->swd_mutex); + + // Reset GPIO pins to default state + for(int io = 0; io < 8; io++) { + furi_hal_gpio_init(gpios[io], GpioModeAnalog, GpioPullNo, GpioSpeedLow); + } free(app); furi_record_close(RECORD_GUI); From 3b40696c9efa713c5460800b8d1403502a4a25e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:37:25 +0300 Subject: [PATCH 12/23] Add files via upload --- .../external/flipperzero-bomberduck/LICENSE | 22 + .../external/flipperzero-bomberduck/README.md | 2 + .../flipperzero-bomberduck/application.fam | 15 + .../flipperzero-bomberduck/assets/bomb0.png | Bin 0 -> 4536 bytes .../flipperzero-bomberduck/assets/bomb1.png | Bin 0 -> 4529 bytes .../flipperzero-bomberduck/assets/bomb2.png | Bin 0 -> 4531 bytes .../flipperzero-bomberduck/assets/box.png | Bin 0 -> 4329 bytes .../flipperzero-bomberduck/assets/end.png | Bin 0 -> 4739 bytes .../flipperzero-bomberduck/assets/enemy1.png | Bin 0 -> 4757 bytes .../assets/enemyleft.png | Bin 0 -> 4761 bytes .../assets/enemyright.png | Bin 0 -> 4536 bytes .../flipperzero-bomberduck/assets/explore.png | Bin 0 -> 4540 bytes .../assets/playerleft.png | Bin 0 -> 4311 bytes .../assets/playerright.png | Bin 0 -> 4307 bytes .../assets/unbreakbox.png | Bin 0 -> 4763 bytes .../external/flipperzero-bomberduck/bomb.png | Bin 0 -> 4534 bytes .../flipperzero-bomberduck/bomberduck.c | 645 ++++++++++++++++++ 17 files changed, 684 insertions(+) create mode 100644 applications/external/flipperzero-bomberduck/LICENSE create mode 100644 applications/external/flipperzero-bomberduck/README.md create mode 100644 applications/external/flipperzero-bomberduck/application.fam create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb0.png create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb1.png create mode 100644 applications/external/flipperzero-bomberduck/assets/bomb2.png create mode 100644 applications/external/flipperzero-bomberduck/assets/box.png create mode 100644 applications/external/flipperzero-bomberduck/assets/end.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemy1.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemyleft.png create mode 100644 applications/external/flipperzero-bomberduck/assets/enemyright.png create mode 100644 applications/external/flipperzero-bomberduck/assets/explore.png create mode 100644 applications/external/flipperzero-bomberduck/assets/playerleft.png create mode 100644 applications/external/flipperzero-bomberduck/assets/playerright.png create mode 100644 applications/external/flipperzero-bomberduck/assets/unbreakbox.png create mode 100644 applications/external/flipperzero-bomberduck/bomb.png create mode 100644 applications/external/flipperzero-bomberduck/bomberduck.c diff --git a/applications/external/flipperzero-bomberduck/LICENSE b/applications/external/flipperzero-bomberduck/LICENSE new file mode 100644 index 0000000000..bce361a99c --- /dev/null +++ b/applications/external/flipperzero-bomberduck/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/applications/external/flipperzero-bomberduck/README.md b/applications/external/flipperzero-bomberduck/README.md new file mode 100644 index 0000000000..2d133145aa --- /dev/null +++ b/applications/external/flipperzero-bomberduck/README.md @@ -0,0 +1,2 @@ +# flipperzero-bomberduck +Bomberman clone on flipper zero! diff --git a/applications/external/flipperzero-bomberduck/application.fam b/applications/external/flipperzero-bomberduck/application.fam new file mode 100644 index 0000000000..afcd5a6ee1 --- /dev/null +++ b/applications/external/flipperzero-bomberduck/application.fam @@ -0,0 +1,15 @@ +App( + appid="bomberduck", + name="Bomberduck", + apptype=FlipperAppType.EXTERNAL, + entry_point="bomberduck_app", + cdefines=["BOMBERDUCK"], + requires=[ + "gui", + ], + stack_size=1 * 1024, + order=90, + fap_icon="bomb.png", + fap_category="Games", + fap_icon_assets="assets", +) diff --git a/applications/external/flipperzero-bomberduck/assets/bomb0.png b/applications/external/flipperzero-bomberduck/assets/bomb0.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdc3a3c12c7ede770e1c99c2003c777b03f4d75 GIT binary patch literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/bomb1.png b/applications/external/flipperzero-bomberduck/assets/bomb1.png new file mode 100644 index 0000000000000000000000000000000000000000..11d05b9b7c445452253792c5a51ad6448cca8aee GIT binary patch literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/bomb2.png b/applications/external/flipperzero-bomberduck/assets/bomb2.png new file mode 100644 index 0000000000000000000000000000000000000000..38ce7c732bfa5e3586d1c9b9a754b85405cd4566 GIT binary patch literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 zmV1XgTMc#X89QHDSYsLZ;Eip?zDuDazMnbho_o`dKC?ON)Zz6(Vr-zHP8ftfT+~0UY?>&{B)Aq|tz7sb~K6-mW>0A5f zzg)ga`Wu$MC-c$Ot2Uf1ICkwN`u6i(&STi{h11<%>*4a^4JQb*;G_-DjB@{Y~GX07XI+&jiGnm9m+u7+OqYup4iZn!)Gr} zGxskghU;}tTzrz~e7%$8SFf3S;YQ`c6^~p$>iFZ$zcwEGR@cMxKi=Cx@Q0QTRt}!% zs&A`qw0G8@+Wcsd<2&8=>|JrTx#iX$&JMizdviNaTMN>^ao@bi3%?<9e)7PLRTb`D z<;^tGbn@^^_VT9e@^|*P;y>y+c(A2NUNm>@uEqDdvyKOoSNj(=J(T%sUj66qF29rX z8n$oC*ZXEKqyAa^#O(eXd+xSfkN)abN6T|d>XS3DGq;KPv*NXzy3VvVM9x*{hZ}2i ze)kWoul9p&-Q_4M&H5~yoYseW`;$%a@88LE*+9W3Jxe~R9=QF~D{JO`c3J=JlTop2 z_u+Lq;c9kua(cRc*rdHh`>3GJFH&Z8*_m&p|C~*+iQyaY)v^! zamMxQ42}d12_isYkVGULmFa}jsPWRUt(q|-qCu2$r!nC5Audq@h{a?v;b?wBs3MK) z42VPGc)G;BX_NxKIgMqC5~DFJ9*>*iW|Js|FoL2e3@0&?L?Hr|tD_2&K%??Xm12a$ z4P;glVu~O}5tWk(ij|7fXoUU9SbUL~*E>!hl}A;8dSD4Ah7l$li$t)=9jpYw2(-2Erf$p)wqmm@;I6$LkySP$dWn zk(lNM#h!vx1b#xSDY2m)?z1ZRthC? zibX99V?%>x!iMsUg=EZDU}q_662&%2fK|zaCr71Hagd4vI0%~U0HuPA1+@TcE=mCo z@>wV|p9}CH$1)lf$I_cbDZ;?%6e3IrV6kXO>re%!H~KtIBWc1XEWR+K@X*0&+$uyX z6B8YNAp*85jH)JKvy-_LZp$Tb_#nv%P$`gPScxhpft$=0tw)^}8YTmUWz;%_1ezV@ zLc1iuD5B&S#jw+;hJ>h|8PsDNdSc+(MI-pTub^K@)fm4lR@LA}8?G z{|l`y9>g&+<%NO_$FJ5*BP(hIk)h z<*8|fWN8z%W-2;f2Gm)Af}ywtoe+!|6$~3q7*qF*v5Xzqe`(^-0FyQu=r>}6n-|;* zvGL7tR5Nwk`3gUybMY090I6pNnU=mYa?Qv!Ed{0po~f=Gxu&JSw7@gf^?#GgFmas% zQFsc9!^_gAH7PcD(V89HQsCCET)Ka|&V3KI=Ee#imUTMQO7)kNXj)$djdK)_H-FBR zSs9DX^M)S0dBQaH zlF4IiN?T%=QXmAF5>khuB+w?ABtw&-4MQMFO-egsU})OldTbuSv=C^fWD2hPog}}e znaOw>`j<5$>AU@Qf4lqJ-TUsItzKR+EqhKjf*{lUmA)GIZ?3Z^XTsmi>R=!I`}_LZ zpi#re(U_*nN*JIo zICuO{Iol7PyT13C>066Ceo^!0<*Hm=S0)!v+kFJQ5&h9ypWQiex&dv@d#s{w#upO{ z$ck&^#y|e+(8{b&as#&(wPlo)-C*Y|?GNWoeeOf)d%cV4ntPTwZx-f**Dl_8tD*hC znMVR`7m9Q;IJ3C$!JcAi!tJ#=FWt6weJdcg&x&0Nz0$lrd~)gQ2c5yb_Jh;9o_MIJ z{ijcA1x($Qw)syLE@*z|!=GRM^_>3mr+&K+zxiTlzpL~2@rg68xxRrQ89z|G-fF+s zJD503chA#XJ(b577QFxX>7@@9PjAd!*-`z%-?}ID1P@hj%-;WS-PvOoI&<3n-fcZS z3*NrB;7;(D+}rM}eci>AH+&m?)xNydUehzMZE;(E&QEUNxYpHsZ7zD|qbkNiEgf-)oybv+aH7^MBd3W9p7X ztNW#w=Ukk!X6HBm@W`IC+79M=$K&}Y>pxny_5iyn>)zKl<@tX1vS0zhO`Qj~3f92w zbvXmgy(_jZyYJk@eD>1Hmh6rj-yb-3J$mZB3mboy*J_!IAMPhJv*ImFP8~kFC30k4 z<`*xv-2bbKubpYxy`r-o!?di=qn26cut1l^9&i5l{70$pR@^+Dmp!4o|HtnZP5S(N z=J`WW_0-dQN|D)p#Z8uig3Nv8Cm;JqA|85D9oVb<^OmKfUh8=71I<8?oKgjLVlYs} ziE6~oOR50uiAW5#D1wxfC1Si-4-8ZQAtmauUO#fwiYk)Fx|#_PftVN6DV6IruxkDC zT5)~7$V%3-((IB12LU3$;L$`R9M!pm$C||D;Mx@9Ry3(%)O)PKKsD-BHGtA~+D>5Q z38j&;mS&?Rnj~{Iz9nf0c;&Iy8Ago5@pwFLk2~zD7Q#uEWpRSSDGGxcnBEjM_yiW! zZ6-tt!v}OxQ(}gqMo|-!7t{vBW3|G4bTGb1ED#uikLqa_ARl;wkKv@9z#|cSq=jyj zH$sqfKwoO1*TR9uYk;mcXd)|+gDIGK(l;vftnP*sOs$x$vV{DJBr z3zLG75{V_PAlaid4MiR%YgBCJPBNX5fk5*i+)>(txhIvORv^InRI$Mf&+qeCP5+#v zii*S~m$V?bM4q8BmZT|+cDbAwOEYjKxFu0$c$Yx)BcS|I-Qc4lFrgs0U4b}m2kT-b zH;GXqAz?HnIx)B8ggCq?5rmTl0^=9~u|iW|SMuSJQJGMZ2}QC3OR)?lxG4goS%|_* zZXN@Gkttc^ouZtAl02yC1tpg9LoOVS)cag^(R0!l{ctCAu& zeU-L3JZMR(D7kdkpitkjlR$45f| z-aXRoIw)7Zq!mb6qGT8CzyyJSJtR9|{T#9bbCR-5QiMPO(lr`gS7js4YhY0b@(8(t z?V02XU63qP(P-^>9Wbi^3Bw2)qu5%CrXQvcK92KzoDH%M1;E9G09ck&dFb|Kr_(@OHUGxB< z$DNFc-*LLe=^7IQV^SXPu5r4?#K4%8$Ghumqbqy(r5Hrvvuqr`@*XYn9fhyU_rxmK z=m=uBncs}W{<20WoMiX|<&!RF&6|=r_pgU9RYB2gqdaJM)rk2fg(M&FfrQ2tqYgD6 z@K?7?p9PhQ{JurC`KQG@0|R9ii^XQMZOq7s*{8gbYniyPa^IC761(z0+t6O`Ms^D` W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/enemy1.png b/applications/external/flipperzero-bomberduck/assets/enemy1.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee7cb27f1ee52c63dbdb31e788c1011c8448d35 GIT binary patch literal 4757 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 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/enemyright.png b/applications/external/flipperzero-bomberduck/assets/enemyright.png new file mode 100644 index 0000000000000000000000000000000000000000..45e6a861ad9c914af25be2b6c1b6097fdc6f0d17 GIT binary patch literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/explore.png b/applications/external/flipperzero-bomberduck/assets/explore.png new file mode 100644 index 0000000000000000000000000000000000000000..5eb50b669b3ee364bd25a37991519cf833660ae5 GIT binary patch literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/playerleft.png b/applications/external/flipperzero-bomberduck/assets/playerleft.png new file mode 100644 index 0000000000000000000000000000000000000000..86997a985eab4de991e315858b17ed7e0a981f74 GIT binary patch literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/playerright.png b/applications/external/flipperzero-bomberduck/assets/playerright.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6283d9c26d9f9582fecd0cef9765ab2b288576 GIT binary patch literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/assets/unbreakbox.png b/applications/external/flipperzero-bomberduck/assets/unbreakbox.png new file mode 100644 index 0000000000000000000000000000000000000000..5e65912d53405d04bcd05916947a8de8fc5239c8 GIT binary patch literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/bomb.png b/applications/external/flipperzero-bomberduck/bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..44b9bfdeae76553be52ce1c451133a4baee7bf68 GIT binary patch literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 literal 0 HcmV?d00001 diff --git a/applications/external/flipperzero-bomberduck/bomberduck.c b/applications/external/flipperzero-bomberduck/bomberduck.c new file mode 100644 index 0000000000..7b8b5f14a0 --- /dev/null +++ b/applications/external/flipperzero-bomberduck/bomberduck.c @@ -0,0 +1,645 @@ +#include +#include + +#include +#include +#include +#include +#include +#include "bomberduck_icons.h" +#include + +int max(int a, int b) { + return (a > b) ? a : b; +} + +int min(int a, int b) { + return (a < b) ? a : b; +} + +#define WorldSizeX 12 +#define WorldSizeY 6 +#define BombRange 1 + + +typedef struct { + FuriMutex* mutex; +} BomberState; + +typedef struct { + int row; + int col; +} Cell; + +typedef struct { + Cell cells[WorldSizeY * WorldSizeX]; + int front; + int rear; +} Queue; + +void enqueue(Queue* q, Cell c) { + q->cells[q->rear] = c; + q->rear++; +} + +Cell dequeue(Queue* q) { + Cell c = q->cells[q->front]; + q->front++; + + return c; +} + +bool is_empty(Queue* q) { + return q->front == q->rear; +} + +typedef struct { + int x; + int y; + int planted; +} Bomb; + +typedef struct { + int x; + int y; + bool side; +} Player; + +typedef struct { + int x; + int y; + int last; + bool side; + int level; +} Enemy; + +typedef struct { + int matrix[WorldSizeY][WorldSizeX]; + Player* player; + bool running; + int level; + + Enemy enemies[10]; + int enemies_count; + + Bomb bombs[100]; + int bombs_count; + + int endx; + int endy; +} World; + +Player player = {0, 0, 1}; +World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; +bool vibration = false; + +void init() { + player.x = 1; + player.y = 1; + + world.endx = 4 + rand() % 8; + world.endy = rand() % 6; + for(int i = 0; i < WorldSizeY; i++) { + for(int j = 0; j < WorldSizeX; j++) { + world.matrix[i][j] = rand() % 3; + } + } + world.running = 1; + world.bombs_count =0; + vibration = false; + for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { + world.matrix[j][player.x] = 0; + } + + for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { + world.matrix[player.y][j] = 0; + } + + world.enemies_count = 0; + for(int j = 0; j < rand() % 4 + world.level / 5; j++) { + Enemy enemy; + enemy.x = 4 + rand() % 7; + enemy.y = rand() % 6; + enemy.last = 0; + enemy.side = 1; + enemy.level = 0; + + world.enemies[j] = enemy; + world.enemies_count++; + + for(int m = max(0, world.enemies[j].y - BombRange); + m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); + m++) { + world.matrix[m][world.enemies[j].x] = 0; + } + + for(int m = max(0, world.enemies[j].x - BombRange); + m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); + m++) { + world.matrix[world.enemies[j].y][m] = 0; + } + } + world.matrix[world.endy][world.endx] = 1; +} + +const NotificationSequence end = { + &message_vibro_on, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb2 = { + &message_vibro_on, + &message_delay_25, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb_explore = { + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence vibr1 = { + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + + NULL, +}; + + +void intToStr(int num, char* str) { + int i = 0, sign = 0; + + if(num < 0) { + num = -num; + sign = 1; + } + + do { + str[i++] = num % 10 + '0'; + num /= 10; + } while(num > 0); + + if(sign) { + str[i++] = '-'; + } + + str[i] = '\0'; + + // Reverse the string + int j, len = i; + char temp; + for(j = 0; j < len / 2; j++) { + temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} + +bool BFS() { + // Initialize visited array and queue + int visited[WorldSizeY][WorldSizeX] = {0}; + Queue q = {.front = 0, .rear = 0}; + // Mark the starting cell as visited and enqueue it + visited[world.player->y][world.player->x] = 1; + Cell startCell = {.row = world.player->y, .col = world.player->x}; + enqueue(&q, startCell); + // Traverse the field + while(!is_empty(&q)) { + // Dequeue a cell from the queue + Cell currentCell = dequeue(&q); + // Check if the current cell is the destination cell + if(currentCell.row == world.endy && currentCell.col == world.endx) { + return true; + } + // Check the neighboring cells + for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { + for(int colOffset = -1; colOffset <= 1; colOffset++) { + // Skip diagonals and the current cell + if(rowOffset == 0 && colOffset == 0) { + continue; + } + if(rowOffset != 0 && colOffset != 0) { + continue; + } + // Calculate the row and column of the neighboring cell + int neighborRow = currentCell.row + rowOffset; + int neighborCol = currentCell.col + colOffset; + // Skip out-of-bounds cells and already visited cells + if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || + neighborCol >= WorldSizeX) { + continue; + } + if(visited[neighborRow][neighborCol]) { + continue; + } + // Mark the neighboring cell as visited and enqueue it + if(world.matrix[neighborRow][neighborCol] != 2) { + visited[neighborRow][neighborCol] = 1; + Cell neighborCell = {.row = neighborRow, .col = neighborCol}; + enqueue(&q, neighborCell); + } + } + } + } + return false; +} + +static void draw_callback(Canvas* canvas, void* ctx) { + furi_assert(ctx); + const BomberState* bomber_state = ctx; + + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + if(!BFS()) { + init(); + } + canvas_clear(canvas); + + canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); + + if(world.running) { + for(size_t i = 0; i < WorldSizeY; i++) { + for(size_t j = 0; j < WorldSizeX; j++) { + switch(world.matrix[i][j]) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); + break; + case 2: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); + break; + case 3: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); + break; + case 4: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); + break; + case 5: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); + break; + case 6: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); + world.matrix[i][j] = 0; + break; + } + } + } + + if(world.player->side) { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); + } else { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); + } + + for(int i = 0; i < world.enemies_count; i++) { + if(world.enemies[i].level > 0) { + canvas_draw_icon( + canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); + } else { + if(world.enemies[i].side) { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyright); + } else { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyleft); + } + } + } + } else { + canvas_set_font(canvas, FontPrimary); + if(world.player->x == world.endx && world.player->y == world.endy) { + if(world.level == 20) { + canvas_draw_str(canvas, 30, 35, "You win!"); + }else{ + canvas_draw_str(canvas, 30, 35, "Next level!"); + char str[20]; + intToStr(world.level, str); + canvas_draw_str(canvas, 90, 35, str); + } + + } else { + canvas_draw_str(canvas, 30, 35, "You died :("); + } + } + + furi_mutex_release(bomber_state->mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + // Проверяем, что контекст не нулевой + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + + furi_message_queue_put(event_queue, input_event, FuriWaitForever); +} + +int32_t bomberduck_app(void* p) { + UNUSED(p); + + // Текущее событие типа InputEvent + InputEvent event; + // Очередь событий на 8 элементов размера InputEvent + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + BomberState* bomber_state = malloc(sizeof(BomberState)); + + bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex + if(!bomber_state->mutex) { + FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + free(bomber_state); + return 255; + } + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + // Создаем новый view port + ViewPort* view_port = view_port_alloc(); + // Создаем callback отрисовки, без контекста + view_port_draw_callback_set(view_port, draw_callback, bomber_state); + // Создаем callback нажатий на клавиши, в качестве контекста передаем + // нашу очередь сообщений, чтоб запихивать в неё эти события + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Создаем GUI приложения + Gui* gui = furi_record_open(RECORD_GUI); + // Подключаем view port к GUI в полноэкранном режиме + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message_block(notification, &sequence_display_backlight_enforce_on); + + init(); + + // Бесконечный цикл обработки очереди событий + while(1) { + if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения + + if(event.type == InputTypePress) { + if(event.key == InputKeyOk) { + if(world.running) { + if(world.matrix[world.player->y][world.player->x] == 0 && + world.bombs_count < 2) { + notification_message(notification, &bomb2); + world.matrix[world.player->y][world.player->x] = 3; + Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; + world.bombs[world.bombs_count] = bomb; + world.bombs_count++; + } + } else { + init(); + } + } + if(world.running) { + if(event.key == InputKeyUp) { + if(world.player->y > 0 && + world.matrix[world.player->y - 1][world.player->x] == 0) + world.player->y--; + } + if(event.key == InputKeyDown) { + if(world.player->y < WorldSizeY - 1 && + world.matrix[world.player->y + 1][world.player->x] == 0) + world.player->y++; + } + if(event.key == InputKeyLeft) { + world.player->side = 0; + if(world.player->x > 0 && + world.matrix[world.player->y][world.player->x - 1] == 0) + world.player->x--; + } + if(event.key == InputKeyRight) { + world.player->side = 1; + if(world.player->x < WorldSizeX - 1 && + world.matrix[world.player->y][world.player->x + 1] == 0) + world.player->x++; + } + } + } else if(event.type == InputTypeLong) { + if(event.key == InputKeyBack) { + break; + } + } + } + if(world.running) { + if(world.player->x == world.endx && world.player->y == world.endy) { + notification_message(notification, &end); + world.running = 0; + world.level += 1; + if(world.level%5==0){ + DOLPHIN_DEED(DolphinDeedPluginGameWin); + } + } + for(int i = 0; i < world.bombs_count; i++) { + if(furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150), 1000)) { + vibration = false; + world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; + notification_message(notification, &bomb_explore); + + for(int j = max(0, world.bombs[i].y - BombRange); + j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); + j++) { + if(world.matrix[j][world.bombs[i].x] != 2) { + world.matrix[j][world.bombs[i].x] = 6; + if(j == world.player->y && world.bombs[i].x == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(j == world.enemies[e].y && + world.bombs[i].x == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = max(0, world.bombs[i].x - BombRange); + j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); + j++) { + if(world.matrix[world.bombs[i].y][j] != 2) { + world.matrix[world.bombs[i].y][j] = 6; + if(world.bombs[i].y == world.player->y && j == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.bombs[i].y == world.enemies[e].y && + j == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = i; j < world.bombs_count - 1; j++) { + world.bombs[j] = world.bombs[j + 1]; + } + world.bombs_count--; + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration=true; + + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; + + } + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.player->y == world.enemies[e].y && + world.player->x == world.enemies[e].x) { + notification_message(notification, &end); + world.running = 0; + } + } + + for(int e = 0; e < world.enemies_count; e++) { + if(world.enemies[e].level > 0) { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((2000 - world.level * 100), 1000)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) + world.enemies[e].x++; + default: + break; + } + } + } else { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((1000 - world.level * 50), 500)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) + world.enemies[e].x++; + default: + break; + } + } + } + } + for(int e = 0; e < world.enemies_count; e++) { + for(int h = e + 1; h < world.enemies_count; h++) { + if(world.enemies[e].y == world.enemies[h].y && + world.enemies[e].x == world.enemies[h].x) { + world.enemies[h].level++; + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + if(vibration){ + notification_message(notification, &vibr1); + } + } + + view_port_update(view_port); + furi_mutex_release(bomber_state->mutex); + } + + // Return to normal backlight settings + notification_message_block(notification, &sequence_display_backlight_enforce_auto); + furi_record_close(RECORD_NOTIFICATION); + // Специальная очистка памяти, занимаемой очередью + furi_message_queue_free(event_queue); + + // Чистим созданные объекты, связанные с интерфейсом + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + + furi_mutex_free(bomber_state->mutex); + furi_record_close(RECORD_GUI); + free(bomber_state); + + return 0; +} From b65f6665785feb802852560894b28bf20f68ae93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:38:57 +0300 Subject: [PATCH 13/23] Delete applications/external/flipperzero-bomberduck directory --- .../external/flipperzero-bomberduck/LICENSE | 22 - .../external/flipperzero-bomberduck/README.md | 2 - .../flipperzero-bomberduck/application.fam | 15 - .../flipperzero-bomberduck/assets/bomb0.png | Bin 4536 -> 0 bytes .../flipperzero-bomberduck/assets/bomb1.png | Bin 4529 -> 0 bytes .../flipperzero-bomberduck/assets/bomb2.png | Bin 4531 -> 0 bytes .../flipperzero-bomberduck/assets/box.png | Bin 4329 -> 0 bytes .../flipperzero-bomberduck/assets/end.png | Bin 4739 -> 0 bytes .../flipperzero-bomberduck/assets/enemy1.png | Bin 4757 -> 0 bytes .../assets/enemyleft.png | Bin 4761 -> 0 bytes .../assets/enemyright.png | Bin 4536 -> 0 bytes .../flipperzero-bomberduck/assets/explore.png | Bin 4540 -> 0 bytes .../assets/playerleft.png | Bin 4311 -> 0 bytes .../assets/playerright.png | Bin 4307 -> 0 bytes .../assets/unbreakbox.png | Bin 4763 -> 0 bytes .../external/flipperzero-bomberduck/bomb.png | Bin 4534 -> 0 bytes .../flipperzero-bomberduck/bomberduck.c | 645 ------------------ 17 files changed, 684 deletions(-) delete mode 100644 applications/external/flipperzero-bomberduck/LICENSE delete mode 100644 applications/external/flipperzero-bomberduck/README.md delete mode 100644 applications/external/flipperzero-bomberduck/application.fam delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb0.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb1.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/bomb2.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/box.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/end.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemy1.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemyleft.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/enemyright.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/explore.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/playerleft.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/playerright.png delete mode 100644 applications/external/flipperzero-bomberduck/assets/unbreakbox.png delete mode 100644 applications/external/flipperzero-bomberduck/bomb.png delete mode 100644 applications/external/flipperzero-bomberduck/bomberduck.c diff --git a/applications/external/flipperzero-bomberduck/LICENSE b/applications/external/flipperzero-bomberduck/LICENSE deleted file mode 100644 index bce361a99c..0000000000 --- a/applications/external/flipperzero-bomberduck/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) [year] [fullname] - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/applications/external/flipperzero-bomberduck/README.md b/applications/external/flipperzero-bomberduck/README.md deleted file mode 100644 index 2d133145aa..0000000000 --- a/applications/external/flipperzero-bomberduck/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# flipperzero-bomberduck -Bomberman clone on flipper zero! diff --git a/applications/external/flipperzero-bomberduck/application.fam b/applications/external/flipperzero-bomberduck/application.fam deleted file mode 100644 index afcd5a6ee1..0000000000 --- a/applications/external/flipperzero-bomberduck/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="bomberduck", - name="Bomberduck", - apptype=FlipperAppType.EXTERNAL, - entry_point="bomberduck_app", - cdefines=["BOMBERDUCK"], - requires=[ - "gui", - ], - stack_size=1 * 1024, - order=90, - fap_icon="bomb.png", - fap_category="Games", - fap_icon_assets="assets", -) diff --git a/applications/external/flipperzero-bomberduck/assets/bomb0.png b/applications/external/flipperzero-bomberduck/assets/bomb0.png deleted file mode 100644 index 3fdc3a3c12c7ede770e1c99c2003c777b03f4d75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U diff --git a/applications/external/flipperzero-bomberduck/assets/bomb1.png b/applications/external/flipperzero-bomberduck/assets/bomb1.png deleted file mode 100644 index 11d05b9b7c445452253792c5a51ad6448cca8aee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& diff --git a/applications/external/flipperzero-bomberduck/assets/bomb2.png b/applications/external/flipperzero-bomberduck/assets/bomb2.png deleted file mode 100644 index 38ce7c732bfa5e3586d1c9b9a754b85405cd4566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 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 W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX diff --git a/applications/external/flipperzero-bomberduck/assets/enemy1.png b/applications/external/flipperzero-bomberduck/assets/enemy1.png deleted file mode 100644 index 7ee7cb27f1ee52c63dbdb31e788c1011c8448d35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4757 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 diff --git a/applications/external/flipperzero-bomberduck/assets/enemyright.png b/applications/external/flipperzero-bomberduck/assets/enemyright.png deleted file mode 100644 index 45e6a861ad9c914af25be2b6c1b6097fdc6f0d17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD diff --git a/applications/external/flipperzero-bomberduck/assets/explore.png b/applications/external/flipperzero-bomberduck/assets/explore.png deleted file mode 100644 index 5eb50b669b3ee364bd25a37991519cf833660ae5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 diff --git a/applications/external/flipperzero-bomberduck/assets/playerleft.png b/applications/external/flipperzero-bomberduck/assets/playerleft.png deleted file mode 100644 index 86997a985eab4de991e315858b17ed7e0a981f74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF diff --git a/applications/external/flipperzero-bomberduck/assets/playerright.png b/applications/external/flipperzero-bomberduck/assets/playerright.png deleted file mode 100644 index 1a6283d9c26d9f9582fecd0cef9765ab2b288576..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng diff --git a/applications/external/flipperzero-bomberduck/assets/unbreakbox.png b/applications/external/flipperzero-bomberduck/assets/unbreakbox.png deleted file mode 100644 index 5e65912d53405d04bcd05916947a8de8fc5239c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX diff --git a/applications/external/flipperzero-bomberduck/bomb.png b/applications/external/flipperzero-bomberduck/bomb.png deleted file mode 100644 index 44b9bfdeae76553be52ce1c451133a4baee7bf68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 diff --git a/applications/external/flipperzero-bomberduck/bomberduck.c b/applications/external/flipperzero-bomberduck/bomberduck.c deleted file mode 100644 index 7b8b5f14a0..0000000000 --- a/applications/external/flipperzero-bomberduck/bomberduck.c +++ /dev/null @@ -1,645 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include "bomberduck_icons.h" -#include - -int max(int a, int b) { - return (a > b) ? a : b; -} - -int min(int a, int b) { - return (a < b) ? a : b; -} - -#define WorldSizeX 12 -#define WorldSizeY 6 -#define BombRange 1 - - -typedef struct { - FuriMutex* mutex; -} BomberState; - -typedef struct { - int row; - int col; -} Cell; - -typedef struct { - Cell cells[WorldSizeY * WorldSizeX]; - int front; - int rear; -} Queue; - -void enqueue(Queue* q, Cell c) { - q->cells[q->rear] = c; - q->rear++; -} - -Cell dequeue(Queue* q) { - Cell c = q->cells[q->front]; - q->front++; - - return c; -} - -bool is_empty(Queue* q) { - return q->front == q->rear; -} - -typedef struct { - int x; - int y; - int planted; -} Bomb; - -typedef struct { - int x; - int y; - bool side; -} Player; - -typedef struct { - int x; - int y; - int last; - bool side; - int level; -} Enemy; - -typedef struct { - int matrix[WorldSizeY][WorldSizeX]; - Player* player; - bool running; - int level; - - Enemy enemies[10]; - int enemies_count; - - Bomb bombs[100]; - int bombs_count; - - int endx; - int endy; -} World; - -Player player = {0, 0, 1}; -World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; -bool vibration = false; - -void init() { - player.x = 1; - player.y = 1; - - world.endx = 4 + rand() % 8; - world.endy = rand() % 6; - for(int i = 0; i < WorldSizeY; i++) { - for(int j = 0; j < WorldSizeX; j++) { - world.matrix[i][j] = rand() % 3; - } - } - world.running = 1; - world.bombs_count =0; - vibration = false; - for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { - world.matrix[j][player.x] = 0; - } - - for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { - world.matrix[player.y][j] = 0; - } - - world.enemies_count = 0; - for(int j = 0; j < rand() % 4 + world.level / 5; j++) { - Enemy enemy; - enemy.x = 4 + rand() % 7; - enemy.y = rand() % 6; - enemy.last = 0; - enemy.side = 1; - enemy.level = 0; - - world.enemies[j] = enemy; - world.enemies_count++; - - for(int m = max(0, world.enemies[j].y - BombRange); - m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); - m++) { - world.matrix[m][world.enemies[j].x] = 0; - } - - for(int m = max(0, world.enemies[j].x - BombRange); - m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); - m++) { - world.matrix[world.enemies[j].y][m] = 0; - } - } - world.matrix[world.endy][world.endx] = 1; -} - -const NotificationSequence end = { - &message_vibro_on, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_note_ds4, - &message_delay_10, - &message_sound_off, - &message_delay_10, - - &message_vibro_off, - NULL, -}; - -static const NotificationSequence bomb2 = { - &message_vibro_on, - &message_delay_25, - &message_vibro_off, - NULL, -}; - -static const NotificationSequence bomb_explore = { - &message_vibro_on, - &message_delay_50, - &message_vibro_off, - NULL, -}; - -static const NotificationSequence vibr1 = { - &message_vibro_on, - &message_delay_10, - &message_vibro_off, - &message_delay_10, - &message_vibro_on, - &message_delay_10, - &message_vibro_off, - &message_delay_10, - - NULL, -}; - - -void intToStr(int num, char* str) { - int i = 0, sign = 0; - - if(num < 0) { - num = -num; - sign = 1; - } - - do { - str[i++] = num % 10 + '0'; - num /= 10; - } while(num > 0); - - if(sign) { - str[i++] = '-'; - } - - str[i] = '\0'; - - // Reverse the string - int j, len = i; - char temp; - for(j = 0; j < len / 2; j++) { - temp = str[j]; - str[j] = str[len - j - 1]; - str[len - j - 1] = temp; - } -} - -bool BFS() { - // Initialize visited array and queue - int visited[WorldSizeY][WorldSizeX] = {0}; - Queue q = {.front = 0, .rear = 0}; - // Mark the starting cell as visited and enqueue it - visited[world.player->y][world.player->x] = 1; - Cell startCell = {.row = world.player->y, .col = world.player->x}; - enqueue(&q, startCell); - // Traverse the field - while(!is_empty(&q)) { - // Dequeue a cell from the queue - Cell currentCell = dequeue(&q); - // Check if the current cell is the destination cell - if(currentCell.row == world.endy && currentCell.col == world.endx) { - return true; - } - // Check the neighboring cells - for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { - for(int colOffset = -1; colOffset <= 1; colOffset++) { - // Skip diagonals and the current cell - if(rowOffset == 0 && colOffset == 0) { - continue; - } - if(rowOffset != 0 && colOffset != 0) { - continue; - } - // Calculate the row and column of the neighboring cell - int neighborRow = currentCell.row + rowOffset; - int neighborCol = currentCell.col + colOffset; - // Skip out-of-bounds cells and already visited cells - if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || - neighborCol >= WorldSizeX) { - continue; - } - if(visited[neighborRow][neighborCol]) { - continue; - } - // Mark the neighboring cell as visited and enqueue it - if(world.matrix[neighborRow][neighborCol] != 2) { - visited[neighborRow][neighborCol] = 1; - Cell neighborCell = {.row = neighborRow, .col = neighborCol}; - enqueue(&q, neighborCell); - } - } - } - } - return false; -} - -static void draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const BomberState* bomber_state = ctx; - - furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); - if(!BFS()) { - init(); - } - canvas_clear(canvas); - - canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); - - if(world.running) { - for(size_t i = 0; i < WorldSizeY; i++) { - for(size_t j = 0; j < WorldSizeX; j++) { - switch(world.matrix[i][j]) { - case 0: - break; - case 1: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); - break; - case 2: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); - break; - case 3: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); - break; - case 4: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); - break; - case 5: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); - break; - case 6: - canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); - world.matrix[i][j] = 0; - break; - } - } - } - - if(world.player->side) { - canvas_draw_icon( - canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); - } else { - canvas_draw_icon( - canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); - } - - for(int i = 0; i < world.enemies_count; i++) { - if(world.enemies[i].level > 0) { - canvas_draw_icon( - canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); - } else { - if(world.enemies[i].side) { - canvas_draw_icon( - canvas, - world.enemies[i].x * 10 + 4, - world.enemies[i].y * 10 + 2, - &I_enemyright); - } else { - canvas_draw_icon( - canvas, - world.enemies[i].x * 10 + 4, - world.enemies[i].y * 10 + 2, - &I_enemyleft); - } - } - } - } else { - canvas_set_font(canvas, FontPrimary); - if(world.player->x == world.endx && world.player->y == world.endy) { - if(world.level == 20) { - canvas_draw_str(canvas, 30, 35, "You win!"); - }else{ - canvas_draw_str(canvas, 30, 35, "Next level!"); - char str[20]; - intToStr(world.level, str); - canvas_draw_str(canvas, 90, 35, str); - } - - } else { - canvas_draw_str(canvas, 30, 35, "You died :("); - } - } - - furi_mutex_release(bomber_state->mutex); -} - -static void input_callback(InputEvent* input_event, void* ctx) { - // Проверяем, что контекст не нулевой - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -int32_t bomberduck_app(void* p) { - UNUSED(p); - - // Текущее событие типа InputEvent - InputEvent event; - // Очередь событий на 8 элементов размера InputEvent - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - BomberState* bomber_state = malloc(sizeof(BomberState)); - - bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex - if(!bomber_state->mutex) { - FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(bomber_state); - return 255; - } - - DOLPHIN_DEED(DolphinDeedPluginGameStart); - // Создаем новый view port - ViewPort* view_port = view_port_alloc(); - // Создаем callback отрисовки, без контекста - view_port_draw_callback_set(view_port, draw_callback, bomber_state); - // Создаем callback нажатий на клавиши, в качестве контекста передаем - // нашу очередь сообщений, чтоб запихивать в неё эти события - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Создаем GUI приложения - Gui* gui = furi_record_open(RECORD_GUI); - // Подключаем view port к GUI в полноэкранном режиме - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message_block(notification, &sequence_display_backlight_enforce_on); - - init(); - - // Бесконечный цикл обработки очереди событий - while(1) { - if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { - furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); - // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения - - if(event.type == InputTypePress) { - if(event.key == InputKeyOk) { - if(world.running) { - if(world.matrix[world.player->y][world.player->x] == 0 && - world.bombs_count < 2) { - notification_message(notification, &bomb2); - world.matrix[world.player->y][world.player->x] = 3; - Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; - world.bombs[world.bombs_count] = bomb; - world.bombs_count++; - } - } else { - init(); - } - } - if(world.running) { - if(event.key == InputKeyUp) { - if(world.player->y > 0 && - world.matrix[world.player->y - 1][world.player->x] == 0) - world.player->y--; - } - if(event.key == InputKeyDown) { - if(world.player->y < WorldSizeY - 1 && - world.matrix[world.player->y + 1][world.player->x] == 0) - world.player->y++; - } - if(event.key == InputKeyLeft) { - world.player->side = 0; - if(world.player->x > 0 && - world.matrix[world.player->y][world.player->x - 1] == 0) - world.player->x--; - } - if(event.key == InputKeyRight) { - world.player->side = 1; - if(world.player->x < WorldSizeX - 1 && - world.matrix[world.player->y][world.player->x + 1] == 0) - world.player->x++; - } - } - } else if(event.type == InputTypeLong) { - if(event.key == InputKeyBack) { - break; - } - } - } - if(world.running) { - if(world.player->x == world.endx && world.player->y == world.endy) { - notification_message(notification, &end); - world.running = 0; - world.level += 1; - if(world.level%5==0){ - DOLPHIN_DEED(DolphinDeedPluginGameWin); - } - } - for(int i = 0; i < world.bombs_count; i++) { - if(furi_get_tick() - world.bombs[i].planted > - (unsigned long)max((3000 - world.level * 150), 1000)) { - vibration = false; - world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; - notification_message(notification, &bomb_explore); - - for(int j = max(0, world.bombs[i].y - BombRange); - j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); - j++) { - if(world.matrix[j][world.bombs[i].x] != 2) { - world.matrix[j][world.bombs[i].x] = 6; - if(j == world.player->y && world.bombs[i].x == world.player->x) { - notification_message(notification, &end); - world.running = 0; - } - for(int e = 0; e < world.enemies_count; e++) { - if(j == world.enemies[e].y && - world.bombs[i].x == world.enemies[e].x) { - if(world.enemies[e].level > 0) { - world.enemies[e].level--; - } else { - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - } - } - - for(int j = max(0, world.bombs[i].x - BombRange); - j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); - j++) { - if(world.matrix[world.bombs[i].y][j] != 2) { - world.matrix[world.bombs[i].y][j] = 6; - if(world.bombs[i].y == world.player->y && j == world.player->x) { - notification_message(notification, &end); - world.running = 0; - } - for(int e = 0; e < world.enemies_count; e++) { - if(world.bombs[i].y == world.enemies[e].y && - j == world.enemies[e].x) { - if(world.enemies[e].level > 0) { - world.enemies[e].level--; - } else { - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - } - } - - for(int j = i; j < world.bombs_count - 1; j++) { - world.bombs[j] = world.bombs[j + 1]; - } - world.bombs_count--; - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; - vibration=true; - - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; - - } - } - for(int e = 0; e < world.enemies_count; e++) { - if(world.player->y == world.enemies[e].y && - world.player->x == world.enemies[e].x) { - notification_message(notification, &end); - world.running = 0; - } - } - - for(int e = 0; e < world.enemies_count; e++) { - if(world.enemies[e].level > 0) { - if(furi_get_tick() - world.enemies[e].last > - (unsigned long)max((2000 - world.level * 100), 1000)) { - world.enemies[e].last = furi_get_tick(); - int move = rand() % 4; - switch(move) { - case 0: - if(world.enemies[e].y > 0 && - world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) - world.enemies[e].y--; - break; - case 1: - if(world.enemies[e].y < WorldSizeY - 1 && - world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) - world.enemies[e].y++; - break; - case 2: - world.enemies[e].side = 0; - if(world.enemies[e].x > 0 && - world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) - world.enemies[e].x--; - break; - case 3: - world.enemies[e].side = 1; - if(world.enemies[e].x < WorldSizeX - 1 && - world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) - world.enemies[e].x++; - default: - break; - } - } - } else { - if(furi_get_tick() - world.enemies[e].last > - (unsigned long)max((1000 - world.level * 50), 500)) { - world.enemies[e].last = furi_get_tick(); - int move = rand() % 4; - switch(move) { - case 0: - if(world.enemies[e].y > 0 && - world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) - world.enemies[e].y--; - break; - case 1: - if(world.enemies[e].y < WorldSizeY - 1 && - world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) - world.enemies[e].y++; - break; - case 2: - world.enemies[e].side = 0; - if(world.enemies[e].x > 0 && - world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) - world.enemies[e].x--; - break; - case 3: - world.enemies[e].side = 1; - if(world.enemies[e].x < WorldSizeX - 1 && - world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) - world.enemies[e].x++; - default: - break; - } - } - } - } - for(int e = 0; e < world.enemies_count; e++) { - for(int h = e + 1; h < world.enemies_count; h++) { - if(world.enemies[e].y == world.enemies[h].y && - world.enemies[e].x == world.enemies[h].x) { - world.enemies[h].level++; - for(int l = e; l < world.enemies_count - 1; l++) { - world.enemies[l] = world.enemies[l + 1]; - } - world.enemies_count--; - } - } - } - if(vibration){ - notification_message(notification, &vibr1); - } - } - - view_port_update(view_port); - furi_mutex_release(bomber_state->mutex); - } - - // Return to normal backlight settings - notification_message_block(notification, &sequence_display_backlight_enforce_auto); - furi_record_close(RECORD_NOTIFICATION); - // Специальная очистка памяти, занимаемой очередью - furi_message_queue_free(event_queue); - - // Чистим созданные объекты, связанные с интерфейсом - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - - furi_mutex_free(bomber_state->mutex); - furi_record_close(RECORD_GUI); - free(bomber_state); - - return 0; -} From 099f907972beaf3736a7348be665b64d4ffa14a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:39:37 +0300 Subject: [PATCH 14/23] Add files via upload --- applications/external/bomberduck/LICENSE | 22 + applications/external/bomberduck/README.md | 2 + .../external/bomberduck/application.fam | 15 + .../external/bomberduck/assets/bomb0.png | Bin 0 -> 4536 bytes .../external/bomberduck/assets/bomb1.png | Bin 0 -> 4529 bytes .../external/bomberduck/assets/bomb2.png | Bin 0 -> 4531 bytes .../external/bomberduck/assets/box.png | Bin 0 -> 4329 bytes .../external/bomberduck/assets/end.png | Bin 0 -> 4739 bytes .../external/bomberduck/assets/enemy1.png | Bin 0 -> 4757 bytes .../external/bomberduck/assets/enemyleft.png | Bin 0 -> 4761 bytes .../external/bomberduck/assets/enemyright.png | Bin 0 -> 4536 bytes .../external/bomberduck/assets/explore.png | Bin 0 -> 4540 bytes .../external/bomberduck/assets/playerleft.png | Bin 0 -> 4311 bytes .../bomberduck/assets/playerright.png | Bin 0 -> 4307 bytes .../external/bomberduck/assets/unbreakbox.png | Bin 0 -> 4763 bytes applications/external/bomberduck/bomb.png | Bin 0 -> 4534 bytes applications/external/bomberduck/bomberduck.c | 645 ++++++++++++++++++ 17 files changed, 684 insertions(+) create mode 100644 applications/external/bomberduck/LICENSE create mode 100644 applications/external/bomberduck/README.md create mode 100644 applications/external/bomberduck/application.fam create mode 100644 applications/external/bomberduck/assets/bomb0.png create mode 100644 applications/external/bomberduck/assets/bomb1.png create mode 100644 applications/external/bomberduck/assets/bomb2.png create mode 100644 applications/external/bomberduck/assets/box.png create mode 100644 applications/external/bomberduck/assets/end.png create mode 100644 applications/external/bomberduck/assets/enemy1.png create mode 100644 applications/external/bomberduck/assets/enemyleft.png create mode 100644 applications/external/bomberduck/assets/enemyright.png create mode 100644 applications/external/bomberduck/assets/explore.png create mode 100644 applications/external/bomberduck/assets/playerleft.png create mode 100644 applications/external/bomberduck/assets/playerright.png create mode 100644 applications/external/bomberduck/assets/unbreakbox.png create mode 100644 applications/external/bomberduck/bomb.png create mode 100644 applications/external/bomberduck/bomberduck.c diff --git a/applications/external/bomberduck/LICENSE b/applications/external/bomberduck/LICENSE new file mode 100644 index 0000000000..bce361a99c --- /dev/null +++ b/applications/external/bomberduck/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/applications/external/bomberduck/README.md b/applications/external/bomberduck/README.md new file mode 100644 index 0000000000..2d133145aa --- /dev/null +++ b/applications/external/bomberduck/README.md @@ -0,0 +1,2 @@ +# flipperzero-bomberduck +Bomberman clone on flipper zero! diff --git a/applications/external/bomberduck/application.fam b/applications/external/bomberduck/application.fam new file mode 100644 index 0000000000..afcd5a6ee1 --- /dev/null +++ b/applications/external/bomberduck/application.fam @@ -0,0 +1,15 @@ +App( + appid="bomberduck", + name="Bomberduck", + apptype=FlipperAppType.EXTERNAL, + entry_point="bomberduck_app", + cdefines=["BOMBERDUCK"], + requires=[ + "gui", + ], + stack_size=1 * 1024, + order=90, + fap_icon="bomb.png", + fap_category="Games", + fap_icon_assets="assets", +) diff --git a/applications/external/bomberduck/assets/bomb0.png b/applications/external/bomberduck/assets/bomb0.png new file mode 100644 index 0000000000000000000000000000000000000000..3fdc3a3c12c7ede770e1c99c2003c777b03f4d75 GIT binary patch literal 4536 zcmeHKYj6|S6<%y!HW&j1Oo@SwNCLLA+NY$|R^nmFU;#3+tr`c~z&`HETT5CYtu5IJ znE)k#DRI*@1C1$^5T@xs878Hv(-e#gv`h*^utTUBhjB~-37JAnNeB}jy}R;rl9`UD z<)1Yp>F&AT`R+O2Irq-qExw{f8R^r~5d_Kb6uL{`zdlYModSPTeC5~R-}PF5xmLo* z(MVL4l^{U1ng~EaLXi<9adBI5+qM(v*n7XN! z8V(A9salG3vEWq)igso#5Xb;gQUCQc;F zHl-hajl?w1R1tbak+dRm#Zgp znD5TDFF6a3&(A)&s&#QeuBm!_@hRW0pWIycY1w|?Pt*65Rh)1BxFvIs$JNr=Ij3<- z_TBOWTqFDWwT|4;>t~_|%|&(QlFkRe$lp3O^Tltvu3x%*eLDL7lBIu0A?LT|$+;7< z=(fq^*LBDX?`d9zI*S=Gf$2EV#^6q-Z8nes`Gbe z>Y8hIv#0CcT>Na2<0ma6w#7=2vkEQ_+Am@+1G;4qo@>a?!M*0|4W z?`Bcv{X74}R_@EKy!3Jt@ypij+Z&5wXWSq5 zcl@O#k6su#)qbV;g^_Jt8y+;@2><@>iN=OWb*a(T&yMDdx%FYnkN1bw zGi!IwMU-o~HL2OzDYHhr`}DsP@xU|cgI&s3w^L{Mqo4n)^w50-8Mjh_tyu0|%86>o z%uA{O%!yD0_9%il<|QJ$SP3*#00AZJG~IZo$%HDB)3n^;CA<+As89-PqoB05$S>Ab zigw8~Z*ICH!9ju$(0DWv3Wj4`!f7&iIXKqMxCu2NTBXxe?)9NAH40G1%$NzRAfZ%K zrn%{;BPz*UiF;u;1$=UvDl{#^;dneAH^*tS8V%s2-EPMT3a2OxBCuFZSmP5|I5tbC zNOHJAOpGcKO;N+B&dCdEmF6^=;5^zBUnt`B_R@!A-6}vm@B|;hNi%_mLU@0Vm{w2? zNxB32PLG%$?r6LO#MG*&2nwn}Sewcq76!AE423Z^n-#M&7B~`ENt7+TOF z%VPjoWJ(r!t0>b3l_YWt)o6%^wI4Xbg6u&PftxIys}4g@egJVR^kzA%Wom zbKzW3z-wyMuc|?(Ne>CtJ$t9Ua63u7#=Ch9KvIIDIfCJ6!cUMKVdE%!9sw==@T#Q9 zHUAB*ZywZ{51CBi0%mSl_e3i!XI*xM5{F)&33t{;m%MRnlcDti*p?;M5FByI3~hQ~eLd){|z z2IGC0pYC>hm`kAO&?1A8H;+Tm(fQ3^K4=PV`Vk4%l%WMT8i zU6+p|2Sy^F9<5lqb<_El58BHnhwrG5w6+vqZ1P6;XZ(eJBr|7J!+Vem@e~xf59Y64 F{~v;POwj-U literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/bomb1.png b/applications/external/bomberduck/assets/bomb1.png new file mode 100644 index 0000000000000000000000000000000000000000..11d05b9b7c445452253792c5a51ad6448cca8aee GIT binary patch literal 4529 zcmeHKYj6|S6<*swEEzB`38t=zH-ZE|vf77MudM_zlEDIGgsmEfOoR7vSKeCE3hmmG zO&&l(8cb5>#Xtjvl7wkGJcdcr)G0%W3u&1IPlBCsjCSvy`~0E_FP>t|H6jQy#aHI7fOl4^|{MfZC%F{ugZOhB<(1vZ>mp)M`9skt&V!ivdjpyd=Jdl<4+CgUF)_3gPmz-S7 zeUE&xdgGrypCtbQUqyHSbJGVa0==Q#HNSE(ow?bsJhy~+V>;eeuoi1M`N_te6@C1w zxyygCxnz5wuSw*{zU?urHW+Izp1knw{zZ=`l)ej_uZQ+sne^e`6Y1A7bDu$ww2hL-6YzOFgNeg* zcRc#MyX@!#dGD_7TvA$OYM8d-c;J`!KizzxYH#34FDVxXq}mN zy?P(h>iDX+yC`!*K6=1h-fXVux%I-r&9kz9{$2mY&(2<)jefLr*>BUy2Re(zqUkx7 zuDi%@nvthI+)SQ0eu5J3Ei`=4U!R@7y6+X&``>-K>(z(aADnz?(=k%qc2`e*&u`kB z+ZuN{PBg!<-9gs-F@&K%TbZBF3!7eW>#e1n`H6Jx&3q3ct2L( z%c0DBcl_Q_x2LG?vlovLFLiF++FGtmGu&S@eTKK-buQ!H;IutIp7-v;=BsD#zM1wH z{Q0H#oSHPt`NfK-CUx~cajUH_y8rsI*6nvTXUxXmxeE3JOQAM=1(sjMjuDx1oKd{Z6o z6if@|8(m2T5=4N?qRB`&sxV2nN#|wYSTo}$REMZ_Zd0{CfO_OOKxs2=Ca}_^)Igc$ z8&OwW5Sa?^q5%r{n(Ik{eSn@n&X9gHs$^ZSSBqso8^P!BxG#&FV1;E@PE(nC>88z9L* zK;P@31mT9pD}W-`$9YiN0HW%gkrV9tU9%flvjmN{(7`vCkhE^3Ws* zNs*ZD1;rkPR3&j(tWmLPGkQ8B1A*>Cyra;Ax$9tv^7|RD%-3t-`MhqEwmu`syd*IC zkmfi$&su5BNzxQX+wC^YNn7EFa|pa>W$hfzj-c{I6_t(hK%;`>W(o3$qJ`pEs|}-V z0A3uNh;ck=#VDI-rwGE8h6akegtEoxa9F&8wktAuekd)Il45|Wg1$LswNfKrYtVPG;)SXS#(NTAzc zE{rD*SXGV(WjX9NX(6GS=g_ntZYP0NSud*sNJ>x^hM*Y>5hO^4aKJ$^0WBl&vLK0# z{|&8e9@Ld8d6}fZ^&53lYDZOqHL0i6V_4F+5{l}Zf?@eo3JTi*1U*j3m73yf*=PvB z(_^4r2kp}Lv;qlBE!t@d#&HDfA<+WsXAv!!jTA+aA~*_=_R;K$EUF1M4oX5$N2nES zPhBgtKrd9`Xmp|$XjOoMVFZm)&LBlHP&|qp5DdTlDbg0Z18^jPIqY!P&{mGbSc;=C zo~JlMw32o!aEuQ6e@St;C;lx(7p@(PgGF`W|55f7V8l5JrAgV~`3#SHeCWI%&`dj7 zZ{u&E-EQLwka~QPG3h%l*SK6`QeaHr@$MRzYfK7^2|V6i|2Mge!(WUb3SaaR@O!W* z{^U#WThb6Kdr(0T^BnD;mfW+T0UGa6eg4ur&QF*zcD`;u^wIl|ukC9&oAubK9~ufwSNA{`#8+DGJ+QE5!@mG~Pe@e& literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/bomb2.png b/applications/external/bomberduck/assets/bomb2.png new file mode 100644 index 0000000000000000000000000000000000000000..38ce7c732bfa5e3586d1c9b9a754b85405cd4566 GIT binary patch literal 4531 zcmeHKYj6|S6<$9e*oGLGfT_peML+;Mt9|ORTZxAyg9XS4TQv?$fqmSSHA3^WiZAxzpKrA(4i6NVBeq@^iL8oQJ_lVlvzgcO=MrVOMFkKSGRIn7MR z)AG-nk#zUmbH01dcfNaP@3uhs(h1r5*$9G6@RfNh;J-1>9+wV((*xC4;NRzs!D_vN zPoS~5Dl1`t>J2e~f}|oNNb>!sS9Lyp1|5I!#1@WW-qE0gfHd5>Z{-}`g({)!%P z&Fqyw*}iyhV1DPvt7jJf<#OZ15A%B0)#T@#dW>FB2{Wmz+EVqawu+sH-rq1`&9jpy zlT|<1w5X}~iC<=pA#T>_x2q1FK6xT>z4Q)U)tK>KD3S56b|4{0TC?Ku1biM(f8ns) zeNE4}%ida4@b>zSWu--y`iZN~2A+RtYs+Ue|AFQgm(Dv8%+=D((dw2J|)~N-z zs$b?>oma1P6^+|ch#s|;w^%E>@BXM{`?TC0U-y3T(WNh@qkmey;?;C=QAe>{G%1hn zoI-xpf;{=h?c}+$=O}s3{H%9->v9X%_q^cx!`B}iIJEZs!{fi)c7~MqOzE!c{`vWq zwuS@Fb1knd+f?p)qTt>!A&kCVS`oOvsoMoOt**8PHaR{sv3be)cHmW zQ=i}$H~(#Ado6~=Gp~m;@-AZj&J1hfu{(1;cChqX#{<_Ix^6%9oB27{KTQAbk*IpU zY2N}wxl+`SQBaURYs@?A{*g?C9#!w|S8m+Qm=TO${k-zn9R#_5tpb%;?O(x(YQ)M* zssOCXNDN98L0k)yF5Y%C9ojkO{x zSr#tHb|pCo5CJ-mCL`gf#wFbr6PJTy!;D){(?zd!TdMs5)T71$%2*jIft4neddjjO z8+FAcnXB+F>4ShzZcB}>$2c5MBofvHZB^qToMc%RCn%hvFzA744N;v>Vo`0D0g=M+ z0!@r7FA_Yc5FwLTUgA9#|F;iQ$oBN2RPgr=9)Ly*3N zzA-`z!VQgA08Ooni=ea~MDLA4a?1#G0Pd62n-*<9p>F%yXg$Q{C>`>igiYMKCjzitj|fRs7RbS zWCXz>@-_xzNru80hr^Dsj17(irzFZY-XSpj5GY?%)A^_f3@8Y0RUnR?b~3cU5}4f~ z*f550Ix&G_Y#3o<8PXxM5=D_iAXdf|s7gLOG%Ev2f>2J965#Q~q&LRpDHOCZeaG7NBARw&WB zMoOp=IWX;q+ezYe-plI%f)W(X5e!EYL4xE677mIDXc^+KN{Za@ z-@J{@gSt{JFH!Uv6i8X3WCufIfj^#%7Kb2@kSi!p zlPh$d*{J!$y%ROS=mI1RBN&WggA~a@@+h*8F#O(^DB5|_LECvuq$B~Vof0u814xV( zL`oK%EW_GT`WPVae<^WL6V&h$UAS>9_BYjq|3}+X4nxjSNKMKH&u4ht;{)e?A7?P% zd->^;+r3-@MMoDI5x=8!jnXwD21evOs;*JGM#R8~oJZC5f1@jV@Wu$D@I@~H?}KlC zwr(rDOJ>E&9@Y@VI?MQ`B@ZvGhsOJKpTG3J%bC-sW}yQA_qEXUExoi__oxx$nt_;a zzd%A0ie7^nZ@;TI-=Ak(Onu(P!D$^$JAOY2A;zUQ`|e`93fbA6h0fPYDxODT?2Y63 zPrW*&>7})^$)cW1xch3(p$l^^t>3Zrh@Ae&jG38f-#JVCB8d4V+w@^|y107;Q8`s!r9<>K*$8}6g>N;sjATc4yq;7b1@BE%- zrsJ9BKTD(2-nYN+x8L{MZ+CY0`icq`7#=X_bh-teLU#%LSKEdZJ$&kYfvfOusKy^q zN|-njlSEz!14OBg0R$ujUZ+c3db;>8Pj}!cx8h58=&|)#uT^{c+77htKeX!Lk4s

Y(%&x8cXle1Amu0 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 W?%Tg+a|JX){N>AiuP%OK!+!v0;CsXX literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/enemy1.png b/applications/external/bomberduck/assets/enemy1.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee7cb27f1ee52c63dbdb31e788c1011c8448d35 GIT binary patch literal 4757 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 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/enemyright.png b/applications/external/bomberduck/assets/enemyright.png new file mode 100644 index 0000000000000000000000000000000000000000..45e6a861ad9c914af25be2b6c1b6097fdc6f0d17 GIT binary patch literal 4536 zcmeHKeQ*@z8DB1lAqc@j2r_}Jiy-;f+mGA(T5^2kE+mIsIKnl=p;q_f-OHN0+so}H zccEZKiNFixQqR2oRlB(;cCnh8})Y=IykGX&Ci_wqS)rjt?r z%gx-~yU+VPzxR25&+mO_-_8Eg;>l^V(hvlh>@D$>!GC?6mTH2(CVxdY{JXd=P@$D^ zaWooJBsm07tu6{skdP$=NqqeLsx!|YCsS|5GuE26r?*s_<%K)0d_HgfpQT@K{rQQk zbkhfp{lEVQe(T?u?}bl4uHRlbRaGxUXH9--N~`$noc3c^rmb94h~zYGX`6RB!?AwL zM?z}DwKcCqn~$B0?|C2Dwd=<8$$K~0(k8SBG~VN8$|f$ebvb8dDA%eFfZzP~t(!Z_ za}GtVmD653;OLz%X59Q)p9wtE=SLlB{umoxE$o|^RRM=$LuIC=B$4X>T&hl;nE%+l-|;N?9iK8UFm>;DAAGm4{`&bjx5vFt zY<=kd(-USoKU?+8gfl%)_Z__y+24D-`Ipn{Q)UwfZ&CM*k8fPodhp0k!|zm^ZZvGn z`@^Ti>5UgwwpZbJZ2Z+wO6F8}f1vd3lCOW2GA9uG;yKtp*Dlp`+e(mO{mR2E&>8mo`=MctrME?E}?tJjqVgmqPd zQ^Xc8N-IdP5FiXR4o!qZ5tU82Fawu`W8F+(sNtejxv&bKA9X7+fHG#rOyWfext7Kj zrJ)5eQDVzH%laYUlMAcVv?xmu@p#-Ex0sb!kf5ASCqdE#P2n_4x+jBWgbjkPjlkMG4AG65%j0JVMoqY9UB} zLSGx92H=h+%7CiW!~{@O3nJRw;Si!Q7$2>Pg^Y4UfdC;8hOR1Hl^U^RvDfDxjL<0v z%HgOH1<4-asman1StD}OXN+=&Cj!F+Z> z#Lz@Q4ujPir?W}f9D2G=lD665FqyM~R}Nw-RHBYak!A~HgzIf#VKIxgrdf#U^yXKg38qb(Z~~GC8vZ+E)oRr z^yruCfL;C?DNvF~OLoSB^E?SPBw1kpERqGcQIbT_Bu@j%J`!D3BrVRxz|tV(5po6P zX>f%uFdCIJ(mP%W^e#ZcaFW4kXMmR^z-Z&KorCg^@m^p{vb=*QwfQwxayX?xOP*f|QRN!sA~43B$a@VxKm z4CZ?$KmBsMlS`oJ*dn9icZ{wvx<C0@_cz|4+Kr6;E#Xlh|!U&95zbJP9;$F^rDco76M zz5V!0f4N3|vZ}LQ_N0&Ui#rxRF#k)4g?NifJxzs= GJ@sFi98UKD literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/explore.png b/applications/external/bomberduck/assets/explore.png new file mode 100644 index 0000000000000000000000000000000000000000..5eb50b669b3ee364bd25a37991519cf833660ae5 GIT binary patch literal 4540 zcmeHKeQ;FO6@MfFVKICS5~M+%n;>Mv+xNL2?{$}u?1p54jZ0WCDOP=-n@4u{ExT{C zn+O%Cm1dzR>NKrHD9yyy0WywM2%-c=QA^3RBvOVJZ47D=Dm22Vts&`syZIcQ>10~| z%g*fXedqqp@1FBJ=iYg@-cweRshg*RASlyS>MRHU+E_O^4g98gDz1XR>vi4=wVaK? zp|B#!ei2q{Ln183WeI}ffBD(!%HU~ia_?7pbs1(f``yaD?|<)&%Wd`UXJ0CB*4I|- zWKYUZJki#1;r@=?%9ca%ybRpZFs`AeTf1S8;ZcBr2Q~kD%A7$w#ojFVfdSKnl8996U=Iu-z{rB9!`p@z{U;5J8 z6~>1%tBPKmv;Bi74|4ndT6pWV#M4E!##_3^zF!);a*w|{%X9vLmG)g5wwr%tSeVN# zvD&cedv`3_v~cm3VL zagb@XUc1_5n7nNP++r+C7|Xl+pDo%kclxexdai$X`TBhL{gtZ@r{T*w^CiQ~Eb`(# z_}2;OsXy(&&%Sq-kQU}m`D0IX`hrJq{Mz=1Z!Ya?THjuI_do03#-(4}(;e-8xjk{J zcAxcZ;?)(K%4{1tCe|-F*3#Ph&atjnPLgj)jHx91fjLtH2Y-j>zc8;Sccb&XdM1l7 z9%wvjt!_3{fB0M*_IzhULu*-N#*`(G&79?2{97)4p?5~}+C`^}5?@}vuW!P;=oBxc}6R;Gy2PTldUPq|Zl>+{W+Dh;3coex&W`!10Y~U+>$R|K=y? zg{_}G*inrj;f!1U^sEbr`(nB=wxw^8!z`A3(K-8z+OFF>PvlL#^+DPX4+NF=&5cVT z`KqBdJv%!sXX2ShZpLH2$CduQ@|Rzw-{%cq`+UtSeGoKly$o8h!o7;&m4J~I6izh8 z10m3(5M(QehgiN^RAEl^$w9mR#_={iEDLu1Lnb%o4mrdsxwI}UuBj{Y@^#fbE$9oD z>TGca5ClY(h2sH#Fv7&``Xny{#+n(`!%2u*ZP!=0J+MOwi!f!Rj2KcJmum?9QXOmy z3ldZATs}Ynp6vQ6RShvH8jHn@G191neJD=TG>Q=@K_CEuL~4U78%KhX9E~Ey;S?i$ zSPrSO5`;BQmQ$jtU9Si8@L+s_klQ^(AB+sB0Q5lPYzW1T7#awmBRwK&aSb3D2~Bh0r)fAe6;oMrg_eMx0gPB@=7mD0T#uD;QDPATMfEfZQkp9$Msh!Ax)nX%Sh3 z!Z8A&B{Pkf%&di`DcWQ)aU&=m49lP^S^vnWG%5j5S#g@93EG5kRsusP+H6Kx!O9|{ zXp#ttXU)7sCaDCTS+0ZwEGVZOV0|JQ3i^^0n&3>K$7R6agEAqYT{-qVa3cOZl%mtD@_c8)`{T==tPYZ$BZPEoYBg{fMkHMtk$Q1AZZ7= zFpjXus!G_aD1N(M3klXdho;?NI|;1HI$2c&q!>Xm7{!p77sDAGXH4dN3|L0s6+xD2 z{~KD{Jg_ZQ@=`eh)~`*PQafsmxH0vVdi2Z5tpvl#O~J5yDuoDJBMQkl0at2@uVRBf z5u6?a?K)_ezoQj!NgyN(MIsyrx`2{MP(M;45i>4HIDv75h+9UpM-)kov0<^$2Xq8l zf%Z&l1usq(DsMD8RwZgx0D>VHg%Grtz!@MOfe#3V-uVzZq&VCY*3l{2Q0-V8EUFFtR@qa45$7n7CS?QXGdS+iq4Rz~ zGZ62c{0y|)om>Kj#}^rszTq`;WKK zgX^A|eG=Ryr-Vu?BM@ZF(Y_Pn%>^~Uc$eyO7vJ^wjQMk>GKWmDCSbZ(Ev`@N`hPz0O0VZ)6#7jA;DcPn LWzLqO$F}_kO43W9 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/playerleft.png b/applications/external/bomberduck/assets/playerleft.png new file mode 100644 index 0000000000000000000000000000000000000000..86997a985eab4de991e315858b17ed7e0a981f74 GIT binary patch literal 4311 zcmeHKeQ*@z8QF~0mx0CKOUBB$ywxh6RdktHd zO&sK&?)m!b^WCRH-G!^$_a}-oP1cspFMM#|(!zW03)g0!TE3v}Zr#$0vELZGUb-+n z`tcmk4f{`Lq#nI*_apMPhBtb)weEi5)l-XhEletV<{4f2+r2_Tt8+zP&D`Z{#O4PM zw@BN!PF|&d&b$BEbZh?J9iP53`MlWoqIZt|$djhBXS3*cf4?u&_s3n;U$vdPIJM}q zyDDYY=lAB?FP7$K9CysB>pXqwYT(LU>tF7-mmbMD`&m5adGiz;K{9?OIh|g&(>Yi; zEO+PnEsn}J7v>#X+q1Ny#LzTt#XH_#-}_|hvzoo$C$e_cG@S1GxI257+u7aQThwu9 z-p$&5Y=`ah%NI%}J~kI^H&&&L)xG^&7d@4mz4@EID<6JzWj6Yk`YQlbF=yi*SStB z$7fQ;y*ppCHMW&Bez>iZ_(e}kOGj07+N66Qntq3?=(m3TJm0joAI?9vD0Tg#Ikz(2 z#<$#`e`Z21^UoC1X2yza^(+#y2cJd9d@@;Nf+;8?75k zk9>lk*>GujcO!;HGOq>nGtXe2vwCCv(OdJK7O>>Yo}4d}7ruS^_2S9b&g<&-hUAm$ zcP>Dr%Oy#DUY@Stw&M@}I}xw{vE2W>bp0#+9AD(~FIFD71v@k$!A`98EMs{&XygRh z4~&Um7`7;a*vk@Oj&B4C>Id~w$YHp8xYK}2g2S-N>>)g1Cuoo=ng}@KRhhvd|R*t~qAOM088ilixqo!Qq_IQUPR0-;( zU|5TSVvj;9k~l2ZsN7VKR?f&oVE7R4DD+_M8W^HH9@ZuEF*QB6%VALGX9by;1Xdeb z7{bDdem`cj5`K)fnynZ|GXzF56fZCWPf~ty1eH4!Rk#ojR4Pbrlpv2;r2P~iIgB$4 zCXD773&vP^9<$I^nimA#LYajT6w4zL>`E>$GAorzfK)U=`YE0Q7)euBjJD7MW+VIn z1F&N#Mzs3J^%e`)gfie=q7H@!4L>S;OER#a9 z#IVCB1;I*%Q`ICbHp^;%r^peXEC(D0H6>Jy9CCZ$b`m&+b8!lQqy%MR37VxC9~_WombR7>&@uuq3zC@p zUubpnp!W2VS4vShe^N80chpL-F8!2#3`p8mLQ!o~upFN*A<8v@^kPA-w2N=xLiGTi z9s}(BtQ=sVhBxBNdT&{7s#-zZQz~kLDF4ve87!!EByZ&!-WevYh zfe^d}#o^0RvHVgme9@W|u3Q~O5MzP*%}BJBH9_O;irZ6h`=^<+bF#_0?9Os%x=X33 zRh)8Ay@Mm#)es11Tv8fP^=i0k!w+Uckkjod_vQA)HkaRlpc8dnm-^T4dAzEv*jiU! zw5bq5w*DNv|C4Ed>zY*bKyJ>);=gX$e&|PQ8vlgvdH7{q63*53T>oG~`_lQyYkd_@ QKsv--QRQl1^w4Af0rThwxc~qF literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/playerright.png b/applications/external/bomberduck/assets/playerright.png new file mode 100644 index 0000000000000000000000000000000000000000..1a6283d9c26d9f9582fecd0cef9765ab2b288576 GIT binary patch literal 4307 zcmeHKeQ*@z8Q*+ia)5y4BWi$k(Gn8(_IB?hw>x(PxI2RA+3tBttlv!gj$hEe0MKjw9Yu0 z(f@KYclYk|{+{3aJiq68-+6bdyQpBQ<{k}#AXA-%_G0+2j5X=W@Hg3AdI|o0QtK&| zi`gg|j)=Sv0H|CO1}KOLJc7i!x3Bu^_LJz8fnUUP+kS;;H^24s%j?g4kYWBKXnHPm z|3K#3^Hz43wbp$>qpKTTP5jvx5J?i!bEdYxN3DG$1-Inikb~*j8@qNKPi<`|Xx~w1 z_^^Lqb#`)S%f7n3j+B>o4`ih^JvLjDc6zV=VC8+9SD(V}y>VCkXjfmX`}n!<{ikf7 zqwm>cnavr`HO{S^b#z0`q0Q&&XI$O5k36@{+~2={$;PS`)(%Ih0xB8o}Px{Mi(W&9gzMTk?v{A6x+)kTqIB%Hk zuKFF;!V^of-dWeV!jXejPhWM){nCS5;=OAQxS!JOSyTRQ+uzSm+vBvI@9D{InVmII z+RU_=FJHQtlfGd-dPrLo*B18-HZI$iIqjL7*RH(((UrOApC4NJS~9t$GndbqF-L!4 z7WsJ`*>r9j*?y{>;vZO)arRo(wE630DtOC>IKABcPq9!!FkdeMlNo0qQ}-*f2qAbwn^ojP;OYM>QlF3g~M+ zBoExrL@|)Wst5-h)gUA<7)#;fM*PE7k${?xk0U?;1R+#{tCF`ZS>SZJM?4e>{6a9S zdO@*oL&^d_D%NeWDKlz1V*`QiBfPhvhjUlK5an_)c9E-6!gJcKn6f_O6FI@hs6(1I z^9BI)IISmH+`xHtI7@LPo~JXIcrP%SXp$O3R9tE+uiDP-( zU^4JH%jHqH$)`7Y0dJsr-ZzHg;fMgck`0WFN}=*8RC<~RM$U*EeO?o8AUO`F4J^P} zU^a6wPS(sNqVaLeaxoHQVL62$>jy+QP9W@04wv*!HTUELRGQR z36Bs2B{Hk1Nt(=59!={_M#@Z+M&l@G4Twmv6BSNUr_~$O8Ko=?Oa=6hmJkFeldkrQUwt~-#d(CIyK~ea!bf)CR?eIk_BV4#vLJ;i&<(m|1%CCmTJ7lNJamUB0b7xLZJMy99QE0kb zc9hCCF{s?Z5%p>ad}vgV%TeWO_(;Q@b0BDm)4tS`*;)USr5Z$+eq#3E;K!e!PrGF6 zqTlSkg?7Cym&HFjs47bfvH_+H3` NI2}dyL(A50_zI?I5pDng literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/assets/unbreakbox.png b/applications/external/bomberduck/assets/unbreakbox.png new file mode 100644 index 0000000000000000000000000000000000000000..5e65912d53405d04bcd05916947a8de8fc5239c8 GIT binary patch literal 4763 zcmeHKeQ*LAa#*}l_EHe7ZnC@CWRtz7rA^W{(9lqV#IcC`@ou`N$%f6g zNqff~tuoa16pDf(PzIfh5AYZ zc0^x)uxe6uafh&a*{bL7ZU6Qbb<5kAiybrj+}Rh~@;;c=`r;Jt(bwjk*l=HGc<$nP zWy0FK-<anGNJXNLodp5GUkF@7z+}L`+vf=pS>nE*`w^*Ni z_U6;Syz8-FAHI9@QDwdPLf5ja_k!=wuX@JToHp$*%~PERpXE}4zqxxy8>jbNS)SRy z@>E6J{98W$MV9Sf3mbJ^7w_-ie<6J6t$&>py|<-bI+1eX zxv+d_#pVKJ`q{kt)a>k(r(Eyd^KCp9_`TfUE`4`7wJWG}J^GHKB1mR|1eNIblry{> zGO&Wo0Yf|#ff7ZK{K9yI<%2*)IS`P-cKwCd_vukdu#O?Y7E(6D!*{DYoE^5%O_j|mkLskGv87Kpex#ChC zsV~r>`HCPimClj@2zX`JSF37-F&bmBm?35|$V$LS*lacfbbtlOhcV7ZjD!I4>q*15=7-%g$J%W5LRh^et zA~XsDQYey$f@F{KR3&kktWmjXGl_CWCIZ8Ua7TF$)}C;NULFtQl=)gMJ-5@Y*VbnQ znU@46F{C(-=2H$0(b{ zg0X^?#Q-piq{y=tUNj}31fD68l@JTJQwp&GV2p$Vi3yExrpW8I>q!GXZ1L8xst5z@ z`f@2;8y}wVNg=REWi>Vli8CrrtXS_GCSuacKFQlgbmG|?0c%O^{SvUNa6qBAq6xDQqDYW9M*@N#jUJUnHO4BS zC;)kcTtRszxI%ADY}9R|y<^ot+XYA%hEo`6^N|Dt$s>sY!i?9xL>#AW6ie7Jkpdh> z;gl8Qa1)D}N!Cn@g21zMQU^l>{x2m$P2dD$HZwT+|0|KU5QK@xO_-VI2#f+Ef!WM9 z8g?N`5VVyfI4;=&KUawZvbT;dG2f`&`3H5IZ~T$6lMW*u6>#^HHuwmFPc-AuBW*wy zFyCwW8R)2Mxde)iFES>6$LSiUYfKD`$$4B|<8+OQfiXFctLtZ@OE-Kd24VOv8-qvQ z89nFS@VI<^r0lLJf*5kO?}T_qVI4H4t8R}g{Y+ZU^)siu^qJ!YXqv9N{Hj9^X(uTp z@q!NoG$yIlsP=-tq%q?r=v3r(7WuM{bgbR4L-2{kD|YwygIHFp{{wKclAL^e-K+_( zl_?z?d^4U32Ch85aAyv(?N?isr~6iiN)H`tCH8?-F>_AFzD>vWLNLVbTHxGOd~ef# E080^$ApigX literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/bomb.png b/applications/external/bomberduck/bomb.png new file mode 100644 index 0000000000000000000000000000000000000000..44b9bfdeae76553be52ce1c451133a4baee7bf68 GIT binary patch literal 4534 zcmeHKYj6|S6<%z|5CMh~3MO%!MQ#F^?0fat9m^P72CE<}8sWT0;SYAG!)aM&4dO*36QBnfew$RC4{;rDG78SDFiYN#Jwv&HO)-N z)AG-nk#zUm?|k>1@0@#Q??%s(g%eE=nh*q;=qhoR!+&FJ8kY`#o9I&q;or4dZ-rhi z#L$SQ%1RKRdQAkNAg;&=5+SdGG+Oq zj?BQ7b)PkKHl)qI9nkMC+j;2q{r;QBzP_>NX8O53u?cgg)_sN`W1drriaf5OqJhj| zzFXI|I7*HbWF1>`=DXj^&8VJS*5!HmAKhbnDqi(8nA(>G&K>^f^rRiGqSl_C*>6tE zx>K=-f75>TN_XzK^^c%?@gYAB9E1UUb{n6%CTb}&ErB!-G_lrW#=509{4{SPSec^+jv`uJ>H`;&p z%7Y(|U%utrCs%Ggr?pwGcdf~Muk!e!RUO=hv}yY`Om+VL6<;c-*l_w6Ek3jRtF@DQ zpSe`pvgon*(=)lhm(`oPK7Y3N@b&PCcRp%(X=-EY!^9hRsg$%>{ely39BK}|wKnC; z?e%ki`Elpj`WH)2S7Ml!b~Bth{e8@RF%^$J^YyGJ>F+H3=b5Rd`?~M`=02|_>@(0C{qj`DGbIl;@rv0*06Xab^FI?NSr4_c&Z0A+C&C$ZwV zQcaulO=zAb$$YtUK|ck2a+m|U9^nZh7K`CA23IvdL2(>MkTgNl7(`&vny@a!v2ZlU zpy=apf~cq|5nWNksKF`t)GFO!Hp6*zAihwh^?6AZ z6^Ty_S)b1)3KkaQD3-=po6U-GtObsIc1e^ig3ZSY!>C;0s4j#>U{FDFT!B1Ri4p7; zn+;<~ABnLfDPf$QBQdL;v&f`iu}Dc2rJ4e}QV0%@%Ak@Um7U^z9L-rUpPhzOoYjg6 zl3l<6u*kG53RY2O646K^zd+SO0xYKz68wOOg#C#LLvVh+$K^27I5}kT1O;7&4i58T zC0rFBn(!(iuv8ZeH7To|wp$s7qDk7qaMTcJ8PKAz6Aey^#2Gd*W0Zx5$v|NRqfa40 z!VYuci!>nUs^(SIpu=p0gc_cM({8w(BtaLPf({@lNi#gj@(k&vY&=QvEH{^gmSK2R zQskQdhBh`2n%7tI5+w@PuSuBtcGOa^w(qI$F{mWA5{f1^1uuwwDMW>8ASL32Tzykw zKnVK*JU#l`b-=ECLn~0SM9Vgo!F)av_K?iL`Y|$tSt(hDvifL1*^=3#s;tKZ4b1mL z9idjRJri1?vlE4ylZ=i9fKde~7)G)f&3S2xhvLyxzhK0@Pthte5^LjF4A^V{W342I z`6Q9W7>*_d!AAKc%90%P|B~WhPgv;W6!Qq2J4txB{deU1UW1j>4ts8dLNDYP|hEQJ*m#g7RI?`QFSkP0jO7NWr)i=2q{T>eBHuH(vc!dPhO) z7cJG}kr`>8-0$DFdUNQ)ipMUv6x9pvoL~QvcJld^0sOV5X%F#bOaBF#5LfXM=ib7n G*8dyMBTMf9 literal 0 HcmV?d00001 diff --git a/applications/external/bomberduck/bomberduck.c b/applications/external/bomberduck/bomberduck.c new file mode 100644 index 0000000000..7b8b5f14a0 --- /dev/null +++ b/applications/external/bomberduck/bomberduck.c @@ -0,0 +1,645 @@ +#include +#include + +#include +#include +#include +#include +#include +#include "bomberduck_icons.h" +#include + +int max(int a, int b) { + return (a > b) ? a : b; +} + +int min(int a, int b) { + return (a < b) ? a : b; +} + +#define WorldSizeX 12 +#define WorldSizeY 6 +#define BombRange 1 + + +typedef struct { + FuriMutex* mutex; +} BomberState; + +typedef struct { + int row; + int col; +} Cell; + +typedef struct { + Cell cells[WorldSizeY * WorldSizeX]; + int front; + int rear; +} Queue; + +void enqueue(Queue* q, Cell c) { + q->cells[q->rear] = c; + q->rear++; +} + +Cell dequeue(Queue* q) { + Cell c = q->cells[q->front]; + q->front++; + + return c; +} + +bool is_empty(Queue* q) { + return q->front == q->rear; +} + +typedef struct { + int x; + int y; + int planted; +} Bomb; + +typedef struct { + int x; + int y; + bool side; +} Player; + +typedef struct { + int x; + int y; + int last; + bool side; + int level; +} Enemy; + +typedef struct { + int matrix[WorldSizeY][WorldSizeX]; + Player* player; + bool running; + int level; + + Enemy enemies[10]; + int enemies_count; + + Bomb bombs[100]; + int bombs_count; + + int endx; + int endy; +} World; + +Player player = {0, 0, 1}; +World world = {{{0}}, &player, 1, 0, {}, 0, {}, 0, 0, 0}; +bool vibration = false; + +void init() { + player.x = 1; + player.y = 1; + + world.endx = 4 + rand() % 8; + world.endy = rand() % 6; + for(int i = 0; i < WorldSizeY; i++) { + for(int j = 0; j < WorldSizeX; j++) { + world.matrix[i][j] = rand() % 3; + } + } + world.running = 1; + world.bombs_count =0; + vibration = false; + for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { + world.matrix[j][player.x] = 0; + } + + for(int j = max(0, player.x - BombRange); j < min(WorldSizeX, player.x + BombRange + 1); j++) { + world.matrix[player.y][j] = 0; + } + + world.enemies_count = 0; + for(int j = 0; j < rand() % 4 + world.level / 5; j++) { + Enemy enemy; + enemy.x = 4 + rand() % 7; + enemy.y = rand() % 6; + enemy.last = 0; + enemy.side = 1; + enemy.level = 0; + + world.enemies[j] = enemy; + world.enemies_count++; + + for(int m = max(0, world.enemies[j].y - BombRange); + m < min(WorldSizeY, world.enemies[j].y + BombRange + 1); + m++) { + world.matrix[m][world.enemies[j].x] = 0; + } + + for(int m = max(0, world.enemies[j].x - BombRange); + m < min(WorldSizeX, world.enemies[j].x + BombRange + 1); + m++) { + world.matrix[world.enemies[j].y][m] = 0; + } + } + world.matrix[world.endy][world.endx] = 1; +} + +const NotificationSequence end = { + &message_vibro_on, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_10, + &message_sound_off, + &message_delay_10, + + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb2 = { + &message_vibro_on, + &message_delay_25, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence bomb_explore = { + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +static const NotificationSequence vibr1 = { + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + &message_vibro_on, + &message_delay_10, + &message_vibro_off, + &message_delay_10, + + NULL, +}; + + +void intToStr(int num, char* str) { + int i = 0, sign = 0; + + if(num < 0) { + num = -num; + sign = 1; + } + + do { + str[i++] = num % 10 + '0'; + num /= 10; + } while(num > 0); + + if(sign) { + str[i++] = '-'; + } + + str[i] = '\0'; + + // Reverse the string + int j, len = i; + char temp; + for(j = 0; j < len / 2; j++) { + temp = str[j]; + str[j] = str[len - j - 1]; + str[len - j - 1] = temp; + } +} + +bool BFS() { + // Initialize visited array and queue + int visited[WorldSizeY][WorldSizeX] = {0}; + Queue q = {.front = 0, .rear = 0}; + // Mark the starting cell as visited and enqueue it + visited[world.player->y][world.player->x] = 1; + Cell startCell = {.row = world.player->y, .col = world.player->x}; + enqueue(&q, startCell); + // Traverse the field + while(!is_empty(&q)) { + // Dequeue a cell from the queue + Cell currentCell = dequeue(&q); + // Check if the current cell is the destination cell + if(currentCell.row == world.endy && currentCell.col == world.endx) { + return true; + } + // Check the neighboring cells + for(int rowOffset = -1; rowOffset <= 1; rowOffset++) { + for(int colOffset = -1; colOffset <= 1; colOffset++) { + // Skip diagonals and the current cell + if(rowOffset == 0 && colOffset == 0) { + continue; + } + if(rowOffset != 0 && colOffset != 0) { + continue; + } + // Calculate the row and column of the neighboring cell + int neighborRow = currentCell.row + rowOffset; + int neighborCol = currentCell.col + colOffset; + // Skip out-of-bounds cells and already visited cells + if(neighborRow < 0 || neighborRow >= WorldSizeY || neighborCol < 0 || + neighborCol >= WorldSizeX) { + continue; + } + if(visited[neighborRow][neighborCol]) { + continue; + } + // Mark the neighboring cell as visited and enqueue it + if(world.matrix[neighborRow][neighborCol] != 2) { + visited[neighborRow][neighborCol] = 1; + Cell neighborCell = {.row = neighborRow, .col = neighborCol}; + enqueue(&q, neighborCell); + } + } + } + } + return false; +} + +static void draw_callback(Canvas* canvas, void* ctx) { + furi_assert(ctx); + const BomberState* bomber_state = ctx; + + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + if(!BFS()) { + init(); + } + canvas_clear(canvas); + + canvas_draw_icon(canvas, world.endx * 10 + 4, world.endy * 10 + 2, &I_end); + + if(world.running) { + for(size_t i = 0; i < WorldSizeY; i++) { + for(size_t j = 0; j < WorldSizeX; j++) { + switch(world.matrix[i][j]) { + case 0: + break; + case 1: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_box); + break; + case 2: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_unbreakbox); + break; + case 3: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb0); + break; + case 4: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb1); + break; + case 5: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_bomb2); + break; + case 6: + canvas_draw_icon(canvas, j * 10 + 4, i * 10 + 2, &I_explore); + world.matrix[i][j] = 0; + break; + } + } + } + + if(world.player->side) { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerright); + } else { + canvas_draw_icon( + canvas, world.player->x * 10 + 4, world.player->y * 10 + 2, &I_playerleft); + } + + for(int i = 0; i < world.enemies_count; i++) { + if(world.enemies[i].level > 0) { + canvas_draw_icon( + canvas, world.enemies[i].x * 10 + 4, world.enemies[i].y * 10 + 2, &I_enemy1); + } else { + if(world.enemies[i].side) { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyright); + } else { + canvas_draw_icon( + canvas, + world.enemies[i].x * 10 + 4, + world.enemies[i].y * 10 + 2, + &I_enemyleft); + } + } + } + } else { + canvas_set_font(canvas, FontPrimary); + if(world.player->x == world.endx && world.player->y == world.endy) { + if(world.level == 20) { + canvas_draw_str(canvas, 30, 35, "You win!"); + }else{ + canvas_draw_str(canvas, 30, 35, "Next level!"); + char str[20]; + intToStr(world.level, str); + canvas_draw_str(canvas, 90, 35, str); + } + + } else { + canvas_draw_str(canvas, 30, 35, "You died :("); + } + } + + furi_mutex_release(bomber_state->mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx) { + // Проверяем, что контекст не нулевой + furi_assert(ctx); + FuriMessageQueue* event_queue = ctx; + + furi_message_queue_put(event_queue, input_event, FuriWaitForever); +} + +int32_t bomberduck_app(void* p) { + UNUSED(p); + + // Текущее событие типа InputEvent + InputEvent event; + // Очередь событий на 8 элементов размера InputEvent + FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + BomberState* bomber_state = malloc(sizeof(BomberState)); + + bomber_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); // Alloc Mutex + if(!bomber_state->mutex) { + FURI_LOG_E("BomberDuck", "cannot create mutex\r\n"); + furi_message_queue_free(event_queue); + free(bomber_state); + return 255; + } + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + // Создаем новый view port + ViewPort* view_port = view_port_alloc(); + // Создаем callback отрисовки, без контекста + view_port_draw_callback_set(view_port, draw_callback, bomber_state); + // Создаем callback нажатий на клавиши, в качестве контекста передаем + // нашу очередь сообщений, чтоб запихивать в неё эти события + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Создаем GUI приложения + Gui* gui = furi_record_open(RECORD_GUI); + // Подключаем view port к GUI в полноэкранном режиме + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); + notification_message_block(notification, &sequence_display_backlight_enforce_on); + + init(); + + // Бесконечный цикл обработки очереди событий + while(1) { + if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { + furi_mutex_acquire(bomber_state->mutex, FuriWaitForever); + // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения + + if(event.type == InputTypePress) { + if(event.key == InputKeyOk) { + if(world.running) { + if(world.matrix[world.player->y][world.player->x] == 0 && + world.bombs_count < 2) { + notification_message(notification, &bomb2); + world.matrix[world.player->y][world.player->x] = 3; + Bomb bomb = {world.player->x, world.player->y, furi_get_tick()}; + world.bombs[world.bombs_count] = bomb; + world.bombs_count++; + } + } else { + init(); + } + } + if(world.running) { + if(event.key == InputKeyUp) { + if(world.player->y > 0 && + world.matrix[world.player->y - 1][world.player->x] == 0) + world.player->y--; + } + if(event.key == InputKeyDown) { + if(world.player->y < WorldSizeY - 1 && + world.matrix[world.player->y + 1][world.player->x] == 0) + world.player->y++; + } + if(event.key == InputKeyLeft) { + world.player->side = 0; + if(world.player->x > 0 && + world.matrix[world.player->y][world.player->x - 1] == 0) + world.player->x--; + } + if(event.key == InputKeyRight) { + world.player->side = 1; + if(world.player->x < WorldSizeX - 1 && + world.matrix[world.player->y][world.player->x + 1] == 0) + world.player->x++; + } + } + } else if(event.type == InputTypeLong) { + if(event.key == InputKeyBack) { + break; + } + } + } + if(world.running) { + if(world.player->x == world.endx && world.player->y == world.endy) { + notification_message(notification, &end); + world.running = 0; + world.level += 1; + if(world.level%5==0){ + DOLPHIN_DEED(DolphinDeedPluginGameWin); + } + } + for(int i = 0; i < world.bombs_count; i++) { + if(furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150), 1000)) { + vibration = false; + world.matrix[world.bombs[i].y][world.bombs[i].x] = 6; + notification_message(notification, &bomb_explore); + + for(int j = max(0, world.bombs[i].y - BombRange); + j < min(WorldSizeY, world.bombs[i].y + BombRange + 1); + j++) { + if(world.matrix[j][world.bombs[i].x] != 2) { + world.matrix[j][world.bombs[i].x] = 6; + if(j == world.player->y && world.bombs[i].x == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(j == world.enemies[e].y && + world.bombs[i].x == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = max(0, world.bombs[i].x - BombRange); + j < min(WorldSizeX, world.bombs[i].x + BombRange + 1); + j++) { + if(world.matrix[world.bombs[i].y][j] != 2) { + world.matrix[world.bombs[i].y][j] = 6; + if(world.bombs[i].y == world.player->y && j == world.player->x) { + notification_message(notification, &end); + world.running = 0; + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.bombs[i].y == world.enemies[e].y && + j == world.enemies[e].x) { + if(world.enemies[e].level > 0) { + world.enemies[e].level--; + } else { + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + } + } + + for(int j = i; j < world.bombs_count - 1; j++) { + world.bombs[j] = world.bombs[j + 1]; + } + world.bombs_count--; + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration=true; + + } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; + + } + } + for(int e = 0; e < world.enemies_count; e++) { + if(world.player->y == world.enemies[e].y && + world.player->x == world.enemies[e].x) { + notification_message(notification, &end); + world.running = 0; + } + } + + for(int e = 0; e < world.enemies_count; e++) { + if(world.enemies[e].level > 0) { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((2000 - world.level * 100), 1000)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] != 2) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] != 2) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] != 2) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] != 2) + world.enemies[e].x++; + default: + break; + } + } + } else { + if(furi_get_tick() - world.enemies[e].last > + (unsigned long)max((1000 - world.level * 50), 500)) { + world.enemies[e].last = furi_get_tick(); + int move = rand() % 4; + switch(move) { + case 0: + if(world.enemies[e].y > 0 && + world.matrix[world.enemies[e].y - 1][world.enemies[e].x] == 0) + world.enemies[e].y--; + break; + case 1: + if(world.enemies[e].y < WorldSizeY - 1 && + world.matrix[world.enemies[e].y + 1][world.enemies[e].x] == 0) + world.enemies[e].y++; + break; + case 2: + world.enemies[e].side = 0; + if(world.enemies[e].x > 0 && + world.matrix[world.enemies[e].y][world.enemies[e].x - 1] == 0) + world.enemies[e].x--; + break; + case 3: + world.enemies[e].side = 1; + if(world.enemies[e].x < WorldSizeX - 1 && + world.matrix[world.enemies[e].y][world.enemies[e].x + 1] == 0) + world.enemies[e].x++; + default: + break; + } + } + } + } + for(int e = 0; e < world.enemies_count; e++) { + for(int h = e + 1; h < world.enemies_count; h++) { + if(world.enemies[e].y == world.enemies[h].y && + world.enemies[e].x == world.enemies[h].x) { + world.enemies[h].level++; + for(int l = e; l < world.enemies_count - 1; l++) { + world.enemies[l] = world.enemies[l + 1]; + } + world.enemies_count--; + } + } + } + if(vibration){ + notification_message(notification, &vibr1); + } + } + + view_port_update(view_port); + furi_mutex_release(bomber_state->mutex); + } + + // Return to normal backlight settings + notification_message_block(notification, &sequence_display_backlight_enforce_auto); + furi_record_close(RECORD_NOTIFICATION); + // Специальная очистка памяти, занимаемой очередью + furi_message_queue_free(event_queue); + + // Чистим созданные объекты, связанные с интерфейсом + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + + furi_mutex_free(bomber_state->mutex); + furi_record_close(RECORD_GUI); + free(bomber_state); + + return 0; +} From 13a65d45a37549a2373c17c3cd590abfdde42160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:46:10 +0300 Subject: [PATCH 15/23] Update LICENSE --- applications/external/bomberduck/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/bomberduck/LICENSE b/applications/external/bomberduck/LICENSE index bce361a99c..4624b249cc 100644 --- a/applications/external/bomberduck/LICENSE +++ b/applications/external/bomberduck/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) [year] [fullname] +Copyright (c) 2023 лень Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From d01600ea0fc01b4db8f63d7e20f4a5b838865a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BD=D1=8C=20=3A=29?= <88856726+leo-need-more-coffee@users.noreply.github.com> Date: Mon, 1 May 2023 20:46:27 +0300 Subject: [PATCH 16/23] Update application.fam --- applications/external/bomberduck/application.fam | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/external/bomberduck/application.fam b/applications/external/bomberduck/application.fam index afcd5a6ee1..2f8246af98 100644 --- a/applications/external/bomberduck/application.fam +++ b/applications/external/bomberduck/application.fam @@ -3,7 +3,6 @@ App( name="Bomberduck", apptype=FlipperAppType.EXTERNAL, entry_point="bomberduck_app", - cdefines=["BOMBERDUCK"], requires=[ "gui", ], From 2eac821f7f485a7b3df0b1f08e3f0610453bcb94 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 20:53:09 +0300 Subject: [PATCH 17/23] Update readme --- ReadMe.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ReadMe.md b/ReadMe.md index 1611bed679..91ca8235db 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -176,6 +176,7 @@ Games: - Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games) - BlackJack [(by teeebor)](https://github.com/teeebor/flipper_games) - 2048 game [(by eugene-kirzhanov)](https://github.com/eugene-kirzhanov/flipper-zero-2048-game) +- Bomberduck [(by leo-need-more-coffee)](https://github.com/leo-need-more-coffee/flipperzero-bomberduck) # Instructions From 0ef37df4ae9b128f025a4b99ad63084c1e20519d Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Mon, 1 May 2023 20:55:09 +0300 Subject: [PATCH 18/23] Update TOTP / run fbt format --- applications/external/bomberduck/bomberduck.c | 37 ++++++++++--------- .../external/hid_app/views/hid_ytshorts.c | 1 - .../external/totp/workers/type_code_common.c | 13 +++---- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/applications/external/bomberduck/bomberduck.c b/applications/external/bomberduck/bomberduck.c index 7b8b5f14a0..2c1c2940af 100644 --- a/applications/external/bomberduck/bomberduck.c +++ b/applications/external/bomberduck/bomberduck.c @@ -21,7 +21,6 @@ int min(int a, int b) { #define WorldSizeY 6 #define BombRange 1 - typedef struct { FuriMutex* mutex; } BomberState; @@ -105,7 +104,7 @@ void init() { } } world.running = 1; - world.bombs_count =0; + world.bombs_count = 0; vibration = false; for(int j = max(0, player.y - BombRange); j < min(WorldSizeY, player.y + BombRange + 1); j++) { world.matrix[j][player.x] = 0; @@ -191,7 +190,6 @@ static const NotificationSequence vibr1 = { NULL, }; - void intToStr(int num, char* str) { int i = 0, sign = 0; @@ -344,7 +342,7 @@ static void draw_callback(Canvas* canvas, void* ctx) { if(world.player->x == world.endx && world.player->y == world.endy) { if(world.level == 20) { canvas_draw_str(canvas, 30, 35, "You win!"); - }else{ + } else { canvas_draw_str(canvas, 30, 35, "Next level!"); char str[20]; intToStr(world.level, str); @@ -427,24 +425,24 @@ int32_t bomberduck_app(void* p) { if(world.running) { if(event.key == InputKeyUp) { if(world.player->y > 0 && - world.matrix[world.player->y - 1][world.player->x] == 0) + world.matrix[world.player->y - 1][world.player->x] == 0) world.player->y--; } if(event.key == InputKeyDown) { if(world.player->y < WorldSizeY - 1 && - world.matrix[world.player->y + 1][world.player->x] == 0) + world.matrix[world.player->y + 1][world.player->x] == 0) world.player->y++; } if(event.key == InputKeyLeft) { world.player->side = 0; if(world.player->x > 0 && - world.matrix[world.player->y][world.player->x - 1] == 0) + world.matrix[world.player->y][world.player->x - 1] == 0) world.player->x--; } if(event.key == InputKeyRight) { world.player->side = 1; if(world.player->x < WorldSizeX - 1 && - world.matrix[world.player->y][world.player->x + 1] == 0) + world.matrix[world.player->y][world.player->x + 1] == 0) world.player->x++; } } @@ -459,7 +457,7 @@ int32_t bomberduck_app(void* p) { notification_message(notification, &end); world.running = 0; world.level += 1; - if(world.level%5==0){ + if(world.level % 5 == 0) { DOLPHIN_DEED(DolphinDeedPluginGameWin); } } @@ -524,13 +522,18 @@ int32_t bomberduck_app(void* p) { world.bombs[j] = world.bombs[j + 1]; } world.bombs_count--; - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)*2/3, 666)&&world.matrix[world.bombs[i].y][world.bombs[i].x]!=5) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; - vibration=true; - - } else if(furi_get_tick() - world.bombs[i].planted > (unsigned long)max((3000 - world.level * 150)/3, 333)&& world.matrix[world.bombs[i].y][world.bombs[i].x]!=4) { - world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; - + } else if( + furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150) * 2 / 3, 666) && + world.matrix[world.bombs[i].y][world.bombs[i].x] != 5) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 5; + vibration = true; + + } else if( + furi_get_tick() - world.bombs[i].planted > + (unsigned long)max((3000 - world.level * 150) / 3, 333) && + world.matrix[world.bombs[i].y][world.bombs[i].x] != 4) { + world.matrix[world.bombs[i].y][world.bombs[i].x] = 4; } } for(int e = 0; e < world.enemies_count; e++) { @@ -618,7 +621,7 @@ int32_t bomberduck_app(void* p) { } } } - if(vibration){ + if(vibration) { notification_message(notification, &vibr1); } } diff --git a/applications/external/hid_app/views/hid_ytshorts.c b/applications/external/hid_app/views/hid_ytshorts.c index 9be2f853c1..3590916405 100644 --- a/applications/external/hid_app/views/hid_ytshorts.c +++ b/applications/external/hid_app/views/hid_ytshorts.c @@ -109,7 +109,6 @@ static void hid_ytshorts_draw_callback(Canvas* canvas, void* context) { elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); } - static void hid_ytshorts_reset_cursor(HidYTShorts* hid_ytshorts) { // Set cursor to the phone's left up corner // Delays to guarantee one packet per connection interval diff --git a/applications/external/totp/workers/type_code_common.c b/applications/external/totp/workers/type_code_common.c index 696df3b1fb..bf5818ab27 100644 --- a/applications/external/totp/workers/type_code_common.c +++ b/applications/external/totp/workers/type_code_common.c @@ -30,7 +30,7 @@ static uint32_t get_keypress_delay(TokenAutomationFeature features) { } static void totp_type_code_worker_press_key( - uint8_t key, + uint16_t key, TOTP_AUTOMATION_KEY_HANDLER key_press_fn, TOTP_AUTOMATION_KEY_HANDLER key_release_fn, TokenAutomationFeature features) { @@ -47,8 +47,6 @@ void totp_type_code_worker_execute_automation( TokenAutomationFeature features) { furi_delay_ms(500); uint8_t i = 0; - totp_type_code_worker_press_key( - HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); while(i < code_buffer_size && code_buffer[i] != 0) { uint8_t char_index = CONVERT_CHAR_TO_DIGIT(code_buffer[i]); @@ -58,7 +56,11 @@ void totp_type_code_worker_execute_automation( if(char_index > 35) break; - uint8_t hid_kb_key = hid_number_keys[char_index]; + uint16_t hid_kb_key = hid_number_keys[char_index]; + if(char_index > 9) { + hid_kb_key |= KEY_MOD_LEFT_SHIFT; + } + totp_type_code_worker_press_key(hid_kb_key, key_press_fn, key_release_fn, features); furi_delay_ms(get_keystroke_delay(features)); i++; @@ -74,7 +76,4 @@ void totp_type_code_worker_execute_automation( furi_delay_ms(get_keystroke_delay(features)); totp_type_code_worker_press_key(HID_KEYBOARD_TAB, key_press_fn, key_release_fn, features); } - - totp_type_code_worker_press_key( - HID_KEYBOARD_CAPS_LOCK, key_press_fn, key_release_fn, features); } \ No newline at end of file From fe6bf3c7d6fe6c10a3f915f4de8d8ea160b3272f Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 02:25:52 +0300 Subject: [PATCH 19/23] Revert some changes --- lib/nfc/protocols/mifare_classic.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/nfc/protocols/mifare_classic.c b/lib/nfc/protocols/mifare_classic.c index 204e3a5ebe..d2d7467dce 100644 --- a/lib/nfc/protocols/mifare_classic.c +++ b/lib/nfc/protocols/mifare_classic.c @@ -892,25 +892,11 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_ MfClassicSectorTrailer* sector_trailer = (MfClassicSectorTrailer*)emulator->data.block[sector_trailer_block].value; if(cmd == MF_CLASSIC_AUTH_KEY_A_CMD) { - if(mf_classic_is_key_found( - &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyA)) { - key = nfc_util_bytes2num(sector_trailer->key_a, 6); - access_key = MfClassicKeyA; - } else { - FURI_LOG_D(TAG, "Key not known"); - command_processed = true; - break; - } + key = nfc_util_bytes2num(sector_trailer->key_a, 6); + access_key = MfClassicKeyA; } else { - if(mf_classic_is_key_found( - &emulator->data, mf_classic_get_sector_by_block(block), MfClassicKeyB)) { - key = nfc_util_bytes2num(sector_trailer->key_b, 6); - access_key = MfClassicKeyB; - } else { - FURI_LOG_D(TAG, "Key not known"); - command_processed = true; - break; - } + key = nfc_util_bytes2num(sector_trailer->key_b, 6); + access_key = MfClassicKeyB; } uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA; From e24cb944ff795387599abfa6d4895ffb1f522957 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 02:38:42 +0300 Subject: [PATCH 20/23] Temp fix desktop lock bug and update changelog --- CHANGELOG.md | 29 +++++-------------- .../desktop/views/desktop_view_locked.c | 3 +- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dfbf46cf8..70948b2f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,12 @@ ### New changes -* Power + BLE: DeepSleep + required ble stack upgrade added back, all known issues was fixed in OFW, no issues was found during our tests -* Desktop: Allow locking without pin using Up menu on desktop (Short click on `Lock` = Without PIN / Long = With PIN) -* RFID: Add confirmation message before running `Clear T5577 Password` -* RFID: Add more user friendly RAW emulation via UI [(by Dan Caprita)](https://forum.flipperzero.one/t/electra-intercom/6368/43) -* SubGHz: Fixed `Frequency Analyzer` issues, fixed `Read` mode issues -* SubGHz: Fix NFC crash when using external CC1101 radio module -* SubGHz: Fix multiple external CC1101 radio module issues, (int callbacks, SPI handlers init/reinit) -* SubGHz: Using scene manager function in add manually (by @gid9798 | PR #437) -* Plugins: ESP32: WiFi Marauder - add icon for log files in logs browser -* Plugins: Update **ESP32: WiFi Marauder companion** plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion) merged [PR by @tcpassos](https://github.com/0xchocolate/flipperzero-firmware-with-wifi-marauder-companion/pull/11) +* NFC: Temp fix for Detect reader not collecting nonces +* Desktop: Temp fix for old backlight bug when locking by holding up arrow +* BLE Info: Show version instead of branch +* Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) +* Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit +* Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* Plugins: Fix RFID Fuzzer and iButton Fuzzer crashes -* Plugins: iButton Fuzzer default keys update (by @team-orangeBlue) -* Infrared: Updated infrared assets (by @amec0e | PR #441) -* Docs: Update **How To Install** images (by @krolchonok | PR #436) -* OFW PR 2620: NFC: Fix reading Mifare Classic cards with unusual access conditions and fix emulation of unknown keys (by Astrrra) -* OFW PR 2616: Picopass: remove spaces in CSN (by bettse) -* OFW PR 2604: WS: add protocol "Wendox W6726" (by Skorpionm) -* OFW PR 2607: BadUSB: command parser fix (by nminaylov) -* OFW: Keep HSI16 working in stop mode. -* OFW: FuriHal: use proper divider for core2 when transition to sleep, remove extra stop mode transition checks, cleanup code. Furi: proper assert and check messages. -* OFW: Don't reboot on crash in debug builds -* OFW: cubewb: downgraded to v1.15.0 +* Docs: Update HowToInstall (by @krolchonok | PR #443) #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip) diff --git a/applications/services/desktop/views/desktop_view_locked.c b/applications/services/desktop/views/desktop_view_locked.c index 0bf7570361..8a0ddb3af1 100644 --- a/applications/services/desktop/views/desktop_view_locked.c +++ b/applications/services/desktop/views/desktop_view_locked.c @@ -242,5 +242,6 @@ bool desktop_view_locked_is_locked_hint_visible(DesktopViewLocked* locked_view) DesktopViewLockedModel* model = view_get_model(locked_view->view); const DesktopViewLockedState view_state = model->view_state; view_commit_model(locked_view->view, false); - return view_state == DesktopViewLockedStateLockedHintShown; + return view_state == DesktopViewLockedStateLockedHintShown || + view_state == DesktopViewLockedStateLocked; } From b801f70f3a39139d443fba05655e3ad5e38f6769 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:01:50 +0300 Subject: [PATCH 21/23] OFW PR 2627: Add HID mouse auto-clicker by rwl4 --- applications/external/hid_app/hid.c | 21 ++ applications/external/hid_app/hid.h | 2 + applications/external/hid_app/views.h | 1 + .../hid_app/views/hid_mouse_clicker.c | 214 ++++++++++++++++++ .../hid_app/views/hid_mouse_clicker.h | 14 ++ 5 files changed, 252 insertions(+) create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.c create mode 100644 applications/external/hid_app/views/hid_mouse_clicker.h diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index f29a3b22af..f6b853f9c4 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -13,6 +13,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexTikTok, HidSubmenuIndexYTShorts, HidSubmenuIndexMouse, + HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, }; @@ -40,6 +41,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexYTShorts) { app->view_id = BtHidViewYTShorts; view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewYTShorts); + } else if(index == HidSubmenuIndexMouseClicker) { + app->view_id = HidViewMouseClicker; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); @@ -62,6 +66,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); + hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); hid_tiktok_set_connected_status(hid->hid_tiktok, connected); hid_ytshorts_set_connected_status(hid->hid_ytshorts, connected); @@ -136,6 +141,12 @@ Hid* hid_alloc(HidTransport transport) { hid_submenu_callback, app); } + submenu_add_item( + app->device_type_submenu, + "Mouse Clicker", + HidSubmenuIndexMouseClicker, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Mouse Jiggler", @@ -209,6 +220,14 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); + // Mouse clicker view + app->hid_mouse_clicker = hid_mouse_clicker_alloc(app); + view_set_previous_callback( + hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewMouseClicker, + hid_mouse_clicker_get_view(app->hid_mouse_clicker)); // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( @@ -244,6 +263,8 @@ void hid_free(Hid* app) { hid_media_free(app->hid_media); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); hid_mouse_free(app->hid_mouse); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker); + hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index be9176a289..6fe7d381ce 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -24,6 +24,7 @@ #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" #include "views/hid_ytshorts.h" +#include "views/hid_mouse_clicker.h" #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" @@ -46,6 +47,7 @@ struct Hid { HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; + HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; HidTikTok* hid_tiktok; HidYTShorts* hid_ytshorts; diff --git a/applications/external/hid_app/views.h b/applications/external/hid_app/views.h index 81e8d6dbea..297fc7bc2a 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -5,6 +5,7 @@ typedef enum { HidViewKeyboard, HidViewMedia, HidViewMouse, + HidViewMouseClicker, HidViewMouseJiggler, BtHidViewTikTok, BtHidViewYTShorts, diff --git a/applications/external/hid_app/views/hid_mouse_clicker.c b/applications/external/hid_app/views/hid_mouse_clicker.c new file mode 100644 index 0000000000..efaca190a0 --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.c @@ -0,0 +1,214 @@ +#include "hid_mouse_clicker.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidMouseClicker" +#define DEFAULT_CLICK_RATE 1 +#define MAXIMUM_CLICK_RATE 60 + +struct HidMouseClicker { + View* view; + Hid* hid; + FuriTimer* timer; +}; + +typedef struct { + bool connected; + bool running; + int rate; + HidTransport transport; +} HidMouseClickerModel; + +static void hid_mouse_clicker_start_or_restart_timer(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + if(furi_timer_is_running(hid_mouse_clicker->timer)) { + furi_timer_stop(hid_mouse_clicker->timer); + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + furi_timer_start( + hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate); + }, + true); +} + +static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidMouseClickerModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker"); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->running) { + canvas_set_font(canvas, FontPrimary); + + FuriString* rate_label = furi_string_alloc(); + furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate); + elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label)); + canvas_set_font(canvas, FontSecondary); + furi_string_free(rate_label); + + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } else { + canvas_set_font(canvas, FontPrimary); + elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking"); + canvas_set_font(canvas, FontSecondary); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + if(model->running) { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + } else { + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + } + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); +} + +static void hid_mouse_clicker_timer_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + if(model->running) { + hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT); + } + }, + false); +} + +static void hid_mouse_clicker_enter_callback(void* context) { + hid_mouse_clicker_start_or_restart_timer(context); +} + +static void hid_mouse_clicker_exit_callback(void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + furi_timer_stop(hid_mouse_clicker->timer); +} + +static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidMouseClicker* hid_mouse_clicker = context; + + bool consumed = false; + bool rate_changed = false; + + if(event->type != InputTypeRelease) { + return false; + } + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + switch(event->key) { + case InputKeyOk: + model->running = !model->running; + consumed = true; + break; + case InputKeyUp: + if(model->rate < MAXIMUM_CLICK_RATE) { + model->rate++; + } + rate_changed = true; + consumed = true; + break; + case InputKeyDown: + if(model->rate > 1) { + model->rate--; + } + rate_changed = true; + consumed = true; + break; + default: + consumed = true; + break; + } + }, + true); + + if(rate_changed) { + hid_mouse_clicker_start_or_restart_timer(context); + } + + return consumed; +} + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) { + HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker)); + + hid_mouse_clicker->view = view_alloc(); + view_set_context(hid_mouse_clicker->view, hid_mouse_clicker); + view_allocate_model( + hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel)); + view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback); + view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback); + view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback); + view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback); + + hid_mouse_clicker->hid = hid; + + hid_mouse_clicker->timer = furi_timer_alloc( + hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker); + + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { + model->transport = hid->transport; + model->rate = DEFAULT_CLICK_RATE; + }, + true); + + return hid_mouse_clicker; +} + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + + furi_timer_stop(hid_mouse_clicker->timer); + furi_timer_free(hid_mouse_clicker->timer); + + view_free(hid_mouse_clicker->view); + + free(hid_mouse_clicker); +} + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) { + furi_assert(hid_mouse_clicker); + return hid_mouse_clicker->view; +} + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) { + furi_assert(hid_mouse_clicker); + with_view_model( + hid_mouse_clicker->view, + HidMouseClickerModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_mouse_clicker.h b/applications/external/hid_app/views/hid_mouse_clicker.h new file mode 100644 index 0000000000..d72847baa7 --- /dev/null +++ b/applications/external/hid_app/views/hid_mouse_clicker.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidMouseClicker HidMouseClicker; + +HidMouseClicker* hid_mouse_clicker_alloc(Hid* bt_hid); + +void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker); + +View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker); + +void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected); From 28529905662005884e6cbf29416684b41d9d98ac Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:36:28 +0300 Subject: [PATCH 22/23] Add sharp and vizio to ir database --- assets/resources/infrared/assets/tv.ir | 40 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index c55ad267d8..bd246f3d6f 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 07th Mar, 2023 -# Last Checked 25th Apr, 2023 +# Last Updated 2, May, 2023 +# Last Checked 2, May, 2023 # name: POWER type: parsed @@ -1899,3 +1899,39 @@ type: parsed protocol: SIRC20 address: 10 01 00 00 command: 33 00 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 195 1833 300 766 280 760 275 790 276 737 309 731 304 1801 301 1804 309 731 304 1801 270 795 282 758 277 762 273 1832 270 769 246 45851 326 1780 302 739 307 785 282 732 303 736 310 1795 307 732 303 763 303 1775 307 733 334 1798 273 1832 270 1810 251 814 273 1780 281 43762 302 1804 309 758 277 737 330 762 284 730 305 734 301 1803 310 1796 306 733 302 1829 273 767 279 734 301 791 275 1804 278 762 253 45870 307 1798 304 763 272 767 279 787 279 760 275 1829 284 730 305 734 301 1804 309 757 278 1827 275 1804 278 1828 274 765 270 1835 278 43740 303 1776 306 787 279 760 275 765 281 759 307 758 277 1775 307 1799 303 736 299 1832 281 759 276 763 304 736 299 1832 281 733 302 45820 306 1800 302 764 282 758 277 788 278 762 284 1821 281 732 303 736 310 1796 307 733 302 1829 273 1806 276 1830 272 767 268 1837 245 43772 302 1778 304 789 277 762 284 756 279 786 249 765 301 1777 336 1770 301 764 282 1824 278 761 274 765 301 738 308 1824 278 761 274 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 254 1721 360 681 354 738 308 706 329 711 355 1774 307 1772 361 1744 327 687 359 1772 299 742 335 705 330 736 279 1825 298 742 283 44773 384 1721 360 707 308 707 359 733 302 711 335 705 361 704 331 708 338 1766 336 704 331 1773 329 1776 306 1773 360 681 323 1782 331 44726 411 1722 328 686 360 733 302 711 335 705 361 1742 329 1803 330 1749 332 708 327 1777 335 705 330 710 325 741 274 1830 303 737 278 44778 359 1747 355 712 303 711 355 711 335 705 330 709 337 703 363 703 332 1770 332 709 337 1767 335 1771 300 1752 360 733 302 1776 326 44731 355 1751 330 711 355 737 309 705 330 710 336 1793 309 1771 331 1774 307 706 360 1771 300 740 326 714 332 735 280 1798 325 741 274 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4484 662 469 661 469 661 1627 660 471 658 474 656 499 631 499 631 499 631 1657 630 1657 631 500 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 500 630 1657 630 500 631 500 630 500 631 500 630 1657 630 1658 630 1657 631 500 630 1657 631 1658 630 1658 630 1658 630 40107 9106 2202 631 +# +name: VOL+ +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9218 4484 636 495 660 469 661 1627 660 471 658 472 658 474 656 475 655 474 656 1632 655 1632 656 474 657 1632 656 1631 657 1632 656 1631 656 1632 656 474 656 1632 655 475 656 474 657 474 656 474 656 474 656 474 656 1632 655 474 656 1632 656 1632 656 1632 656 1632 656 1632 656 1632 656 40103 9107 2177 655 +# +name: VOL- +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9245 4429 689 467 662 468 661 1626 660 471 658 473 657 474 656 474 656 474 656 1631 657 1631 657 474 656 1631 656 1632 656 1631 657 1631 657 1631 656 1632 656 1631 657 474 656 474 656 474 657 474 656 474 656 474 657 474 656 474 656 1631 656 1632 656 1632 656 1632 656 1632 656 1631 656 40082 9109 2175 656 +# +name: MUTE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 9219 4485 636 495 660 469 661 1626 661 471 658 473 657 474 656 499 631 500 630 1657 630 1657 631 500 630 1657 630 1657 631 1657 631 1657 630 1657 631 1657 631 500 630 500 630 1657 631 500 630 500 630 500 630 500 631 500 630 1657 631 1657 631 500 630 1657 631 1658 630 1657 631 1658 630 39868 9106 2178 655 From 311cbf709c4cdfd7f8ca9a558d7f3ec92f777181 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Tue, 2 May 2023 03:39:17 +0300 Subject: [PATCH 23/23] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70948b2f56..3a861b0a0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,14 @@ ### New changes * NFC: Temp fix for Detect reader not collecting nonces * Desktop: Temp fix for old backlight bug when locking by holding up arrow +* IR: Add Sharp and Vizio to Universal TV remote * BLE Info: Show version instead of branch * Plugins: Add new game - Bomberduck (by @leo-need-more-coffee | PR #450) * Plugins: Fix `SWD Probe` plugin GPIO pins state reset on exit * Plugins: Bluetooth Remote - new UI (by @krolchonok | PR #447) * Plugins: Update **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) * Docs: Update HowToInstall (by @krolchonok | PR #443) +* OFW PR 2627: Add HID mouse auto-clicker (by @rwl4) #### [🎲 Download latest extra apps pack](https://github.com/xMasterX/all-the-plugins/archive/refs/heads/main.zip)