From f821ac9e6de13b9ffac03158b7301b893ed775d2 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Thu, 3 Aug 2023 03:55:59 +0000 Subject: [PATCH] menu: add basic non-interactable menus --- Makefile | 1 + control.hpp | 17 +++++---- coordinates.hpp | 5 +++ graphic.cpp | 91 ++++++++++++++++++++++++++++++++++--------------- graphic.hpp | 26 ++++++++++++-- main.cpp | 7 +++- menu.cpp | 73 +++++++++++++++++++++++++++++++++++++++ menu.hpp | 31 +++++++++++++++++ 8 files changed, 214 insertions(+), 37 deletions(-) create mode 100644 menu.cpp create mode 100644 menu.hpp diff --git a/Makefile b/Makefile index 9747c51..4559600 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ SRC += input.cpp SRC += vram.cpp SRC += font.cpp SRC += graphic.cpp +SRC += menu.cpp DEP = $(patsubst %.cpp,%.cpp.d,$(SRC)) diff --git a/control.hpp b/control.hpp index 6915880..97072ce 100644 --- a/control.hpp +++ b/control.hpp @@ -24,13 +24,16 @@ struct ligatures_t { }; struct extended_t { - static constexpr uint8_t jpy = 0xa5; // ¥ - static constexpr uint8_t colon_sm = 0xa6; // (small ':' symbol) - static constexpr uint8_t e = 0xe9; // é - static constexpr uint8_t ellipsis = 0xa8; // … - static constexpr uint8_t pk = 0xb2; // ᴾₖ - static constexpr uint8_t mn = 0xb3; // ᴹₙ - static constexpr uint8_t times = 0xd7; // × + static constexpr uint8_t jpy = 0xa5; // ¥ + static constexpr uint8_t colon_sm = 0xa6; // (small ':' symbol) + static constexpr uint8_t e = 0xe9; // é + static constexpr uint8_t ellipsis = 0xa8; // … + static constexpr uint8_t pk = 0xb2; // ᴾₖ + static constexpr uint8_t mn = 0xb3; // ᴹₙ + 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; // }; /* diff --git a/coordinates.hpp b/coordinates.hpp index 9482667..5bfec53 100644 --- a/coordinates.hpp +++ b/coordinates.hpp @@ -21,6 +21,11 @@ struct block_t { int32_t y; }; +struct screen_cell_t { + uint32_t x; + uint32_t y; +}; + struct screen_t { int32_t x; int32_t y; diff --git a/graphic.cpp b/graphic.cpp index 23d7a61..57f5008 100644 --- a/graphic.cpp +++ b/graphic.cpp @@ -1,19 +1,16 @@ #include -#include "vdp2.h" - -#include "coordinates.hpp" #include "graphic.hpp" +#include "coordinates.hpp" #include "font.hpp" #include "start_size.hpp" #include "control.hpp" -#include "render_map.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_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 = 110; static constexpr uint8_t horizontal = 111; @@ -21,7 +18,7 @@ struct dialog_border { struct battle_border { 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 vertical = 99; static constexpr uint8_t corner_bot_left = 100; @@ -31,38 +28,84 @@ struct battle_border { static constexpr uint8_t arrow_left = 104; }; -static inline void put_char(const uint32_t base_pattern, - const int32_t x, const int32_t y, - const uint8_t c) +#define S reinterpret_cast + +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) - + ((cell_offset::y + y) * 64 + (cell_offset::x + x)); - vdp2.vram.u16[ix] = ((base_pattern + c) & 0xfff) | PATTERN_NAME_TABLE_1WORD__PALETTE(1); + 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_t& top_left, const screen_t& bot_right) + 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, bot_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, top_left.x, bot_right.y, dialog_border::corner_bot_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_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 put_char(base_pattern, top_left.x, y, dialog_border::vertical); // 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 put_char(base_pattern, x, top_left.y, dialog_border::horizontal); // 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) { draw_box_border(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(' ')); - } + draw_box_background(base_pattern, top_left, bottom_right); uint32_t ix = 0; uint32_t x = top_left.x + 1; diff --git a/graphic.hpp b/graphic.hpp index 2da2324..d86a74c 100644 --- a/graphic.hpp +++ b/graphic.hpp @@ -1,11 +1,33 @@ #pragma once +#include "coordinates.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 { - static constexpr screen_t top_left = { 0, 12}; - static constexpr screen_t bottom_right = {19, 17}; + static constexpr screen_cell_t top_left = { 0, 12}; + static constexpr screen_cell_t bottom_right = {19, 17}; static void draw(const uint32_t base_pattern, const start_size_t& text); diff --git a/main.cpp b/main.cpp index 39b7135..9460b8a 100644 --- a/main.cpp +++ b/main.cpp @@ -24,6 +24,7 @@ #include "ledge_tiles.hpp" #include "graphic.hpp" +#include "menu.hpp" struct draw_t { struct { @@ -420,7 +421,7 @@ void update() 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_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() @@ -437,6 +438,10 @@ void render() vdp2.reg.SCYDN0 = 0; 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" diff --git a/menu.cpp b/menu.cpp new file mode 100644 index 0000000..3128049 --- /dev/null +++ b/menu.cpp @@ -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(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); +} diff --git a/menu.hpp b/menu.hpp new file mode 100644 index 0000000..92abc93 --- /dev/null +++ b/menu.hpp @@ -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);