ReC98/th01/main/boss/boss.hpp

116 lines
3.6 KiB
C++

/// Generic state variables
/// -----------------------
/// Really just freely usable memory shared between all bosses.
extern int boss_hp;
extern int boss_phase_frame;
extern int8_t boss_phase;
/// -----------------------
// No-op function for callbacks.
void pascal boss_nop(void);
static const int BOSS_HIT_INVINCIBILITY_FRAMES = 40;
// Processes collisions between the Orb and a boss, and the resulting
// invincibility of the latter… yeah, that's about the best summary for this
// function that does way too many things on the one hand, yet still leaves the
// caller to do way too much itself:
//
// • If a player shot hitbox is given, it also handles collisions between
// player shots, regardless of invincibility. At the right and bottom edges,
// the coordinates of that hitbox correspond to the top-left edge of the shot
// sprite; use the shot_hitbox_t() macro to express their width and height in
// a more visually correct way.
//
// • The hit testing against the Orb must be done before, with the result
// being passed in [colliding_with_orb]. That parameter is what mainly
// triggers the collision response of adding the [hit_score], decrementing
// [hp], bouncing off the Orb in the opposite direction, calling
// [hit_callback], and rendering the invincibility flashing effect.
//
// • The caller is still responsible to increment [invincibility_frame]. This
// function only reads from it or resets it to 0 once it reaches
// BOSS_HIT_INVINCIBILITY_FRAMES.
//
// • [is_invincible] is always updated from this function, though.
//
// • Therefore, it only indirectly returns whether the boss was hit this
// frame, via ([is_invincible] == true) && ([invincibility_frame] == 0).
// (That fact makes [is_invincible] not quite as redundant as it might seem.)
//
// • Once [invincibility_frame] reaches BOSS_HIT_INVINCIBILITY_FRAMES, this
// function resets the hardware palette to the [boss_palette] to end the
// flash effect, as you would expect. However, this final reset actually
// happens *regardless* of whether [is_invincible] is `true`, which can
// definitely be classified as a bug. Refer to the bug explanation in the
// function definition for more detail.
void boss_hit_update_and_render(
int &invincibility_frame,
bool16 &is_invincible,
int &hp,
const vc_t invincibility_flash_colors[],
unsigned char invincibility_flash_colors_count,
int hit_score,
farfunc_t_far hit_callback,
bool colliding_with_orb,
screen_x_t shot_hitbox_left = 0,
screen_y_t shot_hitbox_top = 0,
pixel_t shot_hitbox_w_minus_shot_w = 0,
pixel_t shot_hitbox_h_minus_shot_h = 0
);
// Individual bosses
// -----------------
enum boss_id_t {
BID_NONE,
BID_SINGYOKU,
BID_YUUGENMAGAN,
BID_MIMA,
BID_KIKURI,
BID_ELIS,
BID_SARIEL,
BID_KONNGARA,
_boss_id_t_FORCE_INT16 = 0x7FFF
};
static const pixel_t SINGYOKU_W = 96;
// Actually required publicly, as singyoku_defeat_animate_and_select_route()
// is part of the regular boss defeat translation unit.
static const pixel_t SINGYOKU_H = 96;
void singyoku_load(void);
void singyoku_main(void);
void singyoku_free(void);
// Makai
void yuugenmagan_load(void);
void yuugenmagan_main(void);
void yuugenmagan_free(void);
void elis_load(void);
void elis_main(void);
void elis_free(void);
void sariel_entrance(int8_t unused);
void sariel_load_and_init(void);
void sariel_main(void);
void sariel_free(void);
// Jigoku
void mima_load(void);
void mima_main(void);
void mima_free(void);
void kikuri_load(void);
void kikuri_main(void);
void kikuri_free(void);
void konngara_load_and_entrance(int8_t unused);
void konngara_init(void);
void konngara_main(void);
void konngara_free(void);
// -----------------