plrmodes: fix bomb-stacking exploits
When a bomb is used, cancel all previous bomb-related tasks just before invoking new bomb tasks. This prevents the possibility of stacking multiple bombs at the same time. Also make sure to YIELD before starting the bomb logic loops, because the bomb task will be scheduled in the same frame after the first yield, due to the initial invocation being from an event handler.
This commit is contained in:
parent
1daf1377d9
commit
f1f5a34a51
7 changed files with 160 additions and 105 deletions
|
@ -512,7 +512,36 @@ static void marisa_laser_masterspark_damage(MarisaAMasterSpark *ms) {
|
|||
// log_debug("%i", iter);
|
||||
}
|
||||
|
||||
TASK(marisa_laser_masterspark, { MarisaAController *ctrl; }) {
|
||||
TASK(marisa_laser_bomb_background, { MarisaAController *ctrl; }) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
float t = player_get_bomb_progress(plr);
|
||||
float fade = 1;
|
||||
|
||||
if(t < 1.0f / 6.0f) {
|
||||
fade = t * 6.0f;
|
||||
}
|
||||
|
||||
if(t > 3.0f / 4.0f) {
|
||||
fade = 1.0f - t * 4.0f + 3.0f;
|
||||
}
|
||||
|
||||
if(fade <= 0.0f) {
|
||||
break;
|
||||
}
|
||||
|
||||
r_state_push();
|
||||
r_color4(0.8f * fade, 0.8f * fade, 0.8f * fade, 0.8f * fade);
|
||||
fill_viewport(sinf(t * 0.3f), t * 3.0f * (1.0f + t * 3.0f), 1.0f, "marisa_bombbg");
|
||||
r_state_pop();
|
||||
};
|
||||
}
|
||||
|
||||
TASK(marisa_laser_bomb_masterspark, { MarisaAController *ctrl; }) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
|
@ -526,6 +555,10 @@ TASK(marisa_laser_masterspark, { MarisaAController *ctrl; }) {
|
|||
Sprite *star_spr = res_sprite("part/maristar_orbit");
|
||||
Sprite *smoke_spr = res_sprite("part/smoke");
|
||||
|
||||
BoxedTask bg_task = cotask_box(INVOKE_SUBTASK(marisa_laser_bomb_background, ctrl));
|
||||
|
||||
YIELD;
|
||||
|
||||
do {
|
||||
real bomb_progress = player_get_bomb_progress(plr);
|
||||
ms->alpha = marisa_laser_masterspark_width(bomb_progress);
|
||||
|
@ -583,45 +616,26 @@ skip_particles:
|
|||
YIELD;
|
||||
} while(player_is_bomb_active(plr));
|
||||
|
||||
// should have faded out by now, but just in case…
|
||||
CANCEL_TASK(bg_task);
|
||||
|
||||
while(ms->alpha > 0) {
|
||||
approach_p(&ms->alpha, 0, 0.2);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(marisa_laser_bomb_background, { MarisaAController *ctrl; }) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
|
||||
do {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
float t = player_get_bomb_progress(plr);
|
||||
float fade = 1;
|
||||
|
||||
if(t < 1./6) {
|
||||
fade = t*6;
|
||||
}
|
||||
|
||||
if(t > 3./4) {
|
||||
fade = 1-t*4 + 3;
|
||||
}
|
||||
|
||||
r_color4(0.8 * fade, 0.8 * fade, 0.8 * fade, 0.8 * fade);
|
||||
fill_viewport(sin(t * 0.3), t * 3 * (1 + t * 3), 1, "marisa_bombbg");
|
||||
r_color4(1, 1, 1, 1);
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
|
||||
TASK(marisa_laser_bomb_handler, { MarisaAController *ctrl; }) {
|
||||
MarisaAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
CANCEL_TASK(bomb_task);
|
||||
play_sfx("bomb_marisa_a");
|
||||
INVOKE_SUBTASK(marisa_laser_bomb_background, ctrl);
|
||||
INVOKE_SUBTASK(marisa_laser_masterspark, ctrl);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(marisa_laser_bomb_masterspark, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -405,7 +405,7 @@ TASK(marisa_star_bomb_background, { MarisaBController *ctrl; }) {
|
|||
Uniform *u_plrpos = r_shader_uniform(bg_shader, "plrpos");
|
||||
Texture *bg_tex = res_texture("marisa_bombbg");
|
||||
|
||||
do {
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&stage_get_draw_events()->background_drawn);
|
||||
|
||||
r_state_push();
|
||||
|
@ -415,13 +415,15 @@ TASK(marisa_star_bomb_background, { MarisaBController *ctrl; }) {
|
|||
r_uniform_vec2_complex(u_plrpos, cwmul(plr->pos, CMPLX(1.0/VIEWPORT_W, 1.0/VIEWPORT_H)));
|
||||
fill_viewport_p(0, 0, 1, 1, 0, bg_tex);
|
||||
r_state_pop();
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
}
|
||||
|
||||
TASK(marisa_star_bomb_controller, { MarisaBController *ctrl; }) {
|
||||
TASK(marisa_star_bomb, { MarisaBController *ctrl; }) {
|
||||
MarisaBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
INVOKE_SUBTASK(marisa_star_bomb_background, ctrl);
|
||||
|
||||
YIELD;
|
||||
|
||||
MarisaBBeams *beams = TASK_HOST_ENT(MarisaBBeams);
|
||||
|
@ -465,11 +467,13 @@ TASK(marisa_star_bomb_handler, { MarisaBController *ctrl; }) {
|
|||
MarisaBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
CANCEL_TASK(bomb_task);
|
||||
play_sfx("bomb_marisa_b");
|
||||
INVOKE_SUBTASK(marisa_star_bomb_background, ctrl);
|
||||
INVOKE_SUBTASK(marisa_star_bomb_controller, ctrl);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(marisa_star_bomb, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -403,41 +403,58 @@ TASK(reimu_spirit_bomb_background, { ReimuAController *ctrl; }) {
|
|||
Player *plr = ctrl->plr;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
|
||||
do {
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
|
||||
float t = player_get_bomb_progress(plr);
|
||||
float alpha = 0;
|
||||
|
||||
if(t >= 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
float alpha = 0.0f;
|
||||
|
||||
if(t > 0) {
|
||||
alpha = fminf(1, 10*t);
|
||||
alpha = fminf(1.0f, 10.0f * t);
|
||||
}
|
||||
|
||||
if(t > 0.7) {
|
||||
alpha *= 1 - powf((t - 0.7) / 0.3, 4);
|
||||
alpha *= 1.0f - powf((t - 0.7f) / 0.3f, 4.0f);
|
||||
}
|
||||
|
||||
reimu_common_bomb_bg(plr, alpha);
|
||||
colorfill(0, 0.05 * alpha, 0.1 * alpha, alpha * 0.5);
|
||||
} while(player_is_bomb_active(plr));
|
||||
colorfill(0.0f, 0.05f * alpha, 0.1f * alpha, alpha * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_spirit_bomb, { ReimuAController *ctrl; }) {
|
||||
ReimuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
INVOKE_SUBTASK(reimu_spirit_bomb_background, ctrl);
|
||||
YIELD;
|
||||
|
||||
const int orb_count = 6;
|
||||
for(int i = 0; i < orb_count; i++) {
|
||||
INVOKE_TASK_DELAYED(1, reimu_spirit_bomb_orb, ENT_BOX(plr), i, M_TAU/orb_count*i);
|
||||
}
|
||||
|
||||
// keep bg renderer alive
|
||||
WAIT(plr->bomb_endtime - global.frames);
|
||||
}
|
||||
|
||||
TASK(reimu_spirit_bomb_handler, { ReimuAController *ctrl; }) {
|
||||
ReimuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
int orb_count = 6;
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
INVOKE_SUBTASK(reimu_spirit_bomb_background, ctrl);
|
||||
|
||||
play_sfx("bomb_reimu_a");
|
||||
play_sfx("bomb_marisa_b");
|
||||
|
||||
for(int i = 0; i < orb_count; i++) {
|
||||
INVOKE_TASK_DELAYED(1, reimu_spirit_bomb_orb, ENT_BOX(plr), i, M_TAU/orb_count*i);
|
||||
}
|
||||
CANCEL_TASK(bomb_task);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(reimu_spirit_bomb, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,23 +146,35 @@ TASK(reimu_dream_gap_bomb_projectile, {
|
|||
}
|
||||
}
|
||||
|
||||
TASK(reimu_dream_bomb_noise, { BoxedPlayer plr; }) {
|
||||
Player *plr = TASK_BIND(ARGS.plr);
|
||||
do {
|
||||
TASK(reimu_dream_bomb_noise, NO_ARGS) {
|
||||
for(;;WAIT(16)) {
|
||||
play_sfx("boon");
|
||||
WAIT(16);
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_dream_bomb_barrage, { ReimuBController *ctrl; }) {
|
||||
TASK(reimu_dream_bomb_background, { ReimuBController *ctrl; }) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
reimu_common_bomb_bg(ctrl->plr, ctrl->bomb_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_dream_bomb, { ReimuBController *ctrl; }) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask noise_task = cotask_box(INVOKE_SUBTASK(reimu_dream_bomb_noise));
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_background, ctrl);
|
||||
|
||||
Sprite *spr_proj = res_sprite("proj/glowball");
|
||||
Sprite *spr_impact = res_sprite("part/blast");
|
||||
|
||||
int t = 0;
|
||||
YIELD;
|
||||
|
||||
int t = 0;
|
||||
do {
|
||||
Color *pcolor = HSLA(t/30.0, 0.5, 0.5, 0.5);
|
||||
|
||||
|
@ -180,28 +192,26 @@ TASK(reimu_dream_bomb_barrage, { ReimuBController *ctrl; }) {
|
|||
stage_shake_view(4);
|
||||
t += WAIT(BOMB_PROJECTILE_FIRE_DELAY);
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
|
||||
TASK(reimu_dream_bomb_background, { ReimuBController *ctrl; }) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
CANCEL_TASK(noise_task);
|
||||
|
||||
do {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
reimu_common_bomb_bg(ctrl->plr, ctrl->bomb_alpha);
|
||||
} while(ctrl->bomb_alpha > 0);
|
||||
while(ctrl->bomb_alpha > 0) {
|
||||
// keep bg renderer alive
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_dream_bomb_handler, { ReimuBController *ctrl; }) {
|
||||
ReimuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
CANCEL_TASK(bomb_task);
|
||||
play_sfx("bomb_marisa_a");
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_noise, ENT_BOX(plr));
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_barrage, ctrl);
|
||||
INVOKE_SUBTASK(reimu_dream_bomb_background, ctrl);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(reimu_dream_bomb, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ DEFINE_EXTERN_TASK(youmu_common_bomb_background) {
|
|||
YoumuBombBGData *bg_data = ARGS.bg_data;
|
||||
CoEvent *draw_event = &stage_get_draw_events()->background_drawn;
|
||||
|
||||
do {
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(draw_event);
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr);
|
||||
|
@ -119,5 +119,5 @@ DEFINE_EXTERN_TASK(youmu_common_bomb_background) {
|
|||
r_state_pop();
|
||||
|
||||
capture_frame(bg_data->buffer, r_framebuffer_current());
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -457,11 +457,45 @@ static void youmu_mirror_draw_speed_trail(Projectile *p, int t, ProjDrawRuleArgs
|
|||
r_draw_sprite(&sp);
|
||||
}
|
||||
|
||||
TASK(youmu_mirror_bomb_controller, { YoumuAController *ctrl; }) {
|
||||
TASK(youmu_mirror_bomb_postprocess, { YoumuAMyon *myon; }) {
|
||||
YoumuAMyon *myon = ARGS.myon;
|
||||
CoEvent *pp_event = &stage_get_draw_events()->postprocess_before_overlay;
|
||||
|
||||
ShaderProgram *shader = res_shader("youmua_bomb");
|
||||
Uniform *u_tbomb = r_shader_uniform(shader, "tbomb");
|
||||
Uniform *u_myon = r_shader_uniform(shader, "myon");
|
||||
Uniform *u_fill_overlay = r_shader_uniform(shader, "fill_overlay");
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(pp_event);
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr);
|
||||
float f = fmaxf(0, 1 - 10 * t);
|
||||
cmplx myonpos = CMPLX(creal(myon->pos)/VIEWPORT_W, 1 - cimag(myon->pos)/VIEWPORT_H);
|
||||
|
||||
FBPair *fbpair = stage_get_postprocess_fbpair();
|
||||
r_framebuffer(fbpair->back);
|
||||
|
||||
r_state_push();
|
||||
r_shader_ptr(shader);
|
||||
r_uniform_float(u_tbomb, t);
|
||||
r_uniform_vec2_complex(u_myon, myonpos);
|
||||
r_uniform_vec4(u_fill_overlay, f, f, f, f);
|
||||
draw_framebuffer_tex(fbpair->front, VIEWPORT_W, VIEWPORT_H);
|
||||
r_state_pop();
|
||||
|
||||
fbpair_swap(fbpair);
|
||||
}
|
||||
}
|
||||
|
||||
TASK(youmu_mirror_bomb, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
INVOKE_SUBTASK(youmu_common_bomb_background, ENT_BOX(plr), &ctrl->bomb_bg);
|
||||
INVOKE_SUBTASK(youmu_mirror_bomb_postprocess, myon);
|
||||
|
||||
cmplx vel = -30 * myon->dir;
|
||||
cmplx pos = myon->pos;
|
||||
|
||||
|
@ -470,6 +504,8 @@ TASK(youmu_mirror_bomb_controller, { YoumuAController *ctrl; }) {
|
|||
|
||||
ShaderProgram *silhouette_shader = res_shader("sprite_silhouette");
|
||||
|
||||
YIELD;
|
||||
|
||||
do {
|
||||
pos += vel;
|
||||
|
||||
|
@ -507,49 +543,17 @@ TASK(youmu_mirror_bomb_controller, { YoumuAController *ctrl; }) {
|
|||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
|
||||
TASK(youmu_mirror_bomb_postprocess, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
YoumuAMyon *myon = &ctrl->myon;
|
||||
CoEvent *pp_event = &stage_get_draw_events()->postprocess_before_overlay;
|
||||
|
||||
ShaderProgram *shader = res_shader("youmua_bomb");
|
||||
Uniform *u_tbomb = r_shader_uniform(shader, "tbomb");
|
||||
Uniform *u_myon = r_shader_uniform(shader, "myon");
|
||||
Uniform *u_fill_overlay = r_shader_uniform(shader, "fill_overlay");
|
||||
|
||||
do {
|
||||
WAIT_EVENT_OR_DIE(pp_event);
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr);
|
||||
float f = fmaxf(0, 1 - 10 * t);
|
||||
cmplx myonpos = CMPLX(creal(myon->pos)/VIEWPORT_W, 1 - cimag(myon->pos)/VIEWPORT_H);
|
||||
|
||||
FBPair *fbpair = stage_get_postprocess_fbpair();
|
||||
r_framebuffer(fbpair->back);
|
||||
|
||||
r_state_push();
|
||||
r_shader_ptr(shader);
|
||||
r_uniform_float(u_tbomb, t);
|
||||
r_uniform_vec2_complex(u_myon, myonpos);
|
||||
r_uniform_vec4(u_fill_overlay, f, f, f, f);
|
||||
draw_framebuffer_tex(fbpair->front, VIEWPORT_W, VIEWPORT_H);
|
||||
r_state_pop();
|
||||
|
||||
fbpair_swap(fbpair);
|
||||
} while(player_is_bomb_active(plr));
|
||||
}
|
||||
|
||||
TASK(youmu_mirror_bomb_handler, { YoumuAController *ctrl; }) {
|
||||
YoumuAController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
CANCEL_TASK(bomb_task);
|
||||
play_sfx("bomb_youmu_b");
|
||||
INVOKE_SUBTASK(youmu_mirror_bomb_controller, ctrl);
|
||||
INVOKE_SUBTASK(youmu_common_bomb_background, ENT_BOX(plr), &ctrl->bomb_bg);
|
||||
INVOKE_SUBTASK(youmu_mirror_bomb_postprocess, ctrl);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(youmu_mirror_bomb, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -535,11 +535,15 @@ TASK(youmu_haunting_bomb_slice, { YoumuBController *ctrl; cmplx pos; real angle;
|
|||
}
|
||||
}
|
||||
|
||||
TASK(youmu_haunting_bomb_controller, { YoumuBController *ctrl; }) {
|
||||
TASK(youmu_haunting_bomb, { YoumuBController *ctrl; }) {
|
||||
YoumuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
cmplx origin = plr->pos;
|
||||
|
||||
INVOKE_SUBTASK(youmu_common_bomb_background, ENT_BOX(plr), &ctrl->bomb_bg);
|
||||
|
||||
YIELD;
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
cmplx ofs = cdir(i) * (100 + 10 * i * i * 0.01);
|
||||
|
@ -554,11 +558,13 @@ TASK(youmu_haunting_bomb_handler, { YoumuBController *ctrl; }) {
|
|||
YoumuBController *ctrl = ARGS.ctrl;
|
||||
Player *plr = ctrl->plr;
|
||||
|
||||
BoxedTask bomb_task = { 0 };
|
||||
|
||||
for(;;) {
|
||||
WAIT_EVENT_OR_DIE(&plr->events.bomb_used);
|
||||
CANCEL_TASK(bomb_task);
|
||||
play_sfx("bomb_youmu_b");
|
||||
INVOKE_SUBTASK(youmu_haunting_bomb_controller, ctrl);
|
||||
INVOKE_SUBTASK(youmu_common_bomb_background, ENT_BOX(plr), &ctrl->bomb_bg);
|
||||
bomb_task = cotask_box(INVOKE_SUBTASK(youmu_haunting_bomb, ctrl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue