From 853457a79d7942cac8f9facce18cde0f0e2adf13 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 2 Aug 2023 23:49:42 +0000 Subject: [PATCH] generate: add pokemon This also includes a handful of functions for creating instances of a pokemon species, though certainly not complete. --- Makefile | 14 +- pokemon.hpp | 81 ++++++ pokemon_instance.cpp | 75 +++++ pokemon_instance.hpp | 83 ++++++ sqrt.hpp | 43 +++ tools/generate/__main__.py | 1 + tools/generate/files.py | 11 +- tools/generate/{move => pokemon}/moves.py | 0 tools/generate/pokemon/pokemon.py | 319 ++++++++++++++++++++++ tools/generate/pokemon/types.py | 21 ++ tools/parse/generic/constants.py | 2 + tools/parse/parse.py | 10 +- tools/parse/pic.py | 28 +- tools/parse/pokemon/base_stats.py | 3 +- tools/parse/pokemon/evos_moves.py | 9 +- tools/parse/types/__init__.py | 1 + tools/parse/types/constants.py | 4 + 17 files changed, 686 insertions(+), 19 deletions(-) create mode 100644 pokemon.hpp create mode 100644 pokemon_instance.cpp create mode 100644 pokemon_instance.hpp create mode 100644 sqrt.hpp rename tools/generate/{move => pokemon}/moves.py (100%) create mode 100644 tools/generate/pokemon/pokemon.py create mode 100644 tools/generate/pokemon/types.py create mode 100644 tools/parse/types/__init__.py create mode 100644 tools/parse/types/constants.py diff --git a/Makefile b/Makefile index d6f72cd..9747c51 100644 --- a/Makefile +++ b/Makefile @@ -30,10 +30,11 @@ res_png = $(subst pokered/,res/,$(patsubst %.png,%.$(1).o,$(wildcard $(2)*.png)) GFX_TILESETS = $(call res_png,2bpp,pokered/gfx/tilesets/) GFX_BLOCKSETS = $(call res,bst,pokered/gfx/blocksets/) GFX_SPRITES = $(call res_png,2bpp,pokered/gfx/sprites/) +GFX_POKEMON = $(call res_png,2bpp,pokered/gfx/pokemon/front/) $(call res_png,2bpp,pokered/gfx/pokemon/back/) MAPS_BLOCKS = $(call res,blk,pokered/maps/) FONTS = res/font.2bpp.o -GENERATED = $(GFX_TILESETS) $(GFX_BLOCKSETS) $(GFX_SPRITES) $(MAPS_BLOCKS) $(GEN_SRC) $(FONTS) +GENERATED = $(GFX_TILESETS) $(GFX_BLOCKSETS) $(GFX_SPRITES) $(GFX_POKEMON) $(MAPS_BLOCKS) $(GEN_SRC) $(FONTS) OBJ = $(patsubst %.cpp,%.o,$(SRC) $(GENERATED)) @@ -63,6 +64,11 @@ define PNG_TO_2BPP python tools/png_to_nbpp.py 2 $@ $< endef +define PNG_TO_2BPP_SPRITE + @mkdir -p $(dir $@) + python tools/png_to_nbpp_sprite.py 2 $@ $< +endef + res/%.2bpp: derived/%.png $(PNG_TO_2BPP) @@ -74,8 +80,10 @@ res/.1bpp: pokered/%.png python tools/png_to_nbpp.py 1 $@ $< res/gfx/sprites/%.2bpp: pokered/gfx/sprites/%.png - @mkdir -p $(dir $@) - python tools/png_to_nbpp_sprite.py 2 $@ $< + $(PNG_TO_2BPP_SPRITE) + +res/gfx/pokemon/%.2bpp: pokered/gfx/pokemon/%.png + $(PNG_TO_2BPP_SPRITE) %.2bpp.h: $(BUILD_BINARY_H) diff --git a/pokemon.hpp b/pokemon.hpp new file mode 100644 index 0000000..0cdbbd9 --- /dev/null +++ b/pokemon.hpp @@ -0,0 +1,81 @@ +#include + +#include "gen/pokemon/moves.hpp" +#include "gen/pokemon/types.hpp" +#include "start_size.hpp" + +enum struct stat_t { + hit_points, + attack, + defense, + speed, + special, +}; + +struct base_stat_values_t { + struct { + uint8_t hit_points; + uint8_t attack; + uint8_t defense; + uint8_t speed; + uint8_t special; + }; +}; + +static_assert((sizeof (base_stat_values_t)) == 5); + +struct level_move_t { + uint8_t level; + enum move_t::move move; +}; + +enum struct growth_t { + medium_fast, + slightly_fast, + slightly_slow, + medium_slow, + fast, + slow, +}; + +struct pokemon_t { + #include "gen/pokemon/pokemon_enum.inc.hpp" + + struct evolution_t { + enum type { + item, + level, + trade + }; + + enum type type; + uint8_t required_item; // fixme + uint8_t required_level; + enum pokemon pokemon; + }; + + const uint8_t * name; + base_stat_values_t base_stat_values; + type_t types[2]; + uint8_t catch_rate; + uint8_t base_exp; + growth_t growth_rate; + struct { + start_size_t front; + start_size_t back; + } pic; + struct { + const level_move_t * moves; + uint8_t length; + } by_level; + struct { + const enum move_t::move * moves; + uint8_t length; + } by_tmhm; + struct { + const evolution_t * evolution; + uint8_t length; + } evolutions; +}; + +extern const pokemon_t pokemon[]; diff --git a/pokemon_instance.cpp b/pokemon_instance.cpp new file mode 100644 index 0000000..cadc9da --- /dev/null +++ b/pokemon_instance.cpp @@ -0,0 +1,75 @@ +#include "pokemon_instance.hpp" + +static uint16_t _determine_stat(const uint32_t base_stat_value, + const uint32_t determinant_value, + const uint32_t stat_experience, + const uint32_t level) +{ + const uint32_t x = base_stat_value + determinant_value; + const uint32_t y = sqrt_ceil(stat_experience) / 4; + const uint32_t z = (x * 2 + y) * level; + return (z / 100); +} + +static_assert(_determine_stat(106, 0b0100, 0, 70) == (234 - 10 - 70)); +static_assert(_determine_stat(110, 0b1110, 0, 70) == (178 - 5)); +static_assert(_determine_stat( 90, 0b0101, 0, 70) == (138 - 5)); +static_assert(_determine_stat(130, 0b1000, 0, 70) == (198 - 5)); +static_assert(_determine_stat(154, 0b0110, 0, 70) == (229 - 5)); + +constexpr inline uint16_t +pokemon_instance_t::determine_stat(enum stat_t stat) +{ + switch (stat) { + default: + case stat_t::hit_points: + return _determine_stat(pokemon[species].base_stat_values.hit_points, + determinant_values.hit_points(), + stat_experience.hit_points, + level) + + 10 + level; + case stat_t::attack: + return _determine_stat(pokemon[species].base_stat_values.attack, + determinant_values.attack(), + stat_experience.attack, + level) + + 5; + case stat_t::defense: + return _determine_stat(pokemon[species].base_stat_values.defense, + determinant_values.defense(), + stat_experience.defense, + level) + + 5; + case stat_t::speed: + return _determine_stat(pokemon[species].base_stat_values.speed, + determinant_values.speed(), + stat_experience.speed, + level) + + 5; + case stat_t::special: + return _determine_stat(pokemon[species].base_stat_values.special, + determinant_values.special(), + stat_experience.special, + level) + + 5; + } +} + +constexpr inline uint16_t +pokemon_instance_t::learn_move(enum move_t::move move, int32_t index) +{ + switch (index) { + case 0: [[fallthrough]]; + case 1: [[fallthrough]]; + case 2: [[fallthrough]]; + case 3: + moves[index] = move; + break; + default: + moves[0] = moves[1]; + moves[1] = moves[2]; + moves[2] = moves[3]; + moves[3] = move; + break; + } +} diff --git a/pokemon_instance.hpp b/pokemon_instance.hpp new file mode 100644 index 0000000..00772c7 --- /dev/null +++ b/pokemon_instance.hpp @@ -0,0 +1,83 @@ +#include + +#include "sqrt.hpp" + +#include "gen/pokemon/moves.hpp" +#include "pokemon.hpp" + +struct determinant_values_t { + uint16_t dvs; + + inline constexpr uint8_t attack() + { + return (dvs >> 12) & 0b1111; + } + + inline constexpr uint8_t defense() + { + return (dvs >> 8) & 0b1111; + } + + inline constexpr uint8_t speed() + { + return (dvs >> 4) & 0b1111; + } + + inline constexpr uint8_t special() + { + return (dvs >> 0) & 0b1111; + } + + inline constexpr uint8_t hit_points() + { + return ((attack() & 1) << 3) + | ((defense() & 1) << 2) + | ((speed() & 1) << 1) + | ((special() & 1) << 0); + } +}; + +struct stat_experience_t { + uint16_t hit_points; + uint16_t attack; + uint16_t defense; + uint16_t speed; + uint16_t special; +}; + +// unlike base_stat_values, stat_values is uint16_t +struct stat_values_t { + union { + struct { + uint16_t hit_points; + uint16_t attack; + uint16_t defense; + uint16_t speed; + uint16_t special; + }; + uint16_t value[5]; + }; +}; + +static_assert((sizeof (stat_values_t)) == 10); + +struct pokemon_instance_t { + enum pokemon_t::pokemon species; + uint8_t * nickname[12]; + uint8_t level; + uint32_t experience; // total experience + determinant_values_t determinant_values; + stat_values_t stat_values; + stat_experience_t stat_experience; + enum move_t::move moves[4]; + uint16_t current_hit_points; + // missing attributes: + // - status modifiers (burn, poison, etc...) + // "fluff" attributes: + // - id number + // - original trainer + + constexpr inline uint16_t determine_stat(enum stat_t stat); + + constexpr inline void learn_move(enum move_t::move move, uint32_t index); +}; diff --git a/sqrt.hpp b/sqrt.hpp new file mode 100644 index 0000000..c282a7f --- /dev/null +++ b/sqrt.hpp @@ -0,0 +1,43 @@ +template +inline constexpr T div_ceil(T a, T b) +{ + return (a / b) + ((a % b) != 0); +} + +static_assert(div_ceil(2, 2) == 1); +static_assert(div_ceil(3, 2) == 2); +static_assert(div_ceil(55, 8) == 7); +static_assert(div_ceil(55, 11) == 5); + +template +inline constexpr T sqrt_floor(T a) +{ + if (a == 0) return 0; + constexpr int num_bits = (sizeof (T)) * 8; + T x = 1 << div_ceil(num_bits, 2); + while (true) { + T y = (x + (a / x)) / 2; + if (y >= x) return x; + x = y; + } +} + +static_assert(sqrt_floor(4) == 2); +static_assert(sqrt_floor(9) == 3); +static_assert(sqrt_floor(7056) == 84); +static_assert(sqrt_floor(7211) == 84); +static_assert(sqrt_floor(7225) == 85); +static_assert(sqrt_floor(7226) == 85); + +template +inline constexpr T sqrt_ceil(T a) +{ + T q = sqrt_floor(a); + if (q * q != a) q += 1; + return q; +} + +static_assert(sqrt_ceil(7056) == 84); +static_assert(sqrt_ceil(7211) == 85); +static_assert(sqrt_ceil(7225) == 85); +static_assert(sqrt_ceil(7226) == 86); diff --git a/tools/generate/__main__.py b/tools/generate/__main__.py index 0868132..a35bde8 100644 --- a/tools/generate/__main__.py +++ b/tools/generate/__main__.py @@ -10,6 +10,7 @@ def generate(base_path, target_path): if path != target_path: continue buf = func().getvalue() + path.parents[0].mkdir(parents=False, exist_ok=True) with open(path, 'w') as f: f.write(buf) diff --git a/tools/generate/files.py b/tools/generate/files.py index acc4ea9..4264dab 100644 --- a/tools/generate/files.py +++ b/tools/generate/files.py @@ -5,7 +5,9 @@ from generate import tilesets from generate import collision_tile_ids from generate import text from generate import text_pointers -from generate.move import moves +from generate.pokemon import moves +from generate.pokemon import types +from generate.pokemon import pokemon files = [ (maps.generate_header, "maps.hpp"), @@ -22,6 +24,9 @@ files = [ (text.generate_source, "text.cpp"), (text_pointers.generate_header, "text_pointers.hpp"), (text_pointers.generate_source, "text_pointers.cpp"), - (moves.generate_header, "moves.hpp"), - (moves.generate_source, "moves.cpp"), + (moves.generate_header, "pokemon/moves.hpp"), + (moves.generate_source, "pokemon/moves.cpp"), + (types.generate_header, "pokemon/types.hpp"), + (pokemon.generate_enum_inc, "pokemon/pokemon_enum.inc.hpp"), + (pokemon.generate_source, "pokemon/pokemon.cpp"), ] diff --git a/tools/generate/move/moves.py b/tools/generate/pokemon/moves.py similarity index 100% rename from tools/generate/move/moves.py rename to tools/generate/pokemon/moves.py diff --git a/tools/generate/pokemon/pokemon.py b/tools/generate/pokemon/pokemon.py new file mode 100644 index 0000000..4629119 --- /dev/null +++ b/tools/generate/pokemon/pokemon.py @@ -0,0 +1,319 @@ +""" +- constants + +pokedex indicies: +- dex_constants + +by constants index: +- evos_moves (pointer table) +- names +- dex_entries (pointer table) + +by dex_constants value: +- base_stats (DEX_*) + (references Front/Back pic) + +translation from constants to dex_constants: +- dex_order + +from pic to gfx/ filename: +- pic +""" + +from itertools import chain, starmap +from generate.generate import renderer +from generate.binary import start_size_value +from parse import parse + +#from pprint import pprint +#print(parse.pokemon_dex_constants_list()) +#print(parse.pokemon_constants_list()) +#print(parse.pokemon_names_list()) +#print(parse.pokemon_dex_entries_list()) +#print(parse.pokemon_dex_order_list()) +#pprint(parse.pokemon_base_stats_list()) + +""" +struct base_stat_values_t { + uint8_t hit_points; + uint8_t attack; + uint8_t defense; + uint8_t speed; + uint8_t special; +}; + +struct level_move_t { + uint8_t level; + enum move_t::move move; +}; + +struct evolution_t { + enum type { + item, + level, + trade + }; + + enum type type; + uint8_t item; // fixme + uint8_t level; + enum pokemon_t::pokemon pokemon; +}; + +struct pokemon_t { + base_stat_values_t stat_values; + type_t types[2]; + uint8_t catch_rate; + uint8_t base_exp; + uint8_t growth_rate; + struct { + uint8_t front; + uint8_t back; + } pics; + struct { + level_move_t * moves; + uint8_t length; + } by_level; + struct { + enum move_t::move * moves; + uint8_t length; + } by_tmhm; + struct { + evolution_t * evolution; // might be null + uint8_t length; + } evolutions; +}; + +[pokemon_t::pidgey] = { + .base_stat_values = {10, 15, 20, 42, 66}, + .types = {type_t::normal, type_t::flying}, + .catch_rate = 80, + .base_exp = 100, + .growth_rate = 0, // fixme + .pics = { + .front = 0, // fixme + .back = 0, // fixme + }, + .by_level = { + .moves = { + { + .level = 1, + .move = move_t::peck, + }, + }, + .length = 1, + }, + .by_tmhm = { + .moves = { + move_t::surf, + }, + .length = 1, + }, + .evolutions = { + .evolutions = { + .type = pokemon_t::evolution_t::level, + .required_item = 0, // fixme + .required_level = 10, + .pokemon = pokemon_t::pidgeotto, + }, + .length = 1, + }, +}; +""" + +def dex_constant_to_enum_name(dex_constant): + assert dex_constant.startswith("DEX_") + name = dex_constant.removeprefix("DEX_") + return name.lower() + +def enum_inc(): + yield "enum pokemon {" + for dex_constant in parse.pokemon_dex_constants_list(): + name = dex_constant_to_enum_name(dex_constant) + yield f"{name.lower()}," + yield "};" + +def generate_enum_inc(): + render, out = renderer() + render(enum_inc()) + return out + +def level_move(level, move): + return [ + "{", + f".level = {level},", + f".move = move_t::{move.lower()},", + "},", + ] + +def moves_by_level(level_1_learnset, learnset): + """ + level_1_learnset=('TACKLE', 'GROWL', 'NO_MOVE', 'NO_MOVE') + learnset=[(7, 'LEECH_SEED'), + (13, 'VINE_WHIP'), + (20, 'POISONPOWDER'), + (27, 'RAZOR_LEAF'), + (34, 'GROWTH'), + (41, 'SLEEP_POWDER'), + (48, 'SOLARBEAM')] + """ + + _learnset = [(1, s) for s in level_1_learnset + if s != 'NO_MOVE'] + learnset + + return [ + ".by_level = {", + ".moves = (level_move_t[]){", + *chain.from_iterable(starmap(level_move, _learnset)), + "},", + f".length = {len(_learnset)},", + "},", + ] + +def moves_by_tmhm(tmhm): + moves = [ + f"move_t::{move.lower()}," + for move in tmhm + if move != 'UNUSED' + ] + return [ + ".by_tmhm = {", + ".moves = (enum move_t::move[]){", + *moves, + "},", + f".length = {len(moves)},", + "}," + ] + +def evolution(ev): + type, _item_name, level, pokemon_name = ev + assert type.startswith('EV_') + type = type.removeprefix('EV_').lower() + return [ + "{", + f".type = pokemon_t::evolution_t::{type},", + ".required_item = 0, // fixme", + f".required_level = {level},", + f".pokemon = pokemon_t::{pokemon_name.lower()},", + "},", + ] + +def evolutions(evs): + return [ + ".evolutions = {", + ".evolution = (pokemon_t::evolution_t[]){", + *chain.from_iterable(evolution(ev) for ev in evs), + "},", + f".length = {len(evs)},", + "},", + ] + +def stat_values(stat_values): + return [ + f".hit_points = {stat_values.hit_points},", + f".attack = {stat_values.attack},", + f".defense = {stat_values.defense},", + f".speed = {stat_values.speed},", + f".special = {stat_values.special},", + ] + +def pic_path(path): + assert path.endswith('.pic') + return f"{path.removesuffix('.pic')}.2bpp" + +def pics(pic_front_back): + front, back = pic_front_back + front_path = pic_path(parse.pic_list()[front]) + back_path = pic_path(parse.pic_list()[back]) + return [ + ".front = {", + *start_size_value(front_path), + "},", + ".back = {", + *start_size_value(back_path), + "},", + ] + +def growth_name(growth_constant): + assert growth_constant.startswith('GROWTH_') + growth_rate = growth_constant.removeprefix('GROWTH_') + return growth_rate.lower() + +def dex_constant_name_to_constant_index(dex_constant_name): + return parse.pokemon_dex_order_list().index(dex_constant_name) + +def pokemon(base_stats, evos_moves): + constant_index = dex_constant_name_to_constant_index(base_stats.pokedex_id) + pokemon_name = parse.pokemon_names_list()[constant_index] + enum_name = dex_constant_to_enum_name(base_stats.pokedex_id) + types = ", ".join( + f"type_t::{type.lower()}" + for type in base_stats.types + ) + growth_rate = growth_name(base_stats.growth_rate) + return [ + f"[pokemon_t::{enum_name}] = {{", + f'.name = reinterpret_cast("{pokemon_name}"),', + ".base_stat_values = {", + *stat_values(base_stats.stat_values), + "},", + f".types = {{{types}}},", + f".catch_rate = {base_stats.catch_rate},", + f".base_exp = {base_stats.base_exp},", + f".growth_rate = growth_t::{growth_rate},", + ".pic = {", + *pics(base_stats.pic_front_back), + "},", + *moves_by_level(base_stats.level_1_learnset, evos_moves.learnset), + *moves_by_tmhm(base_stats.tmhm), + *evolutions(evos_moves.evolutions), + "}," + ] + +def evos_moves(constant_index): + evos_moves_list = parse.pokemon_evos_moves_list() + pointer_table = evos_moves_list[0] + evos_moves = evos_moves_list[1:] + by_label = {em.label: em for em in evos_moves} + return by_label[pointer_table[constant_index]] + +def base_stats_by_dex_id(): + by_dex_id = { + base_stat.pokedex_id: base_stat + for base_stat in parse.pokemon_base_stats_list() + } + assert len(by_dex_id) == len(parse.pokemon_base_stats_list()) + return by_dex_id + +def pokemon_initializers(): + by_dex_id = base_stats_by_dex_id() + for dex_constant_name in parse.pokemon_dex_constants_list(): + base_stats = by_dex_id[dex_constant_name] + constant_index = dex_constant_name_to_constant_index(dex_constant_name) + yield from pokemon(base_stats, evos_moves(constant_index)) + +def source_includes(): + yield "#include " + yield "" + yield '#include "../../pokemon.hpp"' + yield "" + for dex_constant_name in parse.pokemon_dex_constants_list(): + by_dex_id = base_stats_by_dex_id() + base_stats = by_dex_id[dex_constant_name] + front, back = base_stats.pic_front_back + front_path = pic_path(parse.pic_list()[front]) + back_path = pic_path(parse.pic_list()[back]) + yield f'#include "../../res/{front_path}.h"' + yield f'#include "../../res/{back_path}.h"' + yield "" + +def pokemon_source(): + yield "const pokemon_t pokemon[] = {" + yield from pokemon_initializers() + yield "};" + +def generate_source(): + render, out = renderer() + render(source_includes()) + render(pokemon_source()) + return out diff --git a/tools/generate/pokemon/types.py b/tools/generate/pokemon/types.py new file mode 100644 index 0000000..7a164ff --- /dev/null +++ b/tools/generate/pokemon/types.py @@ -0,0 +1,21 @@ +from generate.generate import renderer +from parse import parse + +def includes_header(): + yield "#pragma once" + yield "" + +def struct_type_t(): + _type_constants = parse.type_constants_list() + _type_constants_str = (f"{s.lower()}," for s in _type_constants) + return [ + "enum struct type_t {", + *_type_constants_str, + "};", + ] + +def generate_header(): + render, out = renderer() + render(includes_header()) + render(struct_type_t()) + return out diff --git a/tools/parse/generic/constants.py b/tools/parse/generic/constants.py index 2564b42..46b7ef6 100644 --- a/tools/parse/generic/constants.py +++ b/tools/parse/generic/constants.py @@ -11,6 +11,8 @@ def flatten(tokens): yield None elif t[0] == 'const_def': continue + elif t[0] == 'const_next': + continue else: assert False, t diff --git a/tools/parse/parse.py b/tools/parse/parse.py index 2755675..4121b94 100644 --- a/tools/parse/parse.py +++ b/tools/parse/parse.py @@ -29,6 +29,11 @@ from parse import move # constants # moves # names +from parse import types # constants + # names (fixme) + # matchups (fixme) + # battle_constants.asm + from parse import text from parse import scripts from parse import pic @@ -87,4 +92,7 @@ move_moves_list = memoize(lambda: move.moves.parse(prefix)) move_names_list = memoize(lambda: move.names.parse(prefix)) # pic -pic_list = memoize(lambda: pic.parse(prefix)) +pic_list = memoize(lambda: pic.parse_all(prefix)) + +# type +type_constants_list = memoize(lambda: types.constants.parse(prefix)) diff --git a/tools/parse/pic.py b/tools/parse/pic.py index b0fbd24..2f94b63 100644 --- a/tools/parse/pic.py +++ b/tools/parse/pic.py @@ -8,13 +8,25 @@ def tokenize_lines(lines): if '::' in line: yield tokenize.block(line, delim='::') -def parse(prefix): - path = prefix / 'gfx/pics.asm' +def parse(path): with open(path) as f: tokens = tokenize_lines(f.read().split('\n')) - l = list(flatten(tokens, - endings=['Front', 'Back', 'Pic'], - base_path='gfx/')) - d = dict(l) - assert len(l) == len(d) - return d + l = flatten(tokens, + endings=['Front', 'Back', 'Pic'], + base_path='gfx/') + return l + +def _parse_all(prefix): + pics = [ + "gfx/pics.asm", + "data/pokemon/mew.asm" + ] + for pic in pics: + path = prefix / pic + yield from parse(path) + +def parse_all(prefix): + l = list(_parse_all(prefix)) + d = dict(l) + assert len(l) == len(d) + return d diff --git a/tools/parse/pokemon/base_stats.py b/tools/parse/pokemon/base_stats.py index 24e4c5d..ee40b0c 100644 --- a/tools/parse/pokemon/base_stats.py +++ b/tools/parse/pokemon/base_stats.py @@ -28,7 +28,7 @@ class BaseStats: types: tuple[str, str] catch_rate: int base_exp: int - pic_font_back: tuple[str, str] + pic_front_back: tuple[str, str] level_1_learnset: tuple[str, str, str, str] growth_rate: str tmhm: list[str] @@ -73,5 +73,4 @@ def parse(path): def parse_all(prefix): base_path = prefix / 'data/pokemon/base_stats' paths = [p for p in base_path.iterdir() if p.is_file()] - # in pokedex order return [parse(path) for path in paths] diff --git a/tools/parse/pokemon/evos_moves.py b/tools/parse/pokemon/evos_moves.py index 6c6c949..8e3fb81 100644 --- a/tools/parse/pokemon/evos_moves.py +++ b/tools/parse/pokemon/evos_moves.py @@ -26,10 +26,10 @@ def parse_ev(tokens): ev_type, *rest = tokens if ev_type == 'EV_ITEM': item_name, level_requirement, pokemon_name = rest - return item_name, number.parse(level_requirement), pokemon_name + return ev_type, item_name, number.parse(level_requirement), pokemon_name elif ev_type == 'EV_LEVEL' or ev_type == 'EV_TRADE': level_requirement, pokemon_name = rest - return number.parse(level_requirement), pokemon_name + return ev_type, 0, number.parse(level_requirement), pokemon_name else: assert False, ev_type @@ -74,6 +74,11 @@ def build_tables(tokens): ix += 1 + # yield last evos_moves at the end of parsing + if evos_moves.label != None: + yield evos_moves + + def parse(prefix): path = prefix / "data/pokemon/evos_moves.asm" with open(path) as f: diff --git a/tools/parse/types/__init__.py b/tools/parse/types/__init__.py new file mode 100644 index 0000000..e0a2092 --- /dev/null +++ b/tools/parse/types/__init__.py @@ -0,0 +1 @@ +from parse.types import constants diff --git a/tools/parse/types/constants.py b/tools/parse/types/constants.py new file mode 100644 index 0000000..ed51574 --- /dev/null +++ b/tools/parse/types/constants.py @@ -0,0 +1,4 @@ +from functools import partial +from parse.generic import constants + +parse = partial(constants.parse, path='constants/type_constants.asm')