From 3fffdab78d4d7b467856ea15dc7a7e7f2e7ef69a Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 4 Aug 2023 18:45:50 +0000 Subject: [PATCH] draw stats page 2 --- Makefile | 1 + derived/font.png | Bin 17992 -> 5418 bytes graphic.cpp | 163 +++-------------------- graphic.hpp | 18 +-- main.cpp | 34 ++++- menu/dialog.cpp | 43 ++++++ menu/stats.cpp | 229 ++++++++++++++++++++++++++++++++ menu/stats.hpp | 11 ++ pokemon_instance.cpp | 38 +++++- pokemon_instance.hpp | 8 +- tools/generate/pokemon/moves.py | 2 +- 11 files changed, 375 insertions(+), 172 deletions(-) create mode 100644 menu/dialog.cpp create mode 100644 menu/stats.cpp create mode 100644 menu/stats.hpp diff --git a/Makefile b/Makefile index c03e4aa..95c7716 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ SRC += menu.cpp SRC += number.cpp SRC += pokemon_instance.cpp SRC += ailment.cpp +SRC += menu/stats.cpp DEP = $(patsubst %.cpp,%.cpp.d,$(SRC)) diff --git a/derived/font.png b/derived/font.png index 56efba3e5b97fac53474d339e2e5b5d316c47e39..ac4957af453064de11b1b8b4da7b8e77832ef4b5 100644 GIT binary patch delta 1809 zcmV+s2k!XDi~*`DkRyKp#d=g&bW&k=AaHVTW@&6?Aar?fWgumEX=VTbc-n1H+Y!Sc z4Etw_jsTX!V;s_?cio`lSAfYSxroCE3xu)Tf8URLHAqmWOUkjt=m{-aq>^MmPG3cC>P{LF{LU@VnvIT_`*3F}oT_JZV_kv&j^R*{fwW>m}wGK63T zb$rXmlGFJM>+Y|}W4acQy7ysn-)my`wuMQE>l} z#5++M88*9qnoPqVPjj1UtQ|AbWU8ze!z&$0QG$B@R zrkRQxQ7I>v1JOXF+ce~D)_I;%M)H`*%Ou>9%G2aw{`Y(BK6o*9}>n-*0OWm~rZvf4=bx_7YHQ`at!?vq>|K0wiW-W->N1Vl^!|V`4Qe zG-EktEnze@V=Xc;Fg9f~H8L-25U(w! zS%J4p=LVYb|c}c;Mf9(>5nNQ{Ew{`ZtbwJj=R@+4h#g~qzvTy2h zIxu)T+rs{)cDUE(JW&!i+Anb2w5Dkq9f04Ns` z(&F-x2t0s!2av20e>bi|OHUVWHx6k7NHRdR_ZMK457b3C_UY_g8-2JFk^SABxd_e( zSX{JI$cMhH@F`DGX-!)Z{GP-l+N;l0dJsg+lIc`CWzSm%uuy|XOXKVuf6(cx*MaC& z=DOT&9l*u>NdO|{qYmxOkzQc|6vNetFU+=C4__xHi&81%c8w(+NN~DZ_P)r^>44}9 zLB90hZHAj5pGICrX)d{Iw*rPbz@l99s!7@CiX>M`*r*RF^G}#zg%*zgcRWK)WklQm zLqIMZh8htex(LW`I#YEff7>W%iZRWw*BOkq=SOex(cAX$M0q z-57Bi8Ug;DJ}Tu;n$1I91fgjC?INguKOPMa{2~IfH#dx1jK4O1x@Kt$4ty@A3?Lu3 zpy+CtccbC`6l-F>aU8o!k9uP0@2eUo@Az$|4<-rxPR>$Qn`zLFe*@Z+F!JZ${j{axvR#0F*b%e>0TwtW+4QWE>@Gmu$M)l|uI1KT2`F5s>}LfwDq6J`9s~9Me*H z*KQ?ulglA+t(M9LTdMs)rF3jhEBNkvXXu0mjfM;%BQ delta 14509 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 void draw_text(const uint32_t base_pattern, @@ -134,10 +129,10 @@ constexpr inline uint8_t hp_seg(const int32_t hp_48, const int32_t ix) } } -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) +static inline 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); @@ -150,148 +145,22 @@ void draw_hp_bar(const uint32_t base_pattern, put_char(base_pattern, top_left.x + 8, top_left.y, end_cap); } -const uint8_t * status_string(const pokemon_instance_t& pokemon_instance) +void draw_hp_bar_with_numbers(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance, + const screen_cell_t& pos) { - if (pokemon_instance.current_hit_points == 0) - return S("FNT"); - else - return ailments[pokemon_instance.ailment].name; -} + const int32_t hp_48 = (pokemon_instance.current_hit_points * 48) / pokemon_instance.stat_values.hit_points; + _draw_hp_bar(base_pattern, pos, hp_bar::end_cap_bar, hp_48); -void draw_stats1(const uint32_t base_pattern, - const pokemon_instance_t& pokemon_instance) -{ - // white out the entire screen - draw_box_background(base_pattern, {-1, -1}, {20, 18}); + draw_number_right_align(base_pattern, {pos.x + 1, pos.y + 1}, + pokemon_instance.current_hit_points, + 3, ascii_to_font(' ')); // width, fill - // top status battle box - { - draw_battle_border(base_pattern, {19, 1}, {8, 7}); + put_char(base_pattern, pos.x + 4, pos.y + 1, ascii_to_font('/')); - // hp - { - const int32_t hp_48 = (pokemon_instance.current_hit_points * 48) / pokemon_instance.stat_values.hit_points; - draw_hp_bar(base_pattern, {11, 3}, hp_bar::end_cap_bar, hp_48); - - draw_number_right_align(base_pattern, {12, 4}, - pokemon_instance.current_hit_points, - 3, ascii_to_font(' ')); // width, fill - - put_char(base_pattern, 15, 4, ascii_to_font('/')); - - draw_number_right_align(base_pattern, {16, 4}, - pokemon_instance.stat_values.hit_points, - 3, ascii_to_font(' ')); // width, fill - } - - // name - draw_text(base_pattern, pokemon[pokemon_instance.species].name, 9, 1); - - // level - put_char(base_pattern, 14, 2, battle_border::level); - draw_number_left_align(base_pattern, {15, 2}, - pokemon_instance.level, - 3); // width - - draw_text(base_pattern, S("STATUS/"), 9, 6); - draw_text(base_pattern, status_string(pokemon_instance), 16, 6); - } - - // bottom right border - { - draw_battle_border(base_pattern, {19, 9}, {12, 17}); - - int32_t distinct_types = (pokemon[pokemon_instance.species].types[0] - != pokemon[pokemon_instance.species].types[1]) + 1; - - for (int32_t ix = 0; ix < distinct_types; ix++) { - const enum type_t::type type = pokemon[pokemon_instance.species].types[ix]; - draw_text(base_pattern, S("TYPE"), 10, 9 + (2 * ix)); - put_char(base_pattern, 14, 9 + (2 * ix), ascii_to_font('1' + ix)); - put_char(base_pattern, 15, 9 + (2 * ix), ascii_to_font('/')); - draw_text(base_pattern, types[type].name, 11, 10 + (2 * ix)); - } - } - - { // bottom left dialog box - draw_box_border(base_pattern, {0, 8}, {9, 17}); - - draw_text(base_pattern, S("ATTACK"), 1, 9 + 0); - draw_text(base_pattern, S("DEFENSE"), 1, 9 + 2); - draw_text(base_pattern, S("SPEED"), 1, 9 + 4); - draw_text(base_pattern, S("SPECIAL"), 1, 9 + 6); - - draw_number_right_align(base_pattern, {6, 10 + 0}, - pokemon_instance.stat_values.attack, - 3, ascii_to_font(' ')); // width, fill - - draw_number_right_align(base_pattern, {6, 10 + 2}, - pokemon_instance.stat_values.defense, - 3, ascii_to_font(' ')); // width, fill - - draw_number_right_align(base_pattern, {6, 10 + 4}, - pokemon_instance.stat_values.speed, - 3, ascii_to_font(' ')); // width, fill - - draw_number_right_align(base_pattern, {6, 10 + 6}, - pokemon_instance.stat_values.special, - 3, ascii_to_font(' ')); // width, fill - } // end bottom left dialog box - - // pokedex number - { - put_char(base_pattern, 1, 7, stats::no); - put_char(base_pattern, 2, 7, stats::no_dot); - - const int32_t pokedex_number = static_cast(pokemon_instance.species) + 1; - draw_number_right_align(base_pattern, - {3, 7}, - pokedex_number, - 3, // width - ascii_to_font('0') // fill - ); - } -} - -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++; - } + draw_number_right_align(base_pattern, {pos.x + 5, pos.y + 1}, + pokemon_instance.stat_values.hit_points, + 3, ascii_to_font(' ')); // width, fill } #undef S diff --git a/graphic.hpp b/graphic.hpp index e3f9aec..0b67d4a 100644 --- a/graphic.hpp +++ b/graphic.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "coordinates.hpp" #include "start_size.hpp" #include "render_map.hpp" // for cell_offset @@ -54,6 +56,8 @@ struct hp_bar { struct stats { static constexpr uint8_t id = 0x70; // ID static constexpr uint8_t no = 0x71; // No + static constexpr uint8_t to = 0x4c; // to + static constexpr uint8_t p = 0x4d; // p (bold) static constexpr uint8_t no_dot = 0x4e; // . }; @@ -79,14 +83,6 @@ void draw_box_background(const uint32_t base_pattern, void draw_battle_border(const uint32_t base_pattern, const screen_cell_t& top_corner, const screen_cell_t& bottom_corner); -void draw_stats1(const uint32_t base_pattern, - const pokemon_instance_t& pokemon_instance); - -struct dialog_t -{ - 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); -}; +void draw_hp_bar_with_numbers(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance, + const screen_cell_t& pos); diff --git a/main.cpp b/main.cpp index aad9bbb..929dceb 100644 --- a/main.cpp +++ b/main.cpp @@ -29,6 +29,8 @@ #include "pokemon.hpp" #include "pokemon_instance.hpp" +#include "menu/stats.hpp" + static int32_t pokemon_raw_index = 0; struct draw_t { @@ -166,7 +168,7 @@ uint32_t pokemon_sprite_dimension(const uint32_t size) } void render_pokemon(const uint32_t ix, const enum pokemon_t::pokemon pokemon_id, - const screen_cell_t& screen_cell) + const screen_cell_t& screen_cell, bool horizontal_inversion) { const uint32_t base_pattern = state.draw.base_pattern.pokemon[pokemon_id].front; const uint32_t character_address = (base_pattern * 16) / 8; @@ -181,7 +183,9 @@ void render_pokemon(const uint32_t ix, const enum pokemon_t::pokemon pokemon_id, case 56: x_offset = 1; y_offset = 0; break; } - vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE; + uint16_t dir = horizontal_inversion ? CTRL__DIR__INVERTED_HORIZONTALLY : 0; + + vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__NORMAL_SPRITE | dir; vdp1.vram.cmd[ix].LINK = 0; // The "end code" is 0xf, which is being used in the mai sprite palette. If // both transparency and end codes are enabled, it seems there are only 14 @@ -209,7 +213,8 @@ void render_sprites(const offset_t& offset) ix++; render_pokemon(ix, static_cast(pokemon_raw_index), - {0, 0}); + {0, 0}, + true); // invert horizontally ix++; const object_t& obj = map_objects[state.map]; @@ -470,11 +475,13 @@ void check_sign() const bool position_match = event.position.x == coord.x && event.position.y == coord.y; if (position_match && event.sign_id != 0xff) { const start_size_t& text = map.text_pointers[event.sign_id]; - dialog_t::draw(state.draw.base_pattern.font, text); } } } +static uint32_t stats_page = 1; +static uint8_t level = 70; + void update() { state.player.tick(); @@ -486,14 +493,18 @@ 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(); */ if (event::cursor_left() ) pokemon_raw_index = (pokemon_raw_index - 1); else if (event::cursor_right()) pokemon_raw_index = (pokemon_raw_index + 1); + else if (event::cursor_up() ) level++; + else if (event::cursor_down() ) level--; + else if (event::button_a() ) stats_page = !stats_page; + if (pokemon_raw_index < 0) pokemon_raw_index = pokemon_t::count - 1; else if (pokemon_raw_index >= pokemon_t::count) pokemon_raw_index = 0; - //else if (event::button_a() ) check_sign(); } static uint32_t frame = 0; @@ -523,14 +534,23 @@ void render() pokemon_instance.species = static_cast(pokemon_raw_index); pokemon_instance.stat_experience = {0, 0, 0, 0, 0}; pokemon_instance.determinant_values.dvs = 0b1110'0101'1000'0110; - pokemon_instance.level = 70; + pokemon_instance.level = level; pokemon_instance.determine_stats(); + pokemon_instance.learn_all_moves(); if (frame % 4 == 0) pokemon_instance.current_hit_points++; if (pokemon_instance.current_hit_points > pokemon_instance.stat_values.hit_points) pokemon_instance.current_hit_points = 0; - draw_stats1(state.draw.base_pattern.font, pokemon_instance); + switch (stats_page) { + default: + case 0: + draw_stats1(state.draw.base_pattern.font, pokemon_instance); + break; + case 1: + draw_stats2(state.draw.base_pattern.font, pokemon_instance); + break; + } } extern "C" diff --git a/menu/dialog.cpp b/menu/dialog.cpp new file mode 100644 index 0000000..808ef17 --- /dev/null +++ b/menu/dialog.cpp @@ -0,0 +1,43 @@ +void draw(const uint32_t base_pattern, + const start_size_t& text) +{ + static constexpr screen_cell_t top_left = { 0, 12}; + static constexpr screen_cell_t bottom_right = {19, 17}; + + 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++; + } +} diff --git a/menu/stats.cpp b/menu/stats.cpp new file mode 100644 index 0000000..b17e05d --- /dev/null +++ b/menu/stats.cpp @@ -0,0 +1,229 @@ +#include "../font.hpp" +#include "../number.hpp" +#include "../graphic.hpp" + +#include "../gen/pokemon/types.hpp" +#include "../gen/pokemon/moves.hpp" + +#include "../pokemon_instance.hpp" +#include "../ailment.hpp" + +#define S reinterpret_cast + +const uint8_t * status_string(const pokemon_instance_t& pokemon_instance) +{ + if (pokemon_instance.current_hit_points == 0) + return S("FNT"); + else + return ailments[pokemon_instance.ailment].name; +} + +static void draw_stats_top_right_border_with_name(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance) +{ + draw_battle_border(base_pattern, {19, 1}, {8, 7}); + + // name + draw_text(base_pattern, pokemon[pokemon_instance.species].name, 9, 1); +} + +static void draw_stats_pokedex_number(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance) +{ + // pokedex number + put_char(base_pattern, 1, 7, stats::no); + put_char(base_pattern, 2, 7, stats::no_dot); + + const int32_t pokedex_number = static_cast(pokemon_instance.species) + 1; + draw_number_right_align(base_pattern, + {3, 7}, + pokedex_number, + 3, // width + ascii_to_font('0') // fill + ); +} + +void draw_stats1(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance) +{ + // white out the entire screen + draw_box_background(base_pattern, {-1, -1}, {20, 18}); + + // front picture label + { + draw_stats_pokedex_number(base_pattern, pokemon_instance); + } + + // top status battle box + { + // name and border + draw_stats_top_right_border_with_name(base_pattern, pokemon_instance); + + // level + put_char(base_pattern, 14, 2, battle_border::level); + draw_number_left_align(base_pattern, {15, 2}, + pokemon_instance.level, + 3); // width + + // hp + draw_hp_bar_with_numbers(base_pattern, pokemon_instance, {11, 3}); + + // status + draw_text(base_pattern, S("STATUS/"), 9, 6); + draw_text(base_pattern, status_string(pokemon_instance), 16, 6); + } + + // bottom right border + { + draw_battle_border(base_pattern, {19, 9}, {12, 17}); + + int32_t distinct_types = (pokemon[pokemon_instance.species].types[0] + != pokemon[pokemon_instance.species].types[1]) + 1; + + for (int32_t ix = 0; ix < distinct_types; ix++) { + const enum type_t::type type = pokemon[pokemon_instance.species].types[ix]; + draw_text(base_pattern, S("TYPE"), 10, 9 + (2 * ix)); + put_char(base_pattern, 14, 9 + (2 * ix), ascii_to_font('1' + ix)); + put_char(base_pattern, 15, 9 + (2 * ix), ascii_to_font('/')); + draw_text(base_pattern, types[type].name, 11, 10 + (2 * ix)); + } + } + + { // bottom left dialog box + draw_box_border(base_pattern, {0, 8}, {9, 17}); + + draw_text(base_pattern, S("ATTACK"), 1, 9 + 0); + draw_text(base_pattern, S("DEFENSE"), 1, 9 + 2); + draw_text(base_pattern, S("SPEED"), 1, 9 + 4); + draw_text(base_pattern, S("SPECIAL"), 1, 9 + 6); + + draw_number_right_align(base_pattern, {6, 10 + 0}, + pokemon_instance.stat_values.attack, + 3, ascii_to_font(' ')); // width, fill + + draw_number_right_align(base_pattern, {6, 10 + 2}, + pokemon_instance.stat_values.defense, + 3, ascii_to_font(' ')); // width, fill + + draw_number_right_align(base_pattern, {6, 10 + 4}, + pokemon_instance.stat_values.speed, + 3, ascii_to_font(' ')); // width, fill + + draw_number_right_align(base_pattern, {6, 10 + 6}, + pokemon_instance.stat_values.special, + 3, ascii_to_font(' ')); // width, fill + } // end bottom left dialog box +} + +void draw_stats_move(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance, + const int32_t _ix) +{ + const int32_t ix = _ix & 0b11; + const int32_t y_offset = 2 * ix; + + constexpr int32_t name_x = 2; + constexpr int32_t name_y = 9; + constexpr int32_t pp_x = 11; + constexpr int32_t pp_y = 10; + + // move name + const move_instance_t& move_instance = pokemon_instance.move_instances[ix]; + if (move_instance.type != move_t::no_move) { + const move_t& move = moves[move_instance.type]; + // name + draw_text(base_pattern, move.name, name_x, name_y + y_offset); + + // pp + put_char(base_pattern, pp_x + 0, pp_y + y_offset, stats::p); + put_char(base_pattern, pp_x + 1, pp_y + y_offset, stats::p); + + draw_number_right_align(base_pattern, {pp_x + 3, pp_y + y_offset}, + move_instance.pp, + 2, ascii_to_font(' ')); // width, fill + + put_char(base_pattern, pp_x + 5, pp_y + y_offset, ascii_to_font('/')); + + draw_number_right_align(base_pattern, {pp_x + 6, pp_y + y_offset}, + moves[move_instance.type].pp, + 2, ascii_to_font(' ')); // width, fill + } else { + // name + put_char(base_pattern, name_x, name_y + y_offset, ascii_to_font('-')); + // pp + put_char(base_pattern, pp_x + 0, pp_y + y_offset, ascii_to_font('-')); + put_char(base_pattern, pp_x + 1, pp_y + y_offset, ascii_to_font('-')); + } +} + +void draw_stats2(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance) +{ + // white out the entire screen + draw_box_background(base_pattern, {-1, -1}, {20, 18}); + + // front picture label + { + draw_stats_pokedex_number(base_pattern, pokemon_instance); + } + + // top status battle box + { + // name and border + draw_stats_top_right_border_with_name(base_pattern, pokemon_instance); + + // exp points + draw_text(base_pattern, S("EXP POINTS"), 9, 3); + draw_number_right_align(base_pattern, + {13, 4}, + pokemon_instance.total_experience, + 6, // width + ascii_to_font(' ') // fill + ); + + // level up + draw_text(base_pattern, S("LEVEL UP"), 9, 5); + + put_char(base_pattern, 14, 6, stats::to); + put_char(base_pattern, 16, 6, battle_border::level); + + const int32_t next_level = pokemon_instance.level < 100 + ? (pokemon_instance.level + 1) + : 100; + int32_t exp_to = 1234; + + if (next_level < 100) { + draw_number_left_align(base_pattern, + {17, 6}, + next_level, + 2 // width + ); + } else { + draw_number_left_align(base_pattern, + {16, 6}, + next_level, + 3 // width + ); + } + + // exp + draw_number_right_align(base_pattern, + {9, 6}, + exp_to, + 5, // width + ascii_to_font(' ') // fill + ); + } + + // bottom move list + { + draw_box_border(base_pattern, {0, 8}, {19, 17}); + + draw_stats_move(base_pattern, pokemon_instance, 0); + draw_stats_move(base_pattern, pokemon_instance, 1); + draw_stats_move(base_pattern, pokemon_instance, 2); + draw_stats_move(base_pattern, pokemon_instance, 3); + } +} + +#undef S diff --git a/menu/stats.hpp b/menu/stats.hpp new file mode 100644 index 0000000..fcf2574 --- /dev/null +++ b/menu/stats.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +#include "../pokemon_instance.hpp" + +void draw_stats1(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance); + +void draw_stats2(const uint32_t base_pattern, + const pokemon_instance_t& pokemon_instance); diff --git a/pokemon_instance.cpp b/pokemon_instance.cpp index 94b169b..13086b2 100644 --- a/pokemon_instance.cpp +++ b/pokemon_instance.cpp @@ -59,13 +59,41 @@ pokemon_instance_t::learn_move(enum move_t::move move, int32_t index) case 1: [[fallthrough]]; case 2: [[fallthrough]]; case 3: - moves[index] = move; + move_instances[index].type = move; + move_instances[index].pp = moves[move].pp; break; default: - moves[0] = moves[1]; - moves[1] = moves[2]; - moves[2] = moves[3]; - moves[3] = move; + { + int32_t ix = 0; + while (move_instances[ix].type != move_t::no_move) { + if (move_instances[ix].type == move) return; // do not double-learn move_instances + if (++ix == 4) { + move_instances[0] = move_instances[1]; + move_instances[1] = move_instances[2]; + move_instances[2] = move_instances[3]; + ix--; + break; + } + } + move_instances[ix].type = move; + move_instances[ix].pp = moves[move].pp; + } break; } } + +void pokemon_instance_t::learn_all_moves() +{ + move_instances[0].type = move_t::no_move; + move_instances[1].type = move_t::no_move; + move_instances[2].type = move_t::no_move; + move_instances[3].type = move_t::no_move; + + const level_move_t * level_moves = pokemon[species].by_level.moves; + for (int32_t ix = 0; ix < pokemon[species].by_level.length; ix++) { + if (level_moves[ix].level <= level) + learn_move(level_moves[ix].move, -1); + else + break; + } +} diff --git a/pokemon_instance.hpp b/pokemon_instance.hpp index 999f5d3..39b9c34 100644 --- a/pokemon_instance.hpp +++ b/pokemon_instance.hpp @@ -64,6 +64,11 @@ struct stat_values_t { static_assert((sizeof (stat_values_t)) == 10); +struct move_instance_t { + enum move_t::move type; + uint8_t pp; +}; + struct pokemon_instance_t { uint8_t nickname[12]; enum pokemon_t::pokemon species; @@ -72,7 +77,7 @@ struct pokemon_instance_t { determinant_values_t determinant_values; stat_values_t stat_values; stat_experience_t stat_experience; - enum move_t::move moves[4]; + move_instance_t move_instances[4]; uint16_t current_hit_points; enum ailment_t::ailment ailment; @@ -84,4 +89,5 @@ struct pokemon_instance_t { void determine_stats(); void learn_move(enum move_t::move move, int32_t index); + void learn_all_moves(); }; diff --git a/tools/generate/pokemon/moves.py b/tools/generate/pokemon/moves.py index bbdc976..dd9e29d 100644 --- a/tools/generate/pokemon/moves.py +++ b/tools/generate/pokemon/moves.py @@ -51,7 +51,7 @@ def struct_move_t(): _move_constants_str = (f"{s.lower()}," for s in _move_constants) return [ "struct move_t {", - "const uint8_t * name;" + "const uint8_t * name;", "uint8_t animation;", "uint8_t effect;", "uint8_t power;",