diff --git a/th01/hardware/grpinv32.hpp b/th01/hardware/grpinv32.hpp index 94c332c4..e22e543d 100644 --- a/th01/hardware/grpinv32.hpp +++ b/th01/hardware/grpinv32.hpp @@ -36,12 +36,44 @@ inline long entrance_ring_radius(pixel_t base, unsigned int square_i) { for( \ square_i = (1 * ENTRANCE_RING_SQUARES); \ square_i < ((1 + ENTRANCE_RING_STACK) * ENTRANCE_RING_SQUARES); \ - i++ \ + square_i++ \ ) { \ invert_lhs entrance_ring_invert(square_i, radius_base); \ } \ } -#define entrance_rings_done(squares_offscreen) \ - (squares_offscreen >= (ENTRANCE_RING_STACK * ENTRANCE_RING_SQUARES)) +// Well, well, we'd *really* like call sites to use this macro within an `if` +// statement. That makes it looks as if this macro is actually a function that +// returns whether the animation is done or not. Unfortunately, the completion +// condition is itself nested within a conditional branch. This only leaves +// ugly workarounds: +// +// 1) Forcing calling sites to close a block they didn't open +// 2) A fake lambda function in another macro parameter +// 3) Using `goto` and jumping to a label (`entrance_rings_still_active`) that +// we force the call site to define +// +// Option 3) doesn't introduce weird syntax and thus feels like the most +// natural choice. +#define entrance_rings_update_and_render( \ + radius_base, i, squares_offscreen, frame, radius_base_initial, frame_first \ +) \ + frame == frame_first) { \ + radius_base = radius_base_initial; \ + goto entrance_rings_still_active; \ + } else if(frame == (frame_first + 1)) { \ + entrance_rings_invert(i, {}, radius_base); \ + goto entrance_rings_still_active; \ + } else if((frame > (frame_first + 1)) && ((frame % 4) == 0)) { \ + /* "Un-invert" the previous frame */ \ + entrance_rings_invert(i, {}, radius_base); \ + \ + radius_base += 16; \ + squares_offscreen = 0; \ + \ + entrance_rings_invert(i, squares_offscreen +=, radius_base); \ + } else { \ + goto entrance_rings_still_active; \ + } \ + if(squares_offscreen >= (ENTRANCE_RING_STACK * ENTRANCE_RING_SQUARES) /// ------------------------------------------------ diff --git a/th01/main/boss/b20m.cpp b/th01/main/boss/b20m.cpp index e72d075d..693da6fa 100644 --- a/th01/main/boss/b20m.cpp +++ b/th01/main/boss/b20m.cpp @@ -2648,39 +2648,32 @@ void sariel_main(void) random_seed = frame_rand; while(1) { - boss_phase_frame++; - if(boss_phase_frame == 1) { - entrance_ring_radius_base = 16; - } else if(boss_phase_frame == 2) { - entrance_rings_invert(i, {}, entrance_ring_radius_base); - } else if((boss_phase_frame > 2) && ((boss_phase_frame % 4) == 0)) { - // "Un-invert" the previous frame - entrance_rings_invert(i, {}, entrance_ring_radius_base); + #define frame_half boss_phase_frame - entrance_ring_radius_base += 16; - unsigned int squares_offscreen = 0; + unsigned int tmp; - entrance_rings_invert( - i, squares_offscreen +=, entrance_ring_radius_base - ); - if(entrance_rings_done(squares_offscreen)) { - boss_phase = 1; - phase.pattern_cur = 0; - phase.ax.patterns_done = 0; - phase.patterns_until_next = ((rand() % 6) + 1); - boss_phase_frame = 0; - initial_hp_rendered = 0; - boss_palette_show(); // Unnecessary. - ent_shield.pos_cur_set(SHIELD_LEFT, SHIELD_TOP); - wand_lowered_snap(); - wand_render_raise_both(true); - birds_reset(); - return; - } + frame_half++; + if(entrance_rings_update_and_render( + entrance_ring_radius_base, i, tmp, frame_half, 16, 1 + )) { + boss_phase = 1; + phase.pattern_cur = 0; + phase.ax.patterns_done = 0; + phase.patterns_until_next = ((rand() % 6) + 1); + boss_phase_frame = 0; + initial_hp_rendered = 0; + boss_palette_show(); // Unnecessary. + ent_shield.pos_cur_set(SHIELD_LEFT, SHIELD_TOP); + wand_lowered_snap(); + wand_render_raise_both(true); + birds_reset(); + break; } - if(boss_phase_frame % 2) { +entrance_rings_still_active: + if(frame_half % 2) { // That's why we've renamed the variable frame_delay(1); } + #undef frame_half } } else if(boss_phase == 1) { hud_hp_increment_render(initial_hp_rendered, boss_hp, boss_phase_frame);