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_TILESETS = $(call res_png,2bpp,pokered/gfx/tilesets/)
|
||||||
GFX_BLOCKSETS = $(call res,bst,pokered/gfx/blocksets/)
|
GFX_BLOCKSETS = $(call res,bst,pokered/gfx/blocksets/)
|
||||||
GFX_SPRITES = $(call res_png,2bpp,pokered/gfx/sprites/)
|
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/)
|
MAPS_BLOCKS = $(call res,blk,pokered/maps/)
|
||||||
FONTS = res/font.2bpp.o
|
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))
|
OBJ = $(patsubst %.cpp,%.o,$(SRC) $(GENERATED))
|
||||||
|
|
||||||
@ -63,6 +64,11 @@ define PNG_TO_2BPP
|
|||||||
python tools/png_to_nbpp.py 2 $@ $<
|
python tools/png_to_nbpp.py 2 $@ $<
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define PNG_TO_2BPP_SPRITE
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
python tools/png_to_nbpp_sprite.py 2 $@ $<
|
||||||
|
endef
|
||||||
|
|
||||||
res/%.2bpp: derived/%.png
|
res/%.2bpp: derived/%.png
|
||||||
$(PNG_TO_2BPP)
|
$(PNG_TO_2BPP)
|
||||||
|
|
||||||
@ -74,8 +80,10 @@ res/.1bpp: pokered/%.png
|
|||||||
python tools/png_to_nbpp.py 1 $@ $<
|
python tools/png_to_nbpp.py 1 $@ $<
|
||||||
|
|
||||||
res/gfx/sprites/%.2bpp: pokered/gfx/sprites/%.png
|
res/gfx/sprites/%.2bpp: pokered/gfx/sprites/%.png
|
||||||
@mkdir -p $(dir $@)
|
$(PNG_TO_2BPP_SPRITE)
|
||||||
python tools/png_to_nbpp_sprite.py 2 $@ $<
|
|
||||||
|
res/gfx/pokemon/%.2bpp: pokered/gfx/pokemon/%.png
|
||||||
|
$(PNG_TO_2BPP_SPRITE)
|
||||||
|
|
||||||
%.2bpp.h:
|
%.2bpp.h:
|
||||||
$(BUILD_BINARY_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:
|
if path != target_path:
|
||||||
continue
|
continue
|
||||||
buf = func().getvalue()
|
buf = func().getvalue()
|
||||||
|
path.parents[0].mkdir(parents=False, exist_ok=True)
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
f.write(buf)
|
f.write(buf)
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@ from generate import tilesets
|
|||||||
from generate import collision_tile_ids
|
from generate import collision_tile_ids
|
||||||
from generate import text
|
from generate import text
|
||||||
from generate import text_pointers
|
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 = [
|
files = [
|
||||||
(maps.generate_header, "maps.hpp"),
|
(maps.generate_header, "maps.hpp"),
|
||||||
@ -22,6 +24,9 @@ files = [
|
|||||||
(text.generate_source, "text.cpp"),
|
(text.generate_source, "text.cpp"),
|
||||||
(text_pointers.generate_header, "text_pointers.hpp"),
|
(text_pointers.generate_header, "text_pointers.hpp"),
|
||||||
(text_pointers.generate_source, "text_pointers.cpp"),
|
(text_pointers.generate_source, "text_pointers.cpp"),
|
||||||
(moves.generate_header, "moves.hpp"),
|
(moves.generate_header, "pokemon/moves.hpp"),
|
||||||
(moves.generate_source, "moves.cpp"),
|
(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
|
yield None
|
||||||
elif t[0] == 'const_def':
|
elif t[0] == 'const_def':
|
||||||
continue
|
continue
|
||||||
|
elif t[0] == 'const_next':
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
assert False, t
|
assert False, t
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ from parse import move # constants
|
|||||||
# moves
|
# moves
|
||||||
# names
|
# names
|
||||||
|
|
||||||
|
from parse import types # constants
|
||||||
|
# names (fixme)
|
||||||
|
# matchups (fixme)
|
||||||
|
# battle_constants.asm
|
||||||
|
|
||||||
from parse import text
|
from parse import text
|
||||||
from parse import scripts
|
from parse import scripts
|
||||||
from parse import pic
|
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))
|
move_names_list = memoize(lambda: move.names.parse(prefix))
|
||||||
|
|
||||||
# pic
|
# 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:
|
if '::' in line:
|
||||||
yield tokenize.block(line, delim='::')
|
yield tokenize.block(line, delim='::')
|
||||||
|
|
||||||
def parse(prefix):
|
def parse(path):
|
||||||
path = prefix / 'gfx/pics.asm'
|
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
tokens = tokenize_lines(f.read().split('\n'))
|
tokens = tokenize_lines(f.read().split('\n'))
|
||||||
l = list(flatten(tokens,
|
l = flatten(tokens,
|
||||||
endings=['Front', 'Back', 'Pic'],
|
endings=['Front', 'Back', 'Pic'],
|
||||||
base_path='gfx/'))
|
base_path='gfx/')
|
||||||
d = dict(l)
|
return l
|
||||||
assert len(l) == len(d)
|
|
||||||
return d
|
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]
|
types: tuple[str, str]
|
||||||
catch_rate: int
|
catch_rate: int
|
||||||
base_exp: int
|
base_exp: int
|
||||||
pic_font_back: tuple[str, str]
|
pic_front_back: tuple[str, str]
|
||||||
level_1_learnset: tuple[str, str, str, str]
|
level_1_learnset: tuple[str, str, str, str]
|
||||||
growth_rate: str
|
growth_rate: str
|
||||||
tmhm: list[str]
|
tmhm: list[str]
|
||||||
@ -73,5 +73,4 @@ def parse(path):
|
|||||||
def parse_all(prefix):
|
def parse_all(prefix):
|
||||||
base_path = prefix / 'data/pokemon/base_stats'
|
base_path = prefix / 'data/pokemon/base_stats'
|
||||||
paths = [p for p in base_path.iterdir() if p.is_file()]
|
paths = [p for p in base_path.iterdir() if p.is_file()]
|
||||||
# in pokedex order
|
|
||||||
return [parse(path) for path in paths]
|
return [parse(path) for path in paths]
|
||||||
|
@ -26,10 +26,10 @@ def parse_ev(tokens):
|
|||||||
ev_type, *rest = tokens
|
ev_type, *rest = tokens
|
||||||
if ev_type == 'EV_ITEM':
|
if ev_type == 'EV_ITEM':
|
||||||
item_name, level_requirement, pokemon_name = rest
|
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':
|
elif ev_type == 'EV_LEVEL' or ev_type == 'EV_TRADE':
|
||||||
level_requirement, pokemon_name = rest
|
level_requirement, pokemon_name = rest
|
||||||
return number.parse(level_requirement), pokemon_name
|
return ev_type, 0, number.parse(level_requirement), pokemon_name
|
||||||
else:
|
else:
|
||||||
assert False, ev_type
|
assert False, ev_type
|
||||||
|
|
||||||
@ -74,6 +74,11 @@ def build_tables(tokens):
|
|||||||
|
|
||||||
ix += 1
|
ix += 1
|
||||||
|
|
||||||
|
# yield last evos_moves at the end of parsing
|
||||||
|
if evos_moves.label != None:
|
||||||
|
yield evos_moves
|
||||||
|
|
||||||
|
|
||||||
def parse(prefix):
|
def parse(prefix):
|
||||||
path = prefix / "data/pokemon/evos_moves.asm"
|
path = prefix / "data/pokemon/evos_moves.asm"
|
||||||
with open(path) as f:
|
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