menu: add basic non-interactable menus

This commit is contained in:
Zack Buhman 2023-08-03 03:55:59 +00:00
parent 853457a79d
commit f821ac9e6d
8 changed files with 214 additions and 37 deletions

View File

@ -21,6 +21,7 @@ SRC += input.cpp
SRC += vram.cpp SRC += vram.cpp
SRC += font.cpp SRC += font.cpp
SRC += graphic.cpp SRC += graphic.cpp
SRC += menu.cpp
DEP = $(patsubst %.cpp,%.cpp.d,$(SRC)) DEP = $(patsubst %.cpp,%.cpp.d,$(SRC))

View File

@ -31,6 +31,9 @@ struct extended_t {
static constexpr uint8_t pk = 0xb2; // ᴾₖ static constexpr uint8_t pk = 0xb2; // ᴾₖ
static constexpr uint8_t mn = 0xb3; // ᴹₙ static constexpr uint8_t mn = 0xb3; // ᴹₙ
static constexpr uint8_t times = 0xd7; // × static constexpr uint8_t times = 0xd7; // ×
static constexpr uint8_t l_arrow = 0x75; // →
static constexpr uint8_t l_arrow_solid = 0x76; // →
static constexpr uint8_t d_arrow = 0x77; //
}; };
/* /*

View File

@ -21,6 +21,11 @@ struct block_t {
int32_t y; int32_t y;
}; };
struct screen_cell_t {
uint32_t x;
uint32_t y;
};
struct screen_t { struct screen_t {
int32_t x; int32_t x;
int32_t y; int32_t y;

View File

@ -1,19 +1,16 @@
#include <cstdint> #include <cstdint>
#include "vdp2.h"
#include "coordinates.hpp"
#include "graphic.hpp" #include "graphic.hpp"
#include "coordinates.hpp"
#include "font.hpp" #include "font.hpp"
#include "start_size.hpp" #include "start_size.hpp"
#include "control.hpp" #include "control.hpp"
#include "render_map.hpp"
struct dialog_border { struct dialog_border {
static constexpr uint8_t corner_top_left = 105; static constexpr uint8_t corner_top_left = 105;
static constexpr uint8_t corner_top_right = 106; static constexpr uint8_t corner_top_right = 106;
static constexpr uint8_t corner_bot_left = 107; static constexpr uint8_t corner_bot_left = 107;
static constexpr uint8_t corner_bot_right = 108; static constexpr uint8_t corner_bottom_right = 108;
static constexpr uint8_t vertical_end_cap = 109; static constexpr uint8_t vertical_end_cap = 109;
static constexpr uint8_t vertical = 110; static constexpr uint8_t vertical = 110;
static constexpr uint8_t horizontal = 111; static constexpr uint8_t horizontal = 111;
@ -21,7 +18,7 @@ struct dialog_border {
struct battle_border { struct battle_border {
static constexpr uint8_t horizontal = 96; static constexpr uint8_t horizontal = 96;
static constexpr uint8_t corner_bot_right = 97; static constexpr uint8_t corner_bottom_right = 97;
static constexpr uint8_t arrow_right = 98; static constexpr uint8_t arrow_right = 98;
static constexpr uint8_t vertical = 99; static constexpr uint8_t vertical = 99;
static constexpr uint8_t corner_bot_left = 100; static constexpr uint8_t corner_bot_left = 100;
@ -31,38 +28,84 @@ struct battle_border {
static constexpr uint8_t arrow_left = 104; static constexpr uint8_t arrow_left = 104;
}; };
static inline void put_char(const uint32_t base_pattern, #define S reinterpret_cast<const uint8_t *>
const int32_t x, const int32_t y,
const uint8_t c) void draw_text(const uint32_t base_pattern,
const uint8_t * text,
const uint32_t x, const uint32_t y)
{ {
const int32_t ix = (0x2000 / 2) uint8_t i = 0, x_o = 0;
+ ((cell_offset::y + y) * 64 + (cell_offset::x + x)); uint8_t c;
vdp2.vram.u16[ix] = ((base_pattern + c) & 0xfff) | PATTERN_NAME_TABLE_1WORD__PALETTE(1);
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, void draw_box_border(const uint32_t base_pattern,
const screen_t& top_left, const screen_t& bot_right) const screen_cell_t& top_left, const screen_cell_t& bottom_right)
{ {
// place corners // place corners
put_char(base_pattern, top_left.x, top_left.y, dialog_border::corner_top_left); put_char(base_pattern, top_left.x, top_left.y, dialog_border::corner_top_left);
put_char(base_pattern, bot_right.x, top_left.y, dialog_border::corner_top_right); put_char(base_pattern, bottom_right.x, top_left.y, dialog_border::corner_top_right);
put_char(base_pattern, bot_right.x, bot_right.y, dialog_border::corner_bot_right); put_char(base_pattern, bottom_right.x, bottom_right.y, dialog_border::corner_bottom_right);
put_char(base_pattern, top_left.x, bot_right.y, dialog_border::corner_bot_left); put_char(base_pattern, top_left.x, bottom_right.y, dialog_border::corner_bot_left);
for (int32_t y = top_left.y + 1; y < bot_right.y; y++) { for (uint32_t y = top_left.y + 1; y < bottom_right.y; y++) {
// left vertical bar // left vertical bar
put_char(base_pattern, top_left.x, y, dialog_border::vertical); put_char(base_pattern, top_left.x, y, dialog_border::vertical);
// right vertical bar // right vertical bar
put_char(base_pattern, bot_right.x, y, dialog_border::vertical); put_char(base_pattern, bottom_right.x, y, dialog_border::vertical);
} }
for (int32_t x = top_left.x + 1; x < bot_right.x; x++) { for (uint32_t x = top_left.x + 1; x < bottom_right.x; x++) {
// top horizontal bar // top horizontal bar
put_char(base_pattern, x, top_left.y, dialog_border::horizontal); put_char(base_pattern, x, top_left.y, dialog_border::horizontal);
// bottom horizontal bar // bottom horizontal bar
put_char(base_pattern, x, bot_right.y, dialog_border::horizontal); 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 (uint32_t x = top_left.x + 1; x < bottom_right.x; x++) {
for (uint32_t y = top_left.y + 1; y < bottom_right.y; y++) {
put_char(base_pattern, x, y, ascii_to_font(' '));
}
} }
} }
@ -70,13 +113,7 @@ void dialog_t::draw(const uint32_t base_pattern,
const start_size_t& text) const start_size_t& text)
{ {
draw_box_border(base_pattern, top_left, bottom_right); draw_box_border(base_pattern, top_left, bottom_right);
draw_box_background(base_pattern, top_left, bottom_right);
for (uint32_t x = top_left.x + 1; x < bottom_right.x; x++) {
put_char(base_pattern, x, top_left.y + 1, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 2, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 3, ascii_to_font(' '));
put_char(base_pattern, x, top_left.y + 4, ascii_to_font(' '));
}
uint32_t ix = 0; uint32_t ix = 0;
uint32_t x = top_left.x + 1; uint32_t x = top_left.x + 1;

View File

@ -1,11 +1,33 @@
#pragma once #pragma once
#include "coordinates.hpp"
#include "start_size.hpp" #include "start_size.hpp"
#include "render_map.hpp" // for cell_offset
#include "vdp2.h"
static inline void put_char(const uint32_t base_pattern,
const int32_t x, const int32_t y, // in cells
const uint8_t c)
{
const int32_t ix = (0x2000 / 2)
+ ((cell_offset::y + y) * 64 + (cell_offset::x + x));
vdp2.vram.u16[ix] = ((base_pattern + c) & 0xfff) | PATTERN_NAME_TABLE_1WORD__PALETTE(1);
}
void draw_text(const uint32_t base_pattern,
const uint8_t * text,
const uint32_t x, const uint32_t y);
void draw_box_border(const uint32_t base_pattern,
const screen_cell_t& top_left, const screen_cell_t& bottom_right);
void draw_box_background(const uint32_t base_pattern,
const screen_cell_t& top_left, const screen_cell_t& bottom_right);
struct dialog_t struct dialog_t
{ {
static constexpr screen_t top_left = { 0, 12}; static constexpr screen_cell_t top_left = { 0, 12};
static constexpr screen_t bottom_right = {19, 17}; static constexpr screen_cell_t bottom_right = {19, 17};
static void draw(const uint32_t base_pattern, static void draw(const uint32_t base_pattern,
const start_size_t& text); const start_size_t& text);

View File

@ -24,6 +24,7 @@
#include "ledge_tiles.hpp" #include "ledge_tiles.hpp"
#include "graphic.hpp" #include "graphic.hpp"
#include "menu.hpp"
struct draw_t { struct draw_t {
struct { struct {
@ -420,7 +421,7 @@ void update()
else if (event::cursor_right()) collision_move(maps[state.map], actor_t::right); else if (event::cursor_right()) collision_move(maps[state.map], actor_t::right);
else if (event::cursor_up() ) collision_move(maps[state.map], actor_t::up); else if (event::cursor_up() ) collision_move(maps[state.map], actor_t::up);
else if (event::cursor_down() ) collision_move(maps[state.map], actor_t::down); else if (event::cursor_down() ) collision_move(maps[state.map], actor_t::down);
else if (event::button_a() ) check_sign(); //else if (event::button_a() ) check_sign();
} }
void render() void render()
@ -437,6 +438,10 @@ void render()
vdp2.reg.SCYDN0 = 0; vdp2.reg.SCYDN0 = 0;
render_map(); render_map();
draw_menu(state.draw.base_pattern.font, fight_menu);
cursor_t cursor = { 1, 1 };
draw_menu_cursor(state.draw.base_pattern.font, fight_menu, cursor);
} }
extern "C" extern "C"

73
menu.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "graphic.hpp"
#include "menu.hpp"
#include "control.hpp"
#define POKE "\x94"
#define TRAINER "\x92"
#define PKMN "\x96"
#define S(v) reinterpret_cast<const uint8_t *>(v)
const menu_t start_menu = {
.top_left = {10, 0},
.bottom_right = {19, 15},
.width = 1,
.height = 7,
.h_advance = 0,
.v_advance = 2,
.items = (menu_item_t[]){
{ S(POKE "DEX") },
{ S(POKE "MON") },
{ S("ITEM" ) },
{ S(TRAINER ) },
{ S("SAVE" ) },
{ S("OPTION" ) },
{ S("EXIT" ) },
},
};
const menu_t fight_menu = {
.top_left = {8, 12},
.bottom_right = {19, 17},
.width = 2,
.height = 2,
.h_advance = 6,
.v_advance = 2,
.items = (menu_item_t[]) {
{ S("FIGHT") }, { S(PKMN ) },
{ S("ITEM" ) }, { S("RUN") },
},
};
#undef S
void draw_menu(const uint32_t base_pattern,
const menu_t& menu)
{
draw_box_border(base_pattern,
menu.top_left, menu.bottom_right);
draw_box_background(base_pattern,
menu.top_left, menu.bottom_right);
for (uint32_t y = 0; y < menu.height; y++) {
for (uint32_t x = 0; x < menu.width; x++) {
const menu_item_t& item = menu.items[menu.width * y + x];
const uint32_t cell_x = menu.top_left.x + 2 + (menu.h_advance * x);
const uint32_t cell_y = menu.top_left.y + menu.v_advance + (menu.v_advance * y);
draw_text(base_pattern, item.label, cell_x, cell_y);
}
}
}
void draw_menu_cursor(const uint32_t base_pattern,
const menu_t& menu,
const cursor_t& cursor)
{
const uint32_t cell_x = menu.top_left.x + 1 + (menu.h_advance * cursor.x);
const uint32_t cell_y = menu.top_left.y + menu.v_advance + (menu.v_advance * cursor.y);
put_char(base_pattern, cell_x, cell_y, extended_t::l_arrow_solid);
}

31
menu.hpp Normal file
View File

@ -0,0 +1,31 @@
#include "coordinates.hpp"
struct menu_item_t {
const uint8_t * label;
};
struct menu_t {
screen_cell_t top_left; // in cells
screen_cell_t bottom_right; // in cells
uint8_t width; // in menu items
uint8_t height; // in menu items
uint8_t h_advance; // in cells
uint8_t v_advance; // in cells
const menu_item_t * items;
};
struct cursor_t {
uint16_t x; // in menu items
uint16_t y; // in menu items
};
extern const menu_t start_menu;
extern const menu_t fight_menu;
void draw_menu(const uint32_t base_pattern,
const menu_t& menu);
void draw_menu_cursor(const uint32_t base_pattern,
const menu_t& menu,
const cursor_t& cursor);