RogueLife/src/comp/particle.c

169 lines
4.0 KiB
C

#include "comp/entity.h"
#include "comp/physical.h"
#include "comp/particle.h"
#include "anim.h"
#include "geometry.h"
#include "util.h"
#include <gint/defs/attributes.h>
#include <gint/display.h>
#include <stdio.h>
entity_t *particle_make_damage(entity_t *target, int damage, int color)
{
entity_t *e = entity_make(particle);
particle_t *p = getcomp(e, particle);
physical_t *target_p = getcomp(target, physical);
p->type = PARTICLE_DAMAGE;
p->plane = CEILING;
p->bound_to_entity = false;
p->x = target_p->x;
p->y = target_p->y;
p->z = fix(0.5);
p->age = 0;
p->DAMAGE.damage = damage;
p->DAMAGE.color = color;
return e;
}
entity_t *particle_make_dash(entity_t *target)
{
entity_t *e = entity_make(particle);
particle_t *p = getcomp(e, particle);
physical_t *target_p = getcomp(target, physical);
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;
p->age = 0;
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;
}
static void damage_render(int x, int y, particle_t const *p)
{
font_damage_print(x, y, p->DAMAGE.color, DTEXT_CENTER, DTEXT_MIDDLE,
p->DAMAGE.damage);
}
static bool dash_update(particle_t *p, GUNUSED fixed_t dt)
{
return p->age >= 256;
}
static void dash_render(int x, int y, particle_t const *p)
{
/* 32 * (1 - age/256) */
int radius = 32 - (p->age >> 3);
for(int dx = -5; dx <= +5; dx++)
for(int dy = -5; dy <= +5; dy++) {
if(dx * dx + dy * dy <= radius) {
int index = 396 * (y + dy) + (x + dx);
gint_vram[index] = ~((~gint_vram[index] & 0xf7de) >> 1);
}
}
}
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
//---
bool particle_update(particle_t *p, fixed_t dt)
{
p->age += fround(dt * 1000);
if(p->type == PARTICLE_DAMAGE)
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;
}
void particle_render(int x, int y, particle_t const *p)
{
if(p->type == PARTICLE_DAMAGE)
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);
}