#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; }