307 lines
7.4 KiB
C++
307 lines
7.4 KiB
C++
#include "menu.hpp"
|
|
#include "window.hpp"
|
|
#include "../graphic.hpp"
|
|
#include "../control.hpp"
|
|
#include "../trainer.hpp"
|
|
#include "../font.hpp"
|
|
#include "../number.hpp"
|
|
#include "../gen/pokemon/moves.hpp"
|
|
#include "../gen/pokemon/types.hpp"
|
|
|
|
#define POKE "\x94"
|
|
#define TRAINER "\x92"
|
|
#define PKMN "\x96"
|
|
|
|
#define S(v) reinterpret_cast<const uint8_t *>(v)
|
|
|
|
static void draw_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, interactive::l_arrow_solid);
|
|
}
|
|
|
|
static void draw_menu(const uint32_t base_pattern,
|
|
const menu_t& menu,
|
|
const trainer_state_t& trainer_state)
|
|
{
|
|
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 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);
|
|
const uint32_t menu_entry_index = menu.width * y + x;
|
|
const menu_entry_t& entry = menu.entry;
|
|
|
|
if (menu.entry_type == menu_t::labels) {
|
|
draw_text(base_pattern,
|
|
entry.labels[menu_entry_index],
|
|
cell_x, cell_y);
|
|
} else {
|
|
draw_text(base_pattern,
|
|
entry.label_func(menu_entry_index, trainer_state),
|
|
cell_x, cell_y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
window__menu_t::draw(const uint32_t base_pattern,
|
|
const union window_descriptor_t::data& data,
|
|
const window_t& window,
|
|
const trainer_state_t& trainer_state)
|
|
{
|
|
const menu_t& menu = *data.menu;
|
|
draw_menu(base_pattern, menu, trainer_state);
|
|
draw_cursor(base_pattern, menu, window.cursor);
|
|
}
|
|
|
|
static void
|
|
_draw_move_types(const uint32_t base_pattern,
|
|
const uint8_t index,
|
|
const trainer_state_t& trainer_state)
|
|
{
|
|
// this is fully custom, not worth making a data model for this
|
|
|
|
constexpr screen_cell_t top_left = {0, 8};
|
|
constexpr screen_cell_t bottom_right = {10, 12};
|
|
|
|
draw_box_border(base_pattern, top_left, bottom_right);
|
|
draw_box_background(base_pattern,
|
|
top_left, bottom_right);
|
|
|
|
const pokemon_instance_t& pokemon_instance = trainer_state.party.active_pokemon();
|
|
const move_instance_t& move_instance = pokemon_instance.move_instances[index];
|
|
const move_t& move = moves[move_instance.type];
|
|
|
|
draw_text(base_pattern,
|
|
S("TYPE/"),
|
|
top_left.x + 1, top_left.y + 1);
|
|
|
|
draw_text(base_pattern,
|
|
types[move.type].name,
|
|
top_left.x + 2, top_left.y + 2);
|
|
|
|
draw_number_right_align(base_pattern,
|
|
{top_left.x + 5, top_left.y + 3},
|
|
move_instance.pp,
|
|
2,
|
|
ascii_to_font(' '));
|
|
|
|
put_char(base_pattern,
|
|
top_left.x + 7, top_left.y + 3,
|
|
ascii_to_font('/'));
|
|
|
|
draw_number_right_align(base_pattern,
|
|
{top_left.x + 8, top_left.y + 3},
|
|
move.pp,
|
|
2,
|
|
ascii_to_font(' '));
|
|
}
|
|
|
|
void
|
|
window__menu_t::draw_fight_moves(const uint32_t base_pattern,
|
|
const union window_descriptor_t::data& data,
|
|
const window_t& window,
|
|
const trainer_state_t& trainer_state)
|
|
{
|
|
window__menu_t::draw(base_pattern,
|
|
data,
|
|
window,
|
|
trainer_state);
|
|
|
|
const menu_t& menu = *data.menu;
|
|
const cursor_t& cursor = window.cursor;
|
|
const uint32_t menu_entry_index = menu.width * cursor.y + cursor.x;
|
|
|
|
_draw_move_types(base_pattern,
|
|
menu_entry_index,
|
|
trainer_state);
|
|
}
|
|
|
|
static inline constexpr void
|
|
_move_cursor(const uint8_t width,
|
|
const uint8_t height,
|
|
const enum window_t::input_event event,
|
|
cursor_t& cursor)
|
|
{
|
|
switch (event) {
|
|
case window_t::input_left:
|
|
if ((--cursor.x) < 0) cursor.x = width - 1;
|
|
break;
|
|
case window_t::input_right:
|
|
if ((++cursor.x) >= width) cursor.x = 0;
|
|
break;
|
|
case window_t::input_up:
|
|
if ((--cursor.y) < 0) cursor.y = height - 1;
|
|
break;
|
|
case window_t::input_down:
|
|
if ((++cursor.y) >= height) cursor.y = 0;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
window_descriptor_t::result
|
|
window__menu_t::update(const union window_descriptor_t::data& data,
|
|
window_t& window,
|
|
trainer_state_t& trainer_state,
|
|
const enum window_t::input_event event)
|
|
{
|
|
const menu_t& menu = *data.menu;
|
|
|
|
switch (event) {
|
|
case window_t::input_left: [[fallthrough]];
|
|
case window_t::input_right: [[fallthrough]];
|
|
case window_t::input_up: [[fallthrough]];
|
|
case window_t::input_down:
|
|
_move_cursor(menu.width, menu.height, event, window.cursor);
|
|
break;
|
|
|
|
case window_t::input_a: break;
|
|
case window_t::input_b: break;
|
|
default: break;
|
|
}
|
|
|
|
return { window_t::no_op };
|
|
}
|
|
|
|
window_descriptor_t::result
|
|
window__menu_t::update_fight(const union window_descriptor_t::data& data,
|
|
window_t& window,
|
|
trainer_state_t& trainer_state,
|
|
const enum window_t::input_event event)
|
|
{
|
|
const menu_t& menu = *data.menu;
|
|
|
|
switch (event) {
|
|
case window_t::input_a:
|
|
{
|
|
const cursor_t& cursor = window.cursor;
|
|
const uint32_t menu_entry_index = menu.width * cursor.y + cursor.x;
|
|
switch (menu_entry_index) {
|
|
case 0: // FIGHT
|
|
return { window_t::spawn, window_descriptor_t::fight_moves };
|
|
break;
|
|
case 1: // PKMN
|
|
break;
|
|
case 2: // ITEM
|
|
break;
|
|
case 3: // RUN
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case window_t::input_b:
|
|
break;
|
|
default:
|
|
_move_cursor(menu.width, menu.width, event, window.cursor);
|
|
break;
|
|
}
|
|
|
|
return { window_t::no_op };
|
|
}
|
|
|
|
static uint8_t const * const
|
|
_get_move_string(const uint32_t index,
|
|
const trainer_state_t& trainer_state)
|
|
{
|
|
const pokemon_instance_t& pokemon_instance = trainer_state.party.active_pokemon();
|
|
|
|
if (index >= pokemon_instance_t::maximum_moves ||
|
|
pokemon_instance.move_instances[index].type == move_t::no_move)
|
|
return S("-");
|
|
else {
|
|
return moves[pokemon_instance.move_instances[index].type].name;
|
|
}
|
|
}
|
|
|
|
|
|
window_descriptor_t::result
|
|
window__menu_t::update_fight_moves(const union window_descriptor_t::data& data,
|
|
window_t& window,
|
|
trainer_state_t& trainer_state,
|
|
const enum window_t::input_event event)
|
|
{
|
|
const menu_t& menu = *data.menu;
|
|
const uint8_t max_height = trainer_state.party.active_pokemon().moves_count();
|
|
|
|
switch (event) {
|
|
case window_t::input_a:
|
|
break;
|
|
case window_t::input_b:
|
|
return { window_t::dismiss };
|
|
break;
|
|
default:
|
|
_move_cursor(menu.width, max_height, event, window.cursor);
|
|
break;
|
|
}
|
|
|
|
return { window_t::no_op };
|
|
}
|
|
|
|
const menu_t menu_fight_moves = {
|
|
.top_left = {4, 12},
|
|
.bottom_right = {19, 17},
|
|
.width = 1,
|
|
.height = 4,
|
|
.h_advance = 0,
|
|
.v_advance = 1,
|
|
|
|
.entry_type = menu_t::func,
|
|
.entry = {
|
|
{ .label_func = _get_move_string }
|
|
}
|
|
};
|
|
|
|
const menu_t menu_start = {
|
|
.top_left = {10, 0},
|
|
.bottom_right = {19, 15},
|
|
.width = 1,
|
|
.height = 7,
|
|
.h_advance = 0,
|
|
.v_advance = 2,
|
|
|
|
.entry_type = menu_t::labels,
|
|
.entry {
|
|
.labels = (menu_label_t[]){
|
|
{ S(POKE "DEX") },
|
|
{ S(POKE "MON") },
|
|
{ S("ITEM" ) },
|
|
{ S(TRAINER ) },
|
|
{ S("SAVE" ) },
|
|
{ S("OPTION" ) },
|
|
{ S("EXIT" ) },
|
|
},
|
|
}
|
|
};
|
|
|
|
const menu_t menu_fight = {
|
|
.top_left = {8, 12},
|
|
.bottom_right = {19, 17},
|
|
.width = 2,
|
|
.height = 2,
|
|
.h_advance = 6,
|
|
.v_advance = 2,
|
|
|
|
.entry_type = menu_t::labels,
|
|
.entry = {
|
|
.labels = (menu_label_t[]) {
|
|
{ S("FIGHT") }, { S(PKMN ) },
|
|
{ S("ITEM" ) }, { S("RUN") },
|
|
}
|
|
},
|
|
};
|
|
|
|
#undef S
|