From d1f523687e918725d06d7afe1270b853781f255e Mon Sep 17 00:00:00 2001 From: its your bedtime <23366927+itsyourbedtime@users.noreply.github.com> Date: Tue, 13 Apr 2021 21:06:25 +0300 Subject: [PATCH] [FL-1090] Dolphin scenes (#402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dolphin scene draft wip * gui/elements multiline framed text added * zoom poc * item callbacks * engine tweaks * move scenes out of services * improve dolphin gfx selection * glitch hints * dialogue typewriter effect * app loading from scenes app, small action changes, passport app(WIP) * removed passport from main dolphin app, added statusbar * small elements position fixes * fix thread alloc, dolphin and dolphin_scene free functions, other minor issues * sleep emote improvements * Dolpin: fix memory leaks, variable namings and etc Co-authored-by: gornekich <44112859+gornekich@users.noreply.github.com> Co-authored-by: DrZlo13 Co-authored-by: あく --- applications/applications.c | 21 ++ applications/applications.h | 7 + applications/applications.mk | 14 +- applications/dolphin/dolphin.c | 192 +++++------------- applications/dolphin/dolphin_i.h | 6 +- applications/dolphin/dolphin_state.c | 2 +- applications/dolphin/dolphin_state.h | 2 +- applications/dolphin/dolphin_views.c | 26 +-- applications/dolphin/dolphin_views.h | 5 +- applications/dolphin_scene/dolphin_emotes.h | 15 ++ applications/dolphin_scene/dolphin_scene.c | 31 +++ applications/dolphin_scene/dolphin_scene.h | 141 +++++++++++++ applications/dolphin_scene/engine.c | 115 +++++++++++ applications/dolphin_scene/items.c | 131 ++++++++++++ applications/dolphin_scene/items.h | 5 + applications/dolphin_scene/items_i.h | 8 + applications/dolphin_scene/scene.c | 172 ++++++++++++++++ applications/dolphin_scene/state.c | 101 +++++++++ applications/dolphin_scene/user.c | 111 ++++++++++ applications/gui/canvas.c | 4 + applications/gui/canvas.h | 5 + applications/gui/elements.c | 1 + applications/gui/elements.h | 8 + applications/gui/icon.c | 5 + applications/gui/icon.h | 5 + applications/passport/passport.c | 122 +++++++++++ .../Animations/FX_Sitting_40x27/frame_0.png | Bin 0 -> 369 bytes .../Animations/FX_Sitting_40x27/frame_1.png | Bin 0 -> 368 bytes .../Animations/FX_Sitting_40x27/frame_rate | 1 + .../icons/Animations/MDIB_32x32/frame_0.png | Bin 0 -> 359 bytes .../icons/Animations/MDIB_32x32/frame_1.png | Bin 0 -> 350 bytes .../icons/Animations/MDIB_32x32/frame_2.png | Bin 0 -> 350 bytes .../icons/Animations/MDIB_32x32/frame_3.png | Bin 0 -> 356 bytes assets/icons/Animations/MDIB_32x32/frame_rate | 1 + assets/icons/Animations/MDI_32x32/frame_0.png | Bin 0 -> 382 bytes assets/icons/Animations/MDI_32x32/frame_1.png | Bin 0 -> 383 bytes assets/icons/Animations/MDI_32x32/frame_2.png | Bin 0 -> 383 bytes assets/icons/Animations/MDI_32x32/frame_3.png | Bin 0 -> 381 bytes assets/icons/Animations/MDI_32x32/frame_rate | 1 + .../icons/Animations/MDWLB_32x32/frame_1.png | Bin 0 -> 356 bytes .../icons/Animations/MDWLB_32x32/frame_2.png | Bin 0 -> 365 bytes .../icons/Animations/MDWLB_32x32/frame_3.png | Bin 0 -> 363 bytes .../icons/Animations/MDWLB_32x32/frame_rate | 1 + .../icons/Animations/MDWL_32x32/frame_1.png | Bin 0 -> 384 bytes .../icons/Animations/MDWL_32x32/frame_2.png | Bin 0 -> 390 bytes .../icons/Animations/MDWL_32x32/frame_3.png | Bin 0 -> 382 bytes assets/icons/Animations/MDWL_32x32/frame_rate | 1 + .../icons/Animations/MDWRB_32x32/frame_1.png | Bin 0 -> 357 bytes .../icons/Animations/MDWRB_32x32/frame_2.png | Bin 0 -> 363 bytes .../icons/Animations/MDWRB_32x32/frame_3.png | Bin 0 -> 366 bytes .../icons/Animations/MDWRB_32x32/frame_rate | 1 + .../icons/Animations/MDWR_32x32/frame_1.png | Bin 0 -> 380 bytes .../icons/Animations/MDWR_32x32/frame_2.png | Bin 0 -> 389 bytes .../icons/Animations/MDWR_32x32/frame_3.png | Bin 0 -> 383 bytes assets/icons/Animations/MDWR_32x32/frame_rate | 1 + assets/icons/Dolphin/FX_Bang_32x6.png | Bin 0 -> 325 bytes assets/icons/Dolphin/FX_SittingB_40x27.png | Bin 0 -> 346 bytes assets/icons/Scenes/Home_painting_17x20.png | Bin 0 -> 1007 bytes assets/icons/Scenes/PC_22x29.png | Bin 0 -> 384 bytes assets/icons/Scenes/Sofa_40x13.png | Bin 0 -> 364 bytes assets/icons/Scenes/TV_20x20.png | Bin 0 -> 356 bytes assets/icons/Scenes/TV_20x24.png | Bin 0 -> 367 bytes assets/icons/Scenes/WalkL1_32x32.png | Bin 0 -> 390 bytes assets/icons/Scenes/WalkL2_32x32.png | Bin 0 -> 382 bytes assets/icons/Scenes/WalkLB1_32x32.png | Bin 0 -> 365 bytes assets/icons/Scenes/WalkLB2_32x32.png | Bin 0 -> 363 bytes assets/icons/Scenes/WalkR1_32x32.png | Bin 0 -> 389 bytes assets/icons/Scenes/WalkR2_32x32.png | Bin 0 -> 383 bytes assets/icons/Scenes/WalkRB1_32x32.png | Bin 0 -> 363 bytes assets/icons/Scenes/WalkRB2_32x32.png | Bin 0 -> 366 bytes 70 files changed, 1093 insertions(+), 169 deletions(-) create mode 100644 applications/dolphin_scene/dolphin_emotes.h create mode 100644 applications/dolphin_scene/dolphin_scene.c create mode 100644 applications/dolphin_scene/dolphin_scene.h create mode 100644 applications/dolphin_scene/engine.c create mode 100644 applications/dolphin_scene/items.c create mode 100644 applications/dolphin_scene/items.h create mode 100644 applications/dolphin_scene/items_i.h create mode 100644 applications/dolphin_scene/scene.c create mode 100644 applications/dolphin_scene/state.c create mode 100644 applications/dolphin_scene/user.c create mode 100644 applications/passport/passport.c create mode 100644 assets/icons/Animations/FX_Sitting_40x27/frame_0.png create mode 100644 assets/icons/Animations/FX_Sitting_40x27/frame_1.png create mode 100644 assets/icons/Animations/FX_Sitting_40x27/frame_rate create mode 100644 assets/icons/Animations/MDIB_32x32/frame_0.png create mode 100644 assets/icons/Animations/MDIB_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDIB_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDIB_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDIB_32x32/frame_rate create mode 100644 assets/icons/Animations/MDI_32x32/frame_0.png create mode 100644 assets/icons/Animations/MDI_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDI_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDI_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDI_32x32/frame_rate create mode 100644 assets/icons/Animations/MDWLB_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDWLB_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDWLB_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDWLB_32x32/frame_rate create mode 100644 assets/icons/Animations/MDWL_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDWL_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDWL_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDWL_32x32/frame_rate create mode 100644 assets/icons/Animations/MDWRB_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDWRB_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDWRB_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDWRB_32x32/frame_rate create mode 100644 assets/icons/Animations/MDWR_32x32/frame_1.png create mode 100644 assets/icons/Animations/MDWR_32x32/frame_2.png create mode 100644 assets/icons/Animations/MDWR_32x32/frame_3.png create mode 100644 assets/icons/Animations/MDWR_32x32/frame_rate create mode 100644 assets/icons/Dolphin/FX_Bang_32x6.png create mode 100644 assets/icons/Dolphin/FX_SittingB_40x27.png create mode 100644 assets/icons/Scenes/Home_painting_17x20.png create mode 100644 assets/icons/Scenes/PC_22x29.png create mode 100644 assets/icons/Scenes/Sofa_40x13.png create mode 100644 assets/icons/Scenes/TV_20x20.png create mode 100644 assets/icons/Scenes/TV_20x24.png create mode 100644 assets/icons/Scenes/WalkL1_32x32.png create mode 100644 assets/icons/Scenes/WalkL2_32x32.png create mode 100644 assets/icons/Scenes/WalkLB1_32x32.png create mode 100644 assets/icons/Scenes/WalkLB2_32x32.png create mode 100644 assets/icons/Scenes/WalkR1_32x32.png create mode 100644 assets/icons/Scenes/WalkR2_32x32.png create mode 100644 assets/icons/Scenes/WalkRB1_32x32.png create mode 100644 assets/icons/Scenes/WalkRB2_32x32.png diff --git a/applications/applications.c b/applications/applications.c index 3804a623..eada2daf 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -33,6 +33,8 @@ int32_t sd_filesystem(void* p); int32_t subghz_app(void* p); int32_t gui_test(void* p); int32_t keypad_test(void* p); +int32_t dolphin_scene(void* p); +int32_t passport(void* p); const FlipperApplication FLIPPER_SERVICES[] = { #ifdef APP_CLI @@ -146,6 +148,11 @@ const FlipperApplication FLIPPER_SERVICES[] = { #ifdef APP_KEYPAD_TEST {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, #endif + +#ifdef APP_DOLPHIN_SCENE + {.app = dolphin_scene, .name = "Dolphin [beta]", .stack_size = 1024, .icon = A_Games_14}, +#endif + }; const size_t FLIPPER_SERVICES_COUNT = sizeof(FLIPPER_SERVICES) / sizeof(FlipperApplication); @@ -223,3 +230,17 @@ const FlipperApplication FLIPPER_PLUGINS[] = { }; const size_t FLIPPER_PLUGINS_COUNT = sizeof(FLIPPER_PLUGINS) / sizeof(FlipperApplication); + +#ifdef BUILD_DOLPHIN_SCENE +const FlipperApplication FLIPPER_SCENES = + {.app = dolphin_scene, .name = "Dolphin [beta]", .stack_size = 1024, .icon = A_Games_14}; + +const FlipperApplication FLIPPER_SCENE_APPS[] = { + {.app = passport, .name = "Passport", .stack_size = 1024, .icon = A_Games_14}, + {.app = music_player, .name = "Music player", .stack_size = 1024, .icon = A_Plugins_14}, + {.app = floopper_bloopper, .name = "Floopper Bloopper", .stack_size = 1024, .icon = A_Games_14}, +}; + +const size_t FLIPPER_SCENE_APPS_COUNT = sizeof(FLIPPER_SCENE_APPS) / sizeof(FlipperApplication); + +#endif diff --git a/applications/applications.h b/applications/applications.h index e941a8c3..830dbcc9 100644 --- a/applications/applications.h +++ b/applications/applications.h @@ -27,3 +27,10 @@ extern const size_t FLIPPER_APPS_COUNT; */ extern const FlipperApplication FLIPPER_PLUGINS[]; extern const size_t FLIPPER_PLUGINS_COUNT; + +/* Seperate scene app holder + * Spawned by app-loader + */ +extern const FlipperApplication FLIPPER_SCENES; +extern const FlipperApplication FLIPPER_SCENE_APPS[]; +extern const size_t FLIPPER_SCENE_APPS_COUNT; diff --git a/applications/applications.mk b/applications/applications.mk index 9d0ef667..9cce8147 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -16,6 +16,7 @@ APP_BT = 1 APP_CLI = 1 APP_SD_FILESYSTEM = 1 BUILD_IRDA = 1 +BUILD_DOLPHIN_SCENE = 1 APP_DOLPHIN = 1 BUILD_EXAMPLE_BLINK = 1 BUILD_EXAMPLE_UART_WRITE = 1 @@ -227,7 +228,6 @@ C_SOURCES += $(APP_DIR)/examples/keypad_test.c BUILD_KEYPAD_TEST = 1 endif - APP_GPIO_DEMO ?= 0 ifeq ($(APP_GPIO_DEMO), 1) CFLAGS += -DAPP_GPIO_DEMO @@ -261,6 +261,18 @@ CFLAGS += -DBUILD_FLOOPPER_BLOOPPER C_SOURCES += $(wildcard $(APP_DIR)/floopper-bloopper/*.c) endif +APP_DOLPHIN_SCENE ?= 0 +ifeq ($(APP_DOLPHIN_SCENE), 1) +CFLAGS += -DAPP_DOLPHIN_SCENE +BUILD_DOLPHIN_SCENE = 1 +endif +BUILD_DOLPHIN_SCENE ?= 0 +ifeq ($(BUILD_DOLPHIN_SCENE), 1) +CFLAGS += -DBUILD_DOLPHIN_SCENE +C_SOURCES += $(wildcard $(APP_DIR)/dolphin_scene/*.c) +C_SOURCES += $(wildcard $(APP_DIR)/passport/*.c) +endif + APP_IBUTTON ?= 0 ifeq ($(APP_IBUTTON), 1) CFLAGS += -DAPP_IBUTTON diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index 2eb9baf0..ad3f70ab 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -1,5 +1,19 @@ #include "dolphin_i.h" #include +#include "applications.h" + +static void +dolphin_switch_to_interactive_scene(Dolphin* dolphin, const FlipperApplication* flipper_app) { + furi_assert(dolphin); + furi_assert(flipper_app); + furi_assert(flipper_app->app); + furi_assert(flipper_app->name); + + furi_thread_set_name(dolphin->scene_thread, flipper_app->name); + furi_thread_set_stack_size(dolphin->scene_thread, flipper_app->stack_size); + furi_thread_set_callback(dolphin->scene_thread, flipper_app->app); + furi_thread_start(dolphin->scene_thread); +} // temporary main screen animation managment void dolphin_scene_handler_set_scene(Dolphin* dolphin, IconName icon) { @@ -66,11 +80,10 @@ bool dolphin_view_idle_main_input(InputEvent* event, void* context) { } else if(event->key == InputKeyLeft) { view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleUp); } else if(event->key == InputKeyRight) { - view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMeta); + dolphin_switch_to_interactive_scene(dolphin, &FLIPPER_SCENES); } else if(event->key == InputKeyDown) { view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDown); } - if(event->key == InputKeyBack) { view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); } @@ -121,19 +134,6 @@ static void lock_menu_callback(void* context, uint8_t index) { view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); view_port_enabled_set(dolphin->lock_viewport, true); break; - - default: - break; - } -} - -static void meta_menu_callback(void* context, uint8_t index) { - Dolphin* dolphin = context; - switch(index) { - case 0: - view_port_enabled_set(dolphin->passport, true); - break; - default: break; } @@ -145,59 +145,6 @@ static void lock_icon_callback(Canvas* canvas, void* context) { canvas_draw_icon(canvas, 0, 0, dolphin->lock_icon); } -static void draw_passport_callback(Canvas* canvas, void* context) { - furi_assert(context); - Dolphin* dolphin = context; - - char level[20]; - uint32_t current_level = dolphin_state_get_level(dolphin->state); - uint32_t prev_cap = dolphin_state_xp_to_levelup(dolphin->state, current_level - 1, false); - uint32_t exp = (dolphin_state_xp_to_levelup(dolphin->state, current_level, true) * 63) / - (dolphin_state_xp_to_levelup(dolphin->state, current_level, false) - prev_cap); - - canvas_clear(canvas); - - // multipass - canvas_draw_icon_name(canvas, 0, 0, I_PassportLeft_6x47); - canvas_draw_icon_name(canvas, 0, 47, I_PassportBottom_128x17); - canvas_draw_line(canvas, 6, 0, 125, 0); - canvas_draw_line(canvas, 127, 2, 127, 47); - canvas_draw_dot(canvas, 126, 1); - - //portrait frame - canvas_draw_line(canvas, 9, 6, 9, 53); - canvas_draw_line(canvas, 10, 5, 52, 5); - canvas_draw_line(canvas, 55, 8, 55, 53); - canvas_draw_line(canvas, 10, 54, 54, 54); - canvas_draw_line(canvas, 53, 5, 55, 7); - - // portrait - canvas_draw_icon_name(canvas, 14, 11, I_DolphinOkay_41x43); - canvas_draw_line(canvas, 59, 18, 124, 18); - canvas_draw_line(canvas, 59, 31, 124, 31); - canvas_draw_line(canvas, 59, 44, 124, 44); - - canvas_draw_str(canvas, 59, 15, api_hal_version_get_name_ptr()); - canvas_draw_str(canvas, 59, 28, "Mood: OK"); - - snprintf(level, 20, "Level: %ld", current_level); - - canvas_draw_str(canvas, 59, 41, level); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 123 - exp, 48, exp + 1, 6); - canvas_set_color(canvas, ColorBlack); - canvas_draw_line(canvas, 123 - exp, 48, 123 - exp, 54); -} - -static void passport_input_callback(InputEvent* event, void* context) { - Dolphin* dolphin = context; - if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - view_port_enabled_set(dolphin->passport, false); - } - } -} - bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { furi_assert(event); furi_assert(context); @@ -244,51 +191,6 @@ bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { return true; } -bool dolphin_view_idle_meta_input(InputEvent* event, void* context) { - furi_assert(event); - furi_assert(context); - Dolphin* dolphin = context; - - if(event->type != InputTypeShort) return false; - - if(event->key == InputKeyLeft) { - with_view_model( - dolphin->idle_view_meta, (DolphinViewMenuModel * model) { - if(model->idx <= 0) - model->idx = 0; - else - --model->idx; - return true; - }); - } else if(event->key == InputKeyRight) { - with_view_model( - dolphin->idle_view_meta, (DolphinViewMenuModel * model) { - if(model->idx >= 2) - model->idx = 2; - else - ++model->idx; - return true; - }); - } else if(event->key == InputKeyOk) { - with_view_model( - dolphin->idle_view_meta, (DolphinViewMenuModel * model) { - meta_menu_callback(context, model->idx); - return true; - }); - } else if(event->key == InputKeyBack) { - with_view_model( - dolphin->idle_view_meta, (DolphinViewMenuModel * model) { - model->idx = 0; - return true; - }); - view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); - if(random() % 100 > 50) - dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % sizeof(idle_scenes)]); - } - - return true; -} - Dolphin* dolphin_alloc() { Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); // Message queue @@ -298,8 +200,15 @@ Dolphin* dolphin_alloc() { dolphin->state = dolphin_state_alloc(); // Menu dolphin->menu_vm = furi_record_open("menu"); + // Scene thread + dolphin->scene_thread = furi_thread_alloc(); + // GUI + dolphin->gui = furi_record_open("gui"); + + // Dispatcher dolphin->idle_view_dispatcher = view_dispatcher_alloc(); + // First start View dolphin->idle_view_first_start = view_alloc(); view_allocate_model( @@ -309,6 +218,7 @@ Dolphin* dolphin_alloc() { view_set_input_callback(dolphin->idle_view_first_start, dolphin_view_first_start_input); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewFirstStart, dolphin->idle_view_first_start); + // Main Idle View dolphin->idle_view_main = view_alloc(); view_set_context(dolphin->idle_view_main, dolphin); @@ -319,6 +229,7 @@ Dolphin* dolphin_alloc() { view_set_input_callback(dolphin->idle_view_main, dolphin_view_idle_main_input); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); + // Stats Idle View dolphin->idle_view_up = view_alloc(); view_set_context(dolphin->idle_view_up, dolphin); @@ -330,6 +241,7 @@ Dolphin* dolphin_alloc() { view_set_previous_callback(dolphin->idle_view_up, dolphin_view_idle_back); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewIdleUp, dolphin->idle_view_up); + // Lock Menu View dolphin->view_lockmenu = view_alloc(); view_set_context(dolphin->view_lockmenu, dolphin); @@ -340,22 +252,14 @@ Dolphin* dolphin_alloc() { view_set_previous_callback(dolphin->view_lockmenu, dolphin_view_idle_back); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewLockMenu, dolphin->view_lockmenu); - // Meta View - dolphin->idle_view_meta = view_alloc(); - view_set_context(dolphin->idle_view_meta, dolphin); - view_allocate_model( - dolphin->idle_view_meta, ViewModelTypeLockFree, sizeof(DolphinViewMenuModel)); - view_set_draw_callback(dolphin->idle_view_meta, dolphin_view_idle_meta_draw); - view_set_input_callback(dolphin->idle_view_meta, dolphin_view_idle_meta_input); - view_set_previous_callback(dolphin->idle_view_meta, dolphin_view_idle_back); - view_dispatcher_add_view( - dolphin->idle_view_dispatcher, DolphinViewIdleMeta, dolphin->idle_view_meta); + // Down Idle View dolphin->idle_view_down = view_alloc(); view_set_draw_callback(dolphin->idle_view_down, dolphin_view_idle_down_draw); view_set_previous_callback(dolphin->idle_view_down, dolphin_view_idle_back); view_dispatcher_add_view( dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down); + // HW Mismatch dolphin->view_hw_mismatch = view_alloc(); view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); @@ -370,18 +274,40 @@ Dolphin* dolphin_alloc() { view_port_draw_callback_set(dolphin->lock_viewport, lock_icon_callback, dolphin); view_port_enabled_set(dolphin->lock_viewport, false); - // Passport - dolphin->passport = view_port_alloc(); - view_port_draw_callback_set(dolphin->passport, draw_passport_callback, dolphin); - view_port_input_callback_set(dolphin->passport, passport_input_callback, dolphin); - view_port_enabled_set(dolphin->passport, false); - // Main screen animation dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % sizeof(idle_scenes)]); + view_dispatcher_attach_to_gui( + dolphin->idle_view_dispatcher, dolphin->gui, ViewDispatcherTypeWindow); + gui_add_view_port(dolphin->gui, dolphin->lock_viewport, GuiLayerStatusBarLeft); + return dolphin; } +void dolphin_free(Dolphin* dolphin) { + furi_assert(dolphin); + + gui_remove_view_port(dolphin->gui, dolphin->lock_viewport); + view_port_free(dolphin->lock_viewport); + icon_free(dolphin->lock_icon); + + view_dispatcher_free(dolphin->idle_view_dispatcher); + + furi_record_close("gui"); + dolphin->gui = NULL; + + furi_thread_free(dolphin->scene_thread); + + furi_record_close("menu"); + dolphin->menu_vm = NULL; + + dolphin_state_free(dolphin->state); + + osMessageQueueDelete(dolphin->event_queue); + + free(dolphin); +} + void dolphin_save(Dolphin* dolphin) { furi_assert(dolphin); DolphinEvent event; @@ -400,13 +326,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { int32_t dolphin_task() { Dolphin* dolphin = dolphin_alloc(); - Gui* gui = furi_record_open("gui"); - - view_dispatcher_attach_to_gui(dolphin->idle_view_dispatcher, gui, ViewDispatcherTypeWindow); - gui_add_view_port(gui, dolphin->lock_viewport, GuiLayerStatusBarLeft); - - gui_add_view_port(gui, dolphin->passport, GuiLayerFullscreen); - if(dolphin_state_load(dolphin->state)) { view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); } else { @@ -439,5 +358,6 @@ int32_t dolphin_task() { dolphin_state_save(dolphin->state); } } + dolphin_free(dolphin); return 0; } diff --git a/applications/dolphin/dolphin_i.h b/applications/dolphin/dolphin_i.h index ff257921..6fe17c23 100644 --- a/applications/dolphin/dolphin_i.h +++ b/applications/dolphin/dolphin_i.h @@ -33,7 +33,10 @@ struct Dolphin { DolphinState* state; // Menu ValueMutex* menu_vm; + // Scene + FuriThread* scene_thread; // GUI + Gui* gui; ViewDispatcher* idle_view_dispatcher; View* idle_view_first_start; View* idle_view_main; @@ -42,7 +45,6 @@ struct Dolphin { View* idle_view_meta; View* view_hw_mismatch; View* view_lockmenu; - ViewPort* passport; ViewPort* lock_viewport; Icon* lock_icon; @@ -55,6 +57,8 @@ const IconName idle_scenes[] = {A_Wink_128x64, A_WatchingTV_128x64}; Dolphin* dolphin_alloc(); +void dolphin_free(Dolphin* dolphin); + /* Save Dolphin state (write to permanent memory) * Thread safe */ diff --git a/applications/dolphin/dolphin_state.c b/applications/dolphin/dolphin_state.c index cbe5e117..4c3c0574 100644 --- a/applications/dolphin/dolphin_state.c +++ b/applications/dolphin/dolphin_state.c @@ -40,7 +40,7 @@ DolphinState* dolphin_state_alloc() { return dolphin_state; } -void dolphin_state_release(DolphinState* dolphin_state) { +void dolphin_state_free(DolphinState* dolphin_state) { free(dolphin_state); } diff --git a/applications/dolphin/dolphin_state.h b/applications/dolphin/dolphin_state.h index 6e5a94e0..cbd9611a 100644 --- a/applications/dolphin/dolphin_state.h +++ b/applications/dolphin/dolphin_state.h @@ -8,7 +8,7 @@ typedef struct DolphinState DolphinState; DolphinState* dolphin_state_alloc(); -void dolphin_state_release(DolphinState* dolphin_state); +void dolphin_state_free(DolphinState* dolphin_state); bool dolphin_state_save(DolphinState* dolphin_state); diff --git a/applications/dolphin/dolphin_views.c b/applications/dolphin/dolphin_views.c index 0c0b569b..345e664b 100644 --- a/applications/dolphin/dolphin_views.c +++ b/applications/dolphin/dolphin_views.c @@ -5,7 +5,6 @@ #include static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"}; -static char* Meta_Items[3] = {"Passport", "Games", "???"}; void dolphin_view_first_start_draw(Canvas* canvas, void* model) { DolphinViewFirstStartModel* m = model; @@ -58,7 +57,7 @@ void dolphin_view_first_start_draw(Canvas* canvas, void* model) { void dolphin_view_idle_main_draw(Canvas* canvas, void* model) { canvas_clear(canvas); DolphinViewMainModel* m = model; - if(m->animation) canvas_draw_icon(canvas, 0, 0, m->animation); + if(m->animation) canvas_draw_icon(canvas, 0, -3, m->animation); } void dolphin_view_idle_up_draw(Canvas* canvas, void* model) { @@ -92,29 +91,6 @@ void dolphin_view_lockmenu_draw(Canvas* canvas, void* model) { } } -void dolphin_view_idle_meta_draw(Canvas* canvas, void* model) { - DolphinViewMenuModel* m = model; - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - - canvas_draw_icon_name(canvas, 20, 23, I_BigProfile_24x24); - canvas_draw_icon_name(canvas, 55, 23, I_BigGames_24x24); - canvas_draw_icon_name(canvas, 90, 23, I_BigBurger_24x24); - - canvas_draw_str_aligned(canvas, 66, 12, AlignCenter, AlignCenter, Meta_Items[m->idx]); - - canvas_draw_frame(canvas, 17 + (35 * m->idx), 20, 30, 30); - canvas_set_color(canvas, ColorWhite); - - canvas_draw_dot(canvas, 17 + (35 * m->idx), 20); - canvas_draw_dot(canvas, 17 + (35 * m->idx), 49); - canvas_draw_dot(canvas, 46 + (35 * m->idx), 20); - canvas_draw_dot(canvas, 46 + (35 * m->idx), 49); - - canvas_set_color(canvas, ColorBlack); -} - void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); diff --git a/applications/dolphin/dolphin_views.h b/applications/dolphin/dolphin_views.h index 2be3b14f..9d53626f 100644 --- a/applications/dolphin/dolphin_views.h +++ b/applications/dolphin/dolphin_views.h @@ -8,13 +8,12 @@ // Idle scree typedef enum { - DolphinViewFirstStart, DolphinViewIdleMain, + DolphinViewFirstStart, DolphinViewIdleUp, DolphinViewIdleDown, DolphinViewHwMismatch, DolphinViewLockMenu, - DolphinViewIdleMeta, } DolphinViewIdle; typedef struct { @@ -48,8 +47,6 @@ void dolphin_view_lockmenu_draw(Canvas* canvas, void* model); void dolphin_view_idle_down_draw(Canvas* canvas, void* model); -void dolphin_view_idle_meta_draw(Canvas* canvas, void* model); - void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model); uint32_t dolphin_view_idle_back(void* context); diff --git a/applications/dolphin_scene/dolphin_emotes.h b/applications/dolphin_scene/dolphin_emotes.h new file mode 100644 index 00000000..8f2f5611 --- /dev/null +++ b/applications/dolphin_scene/dolphin_emotes.h @@ -0,0 +1,15 @@ +#pragma once + +static const char* emotes_list[] = { + "(O_o)", "(!_?)", "(^_^)", "(*__*)", "(@_@)", "(X_x)", "(>_<)", "(^ ^)", "(^_^)", + "(-_-)", "(~_~)", "(#^.^#)", "(^ ^)", "(^.^)", "(-.-)", "zZzZ", "(^_-)", "(^_-)", + "(+_+)", "(+o+)", "(' ')", "('-')", "('.')", "('_')", "(* > *)", "(o o)", "(^_^)", + "(^O^)", "(^o^)", "(^o^)", "(._.)", "(_^_)", "('_')", "('_;)", "(T_T)", "(;_;)", + "(ー_ー)", "(-.-)", "(^o^)", "(-_-)", "(=_=)", "(=^ ^=)", "(. .)", "(._.)", "( ^m^)", + "(?_?)", "(*^_^*)", "(^<^)", "(^.^)", "(^·^)", "(^.^)", "(^_^.)", "(^_^)", "(^^)", + "(^J^)", "(*^.^*)", "(#^.^#)", "(~o~)", "(^o^)", "(-o-)", "(^. ^)", "(^o^)", "(*^0^*)", + "(*_*)", "(~ o ~)", "(~_~)", "(p_-)", "d[-_-]b", "(^0_0^)", "- ^ -"}; + +static const char* dialogues_list[] = { + "Let's hack!\n\nbla bla bla\nbla bla..", +}; diff --git a/applications/dolphin_scene/dolphin_scene.c b/applications/dolphin_scene/dolphin_scene.c new file mode 100644 index 00000000..97e94dc1 --- /dev/null +++ b/applications/dolphin_scene/dolphin_scene.c @@ -0,0 +1,31 @@ +#include +#include "dolphin_scene/dolphin_scene.h" + +void dolphin_scene_redraw(Canvas* canvas, void* ctx) { + furi_assert(canvas); + furi_assert(ctx); + + SceneState* state = (SceneState*)acquire_mutex((ValueMutex*)ctx, 25); + if(state == NULL) return; // redraw fail + uint32_t t = xTaskGetTickCount(); + + canvas_clear(canvas); + + dolphin_scene_render(state, canvas, t); + + dolphin_scene_render_dolphin_state(state, canvas); + + release_mutex((ValueMutex*)ctx, state); +} + +void dolphin_scene_handle_input(SceneState* state, InputEvent* input) { + // printf("[kb] event: %02x %s\n", input->key, input->state ? "pressed" : "released"); + dolphin_scene_handle_user_input(state, input); +} + +void dolphin_scene_tick_handler(SceneState* state, uint32_t t, uint32_t dt) { + // printf("t: %d, dt: %d\n", t, dt); + + dolphin_scene_coordinates(state, dt); + dolphin_scene_update_dolphin_state(state, t, dt); +} diff --git a/applications/dolphin_scene/dolphin_scene.h b/applications/dolphin_scene/dolphin_scene.h new file mode 100644 index 00000000..ccfc5d06 --- /dev/null +++ b/applications/dolphin_scene/dolphin_scene.h @@ -0,0 +1,141 @@ +#pragma once + +#include +#include +#include + +#ifndef ARRSIZE +#define ARRSIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef CLAMP +#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) +#endif + +// global +#define SCALE 32 +// screen +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define BONDARIES_X_LEFT 40 +#define BONDARIES_X_RIGHT 88 + +// player +#define DOLPHIN_WIDTH 32 +#define DOLPHIN_HEIGHT 32 +#define DOLPHIN_CENTER (SCREEN_WIDTH / 2 - DOLPHIN_WIDTH / 2) +#define SPEED_X 2 +#define ACTIONS_NUM 5 +#define DOLPHIN_DEFAULT_Y 20 +// world +#define WORLD_WIDTH 2048 +#define WORLD_HEIGHT 64 + +#define LAYERS 8 +#define SCENE_ZOOM 9 +#define DOLPHIN_LAYER 6 +#define PARALLAX_MOD 7 +#define PARALLAX(layer) layer / PARALLAX_MOD - layer +#define ITEMS_NUM 4 + +#define DIALOG_PROGRESS 250 + +enum Actions { SLEEP = 0, IDLE, WALK, EMOTE, INTERACT, MINDCONTROL }; + +static const uint16_t default_timeout[] = + {[SLEEP] = 300, [IDLE] = 100, [WALK] = 100, [EMOTE] = 50, [INTERACT] = 10, [MINDCONTROL] = 50}; + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + union { + InputEvent input; + } value; + EventType type; +} AppEvent; + +typedef struct { + int32_t x; + int32_t y; +} Vec2; + +typedef struct { + Gui* gui; + ViewPort* view_port; + ValueMutex* vm; + osTimerId_t* timer; + osMessageQueueId_t mqueue; + FuriThread* scene_app_thread; + +} SceneAppGui; + +typedef struct { + uint8_t layer; + uint16_t timeout; + int32_t x; + int32_t y; + IconName icon; + char action_name[16]; + void (*draw)(Canvas* canvas, void* model); + void (*callback)(Canvas* canvas, void* model); +} Item; + +typedef struct { + SceneAppGui ui; + /// + Vec2 player; + Vec2 player_global; + Vec2 player_v; + Vec2 screen; + + IconName dolphin_gfx; + IconName dolphin_gfx_b; // temp + + bool player_flipped; + bool use_pending; + // dolphin_scene_debug + bool debug; + + uint8_t player_anim; + uint8_t scene_id; + + uint8_t emote_id; + uint8_t previous_emote; + + uint8_t dialogue_id; + uint8_t previous_dialogue; + + uint32_t action_timeout; + uint8_t poi; + + uint8_t action; + uint8_t next_action; + uint8_t prev_action; + + int8_t zoom_v; + uint8_t scene_zoom; + uint8_t dialog_progress; +} SceneState; + +void dolphin_scene_render(SceneState* state, Canvas* canvas, uint32_t t); +void dolphin_scene_render_dolphin(SceneState* state, Canvas* canvas); +void dolphin_scene_handle_user_input(SceneState* state, InputEvent* input); +void dolphin_scene_coordinates(SceneState* state, uint32_t dt); + +void dolphin_scene_render_dolphin_state(SceneState* state, Canvas* canvas); +void dolphin_scene_update_dolphin_state(SceneState* state, uint32_t t, uint32_t dt); + +void dolphin_scene_redraw(Canvas* canvas, void* ctx); +void dolphin_scene_tick_handler(SceneState* state, uint32_t t, uint32_t dt); +void dolphin_scene_handle_input(SceneState* state, InputEvent* input); diff --git a/applications/dolphin_scene/engine.c b/applications/dolphin_scene/engine.c new file mode 100644 index 00000000..5d0b6127 --- /dev/null +++ b/applications/dolphin_scene/engine.c @@ -0,0 +1,115 @@ +#include +#include "dolphin_scene/dolphin_scene.h" + +void dolphin_engine_tick_cb(void* p) { + osMessageQueueId_t event_queue = p; + AppEvent tick_event; + tick_event.type = EventTypeTick; + osMessageQueuePut(event_queue, (void*)&tick_event, 0, 0); +} + +static void dolphin_engine_event_cb(InputEvent* input_event, void* ctx) { + osMessageQueueId_t event_queue = ctx; + + AppEvent event; + event.type = EventTypeKey; + event.value.input = *input_event; + osMessageQueuePut(event_queue, (void*)&event, 0, osWaitForever); +} + +ValueMutex* scene_init() { + SceneState* scene_state = furi_alloc(sizeof(SceneState)); + scene_state->ui.mqueue = osMessageQueueNew(2, sizeof(AppEvent), NULL); + + scene_state->player.y = DOLPHIN_DEFAULT_Y; + scene_state->player.x = DOLPHIN_CENTER; + + //randomize position + scene_state->player_global.x = random() % WORLD_WIDTH / 4; + + scene_state->screen.x = scene_state->player.x; + scene_state->screen.y = scene_state->player.y; + + ValueMutex* scene_state_mutex = furi_alloc(sizeof(ValueMutex)); + if(scene_state_mutex == NULL || + !init_mutex(scene_state_mutex, scene_state, sizeof(SceneState))) { + printf("[menu_task] cannot create menu mutex\r\n"); + furi_check(0); + } + + // Open GUI and register view_port + scene_state->ui.gui = furi_record_open("gui"); + + // Allocate and configure view_port + scene_state->ui.view_port = view_port_alloc(); + + // Open GUI and register fullscreen view_port + gui_add_view_port(scene_state->ui.gui, scene_state->ui.view_port, GuiLayerMain); + view_port_draw_callback_set( + scene_state->ui.view_port, dolphin_scene_redraw, scene_state_mutex); + view_port_input_callback_set( + scene_state->ui.view_port, dolphin_engine_event_cb, scene_state->ui.mqueue); + view_port_enabled_set(scene_state->ui.view_port, true); + + scene_state->ui.timer = + osTimerNew(dolphin_engine_tick_cb, osTimerPeriodic, scene_state->ui.mqueue, NULL); + + return scene_state_mutex; +} + +void scene_free(ValueMutex* scene_state_mutex) { + furi_assert(scene_state_mutex); + + SceneState* scene_state = (SceneState*)acquire_mutex_block(scene_state_mutex); + + osTimerDelete(scene_state->ui.timer); + gui_remove_view_port(scene_state->ui.gui, scene_state->ui.view_port); + view_port_free(scene_state->ui.view_port); + furi_record_close("gui"); + osMessageQueueDelete(scene_state->ui.mqueue); + free(scene_state); + + release_mutex(scene_state_mutex, scene_state); + delete_mutex(scene_state_mutex); + free(scene_state_mutex); +} + +int32_t dolphin_scene(void* p) { + ValueMutex* scene_state_mutex = scene_init(); + + furi_record_create("scene", scene_state_mutex); + + SceneState* _state = (SceneState*)acquire_mutex_block(scene_state_mutex); + osTimerStart(_state->ui.timer, 40); + uint32_t t = xTaskGetTickCount(); + uint32_t prev_t = 0; + osMessageQueueId_t q = _state->ui.mqueue; + release_mutex(scene_state_mutex, _state); + + while(1) { + AppEvent event; + if(osMessageQueueGet(q, &event, 0, osWaitForever) == osOK) { + SceneState* _state = (SceneState*)acquire_mutex_block(scene_state_mutex); + if(event.type == EventTypeTick) { + t = xTaskGetTickCount(); + dolphin_scene_tick_handler(_state, t, (t - prev_t) % 1024); + prev_t = t; + } else if(event.type == EventTypeKey) { + if(event.value.input.key == InputKeyBack && + event.value.input.type == InputTypeShort) { + release_mutex(scene_state_mutex, _state); + break; + + } else { + dolphin_scene_handle_input(_state, &event.value.input); + } + } + release_mutex(scene_state_mutex, _state); + view_port_update(_state->ui.view_port); + } + } + + scene_free(scene_state_mutex); + + return 0; +} diff --git a/applications/dolphin_scene/items.c b/applications/dolphin_scene/items.c new file mode 100644 index 00000000..1b1ae9fb --- /dev/null +++ b/applications/dolphin_scene/items.c @@ -0,0 +1,131 @@ +#include "dolphin_scene/items_i.h" +#include +#include "applications.h" + +const Item TV = { + .layer = 7, + .timeout = 10, + .x = 160, + .y = 34, + .icon = I_TV_20x24, + .action_name = "Use", + .draw = draw_tv, + .callback = smash_tv}; + +const Item Painting = { + .layer = 3, + .timeout = 20, + .x = 160, + .y = 10, + .icon = I_Home_painting_17x20, + .action_name = "Inspect", + .draw = NULL, + .callback = inspect_painting}; + +const Item Sofa = { + .layer = 4, + .timeout = 100, + .x = 250, + .y = 34, + .icon = I_Sofa_40x13, + .action_name = "Sit", + .draw = NULL, + .callback = sofa_sit}; + +const Item PC = { + .layer = 4, + .timeout = 100, + .x = 400, + .y = 10, + .icon = I_PC_22x29, + .action_name = "Use", + .draw = NULL, + .callback = pc_callback}; + +const Item* Home[ITEMS_NUM] = {&TV, &Sofa, &Painting, &PC}; +const Item** Scenes[1] = {*&Home}; + +const Item** get_scene(SceneState* state) { + return Scenes[state->scene_id]; +} + +static void dolphin_scene_start_app(SceneState* state, const FlipperApplication* flipper_app) { + furi_assert(state); + furi_assert(flipper_app); + + state->ui.scene_app_thread = furi_thread_alloc(); + + furi_assert(flipper_app->app); + furi_assert(flipper_app->name); + + furi_thread_set_name(state->ui.scene_app_thread, flipper_app->name); + furi_thread_set_stack_size(state->ui.scene_app_thread, flipper_app->stack_size); + furi_thread_set_callback(state->ui.scene_app_thread, flipper_app->app); + furi_thread_start(state->ui.scene_app_thread); +} + +const Item* is_nearby(SceneState* state) { + furi_assert(state); + uint8_t item = 0; + bool found = false; + const Item** current = get_scene(state); + while(item < ITEMS_NUM) { + int32_t rel = + (DOLPHIN_CENTER + DOLPHIN_WIDTH / 2 - + (current[item]->x - state->player_global.x) * PARALLAX(current[item]->layer)); + if(abs(rel) <= DOLPHIN_WIDTH / 2) { + found = !found; + break; + } + ++item; + } + return found ? current[item] : NULL; +} + +void draw_tv(Canvas* canvas, void* state) { + furi_assert(state); + SceneState* s = state; + canvas_set_color(canvas, ColorWhite); + canvas_draw_box( + canvas, (TV.x + 3 - s->player_global.x) * PARALLAX(TV.layer), TV.y + 4, 16, 20); + canvas_set_color(canvas, ColorBlack); + canvas_set_bitmap_mode(canvas, true); +} + +void smash_tv(Canvas* canvas, void* state) { + furi_assert(state); + SceneState* s = state; + s->player_flipped = true; + canvas_set_bitmap_mode(canvas, true); + canvas_draw_icon_name( + canvas, ((TV.x - 5) - s->player_global.x) * PARALLAX(TV.layer), TV.y - 2, I_FX_Bang_32x6); + canvas_set_bitmap_mode(canvas, false); + if(s->action_timeout < TV.timeout - 2) { + elements_multiline_text_framed(canvas, 80, 24, "Bang!"); + } +} + +void sofa_sit(Canvas* canvas, void* state) { + furi_assert(state); + SceneState* s = state; + // temp fix pos + s->player_global.x = 154; + s->dolphin_gfx = A_FX_Sitting_40x27; + s->dolphin_gfx_b = I_FX_SittingB_40x27; +} + +void inspect_painting(Canvas* canvas, void* state) { + furi_assert(state); + SceneState* s = state; + if(s->use_pending) { + dolphin_scene_start_app(s, &FLIPPER_SCENE_APPS[0]); + } +} + +void pc_callback(Canvas* canvas, void* state) { + furi_assert(state); + SceneState* s = state; + if(s->use_pending) { + dolphin_scene_start_app(s, &FLIPPER_SCENE_APPS[1]); + } +} diff --git a/applications/dolphin_scene/items.h b/applications/dolphin_scene/items.h new file mode 100644 index 00000000..08f91317 --- /dev/null +++ b/applications/dolphin_scene/items.h @@ -0,0 +1,5 @@ +#pragma once +#include "dolphin_scene/dolphin_scene.h" + +const Item* is_nearby(SceneState* state); +const Item** get_scene(SceneState* state); \ No newline at end of file diff --git a/applications/dolphin_scene/items_i.h b/applications/dolphin_scene/items_i.h new file mode 100644 index 00000000..ac1850f8 --- /dev/null +++ b/applications/dolphin_scene/items_i.h @@ -0,0 +1,8 @@ +#pragma once +#include "dolphin_scene/items.h" + +void smash_tv(Canvas* canvas, void* state); +void draw_tv(Canvas* canvas, void* state); +void sofa_sit(Canvas* canvas, void* state); +void inspect_painting(Canvas* canvas, void* state); +void pc_callback(Canvas* canvas, void* state); diff --git a/applications/dolphin_scene/scene.c b/applications/dolphin_scene/scene.c new file mode 100644 index 00000000..cbe36f0c --- /dev/null +++ b/applications/dolphin_scene/scene.c @@ -0,0 +1,172 @@ +#include +#include "dolphin_scene/dolphin_scene.h" +#include "dolphin_scene/dolphin_emotes.h" +#include "dolphin_scene/items.h" +#include + +const char* action_str[] = {"Sleep", "Idle", "Walk", "Emote", "Use", "MC"}; + +static bool item_screen_bounds(int32_t pos) { + return pos > -SCREEN_WIDTH && pos < (SCREEN_WIDTH * 2); +} + +static void draw_hint(SceneState* state, Canvas* canvas, bool glitching) { + furi_assert(state); + furi_assert(canvas); + char buf[32]; + + const Item* near = is_nearby(state); + if(near) { + int32_t hint_pos_x = (near->x - state->player_global.x) * PARALLAX(near->layer) + 25; + int8_t hint_pos_y = near->y < 15 ? near->y + 4 : near->y - 16; + + strcpy(buf, near->action_name); + if(glitching) { + for(size_t g = 0; g != state->action_timeout; g++) { + buf[(g * 23) % strlen(buf)] = ' ' + (random() % g * 17) % ('z' - ' '); + } + } + + canvas_draw_str(canvas, hint_pos_x, hint_pos_y, buf); + } +} + +static void draw_current_emote(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + elements_multiline_text_framed(canvas, 80, 20, (char*)emotes_list[state->emote_id]); +} + +static void draw_sleep_emote(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + + char dialog_str[] = "zZzZ..."; + char buf[64]; + + if(state->player_global.x == 154 && state->action_timeout % 100 < 30) { + if(state->dialog_progress < strlen(dialog_str)) { + if(state->action_timeout % 5 == 0) state->dialog_progress++; + dialog_str[state->dialog_progress] = '\0'; + snprintf(buf, state->dialog_progress, dialog_str); + // bubble vs just text? + //elements_multiline_text_framed(canvas, 80, 20, buf); + canvas_draw_str(canvas, 80, 20, buf); + } + + } else { + state->dialog_progress = 0; + } +} + +static void draw_dialog(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + + char dialog_str[64]; + char buf[64]; + + strcpy(dialog_str, (char*)dialogues_list[state->dialogue_id]); + + if(state->dialog_progress <= strlen(dialog_str)) { + if(state->action_timeout % 2 == 0) state->dialog_progress++; + dialog_str[state->dialog_progress] = '\0'; + snprintf(buf, state->dialog_progress, dialog_str); + } else { + snprintf(buf, 64, dialog_str); + } + + elements_multiline_text_framed(canvas, 68, 16, buf); +} + +/* +static void draw_idle_emote(SceneState* state, Canvas* canvas){ + if(state->action_timeout % 50 < 40 && state->prev_action == MINDCONTROL){ + elements_multiline_text_framed(canvas, 68, 16, "WUT?!"); + } +} +*/ + +static void activate_item_callback(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + + const Item* near = is_nearby(state); + if(near && state->use_pending == true) { + state->action_timeout = near->timeout; + near->callback(canvas, state); + state->use_pending = false; + } else if(near) { + near->callback(canvas, state); + } +} + +void dolphin_scene_render(SceneState* state, Canvas* canvas, uint32_t t) { + furi_assert(state); + furi_assert(canvas); + + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorBlack); + const Item** current_scene = get_scene(state); + + for(uint8_t l = 0; l < LAYERS; l++) { + if(state->scene_zoom < SCENE_ZOOM) { + for(uint8_t i = 0; i < ITEMS_NUM; i++) { + int32_t item_pos = (current_scene[i]->x - state->player_global.x); + if(item_screen_bounds(item_pos)) { + if(current_scene[i]->draw) current_scene[i]->draw(canvas, state); + + if(l == current_scene[i]->layer) { + canvas_draw_icon_name( + canvas, + item_pos * PARALLAX(l), + current_scene[i]->y, + current_scene[i]->icon); + canvas_set_bitmap_mode(canvas, false); + } + } + } + + if(l == 0) canvas_draw_line(canvas, 0, 42, 128, 42); + } + + if(l == DOLPHIN_LAYER) dolphin_scene_render_dolphin(state, canvas); + } +} + +void dolphin_scene_render_dolphin_state(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + + char buf[64]; + + canvas_set_font(canvas, FontSecondary); + canvas_set_color(canvas, ColorBlack); + + // dolphin_scene_debug + if(state->debug) { + sprintf( + buf, + "x:%ld>%d %ld %s", + state->player_global.x, + state->poi, + state->action_timeout, + action_str[state->action]); + canvas_draw_str(canvas, 0, 13, buf); + } + + if(state->scene_zoom == SCENE_ZOOM) + draw_dialog(state, canvas); + else if(state->action == EMOTE) + draw_current_emote(state, canvas); + else if(state->action == MINDCONTROL) + draw_hint(state, canvas, state->action_timeout > 45); + else if(state->action == INTERACT) + activate_item_callback(state, canvas); + else if(state->action == SLEEP) + draw_sleep_emote(state, canvas); + /* + else if(state->action == IDLE) + draw_idle_emote(state, canvas); + */ +} \ No newline at end of file diff --git a/applications/dolphin_scene/state.c b/applications/dolphin_scene/state.c new file mode 100644 index 00000000..0e0680be --- /dev/null +++ b/applications/dolphin_scene/state.c @@ -0,0 +1,101 @@ +#include +#include "dolphin_scene/dolphin_scene.h" +#include "dolphin_scene/dolphin_emotes.h" + +static uint16_t roll_new(uint16_t prev, uint16_t max) { + uint16_t val = 999; + while(val != prev) { + val = random() % max; + break; + } + return val; +} + +static void dolphin_actions_proceed(SceneState* state) { + furi_assert(state); + + state->prev_action = state->action; + state->action = (state->prev_action != state->next_action) ? + state->next_action : + roll_new(state->next_action, ACTIONS_NUM); + state->action_timeout = default_timeout[state->action]; +} + +static void dolphin_go_to_poi(SceneState* state) { + furi_assert(state); + if(state->player_global.x < state->poi) { + state->player_flipped = false; + state->player_v.x = SPEED_X / 2; + } else if(state->player_global.x > state->poi) { + state->player_flipped = true; + state->player_v.x = -SPEED_X / 2; + } +} + +static void action_handler(SceneState* state) { + furi_assert(state); + if(state->action == MINDCONTROL && state->player_v.x != 0) { + state->action_timeout = default_timeout[state->action]; + } + + if(state->action_timeout > 0) { + state->action_timeout--; + } else { + if(random() % 1000 > 500) { + state->next_action = roll_new(state->prev_action, ACTIONS_NUM); + state->poi = roll_new(state->player_global.x, WORLD_WIDTH / 4); + } + } +} + +void dolphin_scene_update_dolphin_state(SceneState* state, uint32_t t, uint32_t dt) { + furi_assert(state); + action_handler(state); + + switch(state->action) { + case WALK: + if(state->player_global.x == state->poi) { + state->player_v.x = 0; + dolphin_actions_proceed(state); + } else { + dolphin_go_to_poi(state); + } + break; + case EMOTE: + state->player_flipped = false; + if(state->action_timeout == 0) { + dolphin_actions_proceed(state); + state->emote_id = roll_new(state->previous_emote, ARRSIZE(emotes_list)); + break; + } + case INTERACT: + if(state->action_timeout == 0) { + if(state->prev_action == MINDCONTROL) { + state->action = MINDCONTROL; + } else { + dolphin_actions_proceed(state); + } + } + break; + case SLEEP: + if(state->poi != 154) { // temp + state->poi = 154; + } else if(state->player_global.x != state->poi) { + dolphin_go_to_poi(state); + } else { + state->player_v.x = 0; + if(state->action_timeout == 0) { + state->poi = roll_new(state->player_global.x, WORLD_WIDTH / 4); + dolphin_actions_proceed(state); + } + break; + } + default: + if(state->action_timeout == 0) { + dolphin_actions_proceed(state); + } + break; + } + + UNUSED(dialogues_list); +} diff --git a/applications/dolphin_scene/user.c b/applications/dolphin_scene/user.c new file mode 100644 index 00000000..d54e7469 --- /dev/null +++ b/applications/dolphin_scene/user.c @@ -0,0 +1,111 @@ +#include +#include +#include "dolphin_scene/dolphin_scene.h" + +void dolphin_scene_render_dolphin(SceneState* state, Canvas* canvas) { + furi_assert(state); + furi_assert(canvas); + + if(state->scene_zoom == SCENE_ZOOM) { + state->dolphin_gfx = I_DolphinExcited_64x63; + } else if(state->action == SLEEP && state->player_global.x == 154) { + state->dolphin_gfx = A_FX_Sitting_40x27; + state->dolphin_gfx_b = I_FX_SittingB_40x27; + } else if(state->action != INTERACT) { + if(state->player_v.x < 0 || state->player_flipped) { + if(state->player_anim == 0) { + state->dolphin_gfx = I_WalkL1_32x32; + state->dolphin_gfx_b = I_WalkLB1_32x32; + + } else { + state->dolphin_gfx = I_WalkL2_32x32; + state->dolphin_gfx_b = I_WalkLB2_32x32; + } + } else if(state->player_v.x > 0 || !state->player_flipped) { + if(state->player_anim == 0) { + state->dolphin_gfx = I_WalkR1_32x32; + state->dolphin_gfx_b = I_WalkRB1_32x32; + + } else { + state->dolphin_gfx = I_WalkR2_32x32; + state->dolphin_gfx_b = I_WalkRB2_32x32; + } + } + } + + // zoom handlers + canvas_set_bitmap_mode(canvas, true); + canvas_set_color(canvas, ColorWhite); + canvas_draw_icon_name(canvas, state->player.x, state->player.y, state->dolphin_gfx_b); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon_name(canvas, state->player.x, state->player.y, state->dolphin_gfx); + canvas_set_bitmap_mode(canvas, false); +} + +void dolphin_scene_handle_user_input(SceneState* state, InputEvent* input) { + furi_assert(state); + furi_assert(input); + + // dolphin_scene_debug + if(input->type == InputTypeShort) { + if(input->key == InputKeyUp) { + state->debug = !state->debug; + } + } + // toggle mind control on any user interaction + if(input->type == InputTypePress) { + if(input->key == InputKeyLeft || input->key == InputKeyRight || input->key == InputKeyOk) { + state->action = MINDCONTROL; + } + } + // zoom poc for tests + if(input->type == InputTypePress) { + if(input->key == InputKeyDown) { + state->zoom_v = SPEED_X; + } + } else if(input->type == InputTypeRelease) { + if(input->key == InputKeyDown) { + state->zoom_v = -SPEED_X * 2; + state->dialog_progress = 0; + } + } + // mind control + if(state->action == MINDCONTROL) { + if(input->type == InputTypePress) { + if(input->key == InputKeyRight) { + state->player_flipped = false; + state->player_v.x = SPEED_X; + } else if(input->key == InputKeyLeft) { + state->player_flipped = true; + state->player_v.x = -SPEED_X; + } + } else if(input->type == InputTypeRelease) { + if(input->key == InputKeyRight || input->key == InputKeyLeft) { + state->player_v.x = 0; + } + } else if(input->type == InputTypeShort) { + if(input->key == InputKeyOk) { + state->prev_action = MINDCONTROL; + state->action = INTERACT; + state->use_pending = true; + state->action_timeout = 0; + } + } + } +} + +void dolphin_scene_coordinates(SceneState* state, uint32_t dt) { + furi_assert(state); + + // global pos + state->player_global.x = CLAMP(state->player_global.x + state->player_v.x, WORLD_WIDTH, 0); + + // zoom handlers + state->scene_zoom = CLAMP(state->scene_zoom + state->zoom_v, SCENE_ZOOM, 0); + state->player.x = CLAMP(state->player.x - (state->zoom_v * (SPEED_X * 2)), DOLPHIN_CENTER, 0); + state->player.y = CLAMP(state->player.y - (state->zoom_v * SPEED_X / 2), DOLPHIN_DEFAULT_Y, 3); + + //center screen + state->screen.x = state->player_global.x - state->player.x; + state->player_anim = (state->player_global.x / 10) % 2; +} \ No newline at end of file diff --git a/applications/gui/canvas.c b/applications/gui/canvas.c index 0bb61b19..843f64be 100644 --- a/applications/gui/canvas.c +++ b/applications/gui/canvas.c @@ -250,3 +250,7 @@ void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch) { y += canvas->offset_y; u8g2_DrawGlyph(&canvas->fb, x, y, ch); } + +void canvas_set_bitmap_mode(Canvas* canvas, bool alpha) { + u8g2_SetBitmapMode(&canvas->fb, alpha ? 1 : 0); +} diff --git a/applications/gui/canvas.h b/applications/gui/canvas.h index c3a04ed5..0ed6be9f 100644 --- a/applications/gui/canvas.h +++ b/applications/gui/canvas.h @@ -147,6 +147,11 @@ void canvas_draw_disc(Canvas* canvas, uint8_t x, uint8_t y, uint8_t r); */ void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch); +/* + * Set transparency mode + */ +void canvas_set_bitmap_mode(Canvas* canvas, bool alpha); + #ifdef __cplusplus } #endif diff --git a/applications/gui/elements.c b/applications/gui/elements.c index 8881ff06..981bde2a 100644 --- a/applications/gui/elements.c +++ b/applications/gui/elements.c @@ -5,6 +5,7 @@ #include #include "canvas_i.h" #include +#include void elements_scrollbar(Canvas* canvas, uint8_t pos, uint8_t total) { furi_assert(canvas); diff --git a/applications/gui/elements.h b/applications/gui/elements.h index 421e7a50..4f765604 100644 --- a/applications/gui/elements.h +++ b/applications/gui/elements.h @@ -68,6 +68,14 @@ void elements_multiline_text(Canvas* canvas, uint8_t x, uint8_t y, const char* t */ void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const char* text); +/* + * Draw framed multiline text + * @param x, y - top left corner coordinates + * @param text - string (possible multiline) + */ + +void elements_multiline_text_framed(Canvas* canvas, uint8_t x, uint8_t y, const char* text); + /* * Draw slightly rounded frame * @param x, y - top left corner coordinates diff --git a/applications/gui/icon.c b/applications/gui/icon.c index a0cc2505..b3e58b39 100644 --- a/applications/gui/icon.c +++ b/applications/gui/icon.c @@ -48,6 +48,11 @@ bool icon_is_animated(Icon* icon) { return icon->data->frame_count > 1; } +bool icon_is_animating(Icon* icon) { + furi_assert(icon); + return icon->tick > 0; +} + void icon_start_animation(Icon* icon) { furi_assert(icon); icon->tick = osKernelGetTickCount(); diff --git a/applications/gui/icon.h b/applications/gui/icon.h index d9d14c94..73465023 100644 --- a/applications/gui/icon.h +++ b/applications/gui/icon.h @@ -36,6 +36,11 @@ uint8_t icon_get_height(Icon* icon); */ bool icon_is_animated(Icon* icon); +/* + * Check if icon animation is active + */ +bool icon_is_animating(Icon* icon); + /* * Start icon animation */ diff --git a/applications/passport/passport.c b/applications/passport/passport.c new file mode 100644 index 00000000..8973183f --- /dev/null +++ b/applications/passport/passport.c @@ -0,0 +1,122 @@ +#include +#include +#include + +typedef enum { + EventTypeTick, + EventTypeKey, +} EventType; + +typedef struct { + union { + InputEvent input; + } value; + EventType type; +} AppEvent; + +typedef struct { +} State; + +static void input_callback(InputEvent* input_event, void* ctx) { + osMessageQueueId_t event_queue = ctx; + AppEvent event; + event.type = EventTypeKey; + event.value.input = *input_event; + osMessageQueuePut(event_queue, &event, 0, osWaitForever); +} + +static void render_callback(Canvas* canvas, void* ctx) { + State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); + + /* + + char level[20]; + uint32_t current_level = dolphin_state_get_level(dolphin->state); + uint32_t prev_cap = dolphin_state_xp_to_levelup(dolphin->state, current_level - 1, false); + uint32_t exp = (dolphin_state_xp_to_levelup(dolphin->state, current_level, true) * 63) / + (dolphin_state_xp_to_levelup(dolphin->state, current_level, false) - prev_cap); + */ + canvas_clear(canvas); + + // multipass + canvas_draw_icon_name(canvas, 0, 0, I_PassportLeft_6x47); + canvas_draw_icon_name(canvas, 0, 47, I_PassportBottom_128x17); + canvas_draw_line(canvas, 6, 0, 125, 0); + canvas_draw_line(canvas, 127, 2, 127, 47); + canvas_draw_dot(canvas, 126, 1); + + //portrait frame + canvas_draw_line(canvas, 9, 6, 9, 53); + canvas_draw_line(canvas, 10, 5, 52, 5); + canvas_draw_line(canvas, 55, 8, 55, 53); + canvas_draw_line(canvas, 10, 54, 54, 54); + canvas_draw_line(canvas, 53, 5, 55, 7); + + // portrait + canvas_draw_icon_name(canvas, 14, 11, I_DolphinOkay_41x43); + canvas_draw_line(canvas, 59, 18, 124, 18); + canvas_draw_line(canvas, 59, 31, 124, 31); + canvas_draw_line(canvas, 59, 44, 124, 44); + + canvas_draw_str(canvas, 59, 15, api_hal_version_get_name_ptr()); + canvas_draw_str(canvas, 59, 28, "Mood: OK"); + /* + snprintf(level, 20, "Level: %ld", current_level); + + canvas_draw_str(canvas, 59, 41, level); + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 123 - exp, 48, exp + 1, 6); + canvas_set_color(canvas, ColorBlack); + canvas_draw_line(canvas, 123 - exp, 48, 123 - exp, 54); + */ + + release_mutex((ValueMutex*)ctx, state); +} + +int32_t passport(void* p) { + State _state; + ValueMutex state_mutex; + + osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL); + furi_check(event_queue); + + if(!init_mutex(&state_mutex, &_state, sizeof(State))) { + printf("cannot create mutex\r\n"); + return 0; + } + + ViewPort* view_port = view_port_alloc(); + + view_port_draw_callback_set(view_port, render_callback, &state_mutex); + view_port_input_callback_set(view_port, input_callback, event_queue); + + Gui* gui = furi_record_open("gui"); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + AppEvent event; + while(1) { + State* state = (State*)acquire_mutex_block(&state_mutex); + osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 25); + if(event_status == osOK) { + if(event.type == EventTypeKey && event.value.input.type == InputTypeShort) { + release_mutex(&state_mutex, state); + break; + } + } + + view_port_update(view_port); + release_mutex(&state_mutex, state); + } + + gui_remove_view_port(gui, view_port); + + view_port_free(view_port); + + furi_record_close("gui"); + + delete_mutex(&state_mutex); + + osMessageQueueDelete(event_queue); + + return 0; +} diff --git a/assets/icons/Animations/FX_Sitting_40x27/frame_0.png b/assets/icons/Animations/FX_Sitting_40x27/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..22e3d38dbe98a03bea016e52bf04ab272d26ecad GIT binary patch literal 369 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<~#0(^h>s0>&DVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C-zl@CkAK{~yR=0Fno9 zYkdN;7)yfuf*Bm1-ADs*lDyqr7&=&GJ%Akc5>H=O_NUCUd~7o6-pmJpLJ^)Wjv*44 z&z?KTdBA|9HL>-{x(RPCH!we0@O%BGCrh_!o3Q_!AkTBLUaoqTm3ph&rt{^er@V12 z6G>Zr%rBJt#Ppd{H+3G&XjMKWp3QS7XSYkknv>s`|9rrfbcI9R_)`GT2Mnqut`Q|E zi6yC4$wjF^iowXh$WYh7Sl7rh#L&dbz{JYXSlhtB%D_Nkm$o#DhTQy=%(O~O4F={A V4S`JCwSXEJJYD@<);T3K0RZuwarOWJ literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/FX_Sitting_40x27/frame_1.png b/assets/icons/Animations/FX_Sitting_40x27/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2438be9eefedd2b304ace7bcd3098e14acf9919b GIT binary patch literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<~#0(^h>s0>&DVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C-zl@CkAK{~yR=`2YX^ zo0~`Lfh@+7AirP+hi5m^K%69RcNeBK?wS-JhrPtp*OmP#vn(H*jJh}T0iaO0r;B5V z#O1T+4ssqa;Al;3eX?%Co6AkiPZs=Mf9c86joK#cKPSlZT&$P-9aw57;`MFflRMuO zZgXvpOkTc<^~vcoUXe!?)FK#IZ0z{pV7z*yJFGQ`lt%D}|R&{*5Rz{NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPphjS*yd$K(_mNx;TbNTux2^ z0-n?chHDoB*bSUTj&ZmqHDn&Ua6v%gFk`5&b_l13xsm4Si9NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR(00uFf)+tuAVNAArhC9 z6C4<>32^92Nxfo7W?5hq;q0u~C6UN8LB`QdBd<;4O3H$ZFL>Nm7=JL75a3y%#}+tA zA|T$NBf)^hrGbS(@TEw`0jXL^pn<9-t`Q|Ei6yC4$wjF^iowXh$WYh7Sl7rR#K6?b v$O4G84GgRd3@j#h=%Z-J%}>cptHjh`Xb#a}$mu>4sDZ)L)z4*}Q$iB}yWm>s literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDIB_32x32/frame_2.png b/assets/icons/Animations/MDIB_32x32/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce5a67d19a898572ac46e6736964d62616ad74c GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR(00uFf)+tuAVNAArhC9 z6C4<>32^92Nxfo7W?5hq;q0u~C6UN8LB`QdBd<;4O3H$ZFL>Nm7=JL75a3y%#}+tA zA|T$NBf)^hrGbS(@TEw`0jXL^pn<9-t`Q|Ei6yC4$wjF^iowXh$WYh7Sl7rR#K6?b v$O4G84GgRd3@j#h=%Z-J%}>cptHjh`Xb#a}$mu>4sDZ)L)z4*}Q$iB}yWm>s literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDIB_32x32/frame_3.png b/assets/icons/Animations/MDIB_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b5def708a48a12977841ed90fb264465cc4dcb1a GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR(00uFf)+t-kvUwArhC9 z6C9X&76!CsWUOGGA=q^;fyHP+mb3E#p0F807S1B8SPpU=JuAS=o6wNuo^IfD_VDop z2Lq;rKJ`vPrqqrE0~VJC7KTmfqDp(7s{kF!pjzS@QIe8al4_M)lnSI6j0}tnbq$Pl zjVwY8Os$M8fJocGz{ CieGL3 literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDIB_32x32/frame_rate b/assets/icons/Animations/MDIB_32x32/frame_rate new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/assets/icons/Animations/MDIB_32x32/frame_rate @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/assets/icons/Animations/MDI_32x32/frame_0.png b/assets/icons/Animations/MDI_32x32/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..b71622f688e1007a39cfc1692661ebf3ebb9c47c GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpg2HF)-OOaKa{db&7Kv&p=yb1L`h0wNvc(HQ7VvPFfuSQ)HN{HHL?gXFtsu=w=y==HZZUNSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR#gq2{Tvg3LTR2Zjv*44 zr=IubI-tPAa)I-OUE>!!wp)9c>YW8@VDNPHb6Mw<&;$U9hj>r` literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDI_32x32/frame_2.png b/assets/icons/Animations/MDI_32x32/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f58938a9475b50771958338c305c87d5758aa156 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR#gq2{Tvg3LTR2Zjv*44 zr=IubI-tPAa)I-OUE>!!wp)9c>YW8@VDNPHb6Mw<&;$U9hj>r` literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDI_32x32/frame_3.png b/assets/icons/Animations/MDI_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..24fbf7774a08109f25990b18e4f97b95cdffe6ba GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aR#gq2{Tvg3LMfgujv*44 zr=IuaYH;9SeV~3L?%+FP=F9tzmi%8W@-Jjd_JoIz7d9PueQ~0J%vnRp#U^rX)bZq z;zP%Q_NkV*MwFx^mZVxG7o`Fz1|tI_LtO)7T_cMS15+y_b1P#*Z36=<1A_^xroBhe fkei>9nO2FZ!3e5BH&*W~Py>UftDnm{r-UW|kEC;) literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDI_32x32/frame_rate b/assets/icons/Animations/MDI_32x32/frame_rate new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/assets/icons/Animations/MDI_32x32/frame_rate @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/assets/icons/Animations/MDWLB_32x32/frame_1.png b/assets/icons/Animations/MDWLB_32x32/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..e26b3a53a3745499c82b15b6e3ba686c5b0f870c GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRs~iQ@dXQjLf)P(jv*44 zlM@`67V;%@8Jd`|9OH0JHDHhwa9y;J<0_*>kAM@~#zT_p0!-Je33$s>z@~hK>kkjx z3_S_u77n&Hy&aZ4>ozNSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRs~iQ@dXQjLLr_mjv*44 zYtQZGJ)pqDa$&QGTY~(oFCzQ?hI2B>H!2+MjW7Ji;Jxun+7j+NjctObYA%0m(6&7& z`}&nd*>Q_W35Ad3FHCt5|Ae_J{m`lg6SH`S!^~05Vi|G=m`?)DS1oakC`m~yNwrEY zN(E93Mg~TPx(3F&MiwCkrdEa)R)&_^1_o9J2A!RcDp54#=BH$)Rbpx|Fo9?YU1>cV PsDZ)L)z4*}Q$iB}jSg-6 literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWLB_32x32/frame_3.png b/assets/icons/Animations/MDWLB_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..ad269276343f638c0ed32b039f6fa0d1ed4f03cf GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNSWUziEC31xdAc};NL-$J z#!#rifrI&gh4Nn3KhNhSF#iAFwc?52`XH{fZWRUr-sif4)(>4`9NLe1_?uQ9xNq={ zea(WP8%qvF?k+FdRm*Tg=@0uF=kyn|-ZLEX7qt*sw|hF!bk!2qh?11Vl2ohYqEsNo zU}RuqsB2)XYh)2(U}|M(VP$BkZD3$!V9?q5s1ij(ZhlH;S|z3i0~3gb(3RG+ff^V* MUHx3vIVCg!0DISJ{r~^~ literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWLB_32x32/frame_rate b/assets/icons/Animations/MDWLB_32x32/frame_rate new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/assets/icons/Animations/MDWLB_32x32/frame_rate @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/assets/icons/Animations/MDWL_32x32/frame_1.png b/assets/icons/Animations/MDWL_32x32/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..4b0bd151494798ee309c6d73753fda4c42195ba1 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRyom()YUtILg}6^jv*44 zdoMV09Z=w5Ilz0Qy5+}wkvDtWzx|J2Y1%nu-YyP4?+FSYPNjZc#Qmzl#9eyc#!9za zk_)&BH?XcMFxl(AINFTwTw2c$AI&NSt$Ow)VlOy7Bb3CL^*``m(a%Uc|Gq+O599Yw zoZ{#A{I&&JsaoP1QIe8al4_M)lnSI6j0}tnbq$PljVwY8Osx#ftW3$QYvG%p;@QKn)C@u6{1-oD!M<>^pZ3 literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWL_32x32/frame_2.png b/assets/icons/Animations/MDWL_32x32/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..fe8e32c335a408219f4ffa43c8225922538d8290 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRyom()YUtILb;wUjv*44 zQ_o-II-tP88o>Jf-GYC|58N}4`2Sy9Y6EkfC q11kdq%@=FjQ8eV{r(~v8VrnolhG;nR$mlju1B0ilpUXO@geCxst$ZW^ literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWL_32x32/frame_3.png b/assets/icons/Animations/MDWL_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..c63a48fe028d9393f27fb84e164433973ba238ec GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPphzL^D!X?*s~^db&7$>73sc9@cgo;rRG(^%1r?O0g^a{xBv;m2KhlYcMsuz`S8qY&N?>1b|I9_}a zv-tzGP_@K0q9i4;B-JXpC>2OC7#SED>KYj98d-!Gm|7W{S(%t=8yHv_7-+s&NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRt2SrvZAMfLOz}@jv*44 zlM@`6dKLz>Wn`>io*~$EE`h~pL6)=g0iLiKLKe;<&4OLMf()U;5)4=67}5{SdF(LZ zU_%1S0U3W5Ws%8@#_9sc3RnagB=<-#&Ht_=0W?>JNMC9x#cD!C{XNHG{07#Zps z80#8Ygcz7w85vj^m}wgTNdwEcEx%DTgTe~ HDWM4ftx#Xc literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWRB_32x32/frame_2.png b/assets/icons/Animations/MDWRB_32x32/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..3b70ca8914e5f2595097426e0410ea6ea3336f6c GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRt2SrvZAMfLP4G`jv*44 zThAHtH5l+PJEWgDcj^BZPS;ic|BD86DtfUS-A!<3yClin`-XeX2I+}UV+vg3wy><& zySQcUas!j)|C!|5j=i5DI&0#C^UBg34D1Dr6)Ix?{+(xY1DdW{;u=wsl30>zm0Xkx zq!^40j0|-RjCGAHLJUl;j0~&{%(M-Fq=9AJmft8Ea`RI%(<;$47+PAHnnN@kPIid_ PYGCkm^>bP0l+XkKpebuM literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWRB_32x32/frame_3.png b/assets/icons/Animations/MDWRB_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..444dceae586b8d1f1bdcb46fbba3bf872fb84636 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNlqSlGo(2kqdb&7V@B~4I%e}`qT32OC z7#SED>KYj98d-!Gm|7VbSQ(gU8vscI%eXDSQ8eV{r(~v8qG>R+v@$h^XgHkg5(Cu0 N;OXk;vd$@?2>|{iV`TsU literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWRB_32x32/frame_rate b/assets/icons/Animations/MDWRB_32x32/frame_rate new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/assets/icons/Animations/MDWRB_32x32/frame_rate @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/assets/icons/Animations/MDWR_32x32/frame_1.png b/assets/icons/Animations/MDWR_32x32/frame_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e355a1fb8f873a4ea8c499612b07b725bd0310 GIT binary patch literal 380 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRz;5By>DZHLdl*kjv*44 zd(Sv>9Z=wLxyZTXH^(@ifG# z%fAO&r&{6~QIe8al4_M)lnSI6j0}tnbq$PljVwY8Osxzptqcvd4GgRd3__P2S3uE_ fo1c=IR*9*>z!aiEMkZPisDZ)L)z4*}Q$iB}EKhRR literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWR_32x32/frame_2.png b/assets/icons/Animations/MDWR_32x32/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..522f12179761ab90fb7d0bebedda80e65aa0b9e7 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRz;5By>DZHLOGr;jv*44 zQ_lx-H7E$MT!_5!FLuLkjVtwycmHdhe3udU=(uw^8*7}mp3-BjzGWODChb4U)|_2< zBgsXTb<(tknXd6?r&jnq^WoF^nbNOn*KRH#eSuLiKy8N8FX#O$jDplR>IbT@*WXdE z`p0H>f&0tecjh2>sg}4#l%ynwV0|P4q ngU}_%6;L$f=BH$)Rbpx|FokH4k%<-rYGCkm^>bP0l+XkKTzqz> literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWR_32x32/frame_3.png b/assets/icons/Animations/MDWR_32x32/frame_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b01e463eb9d35f323580cdded1934c16f8a694d2 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNIfD1TjR6X!dAc};NL-$J z?jYv@2M(44qB;%-zZ5fa?>N5nf0$5-e*d3G#~lU58J;*zeFVdQ&MBb@0RK92ng9R* literal 0 HcmV?d00001 diff --git a/assets/icons/Animations/MDWR_32x32/frame_rate b/assets/icons/Animations/MDWR_32x32/frame_rate new file mode 100644 index 00000000..9a037142 --- /dev/null +++ b/assets/icons/Animations/MDWR_32x32/frame_rate @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/assets/icons/Dolphin/FX_Bang_32x6.png b/assets/icons/Dolphin/FX_Bang_32x6.png new file mode 100644 index 0000000000000000000000000000000000000000..d842e48f2abfa4569d52e1bf68266ae06b975d15 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^3P8-p#0(_wKP>S9QY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes65fIC7!;n>`$3xxvhD^?$7)P6w>i@aSY+O zo-B~Sk&u$W>Lkb}=*F(VnA9Y}$kW5OhKG-_hmS`=mB)ckhJhiejX6V3%%}*cPqoA~ zq9i4;B-JXpC>2OC7#SED>KYj98d-)I8d{lJS{WK?8yHv_7^r)1@k7y&o1c=IR*9*> Xzzm`x@3TfdPy>UftDnm{r-UW|jlNFt literal 0 HcmV?d00001 diff --git a/assets/icons/Dolphin/FX_SittingB_40x27.png b/assets/icons/Dolphin/FX_SittingB_40x27.png new file mode 100644 index 0000000000000000000000000000000000000000..e95651119a4c64603830ea92cf4657c9409006ae GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^8bB<~#0(^h>s0>&DVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C-zl@CkAK{~yR=0Fno9 zYkdN;7)yfuf*Bm1-ADs*lDyqr7&=&GJ%Akc5>H=O_NUCUe5^cz7ah`pLXMs;jv*44 zlM^It8Vp&ECGqmM8oF*Yl6>g1Kp`YrLxAPLkp(_(0^ExlL=Uo@Zf|KgdVonuVX8oK zgu^FB4)cRE7+$Ot(3+#41avNgYKdz^NlIc#s#S7PDv)9@GB7gKH89pSvJ5dau`)2R uGBMURFt9Q(2#8XxN70a*pOTqYiK)TZ45Fd(*X~-N1_n=8KbLh*2~7ZU^j!}C literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/Home_painting_17x20.png b/assets/icons/Scenes/Home_painting_17x20.png new file mode 100644 index 0000000000000000000000000000000000000000..6732243625207ebd6f6074188f8a31cd6a06afe9 GIT binary patch literal 1007 zcmaJ=PiWIn7!MX?R(9|YiX!8gF;TEdUfO0&SR8B8xnfgFSFr;Rrpa3yw&ca+&1M@a zc<|3j@gkmf5b?Hy9z6^Mg?aEOY_NmgyeM8gI$yfB^I#1m-}gSg-|zdr_xLnq{3y7m{H0LM|%u93a!BLiGw{5Gnx&&L{ye`x;KLB_i4SbdrkDh z_{j8m$O-XCy+p(Kf2!;DvqMrv`~CitIIJ!Eh_9j$F9jA|-27-<%2%`inFI$lj2C;i zSZQH`!xr{|C~|3V-Y_l4iz6305W`T4UPw&OLPcF=DGBE|wo=fhq`Z(z=OifyVIeQ; zl9DBXxTPKgL3yB9;?w(nPrL*@B8DG~n4d-dH^m=Gyb0nWU vIyZ-2eBAi1d}$sY`>^^g`|JJZtB;ukbNe0hW;?qhQf8)DDC_I_8~6SIzm_|a literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/PC_22x29.png b/assets/icons/Scenes/PC_22x29.png new file mode 100644 index 0000000000000000000000000000000000000000..644b5148dab74315188cc897072ea28dc33c4512 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^Vn8g*#0(@a%a&vVDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C-zl@CkAK{~yR=0Fno9 zYkdN;7)yfuf*Bm1-ADs*lDyqr7&=&GJ%Akc5>H=O_NUBpf}HI7m2(|{Lg}6^jv*Y^ zL;Egr9Z=wKT_5nC?^V6jnsWBf|Lar3rE`K`thnguaOa@L0ft?><0Bmz%<9(VMPFd7 z4g7aOe^r~%rvm|p#ri}H`z(@nxc%`zl{0z59-UJvXWpFpdtriD@=oK&bG;WFzhoYL zU%)?R{)KX&m8vDK5hW>!C8<`)MX5lF!N|bKP}jg%*VrJ$(A>(v!phW4+rYrez`*#i j^K29ix%nxXX_c57OrRS2M1JoCYGCkm^>bP0l+XkKi5Gc4 literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/Sofa_40x13.png b/assets/icons/Scenes/Sofa_40x13.png new file mode 100644 index 0000000000000000000000000000000000000000..606955207d18ce567261b084ef72541e8c8d8a05 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^8Xz_kGmu>N@klk0Vo7)Ob!1@J*w6hZkrl{SNcITw zWnidMV_;}#VPNo55CTlyt3bXjkBu0rRDw3D1l9*~|OS-ZfD@{{) zk>=|=`QEMT)*HRMd7sbz60g}SymGF^C+Qyc?mX%5dseO01sbnf;u=wsl30>zm0Xkx zq!^40j0|-RjCGC7LJUo<49%=e%(M**tPBjMr0$-Dq9HdwB{QuOQ-iT7M8iE%fki+K N44$rjF6*2UngDXkY6}1W literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/TV_20x20.png b/assets/icons/Scenes/TV_20x20.png new file mode 100644 index 0000000000000000000000000000000000000000..9af8d1b6384c545390a96c6b65ad9dccb3a78dae GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAf3?x51|2hvyv7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpaf@tPl)UP|3DT4kUV%> z>l2X0SQ6wH%;50sMjD8d21sKV_EUHsWqs*S`oT?)FK#IZ0z{pV7 zz*yJFEX2^z%ES_gv<(cb3=EV`glVB@$jwj5OsmAA!4RS$p=!ZLpaup{S3j3^P6H=O_NUD90_w5}NeM1Mp)gMu#}JO| zsXdNd42nF=$}jFV{q1M3jz9S4zxJ}Y>C+6BI5&3Q>0?@urSR&MThQL8iD6sRe+ZXx zsVX$LDTJr&O8h)0An&VH*ZHoL&-TYX@RXxdPT_vpbe@et`Q|Ei6yC4 z$wjF^iowXh$WYh7Sl8Gv#L&#j*wV_-MBBi?%D_PNg=8{{hTQy=%(O~$4Hj0W<`4~h TSMRj}H86O(`njxgN@xNAyxndc literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkL1_32x32.png b/assets/icons/Scenes/WalkL1_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..fe8e32c335a408219f4ffa43c8225922538d8290 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRyom()YUtILb;wUjv*44 zQ_o-II-tP88o>Jf-GYC|58N}4`2Sy9Y6EkfC q11kdq%@=FjQ8eV{r(~v8VrnolhG;nR$mlju1B0ilpUXO@geCxst$ZW^ literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkL2_32x32.png b/assets/icons/Scenes/WalkL2_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..c63a48fe028d9393f27fb84e164433973ba238ec GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPphzL^D!X?*s~^db&7$>73sc9@cgo;rRG(^%1r?O0g^a{xBv;m2KhlYcMsuz`S8qY&N?>1b|I9_}a zv-tzGP_@K0q9i4;B-JXpC>2OC7#SED>KYj98d-!Gm|7W{S(%t=8yHv_7-+s&NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRs~iQ@dXQjLLr_mjv*44 zYtQZGJ)pqDa$&QGTY~(oFCzQ?hI2B>H!2+MjW7Ji;Jxun+7j+NjctObYA%0m(6&7& z`}&nd*>Q_W35Ad3FHCt5|Ae_J{m`lg6SH`S!^~05Vi|G=m`?)DS1oakC`m~yNwrEY zN(E93Mg~TPx(3F&MiwCkrdEa)R)&_^1_o9J2A!RcDp54#=BH$)Rbpx|Fo9?YU1>cV PsDZ)L)z4*}Q$iB}jSg-6 literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkLB2_32x32.png b/assets/icons/Scenes/WalkLB2_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..ad269276343f638c0ed32b039f6fa0d1ed4f03cf GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNSWUziEC31xdAc};NL-$J z#!#rifrI&gh4Nn3KhNhSF#iAFwc?52`XH{fZWRUr-sif4)(>4`9NLe1_?uQ9xNq={ zea(WP8%qvF?k+FdRm*Tg=@0uF=kyn|-ZLEX7qt*sw|hF!bk!2qh?11Vl2ohYqEsNo zU}RuqsB2)XYh)2(U}|M(VP$BkZD3$!V9?q5s1ij(ZhlH;S|z3i0~3gb(3RG+ff^V* MUHx3vIVCg!0DISJ{r~^~ literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkR1_32x32.png b/assets/icons/Scenes/WalkR1_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..522f12179761ab90fb7d0bebedda80e65aa0b9e7 GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRz;5By>DZHLOGr;jv*44 zQ_lx-H7E$MT!_5!FLuLkjVtwycmHdhe3udU=(uw^8*7}mp3-BjzGWODChb4U)|_2< zBgsXTb<(tknXd6?r&jnq^WoF^nbNOn*KRH#eSuLiKy8N8FX#O$jDplR>IbT@*WXdE z`p0H>f&0tecjh2>sg}4#l%ynwV0|P4q ngU}_%6;L$f=BH$)Rbpx|FokH4k%<-rYGCkm^>bP0l+XkKTzqz> literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkR2_32x32.png b/assets/icons/Scenes/WalkR2_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..b01e463eb9d35f323580cdded1934c16f8a694d2 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNIfD1TjR6X!dAc};NL-$J z?jYv@2M(44qB;%-zZ5fa?>N5nf0$5-e*d3G#~lU58J;*zeFVdQ&MBb@0RK92ng9R* literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkRB1_32x32.png b/assets/icons/Scenes/WalkRB1_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..3b70ca8914e5f2595097426e0410ea6ea3336f6c GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTkj3!-|Nl2P zkJbZOj3q&S!3+-1Zlr-YN#5=*OljOTDL@W;iKnkC`%`8aRt2SrvZAMfLP4G`jv*44 zThAHtH5l+PJEWgDcj^BZPS;ic|BD86DtfUS-A!<3yClin`-XeX2I+}UV+vg3wy><& zySQcUas!j)|C!|5j=i5DI&0#C^UBg34D1Dr6)Ix?{+(xY1DdW{;u=wsl30>zm0Xkx zq!^40j0|-RjCGAHLJUl;j0~&{%(M-Fq=9AJmft8Ea`RI%(<;$47+PAHnnN@kPIid_ PYGCkm^>bP0l+XkKpebuM literal 0 HcmV?d00001 diff --git a/assets/icons/Scenes/WalkRB2_32x32.png b/assets/icons/Scenes/WalkRB2_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..444dceae586b8d1f1bdcb46fbba3bf872fb84636 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!5QEa;`;wTki`Hb58l@L z1Y|Lm1o;IsI6S+N2I3@nySp%Su*!M>IqW5#zOL*~nPpfNlqSlGo(2kqdb&7V@B~4I%e}`qT32OC z7#SED>KYj98d-!Gm|7VbSQ(gU8vscI%eXDSQ8eV{r(~v8qG>R+v@$h^XgHkg5(Cu0 N;OXk;vd$@?2>|{iV`TsU literal 0 HcmV?d00001