improve stage_clear_hazards api, add particle effect for cleared bullets
This commit is contained in:
parent
bb33afbe64
commit
fc8cda89d7
9 changed files with 102 additions and 54 deletions
|
@ -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) {
|
||||
|
|
10
src/laser.c
10
src/laser.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
16
src/player.c
16
src/player.c
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
32
src/stage.c
32
src/stage.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/stage.h
14
src/stage.h
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue