add dynamically-colored buff effect (seen on healing potions)
This commit is contained in:
parent
80fda55e98
commit
861457fdaf
|
@ -90,6 +90,7 @@ set(ASSETS
|
|||
assets-cg/items/sword1.aseprite
|
||||
assets-cg/items/sword2.aseprite
|
||||
assets-cg/items/armor1.aseprite
|
||||
assets-cg/items/buff.aseprite
|
||||
# Player animations
|
||||
assets-cg/player/player_up.aseprite
|
||||
assets-cg/player/player_right.aseprite
|
||||
|
|
Binary file not shown.
|
@ -3,3 +3,6 @@
|
|||
name_regex: (.*)\.aseprite frames_item_\1
|
||||
next: Item=Item
|
||||
profile: p4
|
||||
|
||||
buff.aseprite:
|
||||
section: .data
|
||||
|
|
|
@ -82,6 +82,7 @@ ANIM1(item_stick2);
|
|||
ANIM1(item_sword1);
|
||||
ANIM1(item_sword2);
|
||||
ANIM1(item_armor1);
|
||||
ANIM1(item_buff);
|
||||
|
||||
/* Animation functions. */
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ extern anim_t anims_item_stick2;
|
|||
extern anim_t anims_item_sword1;
|
||||
extern anim_t anims_item_sword2;
|
||||
extern anim_t anims_item_armor1;
|
||||
extern anim_t anims_item_buff;
|
||||
|
||||
/* Expand definitions for enemies */
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "comp/entity.h"
|
||||
#include "comp/physical.h"
|
||||
#include "comp/particle.h"
|
||||
#include "anim.h"
|
||||
#include "geometry.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -17,9 +18,10 @@ entity_t *particle_make_damage(entity_t *target, int damage, int color)
|
|||
|
||||
p->type = PARTICLE_DAMAGE;
|
||||
p->plane = CEILING;
|
||||
p->bound_to_entity = false;
|
||||
p->x = target_p->x;
|
||||
p->y = target_p->y - fix(0.5);
|
||||
p->z = 0;
|
||||
p->y = target_p->y;
|
||||
p->z = fix(0.5);
|
||||
p->age = 0;
|
||||
|
||||
p->DAMAGE.damage = damage;
|
||||
|
@ -37,6 +39,7 @@ entity_t *particle_make_dash(entity_t *target)
|
|||
|
||||
p->type = PARTICLE_DASH;
|
||||
p->plane = HORIZONTAL;
|
||||
p->bound_to_entity = false;
|
||||
p->x = target_p->x;
|
||||
p->y = target_p->y;
|
||||
p->z = 0;
|
||||
|
@ -45,6 +48,23 @@ entity_t *particle_make_dash(entity_t *target)
|
|||
return e;
|
||||
}
|
||||
|
||||
entity_t *particle_make_buff(entity_t *target, int color)
|
||||
{
|
||||
entity_t *e = entity_make(particle);
|
||||
particle_t *p = getcomp(e, particle);
|
||||
|
||||
p->type = PARTICLE_BUFF;
|
||||
p->plane = CEILING;
|
||||
p->bound_to_entity = true;
|
||||
p->bound_entity = target;
|
||||
p->z = fix(0.5);
|
||||
p->age = 0;
|
||||
|
||||
p->BUFF.color = color;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static bool damage_update(particle_t *p, GUNUSED fixed_t dt)
|
||||
{
|
||||
return p->age >= 300;
|
||||
|
@ -75,6 +95,50 @@ static void dash_render(int x, int y, particle_t const *p)
|
|||
}
|
||||
}
|
||||
|
||||
static bool buff_update(particle_t *p, GUNUSED fixed_t dt)
|
||||
{
|
||||
int total_ms = 0;
|
||||
anim_frame_t const *frame = anims_item_buff.start[0];
|
||||
while(frame) {
|
||||
total_ms += frame->duration;
|
||||
frame = frame->next;
|
||||
}
|
||||
|
||||
return p->age >= total_ms;
|
||||
}
|
||||
|
||||
static void buff_render(int x, int y, particle_t const *p)
|
||||
{
|
||||
int ms = p->age;
|
||||
anim_frame_t const *frame = anims_item_buff.start[0];
|
||||
while(frame && ms > frame->duration) {
|
||||
ms -= frame->duration;
|
||||
frame = frame->next;
|
||||
}
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
/* Find black and white in the palette */
|
||||
int black_index = -1;
|
||||
int white_index = -1;
|
||||
for(int i = 0; i < frame->sheet->color_count; i++) {
|
||||
if(black_index == -1 && frame->sheet->palette[i] == 0x0000)
|
||||
black_index = i;
|
||||
if(white_index == -1 && frame->sheet->palette[i] == 0xffff)
|
||||
white_index = i;
|
||||
}
|
||||
|
||||
/* Render while swapping black for p->BUFF.color */
|
||||
frame->sheet->palette[black_index] = p->BUFF.color;
|
||||
frame->sheet->palette[white_index] = ~((~p->BUFF.color & 0xf7de) >> 1);
|
||||
|
||||
dsubimage_p4(x - frame->cx, y - frame->cy, frame->sheet,
|
||||
frame->x, frame->y, frame->w, frame->h, DIMAGE_NONE);
|
||||
|
||||
frame->sheet->palette[black_index] = 0x0000;
|
||||
frame->sheet->palette[white_index] = 0xffff;
|
||||
}
|
||||
|
||||
//---
|
||||
// Generic functions
|
||||
//---
|
||||
|
@ -87,6 +151,8 @@ bool particle_update(particle_t *p, fixed_t dt)
|
|||
return damage_update(p, dt);
|
||||
if(p->type == PARTICLE_DASH)
|
||||
return dash_update(p, dt);
|
||||
if(p->type == PARTICLE_BUFF)
|
||||
return buff_update(p, dt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -97,4 +163,6 @@ void particle_render(int x, int y, particle_t const *p)
|
|||
return damage_render(x, y, p);
|
||||
if(p->type == PARTICLE_DASH)
|
||||
return dash_render(x, y, p);
|
||||
if(p->type == PARTICLE_BUFF)
|
||||
return buff_render(x, y, p);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ enum {
|
|||
PARTICLE_DAMAGE,
|
||||
PARTICLE_DASH,
|
||||
PARTICLE_HPBAR,
|
||||
PARTICLE_BUFF,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -25,10 +26,18 @@ typedef struct
|
|||
uint8_t type;
|
||||
/* Plane of rendering */
|
||||
uint8_t plane;
|
||||
/* Whether the particle's position is bound to an entity, or absolute */
|
||||
bool bound_to_entity;
|
||||
|
||||
/* Location on screen and in the air */
|
||||
fixed_t x, y, z;
|
||||
/* Age and lifetime */
|
||||
fixed_t age;
|
||||
union {
|
||||
struct { fixed_t x, y; };
|
||||
entity_t *bound_entity;
|
||||
};
|
||||
fixed_t z;
|
||||
/* Age (milliseconds) */
|
||||
int age;
|
||||
|
||||
/* 8 bytes of data */
|
||||
union {
|
||||
/* Generic particles or with a lot of extra data */
|
||||
|
@ -39,6 +48,8 @@ typedef struct
|
|||
|
||||
/* PARTICLE_HPBAR: Pointer to entity */
|
||||
struct { entity_t *entity; } HPBAR;
|
||||
/* PARTICLE_BUFF: Buff animation */
|
||||
struct { uint16_t color; } BUFF;
|
||||
};
|
||||
|
||||
} particle_t;
|
||||
|
@ -49,6 +60,9 @@ entity_t *particle_make_damage(entity_t *target, int damage, int color);
|
|||
/* Make a dashing particle at the specified target's position */
|
||||
entity_t *particle_make_dash(entity_t *target);
|
||||
|
||||
/* Make a buff particle of the specified color bound to the specified target */
|
||||
entity_t *particle_make_buff(entity_t *target, int color);
|
||||
|
||||
/* Update time and layout for a particle (type-generic). */
|
||||
bool particle_update(particle_t *p, fixed_t dt);
|
||||
|
||||
|
|
|
@ -414,6 +414,14 @@ void game_remove_dead_entities(game_t *g)
|
|||
}
|
||||
}
|
||||
|
||||
/* Remove particles bound to dead fighters */
|
||||
for(int i = 0; i < g->entity_count; i++) {
|
||||
entity_t *e = g->entities[i];
|
||||
particle_t *p = getcomp(e, particle);
|
||||
if(p && p->bound_to_entity && p->bound_entity->deleted)
|
||||
entity_mark_to_delete(e);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while(i < g->entity_count) {
|
||||
if(g->entities[i]->deleted)
|
||||
|
|
19
src/item.c
19
src/item.c
|
@ -65,6 +65,25 @@ char const *item_name(int item)
|
|||
return "???";
|
||||
}
|
||||
|
||||
int item_buff_color(int item)
|
||||
{
|
||||
if(item == ITEM_LIFE)
|
||||
return C_RGB(31, 0, 31);
|
||||
else if(item == ITEM_POTION_ATK)
|
||||
return C_RGB(31, 16, 16);
|
||||
else if(item == ITEM_POTION_COOLDOWN)
|
||||
return C_BLUE;
|
||||
else if(item == ITEM_POTION_DEF)
|
||||
return C_RGB(0, 15, 31);
|
||||
else if(item == ITEM_POTION_FRZ)
|
||||
return 0x5555;
|
||||
else if(item == ITEM_POTION_HP)
|
||||
return C_RGB(0, 31, 0);
|
||||
else if(item == ITEM_POTION_SPD)
|
||||
return C_RGB(31, 31, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char const *item_description(int item)
|
||||
{
|
||||
if(item == ITEM_LIFE)
|
||||
|
|
|
@ -33,6 +33,9 @@ anim_t const *item_anim(int item);
|
|||
/* Item name (fancy huh?). */
|
||||
char const *item_name(int item);
|
||||
|
||||
/* Buff effect color (-1 for no buff). */
|
||||
int item_buff_color(int item);
|
||||
|
||||
/* Item description, can be multi-line. NULL if none specified. */
|
||||
char const *item_description(int item);
|
||||
|
||||
|
|
|
@ -494,6 +494,12 @@ static int menu_select_play_repeat(void)
|
|||
}
|
||||
else if(item >= 0 && item_use(item, player)) {
|
||||
player_data.inventory[game.menu_cursor] = -1;
|
||||
|
||||
int color = item_buff_color(item);
|
||||
if(color > 0) {
|
||||
entity_t *part = particle_make_buff(player, color);
|
||||
game_add_entity(&game, part);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
src/render.c
23
src/render.c
|
@ -182,6 +182,15 @@ void render_map_layer(map_t const *map, camera_t const *c, int ss_x, int ss_y,
|
|||
static int depth_measure(entity_t const *e, int direction)
|
||||
{
|
||||
particle_t *p = getcomp(e, particle);
|
||||
if(p) {
|
||||
if(p->plane != direction)
|
||||
return -1;
|
||||
if(!p->bound_to_entity)
|
||||
return p->y;
|
||||
|
||||
physical_t *bound_p = getcomp(p->bound_entity, physical);
|
||||
return bound_p ? bound_p->y : -1;
|
||||
}
|
||||
if(p) {
|
||||
return (p->plane != direction) ? -1 : p->y;
|
||||
}
|
||||
|
@ -253,9 +262,15 @@ static void render_entities(game_t const *g, camera_t const *camera,
|
|||
visible_t *v = getcomp(e, visible);
|
||||
particle_t *pt = getcomp(e, particle);
|
||||
|
||||
vec2 xy;
|
||||
fixed_t z;
|
||||
if(pt) {
|
||||
vec2 xy = { 0, 0 };
|
||||
fixed_t z = 0;
|
||||
if(pt && pt->bound_to_entity) {
|
||||
physical_t *bound_p = getcomp(pt->bound_entity, physical);
|
||||
if(bound_p)
|
||||
xy = (vec2) { bound_p->x, bound_p->y };
|
||||
z = pt->z;
|
||||
}
|
||||
else if(pt) {
|
||||
xy = (vec2) { pt->x, pt->y };
|
||||
z = pt->z;
|
||||
}
|
||||
|
@ -292,7 +307,7 @@ static void render_entities(game_t const *g, camera_t const *camera,
|
|||
|
||||
/* Show particle */
|
||||
if(pt) {
|
||||
particle_render(scr.x, scr.y, pt);
|
||||
particle_render(scr.x, elevated_y, pt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue