Allow projectile rules to delete other projectiles; add stage_clear_hazards enhancements
This commit is contained in:
parent
a562ccb87f
commit
d4650d4b92
7 changed files with 112 additions and 19 deletions
36
src/laser.c
36
src/laser.c
|
@ -344,6 +344,42 @@ static bool collision_laser_curve(Laser *l) {
|
|||
return lineseg_circle_intersect(segment, collision_area) >= 0;
|
||||
}
|
||||
|
||||
bool laser_intersects_circle(Laser *l, Circle circle) {
|
||||
// TODO: lots of copypasta from the function above here, maybe refactor both somehow.
|
||||
|
||||
float t_end = (global.frames - l->birthtime) * l->speed + l->timeshift; // end of the laser based on length
|
||||
float t_death = l->deathtime * l->speed + l->timeshift; // end of the laser based on lifetime
|
||||
float t = t_end - l->timespan;
|
||||
|
||||
if(t < 0) {
|
||||
t = 0;
|
||||
}
|
||||
|
||||
LineSegment segment = { .a = l->prule(l, t) };
|
||||
double orig_radius = circle.radius;
|
||||
|
||||
for(t += l->collision_step; t <= min(t_end, t_death); t += l->collision_step) {
|
||||
float t1 = t - l->timespan / 2; // i have no idea
|
||||
float tail = l->timespan / 1.9;
|
||||
float widthfac = -0.75 / pow(tail, 2) * (t1 - tail) * (t1 + tail);
|
||||
widthfac = max(0.25, pow(widthfac, l->width_exponent));
|
||||
|
||||
segment.b = l->prule(l, t);
|
||||
circle.radius = orig_radius + widthfac * l->width * 0.5 + 1;
|
||||
|
||||
if(lineseg_circle_intersect(segment, circle) >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
segment.a = segment.b;
|
||||
}
|
||||
|
||||
segment.b = l->prule(l, min(t_end, t_death));
|
||||
circle.radius = orig_radius + l->width * 0.5; // WTF: what is this sorcery?
|
||||
|
||||
return lineseg_circle_intersect(segment, circle) >= 0;
|
||||
}
|
||||
|
||||
complex las_linear(Laser *l, float t) {
|
||||
if(t == EVENT_BIRTH) {
|
||||
l->shader = r_shader_get_optional("lasers/linear");
|
||||
|
|
|
@ -77,3 +77,5 @@ complex las_circle(Laser *l, float t);
|
|||
|
||||
float laser_charge(Laser *l, int t, float charge, float width);
|
||||
void static_laser(Laser *l, int t);
|
||||
|
||||
bool laser_intersects_circle(Laser *l, Circle circle);
|
||||
|
|
|
@ -112,7 +112,7 @@ static void trace_laser(Enemy *e, complex vel, float damage) {
|
|||
col.fatal = false;
|
||||
}
|
||||
|
||||
apply_projectile_collision(&lproj, lproj.first, &col);
|
||||
apply_projectile_collision(&lproj, lproj.first, &col, NULL);
|
||||
|
||||
if(c) {
|
||||
c->original_hp = ((Enemy*)col.entity)->hp;
|
||||
|
|
|
@ -269,8 +269,13 @@ Projectile* _proj_attach_dbginfo(Projectile *p, DebugInfo *dbg, const char *call
|
|||
|
||||
static void* _delete_projectile(ListAnchor *projlist, List *proj, void *arg) {
|
||||
Projectile *p = (Projectile*)proj;
|
||||
ProjectileListInterface *out_list_pointers = arg;
|
||||
proj_call_rule(p, EVENT_DEATH);
|
||||
|
||||
if(out_list_pointers) {
|
||||
*&out_list_pointers->list_interface = p->list_interface;
|
||||
}
|
||||
|
||||
del_ref(proj);
|
||||
ent_unregister(&p->ent);
|
||||
objpool_release(stage_object_pools.projectiles, (ObjectInterface*)alist_unlink(projlist, proj));
|
||||
|
@ -278,8 +283,8 @@ static void* _delete_projectile(ListAnchor *projlist, List *proj, void *arg) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void delete_projectile(ProjectileList *projlist, Projectile *proj) {
|
||||
_delete_projectile((ListAnchor*)projlist, (List*)proj, NULL);
|
||||
void delete_projectile(ProjectileList *projlist, Projectile *proj, ProjectileListInterface *out_list_pointers) {
|
||||
_delete_projectile((ListAnchor*)projlist, (List*)proj, out_list_pointers);
|
||||
}
|
||||
|
||||
void delete_projectiles(ProjectileList *projlist) {
|
||||
|
@ -361,7 +366,7 @@ void calc_projectile_collision(Projectile *p, ProjCollisionResult *out_col) {
|
|||
}
|
||||
}
|
||||
|
||||
void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col) {
|
||||
void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col, ProjectileListInterface *out_list_pointers) {
|
||||
switch(col->type) {
|
||||
case PCOL_NONE: {
|
||||
break;
|
||||
|
@ -398,7 +403,9 @@ void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCol
|
|||
}
|
||||
|
||||
if(col->fatal) {
|
||||
delete_projectile(projlist, p);
|
||||
delete_projectile(projlist, p, out_list_pointers);
|
||||
} else {
|
||||
*&out_list_pointers->list_interface = p->list_interface;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,8 +481,13 @@ Projectile* spawn_projectile_clear_effect(Projectile *proj) {
|
|||
);
|
||||
}
|
||||
|
||||
bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bool now) {
|
||||
bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bool now, ProjectileListInterface *out_list_pointers) {
|
||||
if(proj->type == PlrProj || (!force && !projectile_is_clearable(proj))) {
|
||||
|
||||
if(out_list_pointers) {
|
||||
*&out_list_pointers->list_interface = proj->list_interface;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -485,9 +497,13 @@ bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bo
|
|||
}
|
||||
|
||||
spawn_projectile_clear_effect(proj);
|
||||
delete_projectile(projlist, proj);
|
||||
delete_projectile(projlist, proj, out_list_pointers);
|
||||
} else {
|
||||
proj->type = DeadProj;
|
||||
|
||||
if(out_list_pointers) {
|
||||
*&out_list_pointers->list_interface = proj->list_interface;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -495,14 +511,15 @@ bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bo
|
|||
|
||||
void process_projectiles(ProjectileList *projlist, bool collision) {
|
||||
ProjCollisionResult col = { 0 };
|
||||
ProjectileListInterface list_ptrs;
|
||||
|
||||
char killed = 0;
|
||||
int action;
|
||||
|
||||
for(Projectile *proj = projlist->first, *next; proj; proj = next) {
|
||||
next = proj->next;
|
||||
for(Projectile *proj = projlist->first; proj; proj = list_ptrs.next) {
|
||||
proj->prevpos = proj->pos;
|
||||
action = proj_call_rule(proj, global.frames - proj->birthtime);
|
||||
*&list_ptrs.list_interface = proj->list_interface;
|
||||
|
||||
if(proj->graze_counter && proj->graze_counter_reset_timer - global.frames <= -90) {
|
||||
proj->graze_counter--;
|
||||
|
@ -513,7 +530,7 @@ void process_projectiles(ProjectileList *projlist, bool collision) {
|
|||
killed++;
|
||||
action = ACTION_DESTROY;
|
||||
|
||||
if(clear_projectile(projlist, proj, true, true)) {
|
||||
if(clear_projectile(projlist, proj, true, true, &list_ptrs)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +553,7 @@ void process_projectiles(ProjectileList *projlist, bool collision) {
|
|||
col.fatal = true;
|
||||
}
|
||||
|
||||
apply_projectile_collision(projlist, proj, &col);
|
||||
apply_projectile_collision(projlist, proj, &col, &list_ptrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ enum {
|
|||
|
||||
typedef struct Projectile Projectile;
|
||||
typedef LIST_ANCHOR(Projectile) ProjectileList;
|
||||
typedef LIST_INTERFACE(Projectile) ProjectileListInterface;
|
||||
|
||||
typedef int (*ProjRule)(Projectile *p, int t);
|
||||
typedef void (*ProjDrawRule)(Projectile *p, int t);
|
||||
|
@ -169,11 +170,11 @@ Projectile* create_particle(ProjArgs *args);
|
|||
#define PROJECTILE(...) _PROJ_GENERIC_SPAWN(create_projectile, __VA_ARGS__)
|
||||
#define PARTICLE(...) _PROJ_GENERIC_SPAWN(create_particle, __VA_ARGS__)
|
||||
|
||||
void delete_projectile(ProjectileList *projlist, Projectile *proj);
|
||||
void delete_projectile(ProjectileList *projlist, Projectile *proj, ProjectileListInterface *out_list_pointers);
|
||||
void delete_projectiles(ProjectileList *projlist);
|
||||
|
||||
void calc_projectile_collision(Projectile *p, ProjCollisionResult *out_col);
|
||||
void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col);
|
||||
void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col, ProjectileListInterface *out_list_pointers);
|
||||
int trace_projectile(Projectile *p, ProjCollisionResult *out_col, ProjCollisionType stopflags, int timeofs);
|
||||
bool projectile_in_viewport(Projectile *proj);
|
||||
void process_projectiles(ProjectileList *projlist, bool collision);
|
||||
|
@ -184,7 +185,7 @@ Projectile* spawn_projectile_clear_effect(Projectile *proj);
|
|||
|
||||
void projectile_set_prototype(Projectile *p, ProjPrototype *proto);
|
||||
|
||||
bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bool now);
|
||||
bool clear_projectile(ProjectileList *projlist, Projectile *proj, bool force, bool now, ProjectileListInterface *out_list_pointers);
|
||||
|
||||
int linear(Projectile *p, int t);
|
||||
int accelerated(Projectile *p, int t);
|
||||
|
|
45
src/stage.c
45
src/stage.c
|
@ -432,22 +432,57 @@ static void stage_logic(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void stage_clear_hazards(ClearHazardsFlags flags) {
|
||||
void stage_clear_hazards_predicate(bool (*predicate)(EntityInterface *ent, void *arg), void *arg, ClearHazardsFlags flags) {
|
||||
if(flags & CLEAR_HAZARDS_BULLETS) {
|
||||
for(Projectile *p = global.projs.first, *next; p; p = next) {
|
||||
next = p->next;
|
||||
clear_projectile(&global.projs, p, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW);
|
||||
ProjectileListInterface list_ptrs;
|
||||
|
||||
for(Projectile *p = global.projs.first; p; p = list_ptrs.next) {
|
||||
if(!predicate || predicate(&p->ent, arg)) {
|
||||
clear_projectile(&global.projs, p, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW, &list_ptrs);
|
||||
} else {
|
||||
*&list_ptrs.list_interface = p->list_interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(flags & CLEAR_HAZARDS_LASERS) {
|
||||
for(Laser *l = global.lasers.first, *next; l; l = next) {
|
||||
next = l->next;
|
||||
clear_laser(&global.lasers, l, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW);
|
||||
|
||||
if(!predicate || predicate(&l->ent, arg)) {
|
||||
clear_laser(&global.lasers, l, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stage_clear_hazards(ClearHazardsFlags flags) {
|
||||
stage_clear_hazards_predicate(NULL, NULL, flags);
|
||||
}
|
||||
|
||||
static bool proximity_predicate(EntityInterface *ent, void *varg) {
|
||||
Circle *area = varg;
|
||||
|
||||
switch(ent->type) {
|
||||
case ENT_PROJECTILE: {
|
||||
Projectile *p = ENT_CAST(ent, Projectile);
|
||||
return cabs(p->pos - area->origin) < area->radius;
|
||||
}
|
||||
|
||||
case ENT_LASER: {
|
||||
Laser *l = ENT_CAST(ent, Laser);
|
||||
return laser_intersects_circle(l, *area);
|
||||
}
|
||||
|
||||
default: UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void stage_clear_hazards_at(complex origin, double radius, ClearHazardsFlags flags) {
|
||||
Circle area = { origin, radius };
|
||||
stage_clear_hazards_predicate(proximity_predicate, &area, flags);
|
||||
}
|
||||
|
||||
static void stage_free(void) {
|
||||
delete_enemies(&global.enemies);
|
||||
delete_enemies(&global.plr.slaves);
|
||||
|
|
|
@ -125,6 +125,8 @@ typedef enum ClearHazardsFlags {
|
|||
} ClearHazardsFlags;
|
||||
|
||||
void stage_clear_hazards(ClearHazardsFlags flags);
|
||||
void stage_clear_hazards_at(complex origin, double radius, ClearHazardsFlags flags);
|
||||
void stage_clear_hazards_predicate(bool (*predicate)(EntityInterface *ent, void *arg), void *arg, ClearHazardsFlags flags);
|
||||
|
||||
#include "stages/stage1.h"
|
||||
#include "stages/stage2.h"
|
||||
|
|
Loading…
Reference in a new issue