pokemon/graphic.cpp
Zack Buhman 3d8110ca1c graphic: add functions to draw stats screen borders
This also draws pokemon sprites on the screen, sequentially.
2023-08-03 22:19:01 +00:00

246 lines
7.2 KiB
C++

#include <cstdint>
#include "graphic.hpp"
#include "coordinates.hpp"
#include "font.hpp"
#include "start_size.hpp"
#include "control.hpp"
struct dialog_border {
static constexpr uint8_t corner_top_left = 105;
static constexpr uint8_t corner_top_right = 106;
static constexpr uint8_t corner_bottom_left = 107;
static constexpr uint8_t corner_bottom_right = 108;
static constexpr uint8_t vertical_end_cap = 109;
static constexpr uint8_t vertical = 110;
static constexpr uint8_t horizontal = 111;
};
struct battle_border {
static constexpr uint8_t horizontal = 96;
static constexpr uint8_t corner_bottom_right = 97;
static constexpr uint8_t arrow_right = 98;
static constexpr uint8_t vertical = 99;
static constexpr uint8_t corner_bottom_left = 100;
static constexpr uint8_t three_dots = 101;
static constexpr uint8_t vertical_end_cap = 102;
static constexpr uint8_t level = 103;
static constexpr uint8_t arrow_left = 104;
};
struct hp_bar {
static constexpr uint8_t hp = 0x50;
static constexpr uint8_t start_cap = 0x51;
static constexpr uint8_t seg0 = 0x52;
static constexpr uint8_t seg1 = 0x53;
static constexpr uint8_t seg2 = 0x54;
static constexpr uint8_t seg3 = 0x55;
static constexpr uint8_t seg4 = 0x56;
static constexpr uint8_t seg5 = 0x57;
static constexpr uint8_t seg6 = 0x58;
static constexpr uint8_t seg7 = 0x59;
static constexpr uint8_t seg8 = 0x5a;
static constexpr uint8_t end_cap_nobar = 0x5b;
static constexpr uint8_t end_cap_bar = 0x66;
};
#define S reinterpret_cast<const uint8_t *>
void draw_text(const uint32_t base_pattern,
const uint8_t * text,
const int32_t x, const int32_t y)
{
uint8_t i = 0, x_o = 0;
uint8_t c;
auto draw_ligature = [&](const uint8_t * l_text)
{
uint8_t j = 0;
uint8_t d;
while ((d = l_text[j++]) != 0)
put_char(base_pattern, x + x_o++, y, ascii_to_font(d));
};
while ((c = text[i++]) != 0) {
switch (c) {
case ligatures_t::pkmn:
{
static const uint8_t * pkmn = S("\xb2\xb3");
draw_ligature(pkmn);
}
break;
case ligatures_t::poke:
{
static const uint8_t * poke = S("POK\xe9");
draw_ligature(poke);
}
break;
case ligatures_t::trainer:
{
static const uint8_t * trainer = S("TRAINER");
draw_ligature(trainer);
}
break;
default:
put_char(base_pattern, x + x_o++, y, ascii_to_font(c));
break;
}
}
}
#undef S
void draw_box_border(const uint32_t base_pattern,
const screen_cell_t& top_left, const screen_cell_t& bottom_right)
{
// place corners
put_char(base_pattern, top_left.x, top_left.y, dialog_border::corner_top_left);
put_char(base_pattern, bottom_right.x, top_left.y, dialog_border::corner_top_right);
put_char(base_pattern, bottom_right.x, bottom_right.y, dialog_border::corner_bottom_right);
put_char(base_pattern, top_left.x, bottom_right.y, dialog_border::corner_bottom_left);
for (int32_t y = top_left.y + 1; y < bottom_right.y; y++) {
// left vertical bar
put_char(base_pattern, top_left.x, y, dialog_border::vertical);
// right vertical bar
put_char(base_pattern, bottom_right.x, y, dialog_border::vertical);
}
for (int32_t x = top_left.x + 1; x < bottom_right.x; x++) {
// top horizontal bar
put_char(base_pattern, x, top_left.y, dialog_border::horizontal);
// bottom horizontal bar
put_char(base_pattern, x, bottom_right.y, dialog_border::horizontal);
}
}
void draw_box_background(const uint32_t base_pattern,
const screen_cell_t& top_left, const screen_cell_t& bottom_right)
{
for (int32_t x = top_left.x + 1; x < bottom_right.x; x++) {
for (int32_t y = top_left.y + 1; y < bottom_right.y; y++) {
put_char(base_pattern, x, y, ascii_to_font(' '));
}
}
}
void draw_battle_border(const uint32_t base_pattern,
const screen_cell_t& top_corner, const screen_cell_t& bottom_corner)
{
// draw the vertical line
for (int32_t y = top_corner.y; y < bottom_corner.y; y++)
put_char(base_pattern, top_corner.x, y, battle_border::vertical);
// decide which direction we are drawing
const int32_t increment = bottom_corner.x <= top_corner.x ? 1 : -1;
// draw the horizontal line
for (int32_t x = bottom_corner.x + increment; x != top_corner.x; x += increment)
put_char(base_pattern, x, bottom_corner.y, battle_border::horizontal);
// draw the end cap and corner piece
const uint8_t end_cap = increment == 1 ? battle_border::arrow_left
: battle_border::arrow_right;
const uint8_t corner = increment == 1 ? battle_border::corner_bottom_right
: battle_border::corner_bottom_left;
put_char(base_pattern, bottom_corner.x, bottom_corner.y, end_cap);
put_char(base_pattern, top_corner.x , bottom_corner.y, corner );
}
constexpr inline uint8_t hp_seg(const int32_t hp_48, const int32_t ix)
{
const int32_t hp_ix = hp_48 - (ix * 8);
if (hp_ix < 0) return hp_bar::seg0;
switch (hp_ix) {
default: [[fallthrough]];
case 8: return hp_bar::seg8;
case 7: return hp_bar::seg7;
case 6: return hp_bar::seg6;
case 5: return hp_bar::seg5;
case 4: return hp_bar::seg4;
case 3: return hp_bar::seg3;
case 2: return hp_bar::seg2;
case 1: return hp_bar::seg1;
case 0: return hp_bar::seg0;
}
}
void draw_hp_bar(const uint32_t base_pattern,
const screen_cell_t& top_left,
const uint8_t end_cap,
const int32_t hp_48)
{
put_char(base_pattern, top_left.x + 0, top_left.y, hp_bar::hp);
put_char(base_pattern, top_left.x + 1, top_left.y, hp_bar::start_cap);
for (int32_t ix = 0; ix < 6; ix++) {
const uint8_t seg = hp_seg(hp_48, ix);
put_char(base_pattern, top_left.x + 2 + ix, top_left.y, seg);
}
put_char(base_pattern, top_left.x + 8, top_left.y, end_cap);
}
static uint32_t hp = 0;
void draw_stats1(const uint32_t base_pattern)
{
// white out the entire screen
draw_box_background(base_pattern, {-1, -1}, {20, 18});
// top status battle box
draw_battle_border(base_pattern, {19, 1}, {8, 7});
draw_hp_bar(base_pattern, {11, 4}, hp_bar::end_cap_bar, (hp >> 3) % 48);
hp++;
// bottom border
draw_battle_border(base_pattern, {19, 9}, {12, 17});
// bottom left dialog box
draw_box_border(base_pattern, {0, 8}, {9, 17});
}
void dialog_t::draw(const uint32_t base_pattern,
const start_size_t& text)
{
draw_box_border(base_pattern, top_left, bottom_right);
draw_box_background(base_pattern, top_left, bottom_right);
uint32_t ix = 0;
int32_t x = top_left.x + 1;
int32_t y = top_left.y + 2;
// ignore C-string null terminator
while (ix < (text.size - 1)) {
const uint8_t c = text.start[ix];
switch (c) {
case control_t::text: break;
case control_t::done: break;
case control_t::prompt: break;
case control_t::page: break;
case control_t::next: [[fallthrough]];
case control_t::line:
while (x < bottom_right.x) {
put_char(base_pattern, x, y, ascii_to_font(' '));
x++;
}
x = top_left.x + 1;
y += 2;
break;
case control_t::para: [[fallthrough]];
case control_t::cont:
// fixme:
ix = text.size;
break;
default:
put_char(base_pattern, x, y, ascii_to_font(c));
x += 1;
break;
}
ix++;
}
}