[FL-1090] Dolphin scenes (#402)
* 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 <who.just.the.doctor@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
| @ -33,6 +33,8 @@ int32_t sd_filesystem(void* p); | |||||||
| int32_t subghz_app(void* p); | int32_t subghz_app(void* p); | ||||||
| int32_t gui_test(void* p); | int32_t gui_test(void* p); | ||||||
| int32_t keypad_test(void* p); | int32_t keypad_test(void* p); | ||||||
|  | int32_t dolphin_scene(void* p); | ||||||
|  | int32_t passport(void* p); | ||||||
| 
 | 
 | ||||||
| const FlipperApplication FLIPPER_SERVICES[] = { | const FlipperApplication FLIPPER_SERVICES[] = { | ||||||
| #ifdef APP_CLI | #ifdef APP_CLI | ||||||
| @ -146,6 +148,11 @@ const FlipperApplication FLIPPER_SERVICES[] = { | |||||||
| #ifdef APP_KEYPAD_TEST | #ifdef APP_KEYPAD_TEST | ||||||
|     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, |     {.app = keypad_test, .name = "keypad_test", .icon = A_Plugins_14}, | ||||||
| #endif | #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); | 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); | 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 | ||||||
|  | |||||||
| @ -27,3 +27,10 @@ extern const size_t FLIPPER_APPS_COUNT; | |||||||
|  */ |  */ | ||||||
| extern const FlipperApplication FLIPPER_PLUGINS[]; | extern const FlipperApplication FLIPPER_PLUGINS[]; | ||||||
| extern const size_t FLIPPER_PLUGINS_COUNT; | 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; | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ APP_BT = 1 | |||||||
| APP_CLI = 1 | APP_CLI = 1 | ||||||
| APP_SD_FILESYSTEM = 1 | APP_SD_FILESYSTEM = 1 | ||||||
| BUILD_IRDA  = 1 | BUILD_IRDA  = 1 | ||||||
|  | BUILD_DOLPHIN_SCENE = 1 | ||||||
| APP_DOLPHIN = 1 | APP_DOLPHIN = 1 | ||||||
| BUILD_EXAMPLE_BLINK = 1 | BUILD_EXAMPLE_BLINK = 1 | ||||||
| BUILD_EXAMPLE_UART_WRITE = 1 | BUILD_EXAMPLE_UART_WRITE = 1 | ||||||
| @ -227,7 +228,6 @@ C_SOURCES	+= $(APP_DIR)/examples/keypad_test.c | |||||||
| BUILD_KEYPAD_TEST = 1 | BUILD_KEYPAD_TEST = 1 | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| APP_GPIO_DEMO ?= 0 | APP_GPIO_DEMO ?= 0 | ||||||
| ifeq ($(APP_GPIO_DEMO), 1) | ifeq ($(APP_GPIO_DEMO), 1) | ||||||
| CFLAGS		+= -DAPP_GPIO_DEMO | CFLAGS		+= -DAPP_GPIO_DEMO | ||||||
| @ -261,6 +261,18 @@ CFLAGS		+= -DBUILD_FLOOPPER_BLOOPPER | |||||||
| C_SOURCES	+= $(wildcard $(APP_DIR)/floopper-bloopper/*.c) | C_SOURCES	+= $(wildcard $(APP_DIR)/floopper-bloopper/*.c) | ||||||
| endif | 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 | APP_IBUTTON ?= 0 | ||||||
| ifeq ($(APP_IBUTTON), 1) | ifeq ($(APP_IBUTTON), 1) | ||||||
| CFLAGS		+= -DAPP_IBUTTON | CFLAGS		+= -DAPP_IBUTTON | ||||||
|  | |||||||
| @ -1,5 +1,19 @@ | |||||||
| #include "dolphin_i.h" | #include "dolphin_i.h" | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | #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
 | // temporary main screen animation managment
 | ||||||
| void dolphin_scene_handler_set_scene(Dolphin* dolphin, IconName icon) { | 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) { |             } else if(event->key == InputKeyLeft) { | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleUp); |                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleUp); | ||||||
|             } else if(event->key == InputKeyRight) { |             } 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) { |             } else if(event->key == InputKeyDown) { | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDown); |                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDown); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             if(event->key == InputKeyBack) { |             if(event->key == InputKeyBack) { | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |                 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_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|         view_port_enabled_set(dolphin->lock_viewport, true); |         view_port_enabled_set(dolphin->lock_viewport, true); | ||||||
|         break; |         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: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| @ -145,59 +145,6 @@ static void lock_icon_callback(Canvas* canvas, void* context) { | |||||||
|     canvas_draw_icon(canvas, 0, 0, dolphin->lock_icon); |     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) { | bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(event); |     furi_assert(event); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -244,51 +191,6 @@ bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { | |||||||
|     return true; |     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_alloc() { | ||||||
|     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); |     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); | ||||||
|     // Message queue
 |     // Message queue
 | ||||||
| @ -298,8 +200,15 @@ Dolphin* dolphin_alloc() { | |||||||
|     dolphin->state = dolphin_state_alloc(); |     dolphin->state = dolphin_state_alloc(); | ||||||
|     // Menu
 |     // Menu
 | ||||||
|     dolphin->menu_vm = furi_record_open("menu"); |     dolphin->menu_vm = furi_record_open("menu"); | ||||||
|  |     // Scene thread
 | ||||||
|  |     dolphin->scene_thread = furi_thread_alloc(); | ||||||
|  | 
 | ||||||
|     // GUI
 |     // GUI
 | ||||||
|  |     dolphin->gui = furi_record_open("gui"); | ||||||
|  | 
 | ||||||
|  |     // Dispatcher
 | ||||||
|     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); |     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); | ||||||
|  | 
 | ||||||
|     // First start View
 |     // First start View
 | ||||||
|     dolphin->idle_view_first_start = view_alloc(); |     dolphin->idle_view_first_start = view_alloc(); | ||||||
|     view_allocate_model( |     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_set_input_callback(dolphin->idle_view_first_start, dolphin_view_first_start_input); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewFirstStart, dolphin->idle_view_first_start); |         dolphin->idle_view_dispatcher, DolphinViewFirstStart, dolphin->idle_view_first_start); | ||||||
|  | 
 | ||||||
|     // Main Idle View
 |     // Main Idle View
 | ||||||
|     dolphin->idle_view_main = view_alloc(); |     dolphin->idle_view_main = view_alloc(); | ||||||
|     view_set_context(dolphin->idle_view_main, dolphin); |     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_set_input_callback(dolphin->idle_view_main, dolphin_view_idle_main_input); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); |         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); | ||||||
|  | 
 | ||||||
|     // Stats Idle View
 |     // Stats Idle View
 | ||||||
|     dolphin->idle_view_up = view_alloc(); |     dolphin->idle_view_up = view_alloc(); | ||||||
|     view_set_context(dolphin->idle_view_up, dolphin); |     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_set_previous_callback(dolphin->idle_view_up, dolphin_view_idle_back); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleUp, dolphin->idle_view_up); |         dolphin->idle_view_dispatcher, DolphinViewIdleUp, dolphin->idle_view_up); | ||||||
|  | 
 | ||||||
|     // Lock Menu View
 |     // Lock Menu View
 | ||||||
|     dolphin->view_lockmenu = view_alloc(); |     dolphin->view_lockmenu = view_alloc(); | ||||||
|     view_set_context(dolphin->view_lockmenu, dolphin); |     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_set_previous_callback(dolphin->view_lockmenu, dolphin_view_idle_back); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewLockMenu, dolphin->view_lockmenu); |         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
 |     // Down Idle View
 | ||||||
|     dolphin->idle_view_down = view_alloc(); |     dolphin->idle_view_down = view_alloc(); | ||||||
|     view_set_draw_callback(dolphin->idle_view_down, dolphin_view_idle_down_draw); |     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_set_previous_callback(dolphin->idle_view_down, dolphin_view_idle_back); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down); |         dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down); | ||||||
|  | 
 | ||||||
|     // HW Mismatch
 |     // HW Mismatch
 | ||||||
|     dolphin->view_hw_mismatch = view_alloc(); |     dolphin->view_hw_mismatch = view_alloc(); | ||||||
|     view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); |     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_draw_callback_set(dolphin->lock_viewport, lock_icon_callback, dolphin); | ||||||
|     view_port_enabled_set(dolphin->lock_viewport, false); |     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
 |     // Main screen animation
 | ||||||
|     dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % sizeof(idle_scenes)]); |     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; |     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) { | void dolphin_save(Dolphin* dolphin) { | ||||||
|     furi_assert(dolphin); |     furi_assert(dolphin); | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
| @ -400,13 +326,6 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | |||||||
| int32_t dolphin_task() { | int32_t dolphin_task() { | ||||||
|     Dolphin* dolphin = dolphin_alloc(); |     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)) { |     if(dolphin_state_load(dolphin->state)) { | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|     } else { |     } else { | ||||||
| @ -439,5 +358,6 @@ int32_t dolphin_task() { | |||||||
|             dolphin_state_save(dolphin->state); |             dolphin_state_save(dolphin->state); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     dolphin_free(dolphin); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -33,7 +33,10 @@ struct Dolphin { | |||||||
|     DolphinState* state; |     DolphinState* state; | ||||||
|     // Menu
 |     // Menu
 | ||||||
|     ValueMutex* menu_vm; |     ValueMutex* menu_vm; | ||||||
|  |     // Scene
 | ||||||
|  |     FuriThread* scene_thread; | ||||||
|     // GUI
 |     // GUI
 | ||||||
|  |     Gui* gui; | ||||||
|     ViewDispatcher* idle_view_dispatcher; |     ViewDispatcher* idle_view_dispatcher; | ||||||
|     View* idle_view_first_start; |     View* idle_view_first_start; | ||||||
|     View* idle_view_main; |     View* idle_view_main; | ||||||
| @ -42,7 +45,6 @@ struct Dolphin { | |||||||
|     View* idle_view_meta; |     View* idle_view_meta; | ||||||
|     View* view_hw_mismatch; |     View* view_hw_mismatch; | ||||||
|     View* view_lockmenu; |     View* view_lockmenu; | ||||||
|     ViewPort* passport; |  | ||||||
|     ViewPort* lock_viewport; |     ViewPort* lock_viewport; | ||||||
|     Icon* lock_icon; |     Icon* lock_icon; | ||||||
| 
 | 
 | ||||||
| @ -55,6 +57,8 @@ const IconName idle_scenes[] = {A_Wink_128x64, A_WatchingTV_128x64}; | |||||||
| 
 | 
 | ||||||
| Dolphin* dolphin_alloc(); | Dolphin* dolphin_alloc(); | ||||||
| 
 | 
 | ||||||
|  | void dolphin_free(Dolphin* dolphin); | ||||||
|  | 
 | ||||||
| /* Save Dolphin state (write to permanent memory)
 | /* Save Dolphin state (write to permanent memory)
 | ||||||
|  * Thread safe |  * Thread safe | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ DolphinState* dolphin_state_alloc() { | |||||||
|     return dolphin_state; |     return dolphin_state; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dolphin_state_release(DolphinState* dolphin_state) { | void dolphin_state_free(DolphinState* dolphin_state) { | ||||||
|     free(dolphin_state); |     free(dolphin_state); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ typedef struct DolphinState DolphinState; | |||||||
| 
 | 
 | ||||||
| DolphinState* dolphin_state_alloc(); | 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); | bool dolphin_state_save(DolphinState* dolphin_state); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ | |||||||
| #include <api-hal.h> | #include <api-hal.h> | ||||||
| 
 | 
 | ||||||
| static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"}; | 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) { | void dolphin_view_first_start_draw(Canvas* canvas, void* model) { | ||||||
|     DolphinViewFirstStartModel* m = 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) { | void dolphin_view_idle_main_draw(Canvas* canvas, void* model) { | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     DolphinViewMainModel* m = model; |     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) { | 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) { | void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|  | |||||||
| @ -8,13 +8,12 @@ | |||||||
| 
 | 
 | ||||||
| // Idle scree
 | // Idle scree
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DolphinViewFirstStart, |  | ||||||
|     DolphinViewIdleMain, |     DolphinViewIdleMain, | ||||||
|  |     DolphinViewFirstStart, | ||||||
|     DolphinViewIdleUp, |     DolphinViewIdleUp, | ||||||
|     DolphinViewIdleDown, |     DolphinViewIdleDown, | ||||||
|     DolphinViewHwMismatch, |     DolphinViewHwMismatch, | ||||||
|     DolphinViewLockMenu, |     DolphinViewLockMenu, | ||||||
|     DolphinViewIdleMeta, |  | ||||||
| } DolphinViewIdle; | } DolphinViewIdle; | ||||||
| 
 | 
 | ||||||
| typedef struct { | 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_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); | void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model); | ||||||
| 
 | 
 | ||||||
| uint32_t dolphin_view_idle_back(void* context); | uint32_t dolphin_view_idle_back(void* context); | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								applications/dolphin_scene/dolphin_emotes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -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..", | ||||||
|  | }; | ||||||
							
								
								
									
										31
									
								
								applications/dolphin_scene/dolphin_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,31 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #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); | ||||||
|  | } | ||||||
							
								
								
									
										141
									
								
								applications/dolphin_scene/dolphin_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,141 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <u8g2/u8g2.h> | ||||||
|  | 
 | ||||||
|  | #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); | ||||||
							
								
								
									
										115
									
								
								applications/dolphin_scene/engine.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,115 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #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; | ||||||
|  | } | ||||||
							
								
								
									
										131
									
								
								applications/dolphin_scene/items.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,131 @@ | |||||||
|  | #include "dolphin_scene/items_i.h" | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #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]); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								applications/dolphin_scene/items.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,5 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "dolphin_scene/dolphin_scene.h" | ||||||
|  | 
 | ||||||
|  | const Item* is_nearby(SceneState* state); | ||||||
|  | const Item** get_scene(SceneState* state); | ||||||
							
								
								
									
										8
									
								
								applications/dolphin_scene/items_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -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); | ||||||
							
								
								
									
										172
									
								
								applications/dolphin_scene/scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,172 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "dolphin_scene/dolphin_scene.h" | ||||||
|  | #include "dolphin_scene/dolphin_emotes.h" | ||||||
|  | #include "dolphin_scene/items.h" | ||||||
|  | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  |     */ | ||||||
|  | } | ||||||
							
								
								
									
										101
									
								
								applications/dolphin_scene/state.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,101 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #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); | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								applications/dolphin_scene/user.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,111 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #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; | ||||||
|  | } | ||||||
| @ -250,3 +250,7 @@ void canvas_draw_glyph(Canvas* canvas, uint8_t x, uint8_t y, uint16_t ch) { | |||||||
|     y += canvas->offset_y; |     y += canvas->offset_y; | ||||||
|     u8g2_DrawGlyph(&canvas->fb, x, y, ch); |     u8g2_DrawGlyph(&canvas->fb, x, y, ch); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void canvas_set_bitmap_mode(Canvas* canvas, bool alpha) { | ||||||
|  |     u8g2_SetBitmapMode(&canvas->fb, alpha ? 1 : 0); | ||||||
|  | } | ||||||
|  | |||||||
| @ -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); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include "canvas_i.h" | #include "canvas_i.h" | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <stdint.h> | ||||||
| 
 | 
 | ||||||
| void elements_scrollbar(Canvas* canvas, uint8_t pos, uint8_t total) { | void elements_scrollbar(Canvas* canvas, uint8_t pos, uint8_t total) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|  | |||||||
| @ -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); | 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 |  * Draw slightly rounded frame | ||||||
|  * @param x, y - top left corner coordinates |  * @param x, y - top left corner coordinates | ||||||
|  | |||||||
| @ -48,6 +48,11 @@ bool icon_is_animated(Icon* icon) { | |||||||
|     return icon->data->frame_count > 1; |     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) { | void icon_start_animation(Icon* icon) { | ||||||
|     furi_assert(icon); |     furi_assert(icon); | ||||||
|     icon->tick = osKernelGetTickCount(); |     icon->tick = osKernelGetTickCount(); | ||||||
|  | |||||||
| @ -36,6 +36,11 @@ uint8_t icon_get_height(Icon* icon); | |||||||
|  */ |  */ | ||||||
| bool icon_is_animated(Icon* icon); | bool icon_is_animated(Icon* icon); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Check if icon animation is active | ||||||
|  |  */ | ||||||
|  | bool icon_is_animating(Icon* icon); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Start icon animation |  * Start icon animation | ||||||
|  */ |  */ | ||||||
|  | |||||||
							
								
								
									
										122
									
								
								applications/passport/passport.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,122 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <api-hal-version.h> | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/FX_Sitting_40x27/frame_0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 369 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/FX_Sitting_40x27/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 368 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/FX_Sitting_40x27/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDIB_32x32/frame_0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 359 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDIB_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 350 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDIB_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 350 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDIB_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 356 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDIB_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDI_32x32/frame_0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 382 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDI_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 383 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDI_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 383 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDI_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 381 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDI_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWLB_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 356 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWLB_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 365 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWLB_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 363 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDWLB_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWL_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 384 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWL_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 390 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWL_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 382 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDWL_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWRB_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 357 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWRB_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 363 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWRB_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 366 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDWRB_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWR_32x32/frame_1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 380 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWR_32x32/frame_2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 389 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Animations/MDWR_32x32/frame_3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 383 B | 
							
								
								
									
										1
									
								
								assets/icons/Animations/MDWR_32x32/frame_rate
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | |||||||
|  | 10 | ||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Dolphin/FX_Bang_32x6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 325 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Dolphin/FX_SittingB_40x27.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 346 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/Home_painting_17x20.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1007 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/PC_22x29.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 384 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/Sofa_40x13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 364 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/TV_20x20.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 356 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/TV_20x24.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 367 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkL1_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 390 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkL2_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 382 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkLB1_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 365 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkLB2_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 363 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkR1_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 389 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkR2_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 383 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkRB1_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 363 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Scenes/WalkRB2_32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 366 B | 
 its your bedtime
						its your bedtime