Zack Buhman 853457a79d generate: add pokemon
This also includes a handful of functions for creating instances of a
pokemon species, though certainly not complete.
2023-08-02 23:49:42 +00:00

320 lines
8.1 KiB
Python

"""
- 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<const uint8_t *>("{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 <cstdint>"
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