RogueLife/src/anim.c

160 lines
4.1 KiB
C

#include "anim.h"
#include <gint/display.h>
#include <gint/defs/util.h>
/* Definition of simple and direction animations. */
#define ANIM1(name) \
extern anim_frame_t frames_ ## name[]; \
anim_t anims_ ## name = { 1, { frames_ ## name }};
#define ANIM_2DIRECTIONAL(prefix, suffix) \
extern anim_frame_t frames_ ## prefix ## _left ## suffix[]; \
extern anim_frame_t frames_ ## prefix ## _right ## suffix[]; \
anim_t anims_ ## prefix ## suffix = { 2, { \
frames_ ## prefix ## _left ## suffix, \
frames_ ## prefix ## _right ## suffix, \
}}; \
#define ANIM_4DIRECTIONAL(prefix, suffix) \
extern anim_frame_t frames_ ## prefix ## _up ## suffix[]; \
extern anim_frame_t frames_ ## prefix ## _right ## suffix[]; \
extern anim_frame_t frames_ ## prefix ## _down ## suffix[]; \
extern anim_frame_t frames_ ## prefix ## _left ## suffix[]; \
anim_t anims_ ## prefix ## suffix = { 4, { \
frames_ ## prefix ## _up ## suffix, \
frames_ ## prefix ## _right ## suffix, \
frames_ ## prefix ## _down ## suffix, \
frames_ ## prefix ## _left ## suffix, \
}};
/* Make suffix optional */
#define ANIM2(prefix, ...) \
ANIM_2DIRECTIONAL(prefix, __VA_OPT__(_ ## __VA_ARGS__))
#define ANIM4(prefix, ...) \
ANIM_4DIRECTIONAL(prefix, __VA_OPT__(_ ## __VA_ARGS__))
/* Basic skills */
ANIM1(skill_hit);
ANIM2(skill_projectile);
ANIM1(skill_teleport);
ANIM1(skill_shock);
ANIM1(skill_judgement);
ANIM1(skill_launch);
/* Directional skills */
ANIM4(skill_swing);
ANIM4(skill_impale);
ANIM4(skill_bullet);
ANIM4(skill_magic);
/* Enemies */
ANIM_ENEMIES(ANIM2)
/* Player */
ANIM4(player, Idle);
ANIM4(player, Walking);
ANIM4(player, Attack);
ANIM4(player, Hit);
ANIM4(player, KO);
ANIM4(player, IdleKO);
/* HUD */
ANIM1(hud_xp_Idle);
ANIM1(hud_xp_Shine);
ANIM1(hud_xp_Explode);
ANIM1(hud_backpack_Idle);
ANIM1(hud_backpack_Open);
ANIM1(hud_backpack_InventoryOpen);
ANIM1(hud_backpack_InventoryIdle);
ANIM1(hud_backpack_InventoryClose);
/* Items */
ANIM1(item_life);
ANIM1(item_chest);
ANIM1(item_potion_atk);
ANIM1(item_potion_cooldown);
ANIM1(item_potion_def);
ANIM1(item_potion_frz);
ANIM1(item_potion_hp);
ANIM1(item_potion_spd);
ANIM1(item_stick1);
ANIM1(item_stick2);
ANIM1(item_sword1);
ANIM1(item_sword2);
ANIM1(item_armor1);
ANIM1(item_buff);
/* Animation functions. */
fixed_t (anim_duration)(anim_t const *anim)
{
anim_frame_t const *frame = anim->start[0];
int ms = 0;
int i = 0;
while(frame == anim->start[0] + i) {
ms += frame->duration;
frame = frame->next;
i++;
}
return fix(ms) / 1000;
}
bool anim_in(anim_frame_t const *frame, anim_t const *anim, int index)
{
if(index >= anim->directions || !frame || !anim)
return false;
anim_frame_t *f = anim->start[index];
for(int i = 0; f == anim->start[index] + i; i++) {
if(f == frame)
return true;
f = f->next;
}
return false;
}
void anim_frame_render(int x, int y, anim_frame_t const *frame)
{
if(!frame) return;
dsubimage(x - frame->cx, y - frame->cy, frame->sheet,
frame->x, frame->y, frame->w, frame->h, DIMAGE_NONE);
}
void anim_frame_subrender(int x, int y, anim_frame_t const *frame, int left,
int top, int width, int height)
{
if(!frame) return;
if(width < 0) width = frame->w;
if(height < 0) height = frame->h;
/* Basic clipping */
if(left < 0) width += left, left = 0;
if(top < 0) height += top, top = 0;
width = min(width, frame->w - left);
height = min(height, frame->h - top);
dsubimage(x - frame->cx, y - frame->cy + top, frame->sheet,
frame->x + left, frame->y + top, width, height, DIMAGE_NONE);
}
bool anim_state_update(anim_state_t *state, fixed_t dt)
{
if(!state->frame) return false;
state->elapsed += fround(dt * 1000);
if(state->elapsed < state->frame->duration) return false;
// TODO: FIXME: This is incorrect if the next animation is just behind
bool transitioning = (state->frame->next != state->frame + 1);
/* Switch to next frame */
state->elapsed -= state->frame->duration;
state->frame = state->frame->next;
return transitioning;
}