[FL-1995] New dolphin animations (part 1) (#835)

* Desktop Animation (part 1): Ugly naked ohmygod architecture
* fix butthurt, fix locked scene
* Change SD icons, fixes
* Fix level update animation
* Fixes, correct butthurt
* Clean up code
* furi_assert(0) -> furi_crash("msg")
* Gui: rename none layer to desktop, update docs.

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Albert Kharisov
2021-11-24 20:21:12 +04:00
committed by GitHub
parent 92c499b41b
commit 9b8a139e2b
235 changed files with 1869 additions and 661 deletions

View File

@@ -1,28 +1,365 @@
#include "desktop_animation.h"
#include "desktop/helpers/desktop_animation.h"
#include "assets_icons.h"
#include "desktop_animation_i.h"
#include "cmsis_os2.h"
#include "furi/common_defines.h"
#include "furi/record.h"
#include "storage/filesystem-api-defines.h"
#include <power/power_service/power.h>
#include <m-list.h>
#include <storage/storage.h>
#include <desktop/desktop.h>
#include <dolphin/dolphin.h>
#define TAG "DesktopAnimation"
LIST_DEF(AnimationList, const PairedAnimation*, M_PTR_OPLIST)
#define M_OPL_AnimationList_t() LIST_OPLIST(AnimationList)
static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64};
#define PUSH_BACK_ANIMATIONS(listname, animations, butthurt) \
for(int i = 0; i < COUNT_OF(animations); ++i) { \
if(!(animations)[i].basic->butthurt_level_mask || \
((animations)[i].basic->butthurt_level_mask & BUTTHURT_LEVEL(butthurt))) { \
AnimationList_push_back(animation_list, &(animations)[i]); \
} \
}
const Icon* desktop_get_icon() {
uint8_t new = 0;
#define IS_BLOCKING_ANIMATION(x) \
(((x) != DesktopAnimationStateBasic) && ((x) != DesktopAnimationStateActive))
#define IS_ONESHOT_ANIMATION(x) ((x) == DesktopAnimationStateLevelUpIsPending)
#if 0
// checking dolphin state here to choose appropriate animation
static void desktop_animation_timer_callback(void* context);
struct DesktopAnimation {
bool sd_shown_error_db;
bool sd_shown_error_card_bad;
osTimerId_t timer;
const PairedAnimation* current;
const Icon* current_blocking_icon;
const Icon** current_one_shot_icons;
uint8_t one_shot_animation_counter;
uint8_t one_shot_animation_size;
DesktopAnimationState state;
TickType_t basic_started_at;
TickType_t active_finished_at;
AnimationChangedCallback animation_changed_callback;
void* animation_changed_callback_context;
};
DesktopAnimation* desktop_animation_alloc(void) {
DesktopAnimation* animation = furi_alloc(sizeof(DesktopAnimation));
animation->timer = osTimerNew(
desktop_animation_timer_callback, osTimerPeriodic /* osTimerOnce */, animation, NULL);
animation->active_finished_at = (TickType_t)(-30);
animation->basic_started_at = 0;
animation->animation_changed_callback = NULL;
animation->animation_changed_callback_context = NULL;
desktop_start_new_idle_animation(animation);
return animation;
}
void desktop_animation_free(DesktopAnimation* animation) {
furi_assert(animation);
osTimerDelete(animation->timer);
free(animation);
}
void desktop_animation_set_animation_changed_callback(
DesktopAnimation* animation,
AnimationChangedCallback callback,
void* context) {
furi_assert(animation);
animation->animation_changed_callback = callback;
animation->animation_changed_callback_context = context;
}
void desktop_start_new_idle_animation(DesktopAnimation* animation) {
Dolphin* dolphin = furi_record_open("dolphin");
DolphinStats stats = dolphin_stats(dolphin);
furi_record_close("dolphin");
furi_assert((stats.level >= 1) && (stats.level <= 3));
uint8_t level = stats.level;
AnimationList_t animation_list;
AnimationList_init(animation_list);
PUSH_BACK_ANIMATIONS(animation_list, mad_animation, stats.butthurt);
PUSH_BACK_ANIMATIONS(animation_list, calm_animation, stats.butthurt);
switch(level) {
case 1:
PUSH_BACK_ANIMATIONS(animation_list, level_1_animation, stats.butthurt);
break;
case 2:
PUSH_BACK_ANIMATIONS(animation_list, level_2_animation, stats.butthurt);
break;
case 3:
PUSH_BACK_ANIMATIONS(animation_list, level_3_animation, stats.butthurt);
break;
default:
furi_crash("Dolphin level is out of bounds");
}
Power* power = furi_record_open("power");
PowerInfo info;
power_get_info(power, &info);
if(!power_is_battery_well(&info)) {
PUSH_BACK_ANIMATIONS(animation_list, check_battery_animation, stats.butthurt);
}
Storage* storage = furi_record_open("storage");
FS_Error sd_status = storage_sd_status(storage);
animation->current = NULL;
if(sd_status == FSE_NOT_READY) {
PUSH_BACK_ANIMATIONS(animation_list, no_sd_animation, stats.butthurt);
animation->sd_shown_error_card_bad = false;
animation->sd_shown_error_db = false;
}
uint32_t whole_weight = 0;
for
M_EACH(item, animation_list, AnimationList_t) {
whole_weight += (*item)->basic->weight;
}
uint32_t lucky_number = random() % whole_weight;
uint32_t weight = 0;
const PairedAnimation* selected = NULL;
for
M_EACH(item, animation_list, AnimationList_t) {
if(lucky_number < weight) {
break;
}
weight += (*item)->basic->weight;
selected = *item;
}
animation->basic_started_at = osKernelGetTickCount();
animation->current = selected;
osTimerStart(animation->timer, animation->current->basic->duration * 1000);
animation->state = DesktopAnimationStateBasic;
furi_assert(selected);
AnimationList_clear(animation_list);
}
static void desktop_animation_timer_callback(void* context) {
furi_assert(context);
DesktopAnimation* animation = context;
TickType_t now_ms = osKernelGetTickCount();
AnimationList_t animation_list;
AnimationList_init(animation_list);
bool new_basic_animation = false;
if(animation->state == DesktopAnimationStateActive) {
animation->state = DesktopAnimationStateBasic;
TickType_t basic_lasts_ms = now_ms - animation->basic_started_at;
animation->active_finished_at = now_ms;
TickType_t basic_duration_ms = animation->current->basic->duration * 1000;
if(basic_lasts_ms > basic_duration_ms) {
// if active animation finished, and basic duration came to an end
// select new idle animation
new_basic_animation = true;
} else {
// if active animation finished, but basic duration is not finished
// play current animation for the rest of time
furi_assert(basic_duration_ms != basic_lasts_ms);
osTimerStart(animation->timer, basic_duration_ms - basic_lasts_ms);
}
} else if(animation->state == DesktopAnimationStateBasic) {
// if basic animation finished
// select new idle animation
new_basic_animation = true;
}
if(new_basic_animation) {
animation->basic_started_at = now_ms;
desktop_start_new_idle_animation(animation);
}
// for oneshot generate events every time
if(animation->animation_changed_callback) {
animation->animation_changed_callback(animation->animation_changed_callback_context);
}
}
void desktop_animation_activate(DesktopAnimation* animation) {
furi_assert(animation);
if(animation->state != DesktopAnimationStateBasic) {
return;
}
if(animation->state == DesktopAnimationStateActive) {
return;
}
if(!animation->current->active) {
return;
}
TickType_t now = osKernelGetTickCount();
TickType_t time_since_last_active = now - animation->active_finished_at;
if(time_since_last_active > (animation->current->basic->active_cooldown * 1000)) {
animation->state = DesktopAnimationStateActive;
furi_assert(animation->current->active->duration > 0);
osTimerStart(animation->timer, animation->current->active->duration * 1000);
if(animation->animation_changed_callback) {
animation->animation_changed_callback(animation->animation_changed_callback_context);
}
}
}
static const Icon* desktop_animation_get_current_idle_animation(DesktopAnimation* animation) {
const Icon* active_icon = animation->current->active->icon;
const Icon* basic_icon = animation->current->basic->icon;
return (animation->state == DesktopAnimationStateActive && active_icon) ? active_icon :
basic_icon;
}
// Every time somebody starts 'desktop_animation_get_animation()'
// 1) check if there is a new level
// 2) check if there is SD card corruption
// 3) check if the SD card is empty
// 4) if all false - get idle animation
const Icon* desktop_animation_get_animation(DesktopAnimation* animation) {
Dolphin* dolphin = furi_record_open("dolphin");
Storage* storage = furi_record_open("storage");
const Icon* icon = NULL;
furi_assert(animation);
FS_Error sd_status = storage_sd_status(storage);
if(IS_BLOCKING_ANIMATION(animation->state)) {
// don't give new animation till blocked animation
// is reseted
icon = animation->current_blocking_icon;
}
if(!icon) {
if(sd_status == FSE_INTERNAL) {
osTimerStop(animation->timer);
icon = &A_CardBad_128x51;
animation->current_blocking_icon = icon;
animation->state = DesktopAnimationStateSDCorrupted;
animation->sd_shown_error_card_bad = true;
animation->sd_shown_error_db = false;
} else if(sd_status == FSE_NOT_READY) {
animation->sd_shown_error_card_bad = false;
animation->sd_shown_error_db = false;
} else if(sd_status == FSE_OK) {
bool db_exists = storage_common_stat(storage, "/ext/manifest.txt", NULL) == FSE_OK;
if(db_exists && !animation->sd_shown_error_db) {
osTimerStop(animation->timer);
icon = &A_CardNoDB_128x51;
animation->current_blocking_icon = icon;
animation->state = DesktopAnimationStateSDEmpty;
animation->sd_shown_error_db = true;
}
}
}
DolphinStats stats = dolphin_stats(dolphin);
if(!icon && stats.level_up_is_pending) {
osTimerStop(animation->timer);
icon = &A_LevelUpPending_128x51;
animation->current_blocking_icon = icon;
animation->state = DesktopAnimationStateLevelUpIsPending;
}
if(!icon) {
icon = desktop_animation_get_current_idle_animation(animation);
}
furi_record_close("storage");
furi_record_close("dolphin");
return icon;
}
DesktopAnimationState desktop_animation_handle_right(DesktopAnimation* animation) {
furi_assert(animation);
bool reset_animation = false;
bool update_animation = false;
switch(animation->state) {
case DesktopAnimationStateActive:
case DesktopAnimationStateBasic:
/* nothing */
break;
case DesktopAnimationStateLevelUpIsPending:
/* do nothing, main scene should change itself */
break;
case DesktopAnimationStateSDCorrupted:
reset_animation = true;
break;
case DesktopAnimationStateSDEmpty:
animation->state = DesktopAnimationStateSDEmptyURL;
animation->current_blocking_icon = &A_CardNoDBUrl_128x51;
update_animation = true;
break;
case DesktopAnimationStateSDEmptyURL:
reset_animation = true;
break;
default:
furi_crash("Unhandled desktop animation state");
}
if(reset_animation) {
desktop_start_new_idle_animation(animation);
update_animation = true;
}
if(update_animation) {
if(animation->animation_changed_callback) {
animation->animation_changed_callback(animation->animation_changed_callback_context);
}
}
return animation->state;
}
#define LEVELUP_FRAME_RATE (0.2)
void desktop_animation_start_oneshot_levelup(DesktopAnimation* animation) {
animation->one_shot_animation_counter = 0;
animation->state = DesktopAnimationStateLevelUpIsPending;
Dolphin* dolphin = furi_record_open("dolphin");
DolphinStats stats = dolphin_stats(dolphin);
float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp()));
furi_record_close("dolphin");
furi_assert(stats.level_up_is_pending);
if(stats.level == 1) {
animation->current_one_shot_icons = animation_level2up;
animation->one_shot_animation_size = COUNT_OF(animation_level2up);
} else if(stats.level == 2) {
animation->current_one_shot_icons = animation_level3up;
animation->one_shot_animation_size = COUNT_OF(animation_level3up);
} else {
furi_crash("Dolphin level is out of bounds");
}
osTimerStart(animation->timer, LEVELUP_FRAME_RATE * 1000);
}
FURI_LOG_I(TAG, "background change");
FURI_LOG_I(TAG, "icounter: %d", stats.icounter);
FURI_LOG_I(TAG, "butthurt: %d", stats.butthurt);
FURI_LOG_I(TAG, "time since deeed: %.0f", timediff);
#endif
const Icon* desktop_animation_get_oneshot_frame(DesktopAnimation* animation) {
furi_assert(IS_ONESHOT_ANIMATION(animation->state));
furi_assert(animation->one_shot_animation_size > 0);
const Icon* icon = NULL;
if((random() % 100) > 50) { // temp rnd selection
new = random() % COUNT_OF(idle_scenes);
if(animation->one_shot_animation_counter < animation->one_shot_animation_size) {
icon = animation->current_one_shot_icons[animation->one_shot_animation_counter];
++animation->one_shot_animation_counter;
} else {
animation->state = DesktopAnimationStateBasic;
animation->one_shot_animation_size = 0;
osTimerStop(animation->timer);
icon = NULL;
}
return idle_scenes[new];
return icon;
}

View File

@@ -1,10 +1,55 @@
#pragma once
#include <furi.h>
#include <math.h>
#include <assets_icons.h>
#include "dolphin/dolphin.h"
#include "dolphin/helpers/dolphin_state.h"
#include "time.h"
#include <stdint.h>
#include <gui/icon.h>
const Icon* desktop_get_icon();
typedef struct DesktopAnimation DesktopAnimation;
typedef struct ActiveAnimation ActiveAnimation;
typedef struct BasicAnimation BasicAnimation;
typedef enum {
DesktopAnimationStateBasic,
DesktopAnimationStateActive,
DesktopAnimationStateLevelUpIsPending,
DesktopAnimationStateSDEmpty,
DesktopAnimationStateSDEmptyURL,
DesktopAnimationStateSDCorrupted,
} DesktopAnimationState;
struct BasicAnimation {
const Icon* icon;
uint16_t duration; // sec
uint16_t active_cooldown;
uint8_t weight;
uint16_t butthurt_level_mask;
};
struct ActiveAnimation {
const Icon* icon;
uint16_t duration; // sec
};
typedef struct {
const BasicAnimation* basic;
const ActiveAnimation* active;
} PairedAnimation;
typedef void (*AnimationChangedCallback)(void*);
DesktopAnimation* desktop_animation_alloc(void);
void desktop_animation_free(DesktopAnimation*);
void desktop_animation_activate(DesktopAnimation* instance);
void desktop_animation_set_animation_changed_callback(
DesktopAnimation* instance,
AnimationChangedCallback callback,
void* context);
DesktopAnimationState desktop_animation_handle_right(DesktopAnimation* animation);
void desktop_animation_start_oneshot_levelup(DesktopAnimation* animation);
const Icon* desktop_animation_get_animation(DesktopAnimation* animation);
const Icon* desktop_animation_get_oneshot_frame(DesktopAnimation* animation);
void desktop_start_new_idle_animation(DesktopAnimation* animation);

View File

@@ -0,0 +1,330 @@
#include <assets_icons.h>
#include <stddef.h>
#include <stdint.h>
#include <gui/icon.h>
#include "desktop_animation.h"
// Calm/Mad Basic Idle Animations
#define COMMON_BASIC_DURATION (60 * 60)
#define COMMON_ACTIVE_CYCLES 7
#define COMMON_ACTIVE_COOLDOWN 30
#define COMMON_WEIGHT 3
#define BUTTHURT_LEVEL(x) (1UL << (x))
#define BUTTHURT_LEVEL_0 0
// frames * cycles / frame_rate
#define COMMON_ACTIVE_DURATION(x) ((x)*COMMON_ACTIVE_CYCLES / 2)
static const BasicAnimation animation_TV = {
.icon = &A_TV_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7)};
static const ActiveAnimation animation_TV_active = {
.icon = &A_TVActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_sleep = {
.icon = &A_Sleep_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8) |
BUTTHURT_LEVEL(9) | BUTTHURT_LEVEL(10)};
static const ActiveAnimation animation_sleep_active = {
.icon = &A_SleepActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_leaving = {
.icon = &A_Leaving_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(13) | BUTTHURT_LEVEL(14),
};
static const ActiveAnimation animation_leaving_active = {
.icon = &A_LeavingActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_laptop = {
.icon = &A_Laptop_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5)};
static const ActiveAnimation animation_laptop_active = {
.icon = &A_LaptopActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_knife = {
.icon = &A_Knife_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(5) | BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) |
BUTTHURT_LEVEL(8) | BUTTHURT_LEVEL(9) | BUTTHURT_LEVEL(10) |
BUTTHURT_LEVEL(11) | BUTTHURT_LEVEL(12) | BUTTHURT_LEVEL(13)};
static const ActiveAnimation animation_knife_active = {
.icon = &A_KnifeActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_cry = {
.icon = &A_Cry_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8) |
BUTTHURT_LEVEL(9) | BUTTHURT_LEVEL(10) | BUTTHURT_LEVEL(11) |
BUTTHURT_LEVEL(12) | BUTTHURT_LEVEL(13)};
static const ActiveAnimation animation_cry_active = {
.icon = &A_CryActive_128x51,
.duration = COMMON_ACTIVE_DURATION(3),
};
static const BasicAnimation animation_box = {
.icon = &A_Box_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8) | BUTTHURT_LEVEL(9) |
BUTTHURT_LEVEL(10) | BUTTHURT_LEVEL(11) | BUTTHURT_LEVEL(12) |
BUTTHURT_LEVEL(13)};
static const ActiveAnimation animation_box_active = {
.icon = &A_BoxActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_waves = {
.icon = &A_Waves_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2)};
static const ActiveAnimation animation_waves_active = {
.icon = &A_WavesActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
// Level Idle Animations
static const BasicAnimation animation_level1furippa = {
.icon = &A_Level1Furippa_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7)};
static const ActiveAnimation animation_level1furippa_active = {
.icon = &A_Level1FurippaActive_128x51,
.duration = COMMON_ACTIVE_DURATION(6),
};
static const BasicAnimation animation_level1read = {
.icon = &A_Level1Read_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2)};
static const ActiveAnimation animation_level1read_active = {
.icon = &A_Level1ReadActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_level1toys = {
.icon = &A_Level1Toys_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8)};
static const ActiveAnimation animation_level1toys_active = {
.icon = &A_Level1ToysActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_level2furippa = {
.icon = &A_Level2Furippa_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7)};
static const ActiveAnimation animation_level2furippa_active = {
.icon = &A_Level2FurippaActive_128x51,
.duration = COMMON_ACTIVE_DURATION(6),
};
static const BasicAnimation animation_level2soldering = {
.icon = &A_Level2Soldering_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8) |
BUTTHURT_LEVEL(9)};
static const ActiveAnimation animation_level2soldering_active = {
.icon = &A_Level2SolderingActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_level2hack = {
.icon = &A_Level2Hack_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8)};
static const ActiveAnimation animation_level2hack_active = {
.icon = &A_Level2HackActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_level3furippa = {
.icon = &A_Level3Furippa_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7)};
static const ActiveAnimation animation_level3furippa_active = {
.icon = &A_Level3FurippaActive_128x51,
.duration = COMMON_ACTIVE_DURATION(6),
};
static const BasicAnimation animation_level3hijack = {
.icon = &A_Level3Hijack_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8) |
BUTTHURT_LEVEL(9)};
static const ActiveAnimation animation_level3hijack_active = {
.icon = &A_Level3HijackActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
static const BasicAnimation animation_level3lab = {
.icon = &A_Level3Lab_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = COMMON_WEIGHT,
.active_cooldown = COMMON_ACTIVE_COOLDOWN,
.butthurt_level_mask = BUTTHURT_LEVEL(0) | BUTTHURT_LEVEL(1) | BUTTHURT_LEVEL(2) |
BUTTHURT_LEVEL(3) | BUTTHURT_LEVEL(4) | BUTTHURT_LEVEL(5) |
BUTTHURT_LEVEL(6) | BUTTHURT_LEVEL(7) | BUTTHURT_LEVEL(8)};
static const ActiveAnimation animation_level3lab_active = {
.icon = &A_Level3LabActive_128x51,
.duration = COMMON_ACTIVE_DURATION(2),
};
// System Idle Animations
static const BasicAnimation animation_bad_battery = {
.icon = &A_BadBattery_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = 7,
};
static const BasicAnimation animation_no_sd_card = {
.icon = &A_NoSdCard_128x51,
.duration = COMMON_BASIC_DURATION,
.weight = 7,
};
const Icon* animation_level2up[] = {
&I_LevelUp2_01,
&I_LevelUp2_02,
&I_LevelUp2_03,
&I_LevelUp2_04,
&I_LevelUp2_05,
&I_LevelUp2_06,
&I_LevelUp2_07};
const Icon* animation_level3up[] = {
&I_LevelUp3_01,
&I_LevelUp3_02,
&I_LevelUp3_03,
&I_LevelUp3_04,
&I_LevelUp3_05,
&I_LevelUp3_06,
&I_LevelUp3_07};
// Blocking Idle Animations & One shot Animations represented as naked Icon
static const PairedAnimation calm_animation[] = {
{.basic = &animation_TV, .active = &animation_TV_active},
{.basic = &animation_waves, .active = &animation_waves_active},
{.basic = &animation_sleep, .active = &animation_sleep_active},
{.basic = &animation_laptop, .active = &animation_laptop_active},
};
static const PairedAnimation mad_animation[] = {
{.basic = &animation_cry, .active = &animation_cry_active},
{.basic = &animation_knife, .active = &animation_knife_active},
{.basic = &animation_box, .active = &animation_box_active},
{.basic = &animation_leaving, .active = &animation_leaving_active},
};
static const PairedAnimation level_1_animation[] = {
{.basic = &animation_level1furippa, .active = &animation_level1furippa_active},
{.basic = &animation_level1read, .active = &animation_level1read_active},
{.basic = &animation_level1toys, .active = &animation_level1toys_active},
};
static const PairedAnimation level_2_animation[] = {
{.basic = &animation_level2furippa, .active = &animation_level2furippa_active},
{.basic = &animation_level2soldering, .active = &animation_level2soldering_active},
{.basic = &animation_level2hack, .active = &animation_level2hack_active},
};
static const PairedAnimation level_3_animation[] = {
{.basic = &animation_level3furippa, .active = &animation_level3furippa_active},
{.basic = &animation_level3hijack, .active = &animation_level3hijack_active},
{.basic = &animation_level3lab, .active = &animation_level3lab_active},
};
static const PairedAnimation no_sd_animation[] = {
{.basic = &animation_no_sd_card, .active = NULL},
};
static const PairedAnimation check_battery_animation[] = {
{.basic = &animation_bad_battery, .active = NULL},
};