mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-03-21 09:45:26 -05:00
tools: Replace use of datagen_species.cpp with speciesproc.c
Some checks are pending
build / build (push) Waiting to run
Some checks are pending
build / build (push) Waiting to run
This commit is contained in:
parent
41c0c2f864
commit
d92f23036b
|
|
@ -31,11 +31,11 @@
|
|||
"safari_flee_rate": 0,
|
||||
"body_color": "MON_COLOR_GRAY",
|
||||
"flip_sprite": false,
|
||||
"icon_palette": {
|
||||
"base": 1,
|
||||
"sandy": 1,
|
||||
"trash": 0
|
||||
},
|
||||
"icon_palette": [
|
||||
[ "base", 1 ],
|
||||
[ "sandy", 1 ],
|
||||
[ "trash", 0 ]
|
||||
],
|
||||
"learnset": {
|
||||
"by_level": [
|
||||
[ 1, "MOVE_PROTECT" ],
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@
|
|||
"MOVE_KNOCK_OFF"
|
||||
]
|
||||
},
|
||||
"evolutions": [ ],
|
||||
"pokedex_data": {
|
||||
"height": 0,
|
||||
"weight": 0,
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@
|
|||
"safari_flee_rate": 0,
|
||||
"body_color": "MON_COLOR_PURPLE",
|
||||
"flip_sprite": false,
|
||||
"icon_palette": {
|
||||
"base": 0,
|
||||
"east_sea": 0
|
||||
},
|
||||
"icon_palette": [
|
||||
[ "base", 0 ],
|
||||
[ "east_sea", 0 ]
|
||||
],
|
||||
"learnset": {
|
||||
"by_level": [
|
||||
[ 1, "MOVE_MUD_SLAP" ],
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ species_orders = custom_target('species_orders',
|
|||
pokefoot_order = species_orders[0]
|
||||
|
||||
|
||||
datagen_species_out = custom_target('datagen_species_out',
|
||||
species_data = custom_target('species_data',
|
||||
output: [
|
||||
'pl_personal.narc',
|
||||
'evo.narc',
|
||||
|
|
@ -198,24 +198,26 @@ datagen_species_out = custom_target('datagen_species_out',
|
|||
'species_egg_moves.h',
|
||||
'species_icon_palettes.h',
|
||||
],
|
||||
|
||||
command: [
|
||||
datagen_species_exe,
|
||||
meson.current_build_dir(),
|
||||
speciesproc_exe,
|
||||
'-M', '@DEPFILE@',
|
||||
'-t', files('move_tutors.json'),
|
||||
'-o', meson.current_build_dir(),
|
||||
pokemon_data_root,
|
||||
form_registry_json,
|
||||
files('move_tutors.json'),
|
||||
],
|
||||
|
||||
env: species_env,
|
||||
depend_files: [
|
||||
species_data_files,
|
||||
],
|
||||
depend_files: species_data_files,
|
||||
depfile: 'species_data.d',
|
||||
)
|
||||
h_headers += datagen_species_out[7]
|
||||
h_headers += datagen_species_out[8]
|
||||
h_headers += datagen_species_out[9]
|
||||
h_headers += datagen_species_out[10]
|
||||
h_headers += datagen_species_out[11]
|
||||
h_headers += datagen_species_out[12]
|
||||
|
||||
h_headers += species_data[7]
|
||||
h_headers += species_data[8]
|
||||
h_headers += species_data[9]
|
||||
h_headers += species_data[10]
|
||||
h_headers += species_data[11]
|
||||
h_headers += species_data[12]
|
||||
|
||||
|
||||
# OLD NARCs
|
||||
|
|
@ -410,7 +412,7 @@ pokefoot_narc = custom_target('pokefoot.narc',
|
|||
)
|
||||
naix_headers += pokefoot_narc[1]
|
||||
|
||||
nitrofs_files += datagen_species_out
|
||||
nitrofs_files += species_data
|
||||
|
||||
nitrofs_files += pl_poke_icon_narc
|
||||
nitrofs_files += pl_pokegra_narc
|
||||
|
|
|
|||
|
|
@ -1,274 +1,306 @@
|
|||
{
|
||||
"static": true,
|
||||
"const": true,
|
||||
"type": "TeachableMove",
|
||||
"name": "sTeachableMoves",
|
||||
"moves": {
|
||||
"MOVE_DIVE": {
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_MUD_SLAP": {
|
||||
"redCost": 4,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_FURY_CUTTER": {
|
||||
"redCost": 0,
|
||||
"blueCost": 8,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_ICY_WIND": {
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_ROLLOUT": {
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_THUNDER_PUNCH": {
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_FIRE_PUNCH": {
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_SUPERPOWER": {
|
||||
"redCost": 8,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_ICE_PUNCH": {
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_IRON_HEAD": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_AQUA_TAIL": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_OMINOUS_WIND": {
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_GASTRO_ACID": {
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_SNORE": {
|
||||
"redCost": 2,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_SPITE": {
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 8,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_AIR_CUTTER": {
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_HELPING_HAND": {
|
||||
"redCost": 2,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_ENDEAVOR": {
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_OUTRAGE": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_ANCIENT_POWER": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_SYNTHESIS": {
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 6,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_SIGNAL_BEAM": {
|
||||
"redCost": 2,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_ZEN_HEADBUTT": {
|
||||
"redCost": 0,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_VACUUM_WAVE": {
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_EARTH_POWER": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_GUNK_SHOT": {
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_TWISTER": {
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_SEED_BOMB": {
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 4,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_IRON_DEFENSE": {
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_MAGNET_RISE": {
|
||||
"redCost": 0,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_LAST_RESORT": {
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 8,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_BOUNCE": {
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_TRICK": {
|
||||
"redCost": 0,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_HEAT_WAVE": {
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
"MOVE_KNOCK_OFF": {
|
||||
"redCost": 4,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_SUCKER_PUNCH": {
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
"MOVE_SWIFT": {
|
||||
"redCost": 0,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 4,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
"MOVE_UPROAR": {
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 6,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
}
|
||||
[
|
||||
{
|
||||
"move": "MOVE_DIVE",
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_MUD_SLAP",
|
||||
"redCost": 4,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_FURY_CUTTER",
|
||||
"redCost": 0,
|
||||
"blueCost": 8,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ICY_WIND",
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ROLLOUT",
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_THUNDER_PUNCH",
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_FIRE_PUNCH",
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SUPERPOWER",
|
||||
"redCost": 8,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ICE_PUNCH",
|
||||
"redCost": 2,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_IRON_HEAD",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_AQUA_TAIL",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_OMINOUS_WIND",
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_GASTRO_ACID",
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SNORE",
|
||||
"redCost": 2,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SPITE",
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 8,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_AIR_CUTTER",
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_HELPING_HAND",
|
||||
"redCost": 2,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ENDEAVOR",
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_OUTRAGE",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ANCIENT_POWER",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SYNTHESIS",
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 6,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SIGNAL_BEAM",
|
||||
"redCost": 2,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_ZEN_HEADBUTT",
|
||||
"redCost": 0,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_VACUUM_WAVE",
|
||||
"redCost": 2,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_EARTH_POWER",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_GUNK_SHOT",
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_TWISTER",
|
||||
"redCost": 6,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SEED_BOMB",
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 4,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_IRON_DEFENSE",
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_MAGNET_RISE",
|
||||
"redCost": 0,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_LAST_RESORT",
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 8,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_BOUNCE",
|
||||
"redCost": 4,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_TRICK",
|
||||
"redCost": 0,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 4,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_HEAT_WAVE",
|
||||
"redCost": 4,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SURVIVAL_AREA"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_KNOCK_OFF",
|
||||
"redCost": 4,
|
||||
"blueCost": 4,
|
||||
"yellowCost": 0,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SUCKER_PUNCH",
|
||||
"redCost": 0,
|
||||
"blueCost": 6,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 0,
|
||||
"location": "TUTOR_LOCATION_ROUTE_212"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_SWIFT",
|
||||
"redCost": 0,
|
||||
"blueCost": 2,
|
||||
"yellowCost": 2,
|
||||
"greenCost": 4,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
},
|
||||
{
|
||||
"move": "MOVE_UPROAR",
|
||||
"redCost": 0,
|
||||
"blueCost": 0,
|
||||
"yellowCost": 6,
|
||||
"greenCost": 2,
|
||||
"location": "TUTOR_LOCATION_SNOWPOINT_CITY"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@
|
|||
"safari_flee_rate": 0,
|
||||
"body_color": "MON_COLOR_PURPLE",
|
||||
"flip_sprite": false,
|
||||
"icon_palette": {
|
||||
"base": 0,
|
||||
"east_sea": 0
|
||||
},
|
||||
"icon_palette": [
|
||||
[ "base", 0 ],
|
||||
[ "east_sea", 0 ]
|
||||
],
|
||||
"learnset": {
|
||||
"by_level": [
|
||||
[ 1, "MOVE_MUD_SLAP" ],
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@
|
|||
"footprint": {
|
||||
"has": false,
|
||||
"size": "FOOTPRINT_LARGE",
|
||||
"type": "FOOTPRINT_TYPE_SCARY",
|
||||
"has_type": true
|
||||
"type": "FOOTPRINT_TYPE_SCARY"
|
||||
},
|
||||
"pokedex_data": {
|
||||
"height": 10,
|
||||
|
|
|
|||
|
|
@ -31,36 +31,37 @@
|
|||
"safari_flee_rate": 0,
|
||||
"body_color": "MON_COLOR_BLACK",
|
||||
"flip_sprite": true,
|
||||
"icon_palette": {
|
||||
"base": 0,
|
||||
"b": 0,
|
||||
"c": 0,
|
||||
"d": 0,
|
||||
"e": 0,
|
||||
"f": 0,
|
||||
"g": 0,
|
||||
"h": 0,
|
||||
"i": 0,
|
||||
"j": 0,
|
||||
"k": 0,
|
||||
"l": 0,
|
||||
"m": 0,
|
||||
"n": 0,
|
||||
"o": 0,
|
||||
"p": 0,
|
||||
"q": 0,
|
||||
"r": 0,
|
||||
"s": 0,
|
||||
"t": 0,
|
||||
"u": 0,
|
||||
"v": 0,
|
||||
"w": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"exc": 0,
|
||||
"que": 0
|
||||
},
|
||||
"icon_palette": [
|
||||
[ "base", 0 ],
|
||||
[ "a", 0 ],
|
||||
[ "b", 0 ],
|
||||
[ "c", 0 ],
|
||||
[ "d", 0 ],
|
||||
[ "e", 0 ],
|
||||
[ "f", 0 ],
|
||||
[ "g", 0 ],
|
||||
[ "h", 0 ],
|
||||
[ "i", 0 ],
|
||||
[ "j", 0 ],
|
||||
[ "k", 0 ],
|
||||
[ "l", 0 ],
|
||||
[ "m", 0 ],
|
||||
[ "n", 0 ],
|
||||
[ "o", 0 ],
|
||||
[ "p", 0 ],
|
||||
[ "q", 0 ],
|
||||
[ "r", 0 ],
|
||||
[ "s", 0 ],
|
||||
[ "t", 0 ],
|
||||
[ "u", 0 ],
|
||||
[ "v", 0 ],
|
||||
[ "w", 0 ],
|
||||
[ "x", 0 ],
|
||||
[ "y", 0 ],
|
||||
[ "z", 0 ],
|
||||
[ "exc", 0 ],
|
||||
[ "que", 0 ]
|
||||
],
|
||||
"learnset": {
|
||||
"by_level": [
|
||||
[ 1, "MOVE_HIDDEN_POWER" ]
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ const u8 PokeIconPaletteIndex(u32 species, u32 form, u32 isEgg)
|
|||
if (species == SPECIES_DEOXYS) {
|
||||
species = ICON_DEOXYS_ATTACK + form - 1;
|
||||
} else if (species == SPECIES_UNOWN) {
|
||||
species = ICON_UNOWN_BASE + form - 1;
|
||||
species = ICON_UNOWN_A + form - 1;
|
||||
} else if (species == SPECIES_BURMY) {
|
||||
species = ICON_BURMY_SANDY + form - 1;
|
||||
} else if (species == SPECIES_WORMADAM) {
|
||||
|
|
|
|||
|
|
@ -1,791 +0,0 @@
|
|||
/*
|
||||
* datagen-species
|
||||
*
|
||||
* Usage: datagen-species <OUT_DIR> <ROOT_DIR> <FORMS_REGISTRY> <TUTOR_SCHEMA>
|
||||
*
|
||||
* This program is responsible for generating data archive from species data files
|
||||
* (res/pokemon/<species>/data.json). Individual files to be polled for packing are
|
||||
* drawn from an environment var SPECIES, which should be a semicolon-delimited list
|
||||
* of subdirectories of res/pokemon.
|
||||
*
|
||||
* <FORMS_REGISTRY> is expected to be a listing of additional subdirectories
|
||||
* belonging to individual species which have distinct data files. These special
|
||||
* forms have their own base stats, types, level-up learnsets, etc., as any base
|
||||
* species form would.
|
||||
*
|
||||
* <TUTOR_SCHEMA> is expected to be a JSON file defining the listing of moves that
|
||||
* can be taught by a given move tutor, agnostic of species. This file is only
|
||||
* consulted to restrict the set of valid moves in a species' tutorable learnset.
|
||||
*
|
||||
* The following files are generated by this program:
|
||||
* - pl_personal.narc
|
||||
* - evo.narc
|
||||
* - wotbl.narc
|
||||
* - ppark.narc
|
||||
* - height.narc
|
||||
* - pl_poke_data.narc
|
||||
* - pms.narc
|
||||
* - tutorable_moves.h
|
||||
* - species_learnsets_by_tutor.h
|
||||
* - species_footprint_sizes.h
|
||||
* - species_footprint_types.h
|
||||
* - species_egg_moves.h
|
||||
* - species_icon_palettes.h
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "datagen.h"
|
||||
|
||||
#define POKEPLATINUM_GENERATED_ENUM
|
||||
#define POKEPLATINUM_GENERATED_LOOKUP
|
||||
#define POKEPLATINUM_GENERATED_LOOKUP_IMPL
|
||||
|
||||
#include "generated/abilities.h"
|
||||
#include "generated/egg_groups.h"
|
||||
#include "generated/evolution_methods.h"
|
||||
#include "generated/exp_rates.h"
|
||||
#include "generated/gender_ratios.h"
|
||||
#include "generated/items.h"
|
||||
#include "generated/moves.h"
|
||||
#include "generated/pal_park_land_area.h"
|
||||
#include "generated/pal_park_water_area.h"
|
||||
#include "generated/pokemon_colors.h"
|
||||
#include "generated/pokemon_types.h"
|
||||
#include "generated/shadow_sizes.h"
|
||||
#include "generated/species.h"
|
||||
|
||||
#include "struct_defs/species.h"
|
||||
#include "struct_defs/species_sprite_data.h"
|
||||
|
||||
#define NUM_TMS 92 // TODO: Move this to a more accessible location, maybe?
|
||||
|
||||
// This struct serves only one purpose: to ensure that the size of the data written
|
||||
// to file-iamges in evo.narc is word-aligned. The vanilla structures pad to word-
|
||||
// alignment with 0s, making for two extra 0-bytes after the array. Without this
|
||||
// manual alignment, the NARC packing routine would instead pad the virtual files
|
||||
// with `FF FF`, which obviously breaks matching.
|
||||
struct SpeciesEvolutionList {
|
||||
ALIGN_4 SpeciesEvolution entries[MAX_EVOLUTIONS];
|
||||
};
|
||||
|
||||
// Entries in `wotbl.narc` are dynamically-sized with a terminating sentinel value
|
||||
// for each entry. So, we need to know how large the learnset itself is for a
|
||||
// proper malloc and memcpy while packing to the VFS.
|
||||
struct SpeciesLearnsetWithSize {
|
||||
SpeciesLearnset learnset;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
static const std::string sHeaderMessage = ""
|
||||
"/*\n"
|
||||
" * This header was generated by datagen-species; DO NOT MODIFY IT!!!\n"
|
||||
" */"
|
||||
"";
|
||||
|
||||
static void Usage(std::ostream &ostr)
|
||||
{
|
||||
ostr << "Usage: datagen-species OUT_DIR ROOT_DIR FORMS_REGISTRY TUTOR_SCHEMA" << std::endl;
|
||||
ostr << std::endl;
|
||||
ostr << "Generates data archives from species data files (res/pokemon/<species>/data.json)" << std::endl;
|
||||
ostr << "Species data files to be polled for packing are drawn from the environment var\n"
|
||||
<< "SPECIES, which must be a semicolon-delimited list of subdirectories of res/pokemon\n"
|
||||
<< "to be crawled at execution." << std::endl;
|
||||
}
|
||||
|
||||
static SpeciesData ParseSpeciesData(rapidjson::Document &root)
|
||||
{
|
||||
SpeciesData species = { 0 };
|
||||
|
||||
rapidjson::Value &baseStats = root["base_stats"];
|
||||
species.baseStats.hp = baseStats["hp"].GetUint();
|
||||
species.baseStats.attack = baseStats["attack"].GetUint();
|
||||
species.baseStats.defense = baseStats["defense"].GetUint();
|
||||
species.baseStats.speed = baseStats["speed"].GetUint();
|
||||
species.baseStats.spAttack = baseStats["special_attack"].GetUint();
|
||||
species.baseStats.spDefense = baseStats["special_defense"].GetUint();
|
||||
|
||||
rapidjson::Value &evYields = root["ev_yields"];
|
||||
species.evYields.hp = evYields["hp"].GetUint();
|
||||
species.evYields.attack = evYields["attack"].GetUint();
|
||||
species.evYields.defense = evYields["defense"].GetUint();
|
||||
species.evYields.speed = evYields["speed"].GetUint();
|
||||
species.evYields.spAttack = evYields["special_attack"].GetUint();
|
||||
species.evYields.spDefense = evYields["special_defense"].GetUint();
|
||||
|
||||
rapidjson::Value &abilities = root["abilities"];
|
||||
species.abilities[0] = LookupConst(abilities[0].GetString(), Ability);
|
||||
species.abilities[1] = LookupConst(abilities[1].GetString(), Ability);
|
||||
|
||||
rapidjson::Value &types = root["types"];
|
||||
species.types[0] = LookupConst(types[0].GetString(), PokemonType);
|
||||
species.types[1] = LookupConst(types[1].GetString(), PokemonType);
|
||||
|
||||
rapidjson::Value &heldItems = root["held_items"];
|
||||
species.wildHeldItems.common = LookupConst(heldItems["common"].GetString(), Item);
|
||||
species.wildHeldItems.rare = LookupConst(heldItems["rare"].GetString(), Item);
|
||||
|
||||
rapidjson::Value &eggGroups = root["egg_groups"];
|
||||
species.eggGroups[0] = LookupConst(eggGroups[0].GetString(), EggGroup);
|
||||
species.eggGroups[1] = LookupConst(eggGroups[1].GetString(), EggGroup);
|
||||
|
||||
species.baseExpReward = root["base_exp_reward"].GetUint();
|
||||
species.baseFriendship = root["base_friendship"].GetUint();
|
||||
species.bodyColor = LookupConst(root["body_color"].GetString(), PokemonColor);
|
||||
species.catchRate = root["catch_rate"].GetUint();
|
||||
species.expRate = LookupConst(root["exp_rate"].GetString(), ExpRate);
|
||||
species.flipSprite = root["flip_sprite"].GetBool();
|
||||
species.genderRatio = LookupConst(root["gender_ratio"].GetString(), GenderRatio);
|
||||
species.hatchCycles = root["hatch_cycles"].GetUint();
|
||||
species.safariFleeRate = root["safari_flee_rate"].GetUint();
|
||||
|
||||
rapidjson::Value &tmLearnset = root["learnset"]["by_tm"];
|
||||
for (auto &tmEntry : tmLearnset.GetArray()) {
|
||||
std::string entry = tmEntry.GetString();
|
||||
int id;
|
||||
if (entry[0] == 'T' && entry[1] == 'M') {
|
||||
id = std::stoi(entry.substr(2)) - 1;
|
||||
} else if (entry[0] == 'H' && entry[1] == 'M') {
|
||||
id = std::stoi(entry.substr(2)) - 1 + NUM_TMS;
|
||||
} else {
|
||||
throw std::invalid_argument("unrecognized TM learnset entry " + entry);
|
||||
}
|
||||
species.tmLearnsetMasks[id / 32] |= (1 << (id % 32));
|
||||
}
|
||||
|
||||
return species;
|
||||
}
|
||||
|
||||
static SpeciesEvolutionList ParseEvolutions(rapidjson::Document &root)
|
||||
{
|
||||
SpeciesEvolutionList evos = { 0 };
|
||||
if (!root.HasMember("evolutions")) {
|
||||
return evos;
|
||||
}
|
||||
|
||||
rapidjson::Value &evoList = root["evolutions"];
|
||||
int i = 0;
|
||||
for (auto &evoEntry : evoList.GetArray()) {
|
||||
EvolutionMethod method = static_cast<EvolutionMethod>(LookupConst(evoEntry[0].GetString(), EvolutionMethod));
|
||||
|
||||
u16 param;
|
||||
int speciesIdx = 2;
|
||||
switch (method) {
|
||||
case EVO_NONE:
|
||||
case EVO_LEVEL_HAPPINESS:
|
||||
case EVO_LEVEL_HAPPINESS_DAY:
|
||||
case EVO_LEVEL_HAPPINESS_NIGHT:
|
||||
case EVO_TRADE:
|
||||
case EVO_LEVEL_MAGNETIC_FIELD:
|
||||
case EVO_LEVEL_MOSS_ROCK:
|
||||
case EVO_LEVEL_ICE_ROCK:
|
||||
param = 0;
|
||||
speciesIdx = 1;
|
||||
break;
|
||||
|
||||
case EVO_LEVEL:
|
||||
case EVO_LEVEL_ATK_GT_DEF:
|
||||
case EVO_LEVEL_ATK_EQ_DEF:
|
||||
case EVO_LEVEL_ATK_LT_DEF:
|
||||
case EVO_LEVEL_PID_LOW:
|
||||
case EVO_LEVEL_PID_HIGH:
|
||||
case EVO_LEVEL_NINJASK:
|
||||
case EVO_LEVEL_SHEDINJA:
|
||||
case EVO_LEVEL_MALE:
|
||||
case EVO_LEVEL_FEMALE:
|
||||
case EVO_LEVEL_BEAUTY:
|
||||
param = evoEntry[1].GetUint();
|
||||
break;
|
||||
|
||||
case EVO_TRADE_WITH_HELD_ITEM:
|
||||
case EVO_USE_ITEM:
|
||||
case EVO_USE_ITEM_MALE:
|
||||
case EVO_USE_ITEM_FEMALE:
|
||||
case EVO_LEVEL_WITH_HELD_ITEM_DAY:
|
||||
case EVO_LEVEL_WITH_HELD_ITEM_NIGHT:
|
||||
param = LookupConst(evoEntry[1].GetString(), Item);
|
||||
break;
|
||||
|
||||
case EVO_LEVEL_KNOW_MOVE:
|
||||
param = LookupConst(evoEntry[1].GetString(), Move);
|
||||
break;
|
||||
|
||||
case EVO_LEVEL_SPECIES_IN_PARTY:
|
||||
param = LookupConst(evoEntry[1].GetString(), Species);
|
||||
break;
|
||||
}
|
||||
|
||||
u16 target = LookupConst(evoEntry[speciesIdx].GetString(), Species);
|
||||
evos.entries[i++] = SpeciesEvolution {
|
||||
.method = static_cast<u16>(method),
|
||||
.param = param,
|
||||
.targetSpecies = target,
|
||||
};
|
||||
}
|
||||
|
||||
return evos;
|
||||
}
|
||||
|
||||
static SpeciesLearnsetWithSize ParseLevelUpLearnset(rapidjson::Document &root)
|
||||
{
|
||||
SpeciesLearnsetWithSize result = {};
|
||||
|
||||
rapidjson::Value &byLevel = root["learnset"]["by_level"];
|
||||
int i = 0;
|
||||
for (auto &byLevelEntry : byLevel.GetArray()) {
|
||||
u16 level = byLevelEntry[0].GetUint();
|
||||
u16 move = LookupConst(byLevelEntry[1].GetString(), Move);
|
||||
result.learnset.entries[i++] = {
|
||||
.move = move,
|
||||
.level = level,
|
||||
};
|
||||
|
||||
if (i == MAX_LEARNSET_ENTRIES) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpragmas" // bitfield-constant-conversion is clang-specific; GCC should ignore it
|
||||
#pragma GCC diagnostic ignored "-Woverflow"
|
||||
#pragma GCC diagnostic ignored "-Wbitfield-constant-conversion"
|
||||
result.learnset.entries[i++] = {
|
||||
.move = static_cast<u16>(-1),
|
||||
.level = static_cast<u16>(-1),
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
result.size = AlignToWord(i * sizeof(SpeciesLearnsetEntry));
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::optional<SpeciesPalPark> TryParsePalPark(rapidjson::Document &root)
|
||||
{
|
||||
if (!root.HasMember("catching_show")) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
rapidjson::Value &catchingShow = root["catching_show"];
|
||||
SpeciesPalPark palPark;
|
||||
palPark.landArea = LookupConst(catchingShow["pal_park_land_area"].GetString(), PalParkLandArea);
|
||||
palPark.waterArea = LookupConst(catchingShow["pal_park_water_area"].GetString(), PalParkWaterArea);
|
||||
palPark.catchingPoints = catchingShow["catching_points"].GetUint();
|
||||
palPark.rarity = catchingShow["rarity"].GetUint();
|
||||
palPark.unused.asU16 = catchingShow["unused"].GetUint();
|
||||
|
||||
return palPark;
|
||||
}
|
||||
|
||||
static u16 TryParseOffspring(rapidjson::Document &root, u16 personalValue)
|
||||
{
|
||||
if (!root.HasMember("offspring")) {
|
||||
return personalValue;
|
||||
}
|
||||
|
||||
return LookupConst(root["offspring"].GetString(), Species);
|
||||
}
|
||||
|
||||
static void PackOffspring(std::vector<u16> offspringData, fs::path path)
|
||||
{
|
||||
std::ofstream ofs(path);
|
||||
ofs.write(reinterpret_cast<char *>(&offspringData[0]), offspringData.size() * sizeof(u16));
|
||||
}
|
||||
|
||||
static std::vector<Move> EmitTutorableMoves(fs::path &tutorSchemaFname, fs::path outFname)
|
||||
{
|
||||
std::string tutorSchema = ReadWholeFile(tutorSchemaFname);
|
||||
rapidjson::Document doc;
|
||||
doc.Parse(tutorSchema.c_str());
|
||||
|
||||
std::ofstream header(outFname, std::ios::out | std::ios::trunc | std::ios::ate);
|
||||
header << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_TUTORABLE_MOVES\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_TUTORABLE_MOVES\n"
|
||||
<< "\n"
|
||||
<< "static const TeachableMove sTeachableMoves[] = {"
|
||||
<< std::endl;
|
||||
|
||||
std::vector<Move> tutorables;
|
||||
rapidjson::Value &moves = doc["moves"];
|
||||
for (const auto &entry : moves.GetObject()) {
|
||||
Move tutorable = static_cast<Move>(LookupConst(entry.name.GetString(), Move));
|
||||
if (std::find(tutorables.begin(), tutorables.end(), tutorable) == tutorables.end()) {
|
||||
tutorables.push_back(tutorable);
|
||||
}
|
||||
|
||||
const rapidjson::Value &moveObj = entry.value;
|
||||
header << " { " << entry.name.GetString() << ", "
|
||||
<< moveObj["redCost"].GetUint() << ", "
|
||||
<< moveObj["blueCost"].GetUint() << ", "
|
||||
<< moveObj["yellowCost"].GetUint() << ", "
|
||||
<< moveObj["greenCost"].GetUint() << ", "
|
||||
<< moveObj["location"].GetString() << ", }, "
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
header << "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_TUTORABLE_MOVES"
|
||||
<< std::endl;
|
||||
header.close();
|
||||
return tutorables;
|
||||
}
|
||||
|
||||
static void TryEmitTutorableLearnset(rapidjson::Document &root, std::ofstream &ofs, std::vector<Move> &tutorableMoves, std::size_t tutorableLearnsetSize)
|
||||
{
|
||||
const rapidjson::Value &learnsets = root["learnset"];
|
||||
if (!learnsets.HasMember("by_tutor")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rapidjson::Value &byTutorLearnset = learnsets["by_tutor"];
|
||||
std::vector<u8> tutorableLearnset(tutorableLearnsetSize);
|
||||
for (const auto &entry : byTutorLearnset.GetArray()) {
|
||||
Move tutorable = static_cast<Move>(LookupConst(entry.GetString(), Move));
|
||||
std::vector<Move>::iterator it = std::find(tutorableMoves.begin(), tutorableMoves.end(), tutorable);
|
||||
if (it == tutorableMoves.end()) {
|
||||
std::stringstream ss;
|
||||
ss << "Move " << entry.GetString() << " is not available via move tutors";
|
||||
throw std::invalid_argument(ss.str());
|
||||
}
|
||||
|
||||
// The mask-index of this move is just the move's index / 8
|
||||
// The bit-index within that mask is the move's index % 8
|
||||
std::size_t idx = it - tutorableMoves.begin();
|
||||
tutorableLearnset[idx / 8] |= (1 << (idx % 8));
|
||||
}
|
||||
|
||||
ofs << " { ";
|
||||
for (const auto &mask : tutorableLearnset) {
|
||||
ofs << "0x" << std::setfill('0') << std::setw(2) << (int)mask << ", ";
|
||||
}
|
||||
ofs << "},\n";
|
||||
}
|
||||
|
||||
static void TryEmitEggMoves(rapidjson::Document &root, std::ofstream &ofs, std::string species)
|
||||
{
|
||||
const rapidjson::Value &learnsets = root["learnset"];
|
||||
if (!learnsets.HasMember("egg_moves")) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::transform(species.begin(), species.end(), species.begin(), ::toupper);
|
||||
ofs << " SPECIES_"
|
||||
<< species
|
||||
<< " + EGG_MOVES_SPECIES_OFFSET,\n";
|
||||
|
||||
const rapidjson::Value &eggMoves = learnsets["egg_moves"];
|
||||
for (const auto &entry : eggMoves.GetArray()) {
|
||||
ofs << " "
|
||||
<< entry.GetString()
|
||||
<< ",\n";
|
||||
}
|
||||
|
||||
ofs << "\n";
|
||||
}
|
||||
|
||||
static std::string FormPathToName(std::string path)
|
||||
{
|
||||
path = std::regex_replace(path, std::regex("/FORMS/"), "_");
|
||||
return path;
|
||||
}
|
||||
|
||||
static void EmitIconEnum(std::ofstream &ofs, std::string species, std::string form)
|
||||
{
|
||||
std::transform(species.begin(), species.end(), species.begin(), ::toupper);
|
||||
std::transform(form.begin(), form.end(), form.begin(), ::toupper);
|
||||
ofs << " ICON_"
|
||||
<< species
|
||||
<< "_"
|
||||
<< form
|
||||
<< ",\n";
|
||||
}
|
||||
|
||||
static void EmitIconPaletteData(rapidjson::Document &root, std::ofstream &ofs, std::string species, u16 personalValue, std::map<std::string, std::vector<std::string>> iconRegistry)
|
||||
{
|
||||
const rapidjson::Value &iconPallete = root["icon_palette"];
|
||||
|
||||
std::string speciesUpper = species;
|
||||
std::transform(speciesUpper.begin(), speciesUpper.end(), speciesUpper.begin(), ::toupper);
|
||||
|
||||
int iconIdx;
|
||||
if (iconPallete.IsInt()) {
|
||||
iconIdx = iconPallete.GetInt();
|
||||
} else {
|
||||
iconIdx = iconPallete["base"].GetInt();
|
||||
|
||||
for (auto &form : iconRegistry.at(species)) {
|
||||
const rapidjson::Value &formIcon = iconPallete[(char *)form.c_str()];
|
||||
std::transform(form.begin(), form.end(), form.begin(), ::toupper);
|
||||
ofs << " [ICON_"
|
||||
<< speciesUpper
|
||||
<< "_"
|
||||
<< form
|
||||
<< "] = "
|
||||
<< formIcon.GetInt()
|
||||
<< ",\n";
|
||||
}
|
||||
}
|
||||
|
||||
ofs << " [";
|
||||
|
||||
if (personalValue == SPECIES_BAD_EGG) {
|
||||
ofs << "ICON_MANAPHY_EGG";
|
||||
} else {
|
||||
if (personalValue < SPECIES_EGG) {
|
||||
ofs << "SPECIES_"
|
||||
<< speciesUpper;
|
||||
} else {
|
||||
ofs << "ICON_"
|
||||
<< FormPathToName(speciesUpper);
|
||||
}
|
||||
}
|
||||
|
||||
ofs << "] = "
|
||||
<< iconIdx
|
||||
<< ",\n";
|
||||
}
|
||||
|
||||
static void PackHeights(NarcBuilder &builder, rapidjson::Document &root, u8 genderRatio)
|
||||
{
|
||||
const rapidjson::Value &backOffsets = root["back"]["y_offset"];
|
||||
const rapidjson::Value &frontOffsets = root["front"]["y_offset"];
|
||||
|
||||
std::byte backFemale, backMale, frontFemale, frontMale;
|
||||
u32 femaleSize = 1, maleSize = 1;
|
||||
|
||||
if (genderRatio == GENDER_RATIO_FEMALE_ONLY) {
|
||||
maleSize = 0;
|
||||
} else {
|
||||
backMale = static_cast<std::byte>(backOffsets["male"].GetUint());
|
||||
frontMale = static_cast<std::byte>(frontOffsets["male"].GetUint());
|
||||
}
|
||||
|
||||
if (genderRatio == GENDER_RATIO_MALE_ONLY || genderRatio == GENDER_RATIO_NO_GENDER) {
|
||||
femaleSize = 0;
|
||||
} else {
|
||||
backFemale = static_cast<std::byte>(backOffsets["female"].GetUint());
|
||||
frontFemale = static_cast<std::byte>(frontOffsets["female"].GetUint());
|
||||
}
|
||||
|
||||
builder.append(&backFemale, femaleSize);
|
||||
builder.append(&backMale, maleSize);
|
||||
builder.append(&frontFemale, femaleSize);
|
||||
builder.append(&frontMale, maleSize);
|
||||
}
|
||||
|
||||
static SpriteAnimFrame ParseSpriteAnimationFrame(const rapidjson::Value &frame)
|
||||
{
|
||||
SpriteAnimFrame data = { 0 };
|
||||
data.spriteFrame = frame["sprite_frame"].GetInt();
|
||||
data.frameDelay = frame["frame_delay"].GetUint();
|
||||
data.xOffset = frame["x_shift"].GetInt();
|
||||
data.yOffset = frame["y_shift"].GetInt();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static SpeciesSpriteAnim ParseSpeciesSpriteAnim(const rapidjson::Value &face)
|
||||
{
|
||||
SpeciesSpriteAnim data = { 0 };
|
||||
data.animation = face["animation"].GetUint();
|
||||
data.cryDelay = face["cry_delay"].GetUint();
|
||||
data.startDelay = face["start_delay"].GetUint();
|
||||
|
||||
int i = 0;
|
||||
for (auto &frame : face["frames"].GetArray()) {
|
||||
data.frames[i++] = ParseSpriteAnimationFrame(frame);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void TryEmitFootprint(const rapidjson::Document &root, std::string species, std::ofstream &ofs_size, std::ofstream &ofs_type)
|
||||
{
|
||||
if (!root.HasMember("footprint")) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::transform(species.begin(), species.end(), species.begin(), ::toupper);
|
||||
|
||||
const rapidjson::Value &footprint = root["footprint"];
|
||||
BOOL hasFootprintType = footprint["has"].GetBool();
|
||||
if (footprint.HasMember("has_type")) { // this is just for Spiritomb
|
||||
hasFootprintType = footprint["has_type"].GetBool();
|
||||
}
|
||||
|
||||
ofs_size << " { "
|
||||
<< (footprint["has"].GetBool() ? "TRUE, " : "FALSE, ")
|
||||
<< footprint["size"].GetString() << ", },\n";
|
||||
ofs_type << " [SPECIES_"
|
||||
<< species
|
||||
<< "] = { "
|
||||
<< footprint["type"].GetString()
|
||||
<< (hasFootprintType ? ", TRUE" : ", FALSE")
|
||||
<< " },\n";
|
||||
}
|
||||
|
||||
static SpeciesSpriteData ParseSpeciesSpriteData(const rapidjson::Document &root)
|
||||
{
|
||||
SpeciesSpriteData data = { 0 };
|
||||
|
||||
const rapidjson::Value &front = root["front"];
|
||||
const rapidjson::Value &back = root["back"];
|
||||
const rapidjson::Value &shadow = root["shadow"];
|
||||
|
||||
data.faceAnims[0] = ParseSpeciesSpriteAnim(front);
|
||||
data.faceAnims[1] = ParseSpeciesSpriteAnim(back);
|
||||
data.yOffset = front["addl_y_offset"].GetInt();
|
||||
data.xOffsetShadow = shadow["x_offset"].GetInt();
|
||||
data.shadowSize = LookupConst(shadow["size"].GetString(), ShadowSize);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
Usage(std::cout);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
fs::path outputRoot = argv[1];
|
||||
fs::path dataRoot = argv[2];
|
||||
fs::path formsRegistryFname = argv[3];
|
||||
fs::path tutorSchemaFname = argv[4];
|
||||
|
||||
// Determine what moves are tutorable and output the corresponding C header.
|
||||
std::vector<Move> tutorableMoves = EmitTutorableMoves(tutorSchemaFname, outputRoot / "tutorable_moves.h");
|
||||
|
||||
// Bootstrap the by-tutor learnsets header.
|
||||
std::ofstream byTutorMovesets(outputRoot / "species_learnsets_by_tutor.h");
|
||||
byTutorMovesets << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H\n"
|
||||
<< "\n"
|
||||
<< "#include \"tutor_movesets.h\"\n"
|
||||
<< "\n"
|
||||
<< "static const MovesetMask sSpeciesLearnsetsByTutor[MOVESET_MAX] = {\n";
|
||||
byTutorMovesets << std::hex << std::setiosflags(std::ios::uppercase); // render all numeric inputs to the stream as hexadecimal
|
||||
|
||||
// Bootstrap the egg moves header.
|
||||
std::ofstream eggMoves(outputRoot / "species_egg_moves.h");
|
||||
eggMoves << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H\n"
|
||||
<< "\n"
|
||||
<< "#include \"constants/species.h\"\n"
|
||||
<< "#include \"generated/moves.h\"\n"
|
||||
<< "\n"
|
||||
<< "#define EGG_MOVES_SPECIES_OFFSET 20000\n"
|
||||
<< "#define EGG_MOVES_TERMINATOR 0xFFFF\n"
|
||||
<< "\n"
|
||||
<< "static const u16 sEggMoves[] = {\n";
|
||||
|
||||
// Bootstrap the footprint sizes header.
|
||||
std::ofstream footprint_sizes(outputRoot / "species_footprint_sizes.h");
|
||||
footprint_sizes << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H\n"
|
||||
<< "\n"
|
||||
<< "#include \"constants/species.h\"\n"
|
||||
<< "#include \"generated/footprint_sizes.h\"\n"
|
||||
<< "\n"
|
||||
<< "#include \"overlay113/footprint_data.h\"\n"
|
||||
<< "\n"
|
||||
<< "static const FootprintData sSpeciesFootprints[NATIONAL_DEX_COUNT + 1] = {\n";
|
||||
|
||||
// Bootstrap the footprint types header.
|
||||
std::ofstream footprint_types(outputRoot / "species_footprint_types.h");
|
||||
footprint_types << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H\n"
|
||||
<< "\n"
|
||||
<< "#include \"constants/footstep_house.h\"\n"
|
||||
<< "#include \"constants/species.h\"\n"
|
||||
<< "\n"
|
||||
<< "typedef struct FootprintType {\n"
|
||||
<< " u16 type;\n"
|
||||
<< " u16 hasPrint;\n"
|
||||
<< "} FootprintType;\n"
|
||||
<< "\n"
|
||||
<< "static const FootprintType sFootprintTypes[NATIONAL_DEX_COUNT + 1] = {\n";
|
||||
|
||||
// Bootstrap the icon palette offset header.
|
||||
std::ofstream iconPalettes(outputRoot / "species_icon_palettes.h");
|
||||
iconPalettes << sHeaderMessage << "\n"
|
||||
<< "#ifndef POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H\n"
|
||||
<< "#define POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H\n"
|
||||
<< "\n"
|
||||
<< "#include \"constants/species.h\"\n"
|
||||
<< "\n"
|
||||
<< "enum FormIconIndex {\n"
|
||||
<< " ICON_EGG = SPECIES_EGG,\n"
|
||||
<< " ICON_MANAPHY_EGG,\n";
|
||||
|
||||
// Tutorable learnsets are stored as an array of bitmasks; each bit in the mask
|
||||
// denotes if a tutorable move can be learned by a given species.
|
||||
std::size_t tutorableLearnsetSize = (tutorableMoves.size() + 7) / 8;
|
||||
|
||||
// Prepare loop contents.
|
||||
std::vector<std::string> speciesRegistry = ReadRegistryEnvVar("SPECIES");
|
||||
std::map<std::string, std::vector<std::string>> iconRegistry;
|
||||
// read form data
|
||||
std::string formsRegistryJson = ReadWholeFile(formsRegistryFname);
|
||||
rapidjson::Document formRegDoc;
|
||||
rapidjson::ParseResult formOk = formRegDoc.Parse(formsRegistryJson.c_str(), formsRegistryJson.length());
|
||||
if (!formOk) {
|
||||
ReportJsonError(formOk, formsRegistryJson, formsRegistryFname);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
for (auto &formRegSpecies : formRegDoc.GetObject()) {
|
||||
std::string speciesName = formRegSpecies.name.GetString();
|
||||
std::vector<std::string> speciesIcons;
|
||||
|
||||
if (formRegSpecies.value.HasMember("__dupe_base_icon")) {
|
||||
EmitIconEnum(iconPalettes, speciesName, "base");
|
||||
speciesIcons.push_back("base");
|
||||
}
|
||||
|
||||
for (auto &form : formRegSpecies.value.GetObject()) {
|
||||
std::string formName = form.name.GetString();
|
||||
if (formName[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
std::string formType = form.value.GetString();
|
||||
if (formType.compare("data") == 0) {
|
||||
EmitIconEnum(iconPalettes, speciesName, formName);
|
||||
|
||||
formName = formRegSpecies.name.GetString();
|
||||
formName.append("/forms/");
|
||||
formName.append(form.name.GetString());
|
||||
speciesRegistry.push_back(formName);
|
||||
}
|
||||
if (formType.compare("icon") == 0) {
|
||||
EmitIconEnum(iconPalettes, speciesName, formName);
|
||||
|
||||
speciesIcons.push_back(formName);
|
||||
}
|
||||
}
|
||||
|
||||
if (speciesIcons.size() > 0) {
|
||||
iconRegistry.insert({ speciesName, speciesIcons });
|
||||
}
|
||||
}
|
||||
iconPalettes << "};\n"
|
||||
<< "\n"
|
||||
<< "/**\n"
|
||||
<< " * @brief This table defines which index of the shared palette file is used\n"
|
||||
<< " * for the icons used by Pokemon in PC boxes, the party list, etc. Alternate\n"
|
||||
<< " * forms are listed after the full National Dex using a custom ordering.\n"
|
||||
<< " */\n"
|
||||
<< "static const u8 sPokemonIconPaletteIndex[] = {\n";
|
||||
|
||||
// Prepare VFSes for each NARC to be output.
|
||||
NarcBuilder personal { speciesRegistry.size() };
|
||||
NarcBuilder evo { speciesRegistry.size() };
|
||||
NarcBuilder wotbl { speciesRegistry.size() };
|
||||
NarcBuilder height { 4 * SPECIES_EGG }; // NOTE: using SPECIES_EGG as an effective NatDex number
|
||||
std::vector<SpeciesPalPark> palParkData;
|
||||
std::vector<u16> offspringData;
|
||||
std::vector<SpeciesSpriteData> speciesSpriteData;
|
||||
|
||||
u16 personalValue = 0;
|
||||
rapidjson::Document doc;
|
||||
for (auto &species : speciesRegistry) {
|
||||
fs::path speciesDataPath = dataRoot / species / "data.json";
|
||||
std::string json = ReadWholeFile(speciesDataPath);
|
||||
rapidjson::ParseResult ok = doc.Parse(json.c_str(), json.length());
|
||||
if (!ok) {
|
||||
ReportJsonError(ok, json, speciesDataPath);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
try {
|
||||
SpeciesData data = ParseSpeciesData(doc);
|
||||
SpeciesEvolutionList evos = ParseEvolutions(doc);
|
||||
SpeciesLearnsetWithSize sizedLearnset = ParseLevelUpLearnset(doc);
|
||||
std::optional<SpeciesPalPark> palPark = TryParsePalPark(doc);
|
||||
u16 offspring = TryParseOffspring(doc, personalValue);
|
||||
TryEmitTutorableLearnset(doc, byTutorMovesets, tutorableMoves, tutorableLearnsetSize);
|
||||
TryEmitEggMoves(doc, eggMoves, species);
|
||||
TryEmitFootprint(doc, species, footprint_sizes, footprint_types);
|
||||
EmitIconPaletteData(doc, iconPalettes, species, personalValue, iconRegistry);
|
||||
|
||||
personal.append(reinterpret_cast<std::byte *>(&data), sizeof(data));
|
||||
evo.append(reinterpret_cast<std::byte *>(&evos), sizeof(evos));
|
||||
wotbl.append(reinterpret_cast<std::byte *>(&sizedLearnset.learnset), sizedLearnset.size);
|
||||
|
||||
if (palPark.has_value()) {
|
||||
palParkData.emplace_back(palPark.value());
|
||||
}
|
||||
|
||||
offspringData.emplace_back(offspring);
|
||||
|
||||
// Mechanically-distinct forms do not have sprite_data.json files
|
||||
fs::path speciesSpriteDataPath = dataRoot / species / "sprite_data.json";
|
||||
std::ifstream spriteDataIFS(speciesSpriteDataPath, std::ios::in);
|
||||
if (spriteDataIFS.good()) {
|
||||
std::string spriteData = ReadWholeFile(spriteDataIFS);
|
||||
ok = doc.Parse(spriteData.c_str());
|
||||
if (!ok) {
|
||||
ReportJsonError(ok, json, speciesSpriteDataPath);
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
u8 genderRatio = species != "none" ? data.genderRatio : GENDER_RATIO_FEMALE_50; // treat SPECIES_NONE as if it has two genders.
|
||||
PackHeights(height, doc, genderRatio);
|
||||
|
||||
SpeciesSpriteData speciesSprite = ParseSpeciesSpriteData(doc);
|
||||
speciesSpriteData.emplace_back(speciesSprite);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
personalValue += 1;
|
||||
}
|
||||
|
||||
byTutorMovesets << "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H\n";
|
||||
byTutorMovesets.close();
|
||||
|
||||
eggMoves << " EGG_MOVES_TERMINATOR,\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H\n";
|
||||
eggMoves.close();
|
||||
|
||||
footprint_sizes << "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H\n";
|
||||
footprint_sizes.close();
|
||||
|
||||
footprint_types << "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H\n";
|
||||
footprint_types.close();
|
||||
|
||||
iconPalettes << "};\n"
|
||||
<< "\n"
|
||||
<< "#endif // POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H\n";
|
||||
iconPalettes.close();
|
||||
|
||||
personal.write(outputRoot / "pl_personal.narc");
|
||||
evo.write(outputRoot / "evo.narc");
|
||||
wotbl.write(outputRoot / "wotbl.narc");
|
||||
height.write(outputRoot / "height.narc");
|
||||
|
||||
NarcBuilder::write(palParkData, outputRoot / "ppark.narc");
|
||||
NarcBuilder::write(speciesSpriteData, outputRoot / "pl_poke_data.narc");
|
||||
PackOffspring(offspringData, outputRoot / "pms.narc");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -16,25 +16,6 @@ datagen_cpp_args = [
|
|||
'-O3',
|
||||
]
|
||||
|
||||
datagen_species_exe = executable(
|
||||
'datagen-species',
|
||||
sources: [
|
||||
files('datagen_species.cpp'),
|
||||
c_consts_generators,
|
||||
],
|
||||
cpp_args: datagen_cpp_args,
|
||||
implicit_include_directories: true,
|
||||
include_directories: [
|
||||
public_includes,
|
||||
toplevel_includes,
|
||||
],
|
||||
dependencies: [
|
||||
nitroarc_dep,
|
||||
rapidjson_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
datagen_trainer_exe = executable(
|
||||
'datagen-trainer',
|
||||
sources: [
|
||||
|
|
|
|||
15
tools/dataproc/data/species_egg_moves.h.template
Normal file
15
tools/dataproc/data/species_egg_moves.h.template
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H
|
||||
#define POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H
|
||||
|
||||
#include "constants/species.h"
|
||||
#include "generated/moves.h"
|
||||
|
||||
#define EGG_MOVES_SPECIES_OFFSET 20000
|
||||
#define EGG_MOVES_TERMINATOR 0xFFFF
|
||||
|
||||
static const u16 sEggMoves[] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
EGG_MOVES_TERMINATOR,
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_SPECIES_EGG_MOVES_H
|
||||
12
tools/dataproc/data/species_footprint_sizes.h.template
Normal file
12
tools/dataproc/data/species_footprint_sizes.h.template
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H
|
||||
#define POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H
|
||||
|
||||
#include "constants/species.h"
|
||||
#include "generated/footprint_sizes.h"
|
||||
#include "overlay113/footprint_data.h"
|
||||
|
||||
static const FootprintData sSpeciesFootprints[NATIONAL_DEX_COUNT + 1] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_SIZES_H
|
||||
16
tools/dataproc/data/species_footprint_types.h.template
Normal file
16
tools/dataproc/data/species_footprint_types.h.template
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H
|
||||
#define POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H
|
||||
|
||||
#include "constants/footstep_house.h"
|
||||
#include "constants/species.h"
|
||||
|
||||
typedef struct FootprintType {
|
||||
u16 type;
|
||||
u16 hasPrint;
|
||||
} FootprintType;
|
||||
|
||||
static const FootprintType sFootprintTypes[NATIONAL_DEX_COUNT + 1] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_SPECIES_FOOTPRINT_TYPES_H
|
||||
59
tools/dataproc/data/species_icon_palettes.h.template
Normal file
59
tools/dataproc/data/species_icon_palettes.h.template
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H
|
||||
#define POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H
|
||||
|
||||
#include "constants/species.h"
|
||||
|
||||
enum FormIconIndex {
|
||||
ICON_EGG = SPECIES_EGG,
|
||||
ICON_MANAPHY_EGG,
|
||||
ICON_DEOXYS_ATTACK,
|
||||
ICON_DEOXYS_DEFENSE,
|
||||
ICON_DEOXYS_SPEED,
|
||||
ICON_UNOWN_A,
|
||||
ICON_UNOWN_B,
|
||||
ICON_UNOWN_C,
|
||||
ICON_UNOWN_D,
|
||||
ICON_UNOWN_E,
|
||||
ICON_UNOWN_F,
|
||||
ICON_UNOWN_G,
|
||||
ICON_UNOWN_H,
|
||||
ICON_UNOWN_I,
|
||||
ICON_UNOWN_J,
|
||||
ICON_UNOWN_K,
|
||||
ICON_UNOWN_L,
|
||||
ICON_UNOWN_M,
|
||||
ICON_UNOWN_N,
|
||||
ICON_UNOWN_O,
|
||||
ICON_UNOWN_P,
|
||||
ICON_UNOWN_Q,
|
||||
ICON_UNOWN_R,
|
||||
ICON_UNOWN_S,
|
||||
ICON_UNOWN_T,
|
||||
ICON_UNOWN_U,
|
||||
ICON_UNOWN_V,
|
||||
ICON_UNOWN_W,
|
||||
ICON_UNOWN_X,
|
||||
ICON_UNOWN_Y,
|
||||
ICON_UNOWN_Z,
|
||||
ICON_UNOWN_EXC,
|
||||
ICON_UNOWN_QUE,
|
||||
ICON_BURMY_SANDY,
|
||||
ICON_BURMY_TRASH,
|
||||
ICON_WORMADAM_SANDY,
|
||||
ICON_WORMADAM_TRASH,
|
||||
ICON_SHELLOS_EAST_SEA,
|
||||
ICON_GASTRODON_EAST_SEA,
|
||||
ICON_GIRATINA_ORIGIN,
|
||||
ICON_SHAYMIN_SKY,
|
||||
ICON_ROTOM_HEAT,
|
||||
ICON_ROTOM_WASH,
|
||||
ICON_ROTOM_FROST,
|
||||
ICON_ROTOM_FAN,
|
||||
ICON_ROTOM_MOW,
|
||||
};
|
||||
|
||||
static const u8 sPokemonIconPaletteIndex[] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_SPECIES_ICON_PALETTES_H
|
||||
10
tools/dataproc/data/species_learnsets_by_tutor.h.template
Normal file
10
tools/dataproc/data/species_learnsets_by_tutor.h.template
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H
|
||||
#define POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H
|
||||
|
||||
#include "tutor_movesets.h"
|
||||
|
||||
static const MovesetMask sSpeciesLearnsetsByTutor[MOVESET_MAX] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_SPECIES_LEARNSETS_BY_TUTOR_H
|
||||
8
tools/dataproc/data/tutorable_moves.h.template
Normal file
8
tools/dataproc/data/tutorable_moves.h.template
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef POKEPLATINUM_GENERATED_TUTORABLE_MOVES
|
||||
#define POKEPLATINUM_GENERATED_TUTORABLE_MOVES
|
||||
|
||||
static const TeachableMove sTeachableMoves[] = {
|
||||
/* =========== MAGIC CONTENT MARKER =========== */
|
||||
};
|
||||
|
||||
#endif // POKEPLATINUM_GENERATED_TUTORABLE_MOVES
|
||||
|
|
@ -24,3 +24,36 @@ dataproc_dep = declare_dependency(
|
|||
native: true,
|
||||
),
|
||||
)
|
||||
|
||||
repo_include = meson.global_source_root() / 'include'
|
||||
repo_build = meson.global_build_root()
|
||||
dataproc_templates_dir = meson.current_source_dir() / 'data'
|
||||
|
||||
commonproc_dep = declare_dependency(
|
||||
link_with: static_library(
|
||||
'commonproc',
|
||||
sources: files('src/common.c', 'src/enum.c'),
|
||||
|
||||
c_args: [
|
||||
dataproc_cflags,
|
||||
f'-DREPO_INCLUDE="@repo_include@"',
|
||||
f'-DREPO_BUILD="@repo_build@"',
|
||||
f'-DTEMPLATES_DIR="@dataproc_templates_dir@"',
|
||||
],
|
||||
|
||||
dependencies: [ dataproc_dep, nitroarc_dep ],
|
||||
native: true,
|
||||
),
|
||||
dependencies: [ dataproc_dep, nitroarc_dep ],
|
||||
)
|
||||
|
||||
speciesproc_exe = executable(
|
||||
'speciesproc',
|
||||
sources: [ files('src/speciesproc.c'), c_consts_generators ],
|
||||
|
||||
c_args: dataproc_cflags,
|
||||
|
||||
include_directories: [ public_includes, toplevel_includes ],
|
||||
dependencies: commonproc_dep,
|
||||
native: true,
|
||||
)
|
||||
|
|
|
|||
413
tools/dataproc/src/common.c
Normal file
413
tools/dataproc/src/common.c
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dataproc.h"
|
||||
#include "enum.h"
|
||||
#include "nitroarc.h"
|
||||
|
||||
#define MAX_LOADED_ENUMS 128
|
||||
|
||||
static enum_t loaded_enums[MAX_LOADED_ENUMS] = { 0 };
|
||||
static size_t num_loaded_enums = 0;
|
||||
|
||||
static void unload_enums(void);
|
||||
static void finish_headers(void);
|
||||
static FILE* open_depfile(const char *depfile_path);
|
||||
static void load_header_template(header_template_t *h, FILE *depfile);
|
||||
static enum_t dp_include(
|
||||
const char *from_file,
|
||||
const char *with_prefix,
|
||||
const char *for_type,
|
||||
bool from_defs,
|
||||
FILE *depfile
|
||||
);
|
||||
|
||||
static archive_template_t *s_archives = NULL;
|
||||
static header_template_t *s_headers = NULL;
|
||||
static const char *s_output_dir = NULL;
|
||||
|
||||
static void* crt_malloc(void *ctx, unsigned items, unsigned size) {
|
||||
(void)ctx;
|
||||
return malloc(items * size);
|
||||
}
|
||||
|
||||
static void* crt_realloc(void *ctx, void *p, unsigned items, unsigned size) {
|
||||
(void)ctx;
|
||||
return realloc(p, items * size);
|
||||
}
|
||||
|
||||
static void crt_free(void *ctx, void *p, unsigned items, unsigned size) {
|
||||
(void)ctx;
|
||||
(void)items;
|
||||
(void)size;
|
||||
free(p);
|
||||
}
|
||||
|
||||
#define default_packer() (nitroarc_packer_t){ \
|
||||
.malloc = crt_malloc, \
|
||||
.realloc = crt_realloc, \
|
||||
.free = crt_free, \
|
||||
}
|
||||
|
||||
static const char *header_comment = ""
|
||||
"/*\n"
|
||||
" * This header was generated by %s\n"
|
||||
" * DO NOT MODIFY IT!!!\n"
|
||||
" */\n";
|
||||
|
||||
static FILE* open_depfile(const char *depfile_path) {
|
||||
FILE *depfile = fopen(depfile_path, "wb");
|
||||
if (depfile == NULL) {
|
||||
fprintf(stderr, "error opening depfile '%s': %s\n",
|
||||
depfile_path, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return depfile;
|
||||
}
|
||||
|
||||
void common_init(
|
||||
enum format format,
|
||||
enum_template_t *lookups,
|
||||
archive_template_t *archives,
|
||||
header_template_t *headers,
|
||||
const char *source_name,
|
||||
const char *depfile_path,
|
||||
const char *output_dir,
|
||||
void (*pre_init_hook)(void),
|
||||
void (*post_init_hook)(void)
|
||||
) {
|
||||
dp_init(format);
|
||||
if (pre_init_hook) pre_init_hook();
|
||||
|
||||
s_archives = archives;
|
||||
s_headers = headers;
|
||||
s_output_dir = output_dir;
|
||||
atexit(unload_enums);
|
||||
atexit(finish_headers);
|
||||
|
||||
FILE *depfile = open_depfile(depfile_path);
|
||||
|
||||
// Initialize all the requested iteratively-packed archives
|
||||
for (archive_template_t *to_init = archives; to_init && to_init->out_filename; to_init++) {
|
||||
to_init->packer = default_packer();
|
||||
int errc = nitroarc_pinit(
|
||||
&to_init->packer,
|
||||
to_init->num_files,
|
||||
to_init->named,
|
||||
to_init->stripped
|
||||
);
|
||||
|
||||
if (errc) {
|
||||
fprintf(stderr, "nitroarc initialization error: %s\n",
|
||||
nitroarc_errs(errc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *full_path = pathjoin(output_dir, NULL, to_init->out_filename);
|
||||
fputs(full_path, depfile);
|
||||
fputc(' ', depfile);
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
// Prepare iteratively-written headers
|
||||
for (header_template_t *to_init = headers; to_init && to_init->out_filename; to_init++) {
|
||||
char *full_path = pathjoin(output_dir, NULL, to_init->out_filename);
|
||||
to_init->out_file = fopen(full_path, "wb");
|
||||
if (to_init->out_file == NULL) {
|
||||
fprintf(stderr, "could not open output file '%s': %s",
|
||||
full_path, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fprintf(to_init->out_file, header_comment, source_name);
|
||||
|
||||
fputs(full_path, depfile);
|
||||
fputc(' ', depfile);
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
fputs(": ", depfile);
|
||||
|
||||
// Load all the requested lookup-tables from their sources
|
||||
for (enum_template_t *to_load = lookups; to_load && to_load->from_file; to_load++) {
|
||||
loaded_enums[num_loaded_enums++] = dp_include(
|
||||
to_load->from_file,
|
||||
to_load->with_prefix,
|
||||
to_load->for_type,
|
||||
to_load->from_defs,
|
||||
depfile
|
||||
);
|
||||
}
|
||||
|
||||
// Second pass: load a header template as a dependency
|
||||
for (header_template_t *to_init = headers; to_init && to_init->out_filename; to_init++) {
|
||||
load_header_template(to_init, depfile);
|
||||
fputs(to_init->header, to_init->out_file);
|
||||
}
|
||||
|
||||
if (post_init_hook) post_init_hook();
|
||||
fclose(depfile);
|
||||
}
|
||||
|
||||
#define HEADER_TEMPLATE_SUFFIX ".template"
|
||||
#define HEADER_TEMPLATE_MAGIC "/* =========== MAGIC CONTENT MARKER =========== */"
|
||||
|
||||
static void load_header_template(header_template_t *h, FILE *depfile) {
|
||||
size_t len_out_fname = strlen(h->out_filename);
|
||||
char *template_fname = calloc(len_out_fname + sizeof(HEADER_TEMPLATE_SUFFIX) + 1, 1);
|
||||
assert(template_fname);
|
||||
|
||||
if (template_fname == NULL) exit(EXIT_FAILURE);
|
||||
memcpy(template_fname, h->out_filename, len_out_fname);
|
||||
memcpy(template_fname + len_out_fname, HEADER_TEMPLATE_SUFFIX, sizeof(HEADER_TEMPLATE_SUFFIX));
|
||||
|
||||
char *full_path = pathjoin(TEMPLATES_DIR, NULL, template_fname);
|
||||
char *template = fload(full_path);
|
||||
char *marker = strstr(template, HEADER_TEMPLATE_MAGIC);
|
||||
char *footer = marker + sizeof(HEADER_TEMPLATE_MAGIC);
|
||||
*marker = '\0';
|
||||
|
||||
h->header = template;
|
||||
h->footer = footer;
|
||||
|
||||
fputs(full_path, depfile);
|
||||
fputc(' ', depfile);
|
||||
|
||||
free(full_path);
|
||||
free(template_fname);
|
||||
}
|
||||
|
||||
static void unload_enums(void) {
|
||||
for (size_t i = 0; i < num_loaded_enums; i++) enum_free(&loaded_enums[i]);
|
||||
}
|
||||
|
||||
static void finish_headers(void) {
|
||||
for (header_template_t *h = s_headers; h && h->out_filename; h++) {
|
||||
if (h->out_file) {
|
||||
fputs(h->footer, h->out_file);
|
||||
fclose(h->out_file);
|
||||
free(h->header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int common_done(int errc, int (*addl_done_hook)(void)) {
|
||||
for (archive_template_t *a = s_archives; a && a->out_filename; a++) {
|
||||
if (fdump_narc(&a->packer, a->out_filename, errc == 0)) errc = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (addl_done_hook) errc = addl_done_hook() || errc;
|
||||
return errc;
|
||||
}
|
||||
|
||||
char* strremove(char *s, const char *sub) {
|
||||
size_t len = strlen(sub);
|
||||
if (len == 0) return s;
|
||||
|
||||
char *p = s;
|
||||
while ((p = strstr(p, sub)) != NULL) {
|
||||
memmove(p, p + len, strlen(p + len) + 1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
char* strreplace(char *s, char r, char c) {
|
||||
for (char *p = s; *p; p++) {
|
||||
if (*p == r) *p = c;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
char* strupper(const char *s) {
|
||||
char *capped = calloc(strlen(s) + 1, 1);
|
||||
for (size_t i = 0; i < strlen(s); i++) {
|
||||
capped[i] = s[i];
|
||||
if (capped[i] >= 'a' && capped[i] <= 'z') capped[i] -= ('a' - 'A');
|
||||
}
|
||||
|
||||
return capped;
|
||||
}
|
||||
|
||||
void splitenv(const char *name, char ***target, size_t *target_len, const char **extra, size_t extra_len) {
|
||||
char *envvar = getenv(name);
|
||||
if (envvar == NULL) {
|
||||
fprintf(stderr, "environment variable %s is undefined\n", name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*target_len = 1;
|
||||
for (char *p = envvar; *p; p++) {
|
||||
if (*p == ';') (*target_len)++;
|
||||
}
|
||||
|
||||
char *envcopy = malloc(strlen(envvar) + 1);
|
||||
memcpy(envcopy, envvar, strlen(envvar) + 1);
|
||||
|
||||
*target = calloc(*target_len + extra_len, sizeof(char*));
|
||||
char *p = envcopy;
|
||||
for (size_t i = 0; i < *target_len; i++) {
|
||||
(*target)[i] = p;
|
||||
|
||||
while (*p != ';' && *p != 0) p++;
|
||||
*p = 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (extra) {
|
||||
for (size_t i = 0; i < extra_len; i++) {
|
||||
(*target)[*target_len + i] = (char *)extra[i];
|
||||
}
|
||||
|
||||
*target_len += extra_len;
|
||||
}
|
||||
|
||||
if (*target_len > UINT16_MAX) {
|
||||
fprintf(stderr, "too many values defined; max: %u, got: %zu\n", UINT16_MAX, *target_len);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
char* fload(const char *filename) {
|
||||
char *buf = NULL;
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "could not open file '%s': %s\n", filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (fsize < 0) {
|
||||
fprintf(stderr, "could not open file '%s': %s\n", filename, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((buf = malloc(fsize + 1)) == NULL) {
|
||||
fprintf(stderr, "allocation failure for file '%s': %s", filename, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fread(buf, 1, fsize, f);
|
||||
buf[fsize] = 0;
|
||||
|
||||
cleanup:
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char* pathjoin(const char *basedir, const char *subdir, const char *file) {
|
||||
size_t size = strlen(basedir) + 1 + strlen(file) + 1 + (subdir ? strlen(subdir) + 1 : 0);
|
||||
char *path = malloc(size);
|
||||
if (subdir) snprintf(path, size, "%s/%s/%s", basedir, subdir, file);
|
||||
else snprintf(path, size, "%s/%s", basedir, file);
|
||||
return path;
|
||||
}
|
||||
|
||||
char* guardify(const char *path) {
|
||||
char *guarded = strupper(path);
|
||||
for (size_t i = 0; i < strlen(guarded); i++) {
|
||||
if (guarded[i] >= '0' && guarded[i] <= '9') continue;
|
||||
if (guarded[i] >= 'A' && guarded[i] <= 'Z') continue;
|
||||
guarded[i] = '_';
|
||||
}
|
||||
|
||||
return guarded;
|
||||
}
|
||||
|
||||
int fdump_blob(const void *data, size_t size, const char *dest) {
|
||||
char *full_path = pathjoin(s_output_dir, NULL, dest);
|
||||
FILE *outf = fopen(full_path, "wb");
|
||||
if (!outf) {
|
||||
fprintf(stderr, "error opening '%s': %s\n", full_path, strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
long written = fwrite(data, 1, size, outf);
|
||||
if (written != (long)size) {
|
||||
fprintf(stderr, "incomplete write to '%s': %s\n", full_path, strerror(errno));
|
||||
fclose(outf);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fclose(outf);
|
||||
free(full_path);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int fdump_narc(nitroarc_packer_t *p, const char *dest, bool ok) {
|
||||
char *data = NULL;
|
||||
u32 size = 0;
|
||||
|
||||
int errc = nitroarc_pseal(p, (void **)&data, &size);
|
||||
if (errc) {
|
||||
fprintf(stderr, "error sealing archive '%s': %s\n", dest, nitroarc_errs(errc));
|
||||
return errc;
|
||||
}
|
||||
|
||||
if (ok) errc = fdump_blob(data, size, dest);
|
||||
|
||||
free(data);
|
||||
return errc;
|
||||
}
|
||||
|
||||
int fdump_blobnarc(const void *data, u32 size, const char *name) {
|
||||
nitroarc_packer_t p = default_packer();
|
||||
nitroarc_pinit(&p, 1, false, false);
|
||||
nitroarc_ppack(&p, (void *)data, size, NULL);
|
||||
return fdump_narc(&p, name, true);
|
||||
}
|
||||
|
||||
#define MAX_INCLUDES 16
|
||||
|
||||
static const char *include_paths[MAX_INCLUDES] = {
|
||||
REPO_INCLUDE,
|
||||
REPO_BUILD,
|
||||
};
|
||||
|
||||
static enum_t dp_include(
|
||||
const char *from_file,
|
||||
const char *with_prefix,
|
||||
const char *for_type,
|
||||
bool from_defs,
|
||||
FILE *depfile
|
||||
) {
|
||||
assert(from_file && "included filename must not be NULL");
|
||||
|
||||
char *found_file = NULL;
|
||||
for (int i = 0; i < MAX_INCLUDES && include_paths[i]; i++) {
|
||||
char *full_path = pathjoin(include_paths[i], NULL, from_file);
|
||||
if (access(full_path, F_OK) == 0) { found_file = full_path; break; }
|
||||
else free(full_path);
|
||||
}
|
||||
|
||||
if (!found_file) {
|
||||
fprintf(stderr, "could not find included file '%s'\n", from_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *buf = fload(found_file);
|
||||
enum_t result = from_defs
|
||||
? enum_parse_def(buf, with_prefix, ENUM_F_SORT | ENUM_F_CONVERT)
|
||||
: enum_parse_one(buf, ENUM_F_SORT | ENUM_F_CONVERT, NULL);
|
||||
|
||||
dp_register((lookup_t *)result.syms, result.len, for_type);
|
||||
fputs(found_file, depfile);
|
||||
fputc(' ', depfile);
|
||||
|
||||
free(buf);
|
||||
free(found_file);
|
||||
return result;
|
||||
}
|
||||
122
tools/dataproc/src/common.h
Normal file
122
tools/dataproc/src/common.h
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef DATAPROC_COMMON_H
|
||||
#define DATAPROC_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dataproc.h"
|
||||
#include "nitroarc.h"
|
||||
|
||||
#define countof(_a) (sizeof(_a)/sizeof(*(_a)))
|
||||
|
||||
#define POKEPLATINUM_GENERATED_ENUM
|
||||
#define POKEPLATINUM_GENERATED_LOOKUP
|
||||
#define POKEPLATINUM_GENERATED_LOOKUP_IMPL
|
||||
|
||||
#define ALIGN_4 __attribute__((aligned(4)))
|
||||
|
||||
#define dp_regmetang(type) dp_register((lookup_t *)lookup__##type, lengthof__##type, #type)
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
|
||||
#define BOOL bool
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
|
||||
#define maxbit(bits) ((1 << bits) - 1)
|
||||
#define boolean(path) (dp_bool(dp_get(df, path)))
|
||||
#define u8(path) (dp_u8(dp_get(df, path)))
|
||||
#define s8(path) (dp_s8(dp_get(df, path)))
|
||||
#define u8_maxbits(path, bits) (u8)(dp_u8range(dp_get(df, path), 0, maxbit(bits)) & maxbit(bits))
|
||||
#define enum_u8(path, type) (dp_u8(dp_lookup(dp_get(df, path), #type)))
|
||||
#define enum_u16(path, type) (dp_u16(dp_lookup(dp_get(df, path), #type)))
|
||||
#define string(path) (dp_string(dp_get(df, path)))
|
||||
|
||||
// Template-struct for an enum-based lookup-table to be used for type-checking
|
||||
// string identifiers. Provide the base filename and the type-name that should
|
||||
// be used for reporting errors. Optionally, provide a prefix to filter the
|
||||
// values that are loaded from the input file.
|
||||
//
|
||||
// When `from_defs` is set to `true`, the lookup-table will be generated from
|
||||
// `#define`d constants rather than `enum` members.
|
||||
typedef struct enum_template enum_template_t;
|
||||
struct enum_template {
|
||||
const char *from_file;
|
||||
const char *with_prefix;
|
||||
const char *for_type;
|
||||
|
||||
bool from_defs;
|
||||
};
|
||||
|
||||
// Template-struct for an archive to be written. Specify the output filename
|
||||
// and the expected number of files, as well as if you want a named or stripped
|
||||
// archive.
|
||||
typedef struct archive_template archive_template_t;
|
||||
struct archive_template {
|
||||
nitroarc_packer_t packer;
|
||||
|
||||
const char *out_filename;
|
||||
uint16_t num_files;
|
||||
unsigned named;
|
||||
unsigned stripped;
|
||||
};
|
||||
|
||||
// Template-struct for a header file to be written. Specify the output filename
|
||||
// and an optional header and footer for the content.
|
||||
typedef struct header_template header_template_t;
|
||||
struct header_template {
|
||||
const char *out_filename;
|
||||
FILE *out_file;
|
||||
char *header;
|
||||
char *footer;
|
||||
};
|
||||
|
||||
// Common initialization routine. Instantiate requested lookup-tables and
|
||||
// prepare requested outputs. Output header-files will also search the data
|
||||
// directory for a file with ".template" suffixed to the output's basename.
|
||||
//
|
||||
// `pre_init_hook`, when provided, will be called after the base library is
|
||||
// initialized, but before any requests are fulfilled.
|
||||
//
|
||||
// `post_init_hook`, when provided, will be called as the function exits, after
|
||||
// all requests have been fulfilled.
|
||||
void common_init(
|
||||
enum format format,
|
||||
enum_template_t *lookups,
|
||||
archive_template_t *archives,
|
||||
header_template_t *headers,
|
||||
const char *source_name,
|
||||
const char *depfile_name,
|
||||
const char *output_dir,
|
||||
void (*pre_init_hook)(void),
|
||||
void (*post_init_hook)(void)
|
||||
);
|
||||
|
||||
// Common completion routine. Write the footer-content for each output header,
|
||||
// seal the initialized archives, and dump everything to disk.
|
||||
//
|
||||
// `addl_done_hook`, when provided, will be called right before the routine
|
||||
// completes, and any failure-code returned by it will propagate into the return
|
||||
// for this function.
|
||||
int common_done(int errc, int (*addl_done_hook)(void));
|
||||
|
||||
char* strremove(char *s, const char *sub);
|
||||
char* strreplace(char *s, char r, char c);
|
||||
char* strupper(const char *s);
|
||||
|
||||
void splitenv(const char *name, char ***target, size_t *target_len, const char **extra, size_t extra_len);
|
||||
char* fload(const char *filename);
|
||||
char* pathjoin(const char *basedir, const char *subdir, const char *file);
|
||||
char* guardify(const char *path);
|
||||
|
||||
int fdump_blob(const void *data, size_t size, const char *dest); // write_blob
|
||||
int fdump_narc(nitroarc_packer_t *p, const char *dest, bool ok); // write_narc
|
||||
int fdump_blobnarc(const void *data, u32 size, const char *dest); // write_narc_onefile
|
||||
|
||||
#endif // DATAPROC_COMMON_H
|
||||
273
tools/dataproc/src/enum.c
Normal file
273
tools/dataproc/src/enum.c
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
#include "enum.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Duplicate a string onto the heap.
|
||||
static char* strdup_(const char *s) {
|
||||
size_t l = strlen(s);
|
||||
char *d = calloc(l + 1, sizeof(*d));
|
||||
memcpy(d, s, l);
|
||||
return d;
|
||||
}
|
||||
|
||||
// Find the first occurrence of `c` (or `\0`) within `s`.
|
||||
static char* strchrnul_(const char *s, int c) {
|
||||
while (s && *s && *s != c) s++;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
// Find the first occurrence of a character OTHER than `c` (or `\0`) within `s`.
|
||||
static char* strnchr(const char *s, int c) {
|
||||
while (s && *s && *s == c) s++;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
// Locates the first occurrence of `c` (or `\0`) within `*s` and replaces it
|
||||
// with `\0`. `*s` is then advanced to the succeeding character, and the
|
||||
// original value of `*s` is returned.
|
||||
//
|
||||
// If `*s` is NULL, then NULL is returned immediately.
|
||||
static char* strcsep(char **s, char c) {
|
||||
char *p = *s;
|
||||
|
||||
char *e = strchrnul_(p, c);
|
||||
if (*e) *e++ = 0; else e = 0;
|
||||
|
||||
*s = e;
|
||||
return p;
|
||||
}
|
||||
|
||||
// Locates the first occurrence of any character from `charset` within `*s` and
|
||||
// replaces it with `\0`. `*s` is then advanced to the succeeding character, and
|
||||
// the original value of `*s` is returned.
|
||||
//
|
||||
// If `*s` is NULL, then NULL is returned immediately.
|
||||
//
|
||||
// Generalization of `strcsep` for multiple-characters.
|
||||
static char* strssep(char **s, const char *charset) {
|
||||
char *p = *s;
|
||||
if (!p) return NULL;
|
||||
|
||||
char *e = p + strcspn(p, charset);
|
||||
if (*e) *e++ = 0; else e = 0;
|
||||
|
||||
*s = e;
|
||||
return p;
|
||||
}
|
||||
|
||||
#define INIT_CAP 256
|
||||
|
||||
static int push_symval(enum_t *table, const char *tok, const char *val, unsigned flags) {
|
||||
if (table->len + 1 >= table->cap) {
|
||||
size_t new_cap = table->cap * 3 / 2;
|
||||
symb_t *new_sym = realloc(table->syms, new_cap * sizeof(*table->syms));
|
||||
if (new_sym == NULL) return 1;
|
||||
|
||||
table->syms = new_sym;
|
||||
table->cap = new_cap;
|
||||
}
|
||||
|
||||
if (flags & ENUM_F_CONVERT) { // if val == NULL, get previous (syms[len-1]) and increment
|
||||
if (val == NULL) {
|
||||
const symb_t *prev_sym = &table->syms[table->len - 1];
|
||||
table->syms[table->len++] = (symb_t){
|
||||
.tok = (char *)tok,
|
||||
.val_int = prev_sym->val_int + 1,
|
||||
};
|
||||
}
|
||||
else {
|
||||
table->syms[table->len++] = (symb_t){
|
||||
.tok = (char *)tok,
|
||||
.val_int = strtol(val, NULL, 0),
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
table->syms[table->len++] = (symb_t){
|
||||
.tok = (char *)tok,
|
||||
.val_lit = (char *)val
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int compare_tok(const void *lhs, const void *rhs) {
|
||||
const symb_t *sym_lhs = lhs;
|
||||
const symb_t *sym_rhs = rhs;
|
||||
return strcmp(sym_lhs->tok, sym_rhs->tok);
|
||||
}
|
||||
|
||||
static int push_define(enum_t *table, char **s, unsigned flags) {
|
||||
char *sym = strcsep(s, ' ');
|
||||
char *val = strnchr(*s, ' ');
|
||||
|
||||
return (val && *val) ? push_symval(table, sym, val, flags) : 0;
|
||||
}
|
||||
|
||||
static void push_enum_member(enum_t *table, char **s, unsigned flags) {
|
||||
char *line = strnchr(strcsep(s, '\n'), ' ');
|
||||
char *sym = strssep(&line, " ,");
|
||||
char *equ = strnchr(line, ' ');
|
||||
char *val = equ && *equ == '=' ? strnchr(equ + 1, ' ') : NULL;
|
||||
char *end = strchrnul_(val, ',');
|
||||
|
||||
if (end) *end = 0;
|
||||
if (*sym) push_symval(table, sym, val, flags);
|
||||
}
|
||||
|
||||
enum_t enum_parse_def(const char *buf, const char *prefix, unsigned flags) {
|
||||
enum_t ret = {
|
||||
.name = prefix ? (char *)prefix : NULL,
|
||||
.pool = strdup_(buf),
|
||||
.syms = calloc(INIT_CAP, sizeof(*ret.syms)),
|
||||
.cnv = !!(flags & ENUM_F_CONVERT),
|
||||
.len = 0,
|
||||
.cap = INIT_CAP,
|
||||
};
|
||||
|
||||
char *s = ret.pool;
|
||||
size_t len = prefix ? strlen(prefix) : 0;
|
||||
|
||||
while (*s) {
|
||||
char *line = strcsep(&s, '\n');
|
||||
|
||||
if (strncmp(line, "#define ", 8) != 0) continue; else line += 8;
|
||||
if (prefix && strncmp(line, prefix, len) != 0) continue;
|
||||
if (push_define(&ret, &line, flags) != 0) break;
|
||||
}
|
||||
|
||||
if (flags & ENUM_F_SORT) qsort(ret.syms, ret.len, sizeof(*ret.syms), compare_tok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum_t enum_parse_one(const char *buf, unsigned flags, char **endptr) {
|
||||
enum_t ret = {
|
||||
.name = NULL,
|
||||
.pool = strdup_(buf),
|
||||
.syms = calloc(INIT_CAP, sizeof(*ret.syms)),
|
||||
.cnv = !!(flags & ENUM_F_CONVERT),
|
||||
.len = 0,
|
||||
.cap = INIT_CAP,
|
||||
};
|
||||
|
||||
char *s = ret.pool;
|
||||
while (*s) {
|
||||
char *line = strcsep(&s, '\n');
|
||||
|
||||
if (strncmp(line, "enum ", 5) != 0) continue; else line += 5;
|
||||
if (*line != '{') {
|
||||
ret.name = strssep(&line, " {");
|
||||
}
|
||||
|
||||
// NOTE: assumption: opening brace is on the same line, and members
|
||||
// are defined one-per-line
|
||||
|
||||
while (*s && strncmp(s, "};", 2) != 0) {
|
||||
push_enum_member(&ret, &s, flags);
|
||||
}
|
||||
|
||||
s += 2;
|
||||
break; // stop after the one `enum` is found
|
||||
}
|
||||
|
||||
if (flags & ENUM_F_SORT) qsort(ret.syms, ret.len, sizeof(*ret.syms), compare_tok);
|
||||
if (endptr) *endptr = (char *)buf + (s - ret.pool);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum_t* push_subtable(enums_t *tables, const char *name, unsigned flags) {
|
||||
if (tables->len + 1 >= tables->cap) {
|
||||
size_t new_cap = tables->cap * 3 / 2;
|
||||
enum_t *new_arr = realloc(tables->enums, new_cap * sizeof(*tables->enums));
|
||||
if (new_arr == NULL) return NULL;
|
||||
|
||||
tables->enums = new_arr;
|
||||
tables->cap = new_cap;
|
||||
}
|
||||
|
||||
enum_t *next = &tables->enums[tables->len++];
|
||||
next->name = (char *)name;
|
||||
next->pool = NULL;
|
||||
next->syms = calloc(INIT_CAP, sizeof(*next->syms));
|
||||
next->cnv = !!(flags & ENUM_F_CONVERT);
|
||||
next->len = 0;
|
||||
next->cap = INIT_CAP;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
static int compare_table(const void *lhs, const void *rhs) {
|
||||
const enum_t *table_lhs = lhs;
|
||||
const enum_t *table_rhs = rhs;
|
||||
return strcmp(table_lhs->name, table_rhs->name);
|
||||
}
|
||||
|
||||
enums_t enum_parse_all(const char *buf, unsigned flags) {
|
||||
enums_t ret = {
|
||||
.enums = calloc(INIT_CAP, sizeof(*ret.enums)),
|
||||
.pool = strdup_(buf),
|
||||
.len = 0,
|
||||
.cap = INIT_CAP,
|
||||
};
|
||||
|
||||
push_subtable(&ret, NULL, flags);
|
||||
|
||||
char *s = ret.pool;
|
||||
while (*s) {
|
||||
char *line = strcsep(&s, '\n');
|
||||
enum_t *sub = &ret.enums[0];
|
||||
|
||||
if (strncmp(line, "enum ", 5) == 0) {
|
||||
line += 5;
|
||||
if (*line != '{') {
|
||||
sub = push_subtable(&ret, strssep(&line, " {"), flags);
|
||||
if (sub == NULL) break;
|
||||
}
|
||||
|
||||
while (*s && strncmp(s, "};", 2) != 0) {
|
||||
push_enum_member(sub, &s, flags);
|
||||
}
|
||||
}
|
||||
else if (strncmp(line, "#define ", 8) == 0) {
|
||||
line += 8;
|
||||
push_define(sub, &line, flags);
|
||||
}
|
||||
else continue;
|
||||
}
|
||||
|
||||
if (flags & ENUM_F_SORT) {
|
||||
for (size_t i = 0; i < ret.len; i++) {
|
||||
qsort(ret.enums[i].syms,
|
||||
ret.enums[i].len,
|
||||
sizeof(*ret.enums[i].syms),
|
||||
compare_tok);
|
||||
}
|
||||
|
||||
qsort(ret.enums + 1, ret.len - 1, sizeof(*ret.enums), compare_table);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void enum_free(enum_t *table) {
|
||||
free(table->pool);
|
||||
free(table->syms);
|
||||
|
||||
table->name = NULL;
|
||||
table->pool = NULL;
|
||||
table->syms = NULL;
|
||||
}
|
||||
|
||||
void enum_free_all(enums_t *tables) {
|
||||
for (size_t i = 0; i < tables->len; i++) enum_free(&tables->enums[i]);
|
||||
|
||||
free(tables->enums);
|
||||
free(tables->pool);
|
||||
|
||||
tables->enums = NULL;
|
||||
tables->pool = NULL;
|
||||
}
|
||||
78
tools/dataproc/src/enum.h
Normal file
78
tools/dataproc/src/enum.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef ENUM_H
|
||||
#define ENUM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct symb_t symb_t;
|
||||
struct symb_t {
|
||||
union {
|
||||
char *val_lit;
|
||||
long val_int;
|
||||
};
|
||||
char *tok;
|
||||
};
|
||||
|
||||
typedef struct enum_t enum_t;
|
||||
struct enum_t {
|
||||
char *name;
|
||||
char *pool;
|
||||
symb_t *syms;
|
||||
bool cnv;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
};
|
||||
|
||||
typedef struct enums_t enums_t;
|
||||
struct enums_t {
|
||||
enum_t *enums;
|
||||
char *pool;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
};
|
||||
|
||||
#define ENUM_F_SORT (1 << 0)
|
||||
#define ENUM_F_CONVERT (1 << 1)
|
||||
|
||||
// Parse a C file `buf` for defined preprocesor tokens with replacement values
|
||||
// and return them as a symbol-table. If `prefix` is given as non-`NULL`, it
|
||||
// will be used to filter preprocessor tokens from `buf` that are included in
|
||||
// the output.
|
||||
//
|
||||
// If `flags` contains `ENUM_F_SORT`, then symbols in the output table will be
|
||||
// sorted lexicographically by their tokens.
|
||||
//
|
||||
// If `flags` contains `ENUM_F_CONVERT`, then numeric strings will be parsed
|
||||
// into integer values.
|
||||
enum_t enum_parse_def(const char *buf, const char *prefix, unsigned flags);
|
||||
|
||||
// Parse a C file `buf` for a named `enum` and return its member-names as a
|
||||
// symbol-table. If `e_name` is given as `NULL`, then this routine will return
|
||||
// an empty symbol-table; otherwise, its value is used to find a matching `enum`
|
||||
// from `buf` whose member-names shall be loaded into the output.
|
||||
//
|
||||
// If `flags` contains `ENUM_F_SORT`, then symbols in the output table will be
|
||||
// sorted lexicographically by their tokens.
|
||||
//
|
||||
// If `flags` contains `ENUM_F_CONVERT`, then numeric strings will be parsed
|
||||
// into integer values.
|
||||
//
|
||||
// If `endptr` is not `NULL`, then `*endptr` will be set to the next unprocessed
|
||||
// character in `buf` upon exit.
|
||||
enum_t enum_parse_one(const char *buf, unsigned flags, char **endptr);
|
||||
|
||||
// Parse a C file `buf` for both `enum`s and defined preprocessor tokens and
|
||||
// return them as a table of symbol-tables. All preprocessor tokens and members
|
||||
// of unnamed `enum`s will be present in the symbol-table at `enums[0]`; members
|
||||
// of named `enum`s will be present in their own individual symbol-tables.
|
||||
//
|
||||
// If `flags` contains `ENUM_F_SORT`, then symbols in the output tables will be
|
||||
// sorted lexicographically by their tokens, and all named output tables wiil be
|
||||
// sorted lexicographically by their names.
|
||||
enums_t enum_parse_all(const char *buf, unsigned flags);
|
||||
|
||||
// Free allocations in a symbol-table.
|
||||
void enum_free(enum_t *table);
|
||||
void enum_free_all(enums_t *tables);
|
||||
|
||||
#endif // ENUM_H
|
||||
746
tools/dataproc/src/speciesproc.c
Normal file
746
tools/dataproc/src/speciesproc.c
Normal file
|
|
@ -0,0 +1,746 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "dataproc.h"
|
||||
#include "nitroarc.h"
|
||||
|
||||
// IWYU pragma: begin_keep
|
||||
#include "constants/items.h"
|
||||
#include "generated/abilities.h"
|
||||
#include "generated/egg_groups.h"
|
||||
#include "generated/exp_rates.h"
|
||||
#include "generated/evolution_methods.h"
|
||||
#include "generated/footprint_sizes.h"
|
||||
#include "generated/gender_ratios.h"
|
||||
#include "generated/moves.h"
|
||||
#include "generated/pal_park_land_area.h"
|
||||
#include "generated/pal_park_water_area.h"
|
||||
#include "generated/pokemon_colors.h"
|
||||
#include "generated/pokemon_types.h"
|
||||
#include "generated/shadow_sizes.h"
|
||||
#include "generated/species.h"
|
||||
#include "generated/tutor_locations.h"
|
||||
// IWYU pragma: end_keep
|
||||
|
||||
#include "struct_defs/species.h"
|
||||
#include "struct_defs/species_sprite_data.h"
|
||||
#include "struct_defs/sprite_animation_frame.h"
|
||||
|
||||
typedef struct SpeciesLearnsetSized {
|
||||
SpeciesLearnset data;
|
||||
size_t size;
|
||||
} SpeciesLearnsetSized;
|
||||
|
||||
typedef struct SpeciesEvolutionList {
|
||||
SpeciesEvolution data[MAX_EVOLUTIONS] ALIGN_4;
|
||||
} SpeciesEvolutionList;
|
||||
|
||||
typedef struct SpeciesHeights {
|
||||
u8 back_female;
|
||||
u8 back_male;
|
||||
u8 front_female;
|
||||
u8 front_male;
|
||||
bool has_female;
|
||||
bool has_male;
|
||||
} SpeciesHeights;
|
||||
|
||||
typedef struct Container {
|
||||
SpeciesData personal;
|
||||
SpeciesEvolutionList evolutions;
|
||||
SpeciesLearnsetSized levelup_learnset;
|
||||
SpeciesPalPark palpark;
|
||||
SpeciesHeights heights;
|
||||
SpeciesSpriteData spritedata;
|
||||
enum Species offspring;
|
||||
} Container;
|
||||
|
||||
static SpeciesData proc_personal(datafile_t *df);
|
||||
static SpeciesEvolutionList proc_evolutions(datafile_t *df);
|
||||
static SpeciesLearnsetSized proc_lvlearnset(datafile_t *df);
|
||||
static SpeciesPalPark proc_palpark(datafile_t *df, size_t i);
|
||||
static enum Species proc_offspring(datafile_t *df, size_t i);
|
||||
static SpeciesHeights proc_heights(datafile_t *df, enum GenderRatio ratio);
|
||||
static SpeciesSpriteData proc_spritedata(datafile_t *df);
|
||||
|
||||
static void emit_tutorables(datafile_t *df, size_t i);
|
||||
static void emit_eggmoves(datafile_t *df, const char *species_upper);
|
||||
static void emit_footprints(datafile_t *df, size_t i, const char *species_upper);
|
||||
static void emit_iconpalettes(datafile_t *df, size_t i, const char *species);
|
||||
static void pack(Container *species, size_t i);
|
||||
|
||||
static void pre_init(void);
|
||||
static void post_init(void);
|
||||
static int addl_done(void);
|
||||
static void parse_args(int *pargc, char ***pargv);
|
||||
|
||||
static char *program_name = NULL;
|
||||
static char *base_dir = NULL;
|
||||
static char *depfile_fpath = "species_data.d";
|
||||
static char *tutorables_fpath = "move_tutors.json";
|
||||
static char *output_dir = ".";
|
||||
static char **registry = NULL;
|
||||
static size_t len_registry = 0;
|
||||
|
||||
static enum_template_t enums[] = {
|
||||
{ .from_file = "constants/footstep_house.h", .with_prefix = "FOOTPRINT_TYPE", .for_type = "FOOTPRINT_TYPE", .from_defs = true },
|
||||
{ .from_file = NULL },
|
||||
};
|
||||
|
||||
static archive_template_t archives[] = {
|
||||
{ .out_filename = "pl_personal.narc" },
|
||||
{ .out_filename = "evo.narc" },
|
||||
{ .out_filename = "wotbl.narc" },
|
||||
{ .out_filename = "height.narc" },
|
||||
{ .out_filename = NULL },
|
||||
};
|
||||
|
||||
static header_template_t headers[] = {
|
||||
{ .out_filename = "tutorable_moves.h" },
|
||||
{ .out_filename = "species_learnsets_by_tutor.h" },
|
||||
{ .out_filename = "species_egg_moves.h" },
|
||||
{ .out_filename = "species_footprint_sizes.h" },
|
||||
{ .out_filename = "species_footprint_types.h" },
|
||||
{ .out_filename = "species_icon_palettes.h" },
|
||||
{ .out_filename = NULL, },
|
||||
};
|
||||
|
||||
static const char *alt_forms_with_data[] = { // NOTE: also implicitly defines the ordering of these forms
|
||||
"deoxys/forms/attack",
|
||||
"deoxys/forms/defense",
|
||||
"deoxys/forms/speed",
|
||||
"wormadam/forms/sandy",
|
||||
"wormadam/forms/trash",
|
||||
"giratina/forms/origin",
|
||||
"shaymin/forms/sky",
|
||||
"rotom/forms/heat",
|
||||
"rotom/forms/wash",
|
||||
"rotom/forms/frost",
|
||||
"rotom/forms/fan",
|
||||
"rotom/forms/mow",
|
||||
};
|
||||
|
||||
#define NATIONAL_DEX_MAX SPECIES_EGG
|
||||
|
||||
#define SOURCE_NAME "tools/dataproc/src/speciesproc.c"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
parse_args(&argc, &argv);
|
||||
|
||||
splitenv("SPECIES", ®istry, &len_registry, alt_forms_with_data, countof(alt_forms_with_data));
|
||||
archives[0].num_files = (u16)len_registry;
|
||||
archives[1].num_files = (u16)len_registry;
|
||||
archives[2].num_files = (u16)len_registry;
|
||||
archives[3].num_files = (u16)(4 * NATIONAL_DEX_MAX);
|
||||
|
||||
common_init(DATAPROC_F_JSON, enums, archives, headers, __FILE__, depfile_fpath, output_dir, pre_init, post_init);
|
||||
|
||||
datafile_t df_d = { 0 };
|
||||
datafile_t df_s = { 0 };
|
||||
unsigned errc = EXIT_SUCCESS;
|
||||
|
||||
for (size_t i = 0; i < len_registry; i++) {
|
||||
char *path_d = pathjoin(base_dir, registry[i], "data.json");
|
||||
char *path_s = pathjoin(base_dir, registry[i], "sprite_data.json");
|
||||
|
||||
if (dp_load(&df_d, path_d) == 0) {
|
||||
char *capped = strupper(registry[i]);
|
||||
|
||||
Container species = {
|
||||
.personal = proc_personal(&df_d),
|
||||
.evolutions = proc_evolutions(&df_d),
|
||||
.levelup_learnset = proc_lvlearnset(&df_d),
|
||||
.palpark = proc_palpark(&df_d, i),
|
||||
.offspring = proc_offspring(&df_d, i),
|
||||
};
|
||||
|
||||
if (i < NATIONAL_DEX_MAX && dp_load(&df_s, path_s) == 0) {
|
||||
enum GenderRatio ratio = species.personal.genderRatio;
|
||||
if (i == SPECIES_NONE) ratio = GENDER_RATIO_FEMALE_50;
|
||||
|
||||
species.heights = proc_heights(&df_s, ratio);
|
||||
species.spritedata = proc_spritedata(&df_s);
|
||||
}
|
||||
|
||||
emit_tutorables(&df_d, i);
|
||||
emit_eggmoves(&df_d, capped);
|
||||
emit_footprints(&df_d, i, capped);
|
||||
emit_iconpalettes(&df_d, i, registry[i]);
|
||||
pack(&species, i);
|
||||
|
||||
free(capped);
|
||||
}
|
||||
|
||||
if (df_d.diag_head && dp_report(&df_d) == DIAG_ERROR) errc = EXIT_FAILURE;
|
||||
if (df_s.diag_head && dp_report(&df_s) == DIAG_ERROR) errc = EXIT_FAILURE;
|
||||
|
||||
free(path_d);
|
||||
free(path_s);
|
||||
dp_free(&df_d);
|
||||
dp_free(&df_s);
|
||||
}
|
||||
|
||||
return common_done(errc, addl_done);
|
||||
}
|
||||
|
||||
static u8 *palpark = NULL;
|
||||
static u16 *offspring = NULL;
|
||||
static u8 *sprite_data = NULL;
|
||||
|
||||
static void pre_init(void) {
|
||||
dp_regmetang(Ability);
|
||||
dp_regmetang(EggGroup);
|
||||
dp_regmetang(ExpRate);
|
||||
dp_regmetang(EvolutionMethod);
|
||||
dp_regmetang(FootprintSize);
|
||||
dp_regmetang(GenderRatio);
|
||||
dp_regmetang(Item);
|
||||
dp_regmetang(Move);
|
||||
dp_regmetang(PalParkLandArea);
|
||||
dp_regmetang(PalParkWaterArea);
|
||||
dp_regmetang(PokemonColor);
|
||||
dp_regmetang(PokemonType);
|
||||
dp_regmetang(ShadowSize);
|
||||
dp_regmetang(Species);
|
||||
dp_regmetang(TutorLocation);
|
||||
|
||||
palpark = calloc(NATIONAL_DEX_MAX - 1, sizeof(SpeciesPalPark)); // NOTE: SPECIES_NONE does not have an entry
|
||||
offspring = calloc(len_registry, sizeof(u16));
|
||||
sprite_data = calloc(NATIONAL_DEX_MAX, sizeof(SpeciesSpriteData));
|
||||
}
|
||||
|
||||
static datafile_t df_tutorables = { 0 };
|
||||
static const char **tutorable_moves = NULL;
|
||||
static size_t len_tutorable_moves = 0;
|
||||
static size_t tutorset_size = 0;
|
||||
static u8 *tutorset = NULL; // NOTE: shared and cleared between species
|
||||
|
||||
static void free_tutorables(void) {
|
||||
free(tutorable_moves);
|
||||
free(tutorset);
|
||||
dp_free(&df_tutorables);
|
||||
}
|
||||
|
||||
static void post_init(void) {
|
||||
static FILE **f_tutorables = &headers[0].out_file;
|
||||
|
||||
if (dp_load(&df_tutorables, tutorables_fpath) == 0) {
|
||||
datanode_t array = dp_get(&df_tutorables, ".");
|
||||
len_tutorable_moves = dp_arrlen(array);
|
||||
tutorable_moves = calloc(len_tutorable_moves, sizeof(*tutorable_moves));
|
||||
|
||||
for (size_t i = 0; i < len_tutorable_moves; i++) {
|
||||
datanode_t elem = dp_arrelem(array, i);
|
||||
datanode_t move = dp_objmemb(elem, "move");
|
||||
if (dp_lookup(move, "Move").type == DATAPROC_T_ERR) continue;
|
||||
|
||||
tutorable_moves[i] = dp_string(move);
|
||||
fprintf(*f_tutorables, " { %s, %u, %u, %u, %u, %s },\n",
|
||||
tutorable_moves[i],
|
||||
dp_u8(dp_objmemb(elem, "redCost")),
|
||||
dp_u8(dp_objmemb(elem, "blueCost")),
|
||||
dp_u8(dp_objmemb(elem, "yellowCost")),
|
||||
dp_u8(dp_objmemb(elem, "greenCost")),
|
||||
dp_string(dp_lookup_s(dp_objmemb(elem, "location"), "TutorLocation")));
|
||||
}
|
||||
|
||||
tutorset_size = (len_tutorable_moves + 7) / 8;
|
||||
tutorset = calloc(tutorset_size, sizeof(*tutorset));
|
||||
}
|
||||
|
||||
if (df_tutorables.diag_head && dp_report(&df_tutorables) == DIAG_ERROR) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
atexit(free_tutorables);
|
||||
}
|
||||
|
||||
static void proc_tmlearnset(datafile_t *df, SpeciesData *out);
|
||||
|
||||
static SpeciesData proc_personal(datafile_t *df) {
|
||||
SpeciesData personal = {
|
||||
.baseStats = {
|
||||
.hp = u8(".base_stats.hp"),
|
||||
.attack = u8(".base_stats.attack"),
|
||||
.defense = u8(".base_stats.defense"),
|
||||
.speed = u8(".base_stats.speed"),
|
||||
.spAttack = u8(".base_stats.special_attack"),
|
||||
.spDefense = u8(".base_stats.special_defense"),
|
||||
},
|
||||
|
||||
.types = {
|
||||
enum_u8(".types[0]", PokemonType),
|
||||
enum_u8(".types[1]", PokemonType),
|
||||
},
|
||||
|
||||
.abilities = {
|
||||
enum_u8(".abilities[0]", Ability),
|
||||
enum_u8(".abilities[1]", Ability),
|
||||
},
|
||||
|
||||
.evYields = {
|
||||
.hp = u8_maxbits(".ev_yields.hp", 2),
|
||||
.attack = u8_maxbits(".ev_yields.attack", 2),
|
||||
.defense = u8_maxbits(".ev_yields.defense", 2),
|
||||
.speed = u8_maxbits(".ev_yields.speed", 2),
|
||||
.spAttack = u8_maxbits(".ev_yields.special_attack", 2),
|
||||
.spDefense = u8_maxbits(".ev_yields.special_defense", 2),
|
||||
},
|
||||
|
||||
.wildHeldItems = {
|
||||
.common = enum_u16(".held_items.common", Item),
|
||||
.rare = enum_u16(".held_items.rare", Item),
|
||||
},
|
||||
|
||||
.eggGroups = {
|
||||
enum_u8(".egg_groups[0]", EggGroup),
|
||||
enum_u8(".egg_groups[1]", EggGroup),
|
||||
},
|
||||
|
||||
.baseExpReward = u8(".base_exp_reward"),
|
||||
.baseFriendship = u8(".base_friendship"),
|
||||
.bodyColor = (u8)(enum_u8(".body_color", PokemonColor) & maxbit(7)),
|
||||
.catchRate = u8(".catch_rate"),
|
||||
.expRate = enum_u8(".exp_rate", ExpRate),
|
||||
.flipSprite = boolean(".flip_sprite"),
|
||||
.genderRatio = enum_u8(".gender_ratio", GenderRatio),
|
||||
.hatchCycles = u8(".hatch_cycles"),
|
||||
.safariFleeRate = u8(".safari_flee_rate"),
|
||||
|
||||
.tmLearnsetMasks = { 0 },
|
||||
};
|
||||
|
||||
proc_tmlearnset(df, &personal);
|
||||
return personal;
|
||||
}
|
||||
|
||||
static void proc_tmlearnset(datafile_t *df, SpeciesData *out) {
|
||||
datanode_t tm_learnset = dp_get(df, ".learnset.by_tm");
|
||||
for (size_t i = 0; i < dp_arrlen(tm_learnset); i++) {
|
||||
datanode_t dn = dp_arrelem(tm_learnset, i);
|
||||
const char *entry = dp_string(dn);
|
||||
|
||||
long value = 0;
|
||||
char *endptr = NULL;
|
||||
if (entry == NULL) continue; // not a string, error is already recorded
|
||||
if ((entry[0] == 'T' || entry[0] == 'H') && entry[1] == 'M') {
|
||||
value = strtol(&entry[2], &endptr, 10);
|
||||
if (*endptr != 0 || value < 1) goto errmarker;
|
||||
if (entry[0] == 'T' && (size_t)value > NUM_TMS) goto errmarker;
|
||||
if (entry[0] == 'H' && (size_t)value > NUM_HMS) goto errmarker;
|
||||
|
||||
value -= 1;
|
||||
value += NUM_TMS * (entry[0] == 'H');
|
||||
}
|
||||
else {
|
||||
errmarker:
|
||||
dp_error(&dn, "expected entry to be a valid TM or HM marker");
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t idx = value / 32;
|
||||
size_t bit = value % 32;
|
||||
out->tmLearnsetMasks[idx] |= ((unsigned)1 << bit); // NOTE: cast is required here to avoid SIGILL
|
||||
}
|
||||
}
|
||||
|
||||
static SpeciesEvolutionList proc_evolutions(datafile_t *df) {
|
||||
SpeciesEvolutionList result = { 0 };
|
||||
|
||||
datanode_t evolutions = dp_get(df, ".evolutions");
|
||||
size_t len_evos = dp_arrlen(evolutions);
|
||||
if (len_evos > MAX_EVOLUTIONS) {
|
||||
dp_error(&evolutions,
|
||||
"expected at most %u entries, but found %zu",
|
||||
MAX_LEARNSET_ENTRIES, len_evos);
|
||||
return result;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len_evos; i++) {
|
||||
datanode_t entry = dp_arrelem(evolutions, i);
|
||||
datanode_t method = dp_lookup(dp_arrelem(entry, 0), "EvolutionMethod");
|
||||
if (method.type == DATAPROC_T_ERR) continue; // Don't bother if the evolution method is invalid
|
||||
|
||||
datanode_t param = { .type = DATAPROC_T_MAPPED, .mapped = 0 };
|
||||
datanode_t species = { 0 };
|
||||
switch ((enum EvolutionMethod)dp_u16(method)) {
|
||||
case EVO_NONE:
|
||||
case EVO_LEVEL_HAPPINESS:
|
||||
case EVO_LEVEL_HAPPINESS_DAY:
|
||||
case EVO_LEVEL_HAPPINESS_NIGHT:
|
||||
case EVO_TRADE:
|
||||
case EVO_LEVEL_MAGNETIC_FIELD:
|
||||
case EVO_LEVEL_MOSS_ROCK:
|
||||
case EVO_LEVEL_ICE_ROCK:
|
||||
species = dp_lookup(dp_arrelem(entry, 1), "Species");
|
||||
break;
|
||||
|
||||
case EVO_LEVEL:
|
||||
case EVO_LEVEL_ATK_GT_DEF:
|
||||
case EVO_LEVEL_ATK_EQ_DEF:
|
||||
case EVO_LEVEL_ATK_LT_DEF:
|
||||
case EVO_LEVEL_PID_LOW:
|
||||
case EVO_LEVEL_PID_HIGH:
|
||||
case EVO_LEVEL_NINJASK:
|
||||
case EVO_LEVEL_SHEDINJA:
|
||||
case EVO_LEVEL_BEAUTY:
|
||||
case EVO_LEVEL_MALE:
|
||||
case EVO_LEVEL_FEMALE:
|
||||
param = dp_arrelem(entry, 1);
|
||||
species = dp_lookup(dp_arrelem(entry, 2), "Species");
|
||||
break;
|
||||
|
||||
case EVO_TRADE_WITH_HELD_ITEM:
|
||||
case EVO_USE_ITEM:
|
||||
case EVO_USE_ITEM_MALE:
|
||||
case EVO_USE_ITEM_FEMALE:
|
||||
case EVO_LEVEL_WITH_HELD_ITEM_DAY:
|
||||
case EVO_LEVEL_WITH_HELD_ITEM_NIGHT:
|
||||
param = dp_lookup(dp_arrelem(entry, 1), "Item");
|
||||
species = dp_lookup(dp_arrelem(entry, 2), "Species");
|
||||
break;
|
||||
|
||||
case EVO_LEVEL_KNOW_MOVE:
|
||||
param = dp_lookup(dp_arrelem(entry, 1), "Move");
|
||||
species = dp_lookup(dp_arrelem(entry, 2), "Species");
|
||||
break;
|
||||
|
||||
case EVO_LEVEL_SPECIES_IN_PARTY:
|
||||
param = dp_lookup(dp_arrelem(entry, 1), "Species");
|
||||
species = dp_lookup(dp_arrelem(entry, 2), "Species");
|
||||
break;
|
||||
|
||||
default:
|
||||
// NOTE: This is a sanity-check for users that add a new EvolutionMethod
|
||||
// but fail to add a case to this switch.
|
||||
dp_error(&method, "no handler implemented for EvolutionMethod member '%s'",
|
||||
dp_string(dp_arrelem(entry, 0)));
|
||||
break;
|
||||
}
|
||||
|
||||
result.data[i] = (SpeciesEvolution){
|
||||
.method = dp_u16(method),
|
||||
.param = dp_u16(param),
|
||||
.targetSpecies = dp_u16(species),
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static SpeciesLearnsetSized proc_lvlearnset(datafile_t *df) {
|
||||
SpeciesLearnsetSized result = { 0 };
|
||||
|
||||
datanode_t lv_learnset = dp_get(df, ".learnset.by_level");
|
||||
size_t len_learnset = dp_arrlen(lv_learnset);
|
||||
if (len_learnset > MAX_LEARNSET_ENTRIES) {
|
||||
dp_error(&lv_learnset,
|
||||
"expected at most %u entries, but found %zu",
|
||||
MAX_LEARNSET_ENTRIES, len_learnset);
|
||||
return result;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len_learnset; i++) {
|
||||
datanode_t entry = dp_arrelem(lv_learnset, i);
|
||||
datanode_t level = dp_arrelem(entry, 0);
|
||||
datanode_t move = dp_arrelem(entry, 1);
|
||||
|
||||
result.data.entries[result.size].move = (u16)(dp_u16(dp_lookup(move, "Move")) & maxbit(9));
|
||||
result.data.entries[result.size].level = (u16)(dp_u8(level) & maxbit(7));
|
||||
result.size++;
|
||||
}
|
||||
|
||||
result.data.entries[result.size].move = (u16)UINT16_MAX & maxbit(9);
|
||||
result.data.entries[result.size].level = (u16)UINT16_MAX & maxbit(7);
|
||||
result.size++;
|
||||
|
||||
result.size *= sizeof(SpeciesLearnsetEntry);
|
||||
result.size += (-result.size & 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
static SpeciesPalPark proc_palpark(datafile_t *df, size_t i) {
|
||||
SpeciesPalPark result = { 0 };
|
||||
if (i == SPECIES_NONE || i >= NATIONAL_DEX_MAX) return result;
|
||||
|
||||
datanode_t catching_show = dp_get(df, ".catching_show");
|
||||
datanode_t land_area = dp_lookup(dp_objmemb(catching_show, "pal_park_land_area"), "PalParkLandArea");
|
||||
datanode_t water_area = dp_lookup(dp_objmemb(catching_show, "pal_park_water_area"), "PalParkWaterArea");
|
||||
datanode_t catching_points = dp_objmemb(catching_show, "catching_points");
|
||||
datanode_t rarity = dp_objmemb(catching_show, "rarity");
|
||||
datanode_t unused_u16 = dp_objmemb(catching_show, "unused");
|
||||
|
||||
result.landArea = dp_u8(land_area);
|
||||
result.waterArea = dp_u8(water_area);
|
||||
result.catchingPoints = dp_u8(catching_points);
|
||||
result.rarity = dp_u8(rarity);
|
||||
result.unused.asU16 = dp_u16(unused_u16);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum Species proc_offspring(datafile_t *df, size_t i) {
|
||||
return i <= SPECIES_BAD_EGG
|
||||
? (enum Species)enum_u16(".offspring", Species)
|
||||
: (enum Species)i;
|
||||
}
|
||||
|
||||
static SpeciesHeights proc_heights(datafile_t *df, enum GenderRatio ratio) {
|
||||
datanode_t back = dp_get(df, ".back.y_offset");
|
||||
datanode_t front = dp_get(df, ".front.y_offset");
|
||||
|
||||
SpeciesHeights result = { 0 };
|
||||
|
||||
if (ratio != GENDER_RATIO_FEMALE_ONLY) {
|
||||
result.has_male = true;
|
||||
result.back_male = dp_u8(dp_objmemb(back, "male"));
|
||||
result.front_male = dp_u8(dp_objmemb(front, "male"));
|
||||
}
|
||||
|
||||
if (ratio != GENDER_RATIO_MALE_ONLY && ratio != GENDER_RATIO_NO_GENDER) {
|
||||
result.has_female = true;
|
||||
result.back_female = dp_u8(dp_objmemb(back, "female"));
|
||||
result.front_female = dp_u8(dp_objmemb(front, "female"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static SpeciesSpriteAnim proc_spriteanim(datanode_t dn) {
|
||||
SpeciesSpriteAnim result = {
|
||||
.animation = dp_u8(dp_objmemb(dn, "animation")),
|
||||
.cryDelay = dp_u8(dp_objmemb(dn, "cry_delay")),
|
||||
.startDelay = dp_u8(dp_objmemb(dn, "start_delay")),
|
||||
};
|
||||
|
||||
datanode_t frames = dp_objmemb(dn, "frames");
|
||||
const size_t num_frames = dp_arrlen(frames);
|
||||
for (size_t i = 0; i < num_frames; i++) {
|
||||
datanode_t frame = dp_arrelem(frames, i);
|
||||
|
||||
result.frames[i] = (SpriteAnimFrame){
|
||||
.spriteFrame = dp_s8(dp_objmemb(frame, "sprite_frame")),
|
||||
.frameDelay = dp_u8(dp_objmemb(frame, "frame_delay")),
|
||||
.xOffset = dp_s8(dp_objmemb(frame, "x_shift")),
|
||||
.yOffset = dp_s8(dp_objmemb(frame, "y_shift")),
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static SpeciesSpriteData proc_spritedata(datafile_t *df) {
|
||||
return (SpeciesSpriteData){
|
||||
.yOffset = s8(".front.addl_y_offset"),
|
||||
.xOffsetShadow = s8(".shadow.x_offset"),
|
||||
.shadowSize = enum_u8(".shadow.size", ShadowSize),
|
||||
.faceAnims = {
|
||||
[0] = proc_spriteanim(dp_get(df, ".front")),
|
||||
[1] = proc_spriteanim(dp_get(df, ".back")),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static FILE **f_tutor_sets = &headers[1].out_file;
|
||||
static FILE **f_egg_moves = &headers[2].out_file;
|
||||
static FILE **f_footprint_sizes = &headers[3].out_file;
|
||||
static FILE **f_footprint_types = &headers[4].out_file;
|
||||
static FILE **f_icon_palettes = &headers[5].out_file;
|
||||
|
||||
static void emit_tutorables(datafile_t *df, size_t i) {
|
||||
// NOTE: none of these have any tutorable learnsets, but mechanically-distinct forms
|
||||
// (e.g., Giratina-Origin) do
|
||||
if (i == SPECIES_NONE || i == SPECIES_EGG || i == SPECIES_BAD_EGG) return;
|
||||
|
||||
datanode_t dn = dp_get(df, ".learnset.by_tutor");
|
||||
memset(tutorset, 0, tutorset_size);
|
||||
fputs(" { ", *f_tutor_sets);
|
||||
|
||||
for (size_t i = 0; i < dp_arrlen(dn); i++) {
|
||||
datanode_t move = dp_arrelem(dn, i);
|
||||
const char *move_s = dp_string(move);
|
||||
if (dp_lookup(move, "Move").type == DATAPROC_T_ERR) continue;
|
||||
|
||||
const char *found = NULL;
|
||||
size_t idx = 0;
|
||||
for (size_t j = 0; j < len_tutorable_moves && !found; j++) {
|
||||
if (strcmp(tutorable_moves[j], move_s) == 0) { found = tutorable_moves[j]; idx = j; }
|
||||
}
|
||||
|
||||
if (found) tutorset[idx / 8] |= (u8)(1 << (idx % 8));
|
||||
else dp_warn(&move, "'%s' is not available from any move tutors", move_s);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < tutorset_size; i++) fprintf(*f_tutor_sets, "0x%02X, ", tutorset[i]);
|
||||
fputs("},\n", *f_tutor_sets);
|
||||
}
|
||||
|
||||
static void emit_eggmoves(datafile_t *df, const char *species_upper) {
|
||||
datanode_t dn = dp_try(df, ".learnset.egg_moves");
|
||||
if (dn.type == DATAPROC_T_ERR) return;
|
||||
|
||||
fprintf(*f_egg_moves, " SPECIES_%s + EGG_MOVES_SPECIES_OFFSET,\n", species_upper);
|
||||
for (size_t i = 0; i < dp_arrlen(dn); i++) {
|
||||
datanode_t move = dp_arrelem(dn, i);
|
||||
const char *move_s = dp_string(move);
|
||||
dp_lookup(move, "Move"); // only to verify that this is a move name
|
||||
|
||||
fprintf(*f_egg_moves, " %s,\n", move_s);
|
||||
}
|
||||
|
||||
fputc('\n', *f_egg_moves);
|
||||
}
|
||||
|
||||
static void emit_footprints(datafile_t *df, size_t i, const char *species_upper) {
|
||||
// NOTE: eggs and alternate-forms do not have any footprint data
|
||||
if (i >= NATIONAL_DEX_MAX) return;
|
||||
|
||||
datanode_t root = dp_get(df, ".footprint");
|
||||
const bool has = dp_bool(dp_objmemb(root, "has"));
|
||||
const char *size = dp_string(dp_lookup_s(dp_objmemb(root, "size"), "FootprintSize"));
|
||||
const char *type = dp_string(dp_lookup_s(dp_objmemb(root, "type"), "FOOTPRINT_TYPE"));
|
||||
|
||||
fprintf(*f_footprint_sizes, " { %s, %s },\n",
|
||||
has ? "TRUE" : "FALSE",
|
||||
size);
|
||||
fprintf(*f_footprint_types, " [SPECIES_%s] = { %s, %s },\n",
|
||||
species_upper,
|
||||
type,
|
||||
has || i == SPECIES_SPIRITOMB ? "TRUE" : "FALSE");
|
||||
}
|
||||
|
||||
static void emit_iconpalettes(datafile_t *df, size_t i, const char *species) {
|
||||
// We make a separate-copy to make this fool-proof, since the surrounding functions modify the string
|
||||
char *capped = strreplace(strremove(strupper(species), "/FORMS"), '/', '_');
|
||||
|
||||
datanode_t palette = dp_get(df, ".icon_palette");
|
||||
if (palette.type == DATAPROC_T_INT) {
|
||||
long idx = dp_int(palette);
|
||||
|
||||
switch (i) {
|
||||
default:
|
||||
fprintf(*f_icon_palettes, " [%s_%s] = %ld,\n",
|
||||
i > SPECIES_BAD_EGG ? "ICON" : "SPECIES", capped, idx);
|
||||
break;
|
||||
|
||||
case SPECIES_EGG: fprintf(*f_icon_palettes, " [ICON_EGG] = %ld,\n", idx); break;
|
||||
case SPECIES_BAD_EGG: fprintf(*f_icon_palettes, " [ICON_MANAPHY_EGG] = %ld,\n", idx); break;
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Must be an array of tuples like: [form_name, palette_index]
|
||||
for (size_t j = 0; j < dp_arrlen(palette); j++) {
|
||||
datanode_t elem = dp_arrelem(palette, j);
|
||||
datanode_t form = dp_arrelem(elem, 0);
|
||||
datanode_t pltt = dp_arrelem(elem, 1);
|
||||
|
||||
if (form.type != DATAPROC_T_ERR && pltt.type != DATAPROC_T_ERR) {
|
||||
const char *form_s = dp_string(form);
|
||||
const long pltt_i = dp_int(pltt);
|
||||
if (strcmp(form_s, "base") == 0) {
|
||||
fprintf(*f_icon_palettes, " [SPECIES_%s] = %ld,\n", capped, pltt_i);
|
||||
}
|
||||
else {
|
||||
char *form_capped = strupper(form_s);
|
||||
fprintf(*f_icon_palettes, " [ICON_%s_%s] = %ld,\n", capped, form_capped, pltt_i);
|
||||
free(form_capped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(capped);
|
||||
}
|
||||
|
||||
static void pack(Container *species, size_t i) {
|
||||
nitroarc_ppack(&archives[0].packer, &species->personal, sizeof(SpeciesData), NULL);
|
||||
nitroarc_ppack(&archives[1].packer, &species->evolutions, sizeof(SpeciesEvolutionList), NULL);
|
||||
nitroarc_ppack(&archives[2].packer, &species->levelup_learnset.data, (u32)species->levelup_learnset.size, NULL);
|
||||
|
||||
if (i > SPECIES_NONE && i < NATIONAL_DEX_MAX) {
|
||||
size_t offset = sizeof(SpeciesPalPark) * (i - 1);
|
||||
memcpy(palpark + offset, &species->palpark, sizeof(SpeciesPalPark));
|
||||
}
|
||||
|
||||
if (i < NATIONAL_DEX_MAX) {
|
||||
nitroarc_ppack(&archives[3].packer, &species->heights.back_female, species->heights.has_female ? 1 : 0, NULL);
|
||||
nitroarc_ppack(&archives[3].packer, &species->heights.back_male, species->heights.has_male ? 1 : 0, NULL);
|
||||
nitroarc_ppack(&archives[3].packer, &species->heights.front_female, species->heights.has_female ? 1 : 0, NULL);
|
||||
nitroarc_ppack(&archives[3].packer, &species->heights.front_male, species->heights.has_male ? 1 : 0, NULL);
|
||||
|
||||
size_t offset = sizeof(SpeciesSpriteData) * i;
|
||||
memcpy(sprite_data + offset, &species->spritedata, sizeof(SpeciesSpriteData));
|
||||
}
|
||||
|
||||
offspring[i] = (u16)species->offspring;
|
||||
}
|
||||
|
||||
static int addl_done(void) {
|
||||
return fdump_blobnarc(palpark, sizeof(SpeciesPalPark) * (NATIONAL_DEX_MAX - 1), "ppark.narc")
|
||||
|| fdump_blobnarc(sprite_data, sizeof(SpeciesSpriteData) * NATIONAL_DEX_MAX, "pl_poke_data.narc")
|
||||
|| fdump_blob(offspring, sizeof(u16) * len_registry, "pms.narc")
|
||||
|| EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void usage(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
static void parse_args(int *pargc, char ***pargv) {
|
||||
program_name = (*pargv)[0];
|
||||
opterr = 0;
|
||||
|
||||
int c = 0;
|
||||
while ((c = getopt(*pargc, *pargv, "o:t:M:h")) != -1) {
|
||||
switch (c) {
|
||||
case 'o': output_dir = optarg; break;
|
||||
case 't': tutorables_fpath = optarg; break;
|
||||
case 'M': depfile_fpath = optarg; break;
|
||||
|
||||
case 'h': usage(NULL); break;
|
||||
case ':': usage("missing argument for '-%c'", optopt); break;
|
||||
default: usage("unknown option '-%c'", optopt); break;
|
||||
}
|
||||
}
|
||||
|
||||
*pargc -= optind;
|
||||
*pargv += optind;
|
||||
if (*pargc < 1) usage("missing required argument BASEDIR");
|
||||
|
||||
base_dir = (*pargv)[0];
|
||||
}
|
||||
|
||||
static void usage(const char *fmt, ...) {
|
||||
FILE *f = stdout;
|
||||
if (fmt != NULL) {
|
||||
f = stderr;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fputs(program_name, f);
|
||||
fputs(": ", f);
|
||||
vfprintf(f, fmt, args);
|
||||
fputc('\n', f);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define fputf(fmt, ...) fprintf(f, fmt, __VA_ARGS__)
|
||||
fputf("usage: %s [-M DEPFILE] [-t TUTORABLES_JSON] [-o OUTDIR] BASEDIR\n", program_name);
|
||||
fputs("\n", f);
|
||||
fputs("options:\n", f);
|
||||
fputs(" -o OUTDIR Write output files to OUTDIR. Does not affect DEPFILE.\n", f);
|
||||
fputs(" Defaults to the current working directory.\n", f);
|
||||
fputs(" -t TUTORABLES_JSON Specify the full path to the tutorable-moves JSON file.\n", f);
|
||||
fputs(" Defaults to 'move_tutors.json'.\n", f);
|
||||
fputs(" -M DEPFILE Specify the full path to an output dependency file.\n", f);
|
||||
fputs(" Defaults to 'species_data.d'.\n", f);
|
||||
#undef fputf
|
||||
|
||||
exit(f == stdout ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -321,6 +321,9 @@ dataproc_c_commands = [
|
|||
f"-I{homedir}/tools/dataproc/lib/include",
|
||||
f"-I{homedir}/include",
|
||||
f"-I{builddir}",
|
||||
f'-DREPO_INCLUDE="{homedir}/include"',
|
||||
f'-DREPO_BUILD="{builddir}"',
|
||||
f'-DTEMPLATES_DIR="{homedir}/tools/dataproc/data"',
|
||||
"-std=gnu17",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user