improve stage_clear_hazards api, add particle effect for cleared bullets

This commit is contained in:
Andrei Alexeyev 2018-01-06 11:24:46 +02:00
parent bb33afbe64
commit fc8cda89d7
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
9 changed files with 102 additions and 54 deletions

View file

@ -511,7 +511,7 @@ void boss_finish_current_attack(Boss *boss) {
aniplayer_reset(&boss->ani);
if(t != AT_Move) {
stage_clear_hazards(true);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_FORCE);
}
if(ATTACK_IS_SPELL(t)) {
@ -635,7 +635,7 @@ void process_boss(Boss **pboss) {
// XXX: do we actually need to call this for AT_Move attacks at all?
// it should be harmless, but probably unnecessary.
// i'll be conservative and leave it in for now.
stage_clear_hazards(true);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_FORCE);
}
}
@ -729,7 +729,7 @@ void boss_death(Boss **boss) {
}
if(!fleed) {
stage_clear_hazards(true);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_FORCE);
}
free_boss(*boss);
@ -791,7 +791,7 @@ void boss_start_attack(Boss *b, Attack *a) {
player_cancel_bomb(&global.plr, a->starttime - global.frames);
}
stage_clear_hazards(true);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_FORCE);
}
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {

View file

@ -188,6 +188,16 @@ void delete_lasers(void) {
list_foreach(&global.lasers, _delete_laser, NULL);
}
bool clear_laser(Laser *l, bool force, bool now) {
if(!force && l->unclearable) {
return false;
}
// TODO: implement "now"
l->dead = true;
return true;
}
void process_lasers(void) {
Laser *laser = global.lasers, *del = NULL;

View file

@ -67,6 +67,8 @@ void process_lasers(void);
int collision_laser_line(Laser *l);
int collision_laser_curve(Laser *l);
bool clear_laser(Laser *l, bool force, bool now);
complex las_linear(Laser *l, float t);
complex las_accel(Laser *l, float t);
complex las_sine(Laser *l, float t);

View file

@ -60,7 +60,7 @@ void player_free(Player *plr) {
static void player_full_power(Player *plr) {
play_sound("full_power");
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
stagetext_add("Full Power!", VIEWPORT_W * 0.5 + VIEWPORT_H * 0.33 * I, AL_Center, &_fonts.mainmenu, rgb(1, 1, 1), 0, 60, 20, 20);
}
@ -184,7 +184,7 @@ void player_logic(Player* plr) {
plr->bomb_fragments = 0;
plr->continues_used += 1;
player_set_power(plr, 0);
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
spawn_items(plr->deathpos, Power, (int)ceil(PLR_MAX_POWER/(double)POWER_VALUE), NULL);
}
@ -193,7 +193,7 @@ void player_logic(Player* plr) {
if(plr->deathtime < -1) {
plr->deathtime++;
plr->pos -= I;
stage_clear_hazards_instantly(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
return;
}
@ -210,7 +210,7 @@ void player_logic(Player* plr) {
if(global.frames == plr->deathtime) {
player_realdeath(plr);
} else if(plr->deathtime > global.frames) {
stage_clear_hazards_instantly(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
}
if(global.frames - plr->recovery < 0) {
@ -234,7 +234,7 @@ void player_logic(Player* plr) {
boss_damage(global.boss, 30);
}
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
player_fail_spell(plr);
}
}
@ -245,7 +245,7 @@ bool player_bomb(Player *plr) {
if(global.frames - plr->recovery >= 0 && (plr->bombs > 0 || plr->iddqd) && global.frames - plr->respawntime >= 60) {
player_fail_spell(plr);
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
plr->mode->procs.bomb(plr);
plr->bombs--;
@ -333,7 +333,7 @@ void player_realdeath(Player *plr) {
plr->deathpos = plr->pos;
plr->pos = VIEWPORT_W/2 + VIEWPORT_H*I+30.0*I;
plr->recovery = -(global.frames + DEATH_DELAY + 150);
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
player_fail_spell(plr);
@ -373,7 +373,7 @@ void player_death(Player *plr) {
);
}
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
PARTICLE(
.texture = "blast",

View file

@ -375,6 +375,55 @@ bool projectile_in_viewport(Projectile *proj) {
|| cimag(proj->pos) + h/2 + e < 0 || cimag(proj->pos) - h/2 - e > VIEWPORT_H);
}
static Projectile* spawn_projectile_death_effect(Projectile *proj) {
if(proj->tex == NULL) {
return NULL;
}
return PARTICLE(
.texture_ptr = proj->tex,
.pos = proj->pos,
.color = proj->color,
.flags = proj->flags,
.color_transform_rule = proj->color_transform_rule,
.rule = timeout_linear,
.draw_rule = DeathShrink,
.args = { 10, 5*cexp(proj->angle*I) },
.type = proj->type >= PlrProj ? PlrProj : Particle,
);
}
Projectile* spawn_projectile_collision_effect(Projectile *proj) {
if(proj->flags & PFLAG_NOCOLLISIONEFFECT) {
return NULL;
}
return spawn_projectile_death_effect(proj);
}
Projectile* spawn_projectile_clear_effect(Projectile *proj) {
if(proj->flags & PFLAG_NOCLEAREFFECT) {
return NULL;
}
return spawn_projectile_death_effect(proj);
}
bool clear_projectile(Projectile *proj, bool force, bool now) {
if(!force && !projectile_is_clearable(proj)) {
return false;
}
if(now) {
create_bpoint(proj->pos);
spawn_projectile_clear_effect(proj);
} else {
proj->type = DeadProj;
}
return false;
}
void process_projectiles(Projectile **projs, bool collision) {
ProjCollisionResult col = { 0 };
@ -389,24 +438,14 @@ void process_projectiles(Projectile **projs, bool collision) {
if(proj->type == DeadProj && killed < 5) {
killed++;
action = ACTION_DESTROY;
create_bpoint(proj->pos);
clear_projectile(proj, true, true);
}
if(collision) {
calc_projectile_collision(proj, &col);
if(col.fatal && col.type != PCOL_VOID) {
PARTICLE(
.texture_ptr = proj->tex,
.pos = proj->pos,
.color = proj->color,
.flags = proj->flags,
.color_transform_rule = proj->color_transform_rule,
.rule = timeout_linear,
.draw_rule = DeathShrink,
.args = { 10, 5*cexp(proj->angle*I) },
.type = proj->type >= PlrProj ? PlrProj : Particle,
);
spawn_projectile_collision_effect(proj);
}
} else {
memset(&col, 0, sizeof(col));

View file

@ -52,6 +52,8 @@ typedef enum ProjFlags {
PFLAG_NOSPAWNZOOM = (1 << 2),
PFLAG_NOGRAZE = (1 << 3),
PFLAG_NOCLEAR = (1 << 4),
PFLAG_NOCLEAREFFECT = (1 << 5),
PFLAG_NOCOLLISIONEFFECT = (1 << 6),
} ProjFlags;
struct Projectile {
@ -141,6 +143,11 @@ bool projectile_in_viewport(Projectile *proj);
void process_projectiles(Projectile **projs, bool collision);
bool projectile_is_clearable(Projectile *p);
Projectile* spawn_projectile_collision_effect(Projectile *proj);
Projectile* spawn_projectile_clear_effect(Projectile *proj);
bool clear_projectile(Projectile *proj, bool force, bool now);
int linear(Projectile *p, int t);
int accelerated(Projectile *p, int t);
int asymptotic(Projectile *p, int t);

View file

@ -454,34 +454,16 @@ static void stage_logic(void) {
}
}
void stage_clear_hazards(bool force) {
for(Projectile *p = global.projs; p; p = p->next) {
if(force || projectile_is_clearable(p)) {
p->type = DeadProj;
void stage_clear_hazards(ClearHazardsFlags flags) {
if(flags & CLEAR_HAZARDS_BULLETS) {
for(Projectile *p = global.projs; p; p = p->next) {
clear_projectile(p, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW);
}
}
for(Laser *l = global.lasers; l; l = l->next) {
if(force || !l->unclearable) {
l->dead = true;
}
}
}
void stage_clear_hazards_instantly(bool force) {
for(Projectile *p = global.projs, *next; p; p = next) {
next = p->next;
if(force || projectile_is_clearable(p)) {
create_bpoint(p->pos);
delete_projectile(&global.projs, p);
}
}
// TODO: clear these instantly as well
for(Laser *l = global.lasers; l; l = l->next) {
if(force || !l->unclearable) {
l->dead = true;
if(flags & CLEAR_HAZARDS_LASERS) {
for(Laser *l = global.lasers; l; l = l->next) {
clear_laser(l, flags & CLEAR_HAZARDS_FORCE, flags & CLEAR_HAZARDS_NOW);
}
}
}

View file

@ -114,11 +114,19 @@ void stage_finish(int gameover);
void stage_pause(void);
void stage_gameover(void);
void stage_clear_hazards(bool force);
void stage_clear_hazards_instantly(bool force);
void stage_start_bgm(const char *bgm);
typedef enum ClearHazardsFlags {
CLEAR_HAZARDS_BULLETS = (1 << 0),
CLEAR_HAZARDS_LASERS = (1 << 1),
CLEAR_HAZARDS_FORCE = (1 << 2),
CLEAR_HAZARDS_NOW = (1 << 3),
CLEAR_HAZARDS_ALL = CLEAR_HAZARDS_BULLETS | CLEAR_HAZARDS_LASERS,
} ClearHazardsFlags;
void stage_clear_hazards(ClearHazardsFlags flags);
#include "stages/stage1.h"
#include "stages/stage2.h"
#include "stages/stage3.h"

View file

@ -558,7 +558,7 @@ static int splitcard_elly(Projectile *p, int t) {
p->color = derive_color(p->color, CLRMASK_B, rgb(0,0,-color_component(p->color,CLR_B)));
play_sound_ex("redirect", 10, false);
}
return asymptotic(p, t);
}
@ -1366,7 +1366,7 @@ static int scythe_post_mid(Enemy *e, int t) {
}
FROM_TO(fleetime - 120, fleetime, 1) {
stage_clear_hazards(false);
stage_clear_hazards(CLEAR_HAZARDS_ALL);
}
scythe_common(e, t);