#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(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