ReC98/th01/main/hud/hp.cpp

133 lines
3.7 KiB
C++

#include "th01/sprites/main_ptn.h"
#include "th01/main/hud/hp.hpp"
/// Constants
/// ---------
static const screen_x_t HP_LEFT = 128;
static const vram_y_t HP_TOP = 48;
#define HP_POINT_W 8
#define HP_H 15
/// ---------
/// Foreground
/// ----------
// Yup, numbered right-to-left :zunpet:
enum hp_section_t {
HP_SECTION_WHITE,
HP_SECTION_REDWHITE,
HP_SECTION_RED,
_hp_section_t_FORCE_INT16 = 0x7FFF,
};
void grcg_set_redwhite(void)
{
grcg_setmode(GC_RMW); // Final color: (A7A7A7A7)
outportb(0x7E, 0x55); // B: ( * * * *)
outportb(0x7E, 0xFF); // R: (********)
outportb(0x7E, 0x55); // G: ( * * * *)
outportb(0x7E, 0xAA); // E: (* * * * )
}
void hp_put_with_section_pattern(int point, hp_section_t section)
{
dots8_t dots = 0xFE; // (******* )
vram_offset_t vo = (
vram_offset_shift(HP_LEFT, HP_TOP) + (point * (HP_POINT_W / BYTE_DOTS))
);
if(section == HP_SECTION_RED) {
grcg_setcolor_rmw(10);
} else if(section == HP_SECTION_WHITE) {
grcg_setcolor_rmw(7);
} else if(section == HP_SECTION_REDWHITE) {
grcg_set_redwhite();
}
for(unsigned char y = 0; y < HP_H; y++) {
graph_accesspage_func(1); grcg_put(vo, dots, HP_POINT_W);
graph_accesspage_func(0); grcg_put(vo, dots, HP_POINT_W);
vo += ROW_SIZE;
}
grcg_off();
}
#define hp_put(point_to_put, point_in_hopefully_same_section) \
if(point_in_hopefully_same_section < hud_hp_first_redwhite) { \
hp_put_with_section_pattern(point_to_put, HP_SECTION_RED); \
} else if(point_in_hopefully_same_section < hud_hp_first_white) { \
hp_put_with_section_pattern(point_to_put, HP_SECTION_REDWHITE); \
} else { \
hp_put_with_section_pattern(point_to_put, HP_SECTION_WHITE); \
}
/// ----------
/// Background
/// ----------
/// Whew, using a 16x16 wrapper around a 32x32 set of graphics functions in
/// order to handle backgrounds for 8x16 sprites... That's quite the recipe
// for confusion. *Especially* if you don't write functions to abstract away
// this needless complexity.
#if (HP_POINT_W != (PTN_QUARTER_W / 2))
#error Original code assumes HP_POINT_W == (PTN_QUARTER_W / 2)
#endif
static const pixel_t HP_2POINT_W = PTN_QUARTER_W;
#define hp_bg_left(point_divided_by_2) \
(((point_divided_by_2) * HP_2POINT_W) + HP_LEFT)
// As a result, this one ends up always being called twice as much (i.e., for
// each hit point) as it needs to be (i.e., once for every 2 HP). Not *really*
// a ZUN "bug", just slightly sloppy.
#define hp_bg_snap_nth_doublepoint(point_divided_by_2) \
ptn_snap_quarter_8(\
hp_bg_left(point_divided_by_2), \
HP_TOP, \
(((point_divided_by_2) / 4) + PTN_BG_HP), \
((point_divided_by_2) % 4) \
)
#define hp_bg_put_doublepoint_containing(point) \
ptn_put_quarter_noalpha_8( \
hp_bg_left((point) / 2), \
HP_TOP, \
(((point) / 8) + PTN_BG_HP), \
(((point) / 2) % 4) \
)
//// ---------
bool16 hud_hp_render(int hp_total, int func)
{
if(func == HUD_HP_FUNC_DECREMENT) {
graph_accesspage_func(1); hp_bg_put_doublepoint_containing(hp_total);
graph_accesspage_func(0); hp_bg_put_doublepoint_containing(hp_total);
// Since a .PTN quarter stores the background of two hit points, the
// calls above will unblit two hit points if [hp_total] is odd. So...
if((hp_total % 2) == 1) {
// ZUN bug: Yes, this will use the wrong section pattern when
// the section boundaries are odd. Just use one parameter... sigh.
hp_put((hp_total - 1), hp_total);
}
} else if(func == HUD_HP_FUNC_RERENDER) {
for(int i = 0; i < hp_total; i++) {
hp_bg_snap_nth_doublepoint(i);
hp_put(i, i);
}
} else { // Increment
#define hp_cur func
hp_bg_snap_nth_doublepoint(hp_cur);
hp_put(hp_cur, hp_cur);
if((hp_total - 1) == hp_cur) {
return true;
}
#undef hp_cur
}
return false;
}