generate: add pokemon
This also includes a handful of functions for creating instances of a pokemon species, though certainly not complete.
This commit is contained in:
parent
9e94179a53
commit
853457a79d
14
Makefile
14
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)
|
||||
|
81
pokemon.hpp
Normal file
81
pokemon.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include <cstdint>
|
||||
|
||||
#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[];
|
75
pokemon_instance.cpp
Normal file
75
pokemon_instance.cpp
Normal file
@ -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<uint16_t>(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;
|
||||
}
|
||||
}
|
83
pokemon_instance.hpp
Normal file
83
pokemon_instance.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include <cstdint>
|
||||
|
||||
#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);
|
||||
};
|
43
sqrt.hpp
Normal file
43
sqrt.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
template <typename T>
|
||||
inline constexpr T div_ceil(T a, T b)
|
||||
{
|
||||
return (a / b) + ((a % b) != 0);
|
||||
}
|
||||
|
||||
static_assert(div_ceil<int>(2, 2) == 1);
|
||||
static_assert(div_ceil<int>(3, 2) == 2);
|
||||
static_assert(div_ceil<int>(55, 8) == 7);
|
||||
static_assert(div_ceil<int>(55, 11) == 5);
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T sqrt_floor(T a)
|
||||
{
|
||||
if (a == 0) return 0;
|
||||
constexpr int num_bits = (sizeof (T)) * 8;
|
||||
T x = 1 << div_ceil<T>(num_bits, 2);
|
||||
while (true) {
|
||||
T y = (x + (a / x)) / 2;
|
||||
if (y >= x) return x;
|
||||
x = y;
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(sqrt_floor<int>(4) == 2);
|
||||
static_assert(sqrt_floor<int>(9) == 3);
|
||||
static_assert(sqrt_floor<int>(7056) == 84);
|
||||
static_assert(sqrt_floor<int>(7211) == 84);
|
||||
static_assert(sqrt_floor<int>(7225) == 85);
|
||||
static_assert(sqrt_floor<int>(7226) == 85);
|
||||
|
||||
template <typename T>
|
||||
inline constexpr T sqrt_ceil(T a)
|
||||
{
|
||||
T q = sqrt_floor<T>(a);
|
||||
if (q * q != a) q += 1;
|
||||
return q;
|
||||
}
|
||||
|
||||
static_assert(sqrt_ceil<int>(7056) == 84);
|
||||
static_assert(sqrt_ceil<int>(7211) == 85);
|
||||
static_assert(sqrt_ceil<int>(7225) == 85);
|
||||
static_assert(sqrt_ceil<int>(7226) == 86);
|
@ -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)
|
||||
|
||||
|
@ -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"),
|
||||
]
|
||||
|
319
tools/generate/pokemon/pokemon.py
Normal file
319
tools/generate/pokemon/pokemon.py
Normal file
@ -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<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
|
21
tools/generate/pokemon/types.py
Normal file
21
tools/generate/pokemon/types.py
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
l = flatten(tokens,
|
||||
endings=['Front', 'Back', 'Pic'],
|
||||
base_path='gfx/'))
|
||||
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
|
||||
|
@ -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]
|
||||
|
@ -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:
|
||||
|
1
tools/parse/types/__init__.py
Normal file
1
tools/parse/types/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from parse.types import constants
|
4
tools/parse/types/constants.py
Normal file
4
tools/parse/types/constants.py
Normal file
@ -0,0 +1,4 @@
|
||||
from functools import partial
|
||||
from parse.generic import constants
|
||||
|
||||
parse = partial(constants.parse, path='constants/type_constants.asm')
|
Loading…
x
Reference in New Issue
Block a user