Optimize the MOVESETS table for compression + eliminate 4 KB "handles" buffer from

libsysbase_libsysbase_a-handle_manager.o

So, I optimized the MOVESETS table to only store the "overriding" bits in the movesets of the evolutions
in relation to their base forms. That only improved compression slightly (about 300 bytes)

I also eliminated 4 KB of IWRAM usage by libsysbase_libsysbase_a-handle_manager.o because of the "handles"
buffer. We're not using it and we REALLY need our IWRAM. (and it also reduces the rom size with 4KB too!)
This commit is contained in:
Philippe Symons 2025-04-29 22:22:38 +02:00
parent 8e55a2bd52
commit 4c93ff869c
10 changed files with 600 additions and 68 deletions

View File

@ -59,6 +59,9 @@ endif
ASFLAGS := $(ARCH)
LDFLAGS = -Os $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--gc-sections -mthumb -mcpu=arm7tdmi -mtune=arm7tdmi -Wl,-Map,output.map,--cref -nodefaultlibs
# eliminate libsysbase_libsysbase_a-handle_manager.o and its 4KB IWRAM buffer
LDFLAGS += -Wl,--wrap=__get_handle -Wl,--wrap=_close_r
CFLAGS += -flto
LDFLAGS += -flto

View File

@ -116,7 +116,7 @@ void set_menu_sprite_pal(int frame)
}
}
int path[12][2] = {{19, 18}, {19, 19}, {18, 19}, {17, 19}, {16, 19}, {15, 19}, {14, 19}, {13, 19}, {12, 19}, {11, 19}, {10, 19}, {24, 24}};
static const int path[12][2] = {{19, 18}, {19, 19}, {18, 19}, {17, 19}, {16, 19}, {15, 19}, {14, 19}, {13, 19}, {12, 19}, {11, 19}, {10, 19}, {24, 24}};
void run_link_cable_animation(int frame)
{

View File

@ -11,64 +11,6 @@
// unfortunately itoa is not standardized, so we'll have to make do with snprintf
static char conversion_buffer[33];
extern "C"
{
// HACK:
// Unfortunately, libtonc references siscanf, which in turn causes a "lot" of binary bloat from newlibc (in regards to locale support)
// to be pulled in by the linker.
// However, if you look at what it is actually used for (in libtonc's tte_iohook.c), is just to extract 1 or 2 integers from a string
// by specifying a custom -extremely simplified- version, we can avoid pulling in the version from libc (alongside all the symbols IT references)
// Obviously it doesn't support everything it should. Just enough to support libtonc's current iteration.
//
// Anyway, doing this optimizes away a lot of scanf related functions from newlib and locale support among which a 13KB "categories" symbol.
int siscanf(const char *str, const char *format, ...)
{
bool expectingFormatSpecifier = false;
va_list args;
int* resultVal;
int ret = 0;
va_start(args, format);
while(*format != '\0')
{
if(*str == '\0')
{
//EOF encountered.
return -1;
}
if(expectingFormatSpecifier)
{
if(*format == 'd')
{
resultVal = va_arg(args, int*);
(*resultVal) = 0;
while(isdigit(*str))
{
(*resultVal) *= 10;
(*resultVal) += (*str) - '0';
++str;
}
// go back to the last character of the int, because we'll forward by one again at the end of the outer loop
--str;
++ret;
}
expectingFormatSpecifier = false;
}
else if((*format) == '%')
{
expectingFormatSpecifier = true;
}
++format;
++str;
}
va_end(args);
return ret;
}
}
const char* ptgb::to_string(int intVal)
{
npf_snprintf(conversion_buffer, sizeof(conversion_buffer), "%d", intVal);

View File

@ -0,0 +1,92 @@
#include <cstdarg>
#include <ctype.h>
#include <cstdlib>
#include <errno.h>
#include <sys/iosupport.h>
#define MAX_HANDLES 3
static __handle __stdin_handle = {0, 1, NULL};
static __handle __stdout_handle = {1, 1, NULL};
static __handle __stderr_handle = {2, 1, NULL};
static __handle* handles[MAX_HANDLES] = {
&__stdin_handle,
&__stdout_handle,
&__stderr_handle
};
extern "C"
{
// HACK:
// Unfortunately, libtonc references siscanf, which in turn causes a "lot" of binary bloat from newlibc (in regards to locale support)
// to be pulled in by the linker.
// However, if you look at what it is actually used for (in libtonc's tte_iohook.c), is just to extract 1 or 2 integers from a string
// by specifying a custom -extremely simplified- version, we can avoid pulling in the version from libc (alongside all the symbols IT references)
// Obviously it doesn't support everything it should. Just enough to support libtonc's current iteration.
//
// Anyway, doing this optimizes away a lot of scanf related functions from newlib and locale support among which a 13KB "categories" symbol.
int siscanf(const char *str, const char *format, ...)
{
bool expectingFormatSpecifier = false;
va_list args;
int* resultVal;
int ret = 0;
va_start(args, format);
while(*format != '\0')
{
if(*str == '\0')
{
//EOF encountered.
return -1;
}
if(expectingFormatSpecifier)
{
if(*format == 'd')
{
resultVal = va_arg(args, int*);
(*resultVal) = 0;
while(isdigit(*str))
{
(*resultVal) *= 10;
(*resultVal) += (*str) - '0';
++str;
}
// go back to the last character of the int, because we'll forward by one again at the end of the outer loop
--str;
++ret;
}
expectingFormatSpecifier = false;
}
else if((*format) == '%')
{
expectingFormatSpecifier = true;
}
++format;
++str;
}
va_end(args);
return ret;
}
// HACK: stub the libsysbase_libsysbase_a-handle_manager.o functions
// this, alongside the -Wl,--wrap linker options ensures that this object file
// and its 4KB IWRAM "handles" buffer is not getting pulled in by the linker.
// We don't need it and we could use the 4KB of extra IWRAM!
__handle *__wrap___get_handle(int fd)
{
if ( fd < 0 || fd >= MAX_HANDLES ) return NULL;
return handles[fd];
}
int __wrap__close_r(struct _reent *ptr, int fd)
{
return 0;
}
}

View File

@ -947,7 +947,6 @@ void Pokemon::set_to_event(PokemonTables &data_tables, byte nature)
enable_auto_random();
// Determine and set Ability
data_tables.load_num_abilities();
iv_egg_ability |= ((pid[0] & 0x1) ? data_tables.get_num_abilities(species_index_struct) : 0) << 31;
// Set IVs, Egg, and Ability

View File

@ -1,7 +1,6 @@
#include <tonc.h>
#include <string>
#include <cstring>
#include <stdio.h>
#include "text_engine.h"
#include "global_frame_controller.h"

View File

@ -0,0 +1,32 @@
#ifndef _OPTIMIZE_MOVESETS_H
#define _OPTIMIZE_MOVESETS_H
#include "pokemon_data.h"
typedef struct optimize_moveset_result
{
u16 num_unique_rows;
u16 num_bytes;
} optimize_moveset_result;
/**
* input_buffer has 32 bytes for each pokémon. The first row is index 0, which doesn't actually represent a pokémon
* because the pokémon species index is 1-based.
*
* Anyway, the 32 bytes of the input_data have 1 bit for every available gen I/II move
*
* But we want to optimize it better for compression. For instance, there's a lot of overlap between the bits of evolutions vs base forms.
* So, as optimization, we could clear every move bit of an evolution that is also set for its base form.
*
* This way we can make the evolutions' moveset data a lot of zeros. That will compress better.
*
* But another optimization we can do is to deduplicate the resulting table and only store the unique rows.
*
* TL;DR: this function will turn the original MOVESETS table into this format:
*
* First 252 bytes: this chunk will associate a row index to every pokemon based on (species index - 1)
* Next bytes: rows of 32 bytes each for which every bit of these 32 bytes associates with a gen 1/2 move.
*/
optimize_moveset_result optimize_movesets(u8 *output_buffer, const u8 *input_buffer, u16 input_buffer_size);
#endif

View File

@ -1,6 +1,20 @@
#ifndef _POKEMON_DATA_H
#define _POKEMON_DATA_H
#include <cstddef>
#include <cstdint>
#define NUM_POKEMON 252
#define POKEMON_ARRAY_SIZE NUM_POKEMON + 1
typedef uint8_t u8;
typedef uint8_t byte;
typedef uint16_t u16;
typedef uint32_t u32;
extern const byte MOVESETS[POKEMON_ARRAY_SIZE][32];
extern const size_t MOVESETS_size;
void generate_pokemon_data();
#endif

View File

@ -0,0 +1,446 @@
#include "optimize_movesets.h"
#include <cstring>
const u8 EVOLUTIONS[POKEMON_ARRAY_SIZE]{
0, // Offset the list to remove "off by one" errors
0x0, // Bulbasaur is a base evolution
0x1, // Ivysaur evolves from Bulbasaur
0x2, // Venusaur evolves from Ivysaur
0x0, // Charmander is a base evolution
0x4, // Charmeleon evolves from Charmander
0x5, // Charizard evolves from Charmeleon
0x0, // Squirtle is a base evolution
0x7, // Wartortle evolves from Squirtle
0x8, // Blastoise evolves from Wartortle
0x0, // Caterpie is a base evolution
0xa, // Metapod evolves from Caterpie
0xb, // Butterfree evolves from Metapod
0x0, // Weedle is a base evolution
0xd, // Kakuna evolves from Weedle
0xe, // Beedrill evolves from Kakuna
0x0, // Pidgey is a base evolution
0x10, // Pidgeotto evolves from Pidgey
0x11, // Pidgeot evolves from Pidgeotto
0x0, // Rattata is a base evolution
0x13, // Raticate evolves from Rattata
0x0, // Spearow is a base evolution
0x15, // Fearow evolves from Spearow
0x0, // Ekans is a base evolution
0x17, // Arbok evolves from Ekans
0xac, // Pikachu evolves from Pichu
0x19, // Raichu evolves from Pikachu
0x0, // Sandshrew is a base evolution
0x1b, // Sandslash evolves from Sandshrew
0x0, // Nidoran-f is a base evolution
0x1d, // Nidorina evolves from Nidoran-f
0x1e, // Nidoqueen evolves from Nidorina
0x0, // Nidoran-m is a base evolution
0x20, // Nidorino evolves from Nidoran-m
0x21, // Nidoking evolves from Nidorino
0xad, // Clefairy evolves from Cleffa
0x23, // Clefable evolves from Clefairy
0x0, // Vulpix is a base evolution
0x25, // Ninetales evolves from Vulpix
0xae, // Jigglypuff evolves from Igglybuff
0x27, // Wigglytuff evolves from Jigglypuff
0x0, // Zubat is a base evolution
0x29, // Golbat evolves from Zubat
0x0, // Oddish is a base evolution
0x2b, // Gloom evolves from Oddish
0x2c, // Vileplume evolves from Gloom
0x0, // Paras is a base evolution
0x2e, // Parasect evolves from Paras
0x0, // Venonat is a base evolution
0x30, // Venomoth evolves from Venonat
0x0, // Diglett is a base evolution
0x32, // Dugtrio evolves from Diglett
0x0, // Meowth is a base evolution
0x34, // Persian evolves from Meowth
0x0, // Psyduck is a base evolution
0x36, // Golduck evolves from Psyduck
0x0, // Mankey is a base evolution
0x38, // Primeape evolves from Mankey
0x0, // Growlithe is a base evolution
0x3a, // Arcanine evolves from Growlithe
0x0, // Poliwag is a base evolution
0x3c, // Poliwhirl evolves from Poliwag
0x3d, // Poliwrath evolves from Poliwhirl
0x0, // Abra is a base evolution
0x3f, // Kadabra evolves from Abra
0x40, // Alakazam evolves from Kadabra
0x0, // Machop is a base evolution
0x42, // Machoke evolves from Machop
0x43, // Machamp evolves from Machoke
0x0, // Bellsprout is a base evolution
0x45, // Weepinbell evolves from Bellsprout
0x46, // Victreebel evolves from Weepinbell
0x0, // Tentacool is a base evolution
0x48, // Tentacruel evolves from Tentacool
0x0, // Geodude is a base evolution
0x4a, // Graveler evolves from Geodude
0x4b, // Golem evolves from Graveler
0x0, // Ponyta is a base evolution
0x4d, // Rapidash evolves from Ponyta
0x0, // Slowpoke is a base evolution
0x4f, // Slowbro evolves from Slowpoke
0x0, // Magnemite is a base evolution
0x51, // Magneton evolves from Magnemite
0x0, // Farfetchd is a base evolution
0x0, // Doduo is a base evolution
0x54, // Dodrio evolves from Doduo
0x0, // Seel is a base evolution
0x56, // Dewgong evolves from Seel
0x0, // Grimer is a base evolution
0x58, // Muk evolves from Grimer
0x0, // Shellder is a base evolution
0x5a, // Cloyster evolves from Shellder
0x0, // Gastly is a base evolution
0x5c, // Haunter evolves from Gastly
0x5d, // Gengar evolves from Haunter
0x0, // Onix is a base evolution
0x0, // Drowzee is a base evolution
0x60, // Hypno evolves from Drowzee
0x0, // Krabby is a base evolution
0x62, // Kingler evolves from Krabby
0x0, // Voltorb is a base evolution
0x64, // Electrode evolves from Voltorb
0x0, // Exeggcute is a base evolution
0x66, // Exeggutor evolves from Exeggcute
0x0, // Cubone is a base evolution
0x68, // Marowak evolves from Cubone
0xec, // Hitmonlee evolves from Tyrogue
0xec, // Hitmonchan evolves from Tyrogue
0x0, // Lickitung is a base evolution
0x0, // Koffing is a base evolution
0x6d, // Weezing evolves from Koffing
0x0, // Rhyhorn is a base evolution
0x6f, // Rhydon evolves from Rhyhorn
0x0, // Chansey is a base evolution (in gen 2)
0x0, // Tangela is a base evolution
0x0, // Kangaskhan is a base evolution
0x0, // Horsea is a base evolution
0x74, // Seadra evolves from Horsea
0x0, // Goldeen is a base evolution
0x76, // Seaking evolves from Goldeen
0x0, // Staryu is a base evolution
0x78, // Starmie evolves from Staryu
0x0, // Mr-mime is a base evolution (in gen 2)
0x0, // Scyther is a base evolution
0xee, // Jynx evolves from Smoochum
0xef, // Electabuzz evolves from Elekid
0xf0, // Magmar evolves from Magby
0x0, // Pinsir is a base evolution
0x0, // Tauros is a base evolution
0x0, // Magikarp is a base evolution
0x81, // Gyarados evolves from Magikarp
0x0, // Lapras is a base evolution
0x0, // Ditto is a base evolution
0x0, // Eevee is a base evolution
0x85, // Vaporeon evolves from Eevee
0x85, // Jolteon evolves from Eevee
0x85, // Flareon evolves from Eevee
0x0, // Porygon is a base evolution
0x0, // Omanyte is a base evolution
0x8a, // Omastar evolves from Omanyte
0x0, // Kabuto is a base evolution
0x8c, // Kabutops evolves from Kabuto
0x0, // Aerodactyl is a base evolution
0x0, // Snorlax is a base evolution (in gen 2)
0x0, // Articuno is a base evolution
0x0, // Zapdos is a base evolution
0x0, // Moltres is a base evolution
0x0, // Dratini is a base evolution
0x93, // Dragonair evolves from Dratini
0x94, // Dragonite evolves from Dragonair
0x0, // Mewtwo is a base evolution
0x0, // Mew is a base evolution
0x0, // Chikorita is a base evolution
0x98, // Bayleef evolves from Chikorita
0x99, // Meganium evolves from Bayleef
0x0, // Cyndaquil is a base evolution
0x9b, // Quilava evolves from Cyndaquil
0x9c, // Typhlosion evolves from Quilava
0x0, // Totodile is a base evolution
0x9e, // Croconaw evolves from Totodile
0x9f, // Feraligatr evolves from Croconaw
0x0, // Sentret is a base evolution
0xa1, // Furret evolves from Sentret
0x0, // Hoothoot is a base evolution
0xa3, // Noctowl evolves from Hoothoot
0x0, // Ledyba is a base evolution
0xa5, // Ledian evolves from Ledyba
0x0, // Spinarak is a base evolution
0xa7, // Ariados evolves from Spinarak
0x2a, // Crobat evolves from Golbat
0x0, // Chinchou is a base evolution
0xaa, // Lanturn evolves from Chinchou
0x0, // Pichu is a base evolution
0x0, // Cleffa is a base evolution
0x0, // Igglybuff is a base evolution
0x0, // Togepi is a base evolution
0xaf, // Togetic evolves from Togepi
0x0, // Natu is a base evolution
0xb1, // Xatu evolves from Natu
0x0, // Mareep is a base evolution
0xb3, // Flaaffy evolves from Mareep
0xb4, // Ampharos evolves from Flaaffy
0x2c, // Bellossom evolves from Gloom
0x0, // Marill is a base evolution (in gen 2)
0xb7, // Azumarill evolves from Marill
0x0, // Sudowoodo is a base evolution (in gen 2)
0x3d, // Politoed evolves from Poliwhirl
0x0, // Hoppip is a base evolution
0xbb, // Skiploom evolves from Hoppip
0xbc, // Jumpluff evolves from Skiploom
0x0, // Aipom is a base evolution
0x0, // Sunkern is a base evolution
0xbf, // Sunflora evolves from Sunkern
0x0, // Yanma is a base evolution
0x0, // Wooper is a base evolution
0xc2, // Quagsire evolves from Wooper
0x85, // Espeon evolves from Eevee
0x85, // Umbreon evolves from Eevee
0x0, // Murkrow is a base evolution
0x4f, // Slowking evolves from Slowpoke
0x0, // Misdreavus is a base evolution
0x0, // Unown is a base evolution
0x0, // Wobbuffet is a base evolution (in gen 2)
0x0, // Girafarig is a base evolution
0x0, // Pineco is a base evolution
0xcc, // Forretress evolves from Pineco
0x0, // Dunsparce is a base evolution
0x0, // Gligar is a base evolution
0x5f, // Steelix evolves from Onix
0x0, // Snubbull is a base evolution
0xd1, // Granbull evolves from Snubbull
0x0, // Qwilfish is a base evolution
0x7b, // Scizor evolves from Scyther
0x0, // Shuckle is a base evolution
0x0, // Heracross is a base evolution
0x0, // Sneasel is a base evolution
0x0, // Teddiursa is a base evolution
0xd8, // Ursaring evolves from Teddiursa
0x0, // Slugma is a base evolution
0xda, // Magcargo evolves from Slugma
0x0, // Swinub is a base evolution
0xdc, // Piloswine evolves from Swinub
0x0, // Corsola is a base evolution
0x0, // Remoraid is a base evolution
0xdf, // Octillery evolves from Remoraid
0x0, // Delibird is a base evolution
0x0, // Mantine is a base evolution (in gen 2)
0x0, // Skarmory is a base evolution
0x0, // Houndour is a base evolution
0xe4, // Houndoom evolves from Houndour
0x75, // Kingdra evolves from Seadra
0x0, // Phanpy is a base evolution
0xe7, // Donphan evolves from Phanpy
0x89, // Porygon2 evolves from Porygon
0x0, // Stantler is a base evolution
0x0, // Smeargle is a base evolution
0x0, // Tyrogue is a base evolution
0xec, // Hitmontop evolves from Tyrogue
0x0, // Smoochum is a base evolution
0x0, // Elekid is a base evolution
0x0, // Magby is a base evolution
0x0, // Miltank is a base evolution
0x71, // Blissey evolves from Chansey
0x0, // Raikou is a base evolution
0x0, // Entei is a base evolution
0x0, // Suicune is a base evolution
0x0, // Larvitar is a base evolution
0xf6, // Pupitar evolves from Larvitar
0xf7, // Tyranitar evolves from Pupitar
0x0, // Lugia is a base evolution
0x0, // Ho-oh is a base evolution
0x0, // Celebi is a base evolution
0x0, // Treecko is a base evolution
};
static void deduplicate_bits_across_evolutions(u8 *output_buffer, const u8 *input_buffer)
{
const u8 *cur_input = input_buffer;
const u8 ROWSIZE = 32;
u8 base_moveset[ROWSIZE];
u8 evolution;
u8 i, j;
for(i=0; i < POKEMON_ARRAY_SIZE; ++i)
{
evolution = EVOLUTIONS[i];
if(evolution == 0)
{
memcpy(output_buffer, cur_input, ROWSIZE);
}
else
{
memcpy(base_moveset, input_buffer + (evolution * ROWSIZE), ROWSIZE);
// combine moveset of all base forms before comparing with our current moveset
// at most 2 base forms in gen I or gen II
evolution = EVOLUTIONS[evolution];
if(evolution)
{
for(j = 0; j < ROWSIZE; ++j)
{
base_moveset[j] |= input_buffer[evolution * ROWSIZE + j];
}
}
// we want to set the resulting bit to 0 if it already was zero or if the basemoveset and current moveset both have 1
// if only the current moveset is set to 1, it should be 1.
// This looks like a XOR operation is appropriate.
// technically a side-effect would be that if the base set has it set to 1 and the current moveset doesn't, that it will end up
// being a 1. But I don't think that's a valid scenario, especially because can_learn_move() in PTGB already OR'ed
// the results of evolution + bases together.
for (j = 0; j < ROWSIZE; ++j)
{
output_buffer[j] = cur_input[j] ^ base_moveset[j];
}
}
output_buffer += ROWSIZE;
cur_input += ROWSIZE;
}
}
static u16 deduplicate_rows(u8 *output_buffer, const u8 *input_buffer)
{
u16 num_unique_rows;
u8 *row_index = output_buffer;
u8 *row_space = output_buffer + POKEMON_ARRAY_SIZE;
const u8 ROWSIZE = 32;
u8 i;
int16_t j;
bool found;
// first row is all zeros
memcpy(row_space, input_buffer, ROWSIZE);
row_index[0] = 0;
num_unique_rows = 1;
for(i = 1; i < POKEMON_ARRAY_SIZE; ++i)
{
found = false;
for(j = num_unique_rows - 1; j >= 0; --j)
{
if(!memcmp(row_space + (j * ROWSIZE), input_buffer + (i * ROWSIZE), ROWSIZE))
{
// matching entry found in previous rows. store a reference to it in the row index
row_index[i] = static_cast<uint8_t>(j);
found = true;
break;
}
}
if(!found)
{
// no matching entry found in previous rows (which means this is a unique entry up until now)
// insert the current entry into the resulting table and
memcpy(row_space + (num_unique_rows * ROWSIZE), input_buffer + (i * ROWSIZE), ROWSIZE);
row_index[i] = num_unique_rows;
++num_unique_rows;
}
}
return num_unique_rows;
}
#include <cstdio>
void check_unique_rows(const u8 *input_buffer)
{
uint8_t unique_rows = 0;
const u8 *cur;
const u8 *row;
bool foundMatch;
for(uint8_t i=0; i < POKEMON_ARRAY_SIZE; ++i)
{
cur = input_buffer + (i * 32);
row = input_buffer;
foundMatch = false;
while(row < input_buffer + POKEMON_ARRAY_SIZE * 32)
{
if(row == cur)
{
row += 32;
continue;
}
if(!memcmp(cur, row, 32))
{
foundMatch = true;
break;
}
row += 32;
}
if(!foundMatch)
{
++unique_rows;
}
}
//printf("Unique rows: %hhu\n", unique_rows);
}
/**
* This function is similar to the original implementation in PTGB's pokemon_data.cpp
* But it is used to test for differences between the optimized MOVESETS table and the unoptimized one.
*/
static bool can_learn_move(const u8* movesets_table, int pkmn_index, int move_index)
{
u16 table_index = pkmn_index * 32 + (move_index / 8);
byte data_byte = movesets_table[table_index];
table_index = EVOLUTIONS[pkmn_index] * 32 + (move_index / 8);
data_byte |= movesets_table[table_index]; // add in the previous evolution's moves (if they exist)
table_index = EVOLUTIONS[EVOLUTIONS[pkmn_index]] * 32 + (move_index / 8);
data_byte |= movesets_table[table_index]; // add in the first evolution's moves (if they exist)
return (data_byte >> (7 - (move_index % 8))) & 0x1;
}
optimize_moveset_result optimize_movesets(u8 *output_buffer, const u8 *input_buffer, u16 input_buffer_size)
{
optimize_moveset_result result = {0, 0};
u8 work_buffer[MOVESETS_size];
if(input_buffer_size % 32)
{
// invalid input buffer. Must be divisible by 32 bytes!
return result;
}
deduplicate_bits_across_evolutions(output_buffer, input_buffer);
check_unique_rows(output_buffer);
result.num_bytes = input_buffer_size;
#if 0
// test optimized table
bool problem_found = false;
for(u16 i=0; i < POKEMON_ARRAY_SIZE; ++i)
{
for(u16 move = 0; move < 256; ++move)
{
if(can_learn_move((const uint8_t*)MOVESETS, i, move) != can_learn_move(output_buffer, i, move))
{
printf("ERROR: optimized MOVESETS differs at pkmn %hu, move %hhu!\n", i, move);
problem_found = true;
}
}
}
if(problem_found)
{
printf("ERROR: one or more issues detected in the optimized MOVESETS table\n");
}
else
{
printf("INFO: no problems found in the optimized MOVESETS table!\n");
}
#endif
//deduplicate_bits_across_evolutions(work_buffer, input_buffer);
//check_unique_rows(work_buffer);
//result.num_unique_rows = deduplicate_rows(output_buffer, work_buffer);
//result.num_bytes = NUM_POKEMON + (result.num_unique_rows * 32);
return result;
}

View File

@ -1,12 +1,8 @@
#include "pokemon_data.h"
#include "common.h"
#include "optimize_movesets.h"
typedef unsigned char u8;
typedef unsigned char byte;
typedef unsigned short u16;
#define NUM_POKEMON 252
#define POKEMON_ARRAY_SIZE NUM_POKEMON + 1
#include <cstdio>
const u16 gen_1_charsets[4][256] {
// gen_1_Jpn_char_array
@ -3630,6 +3626,9 @@ const byte MOVESETS[POKEMON_ARRAY_SIZE][32] = {
{0b00000000, 0b00000011, 0b00000000, 0b00000000, 0b00000010, 0b00000000, 0b00000000, 0b00000001, 0b00000000, 0b01001000, 0b00000000, 0b00001110, 0b00000010, 0b11000001, 0b01010010, 0b00000000, 0b01000000, 0b00100000, 0b00001000, 0b00001000, 0b00001000, 0b00000100, 0b00000010, 0b00000100, 0b00010000, 0b01110001, 0b00000011, 0b10110000, 0b00100000, 0b00000100, 0b11001011, 0b10000000}, // Celebi
{0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000010, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000}, // Treecko
};
extern const size_t MOVESETS_size = sizeof(MOVESETS);
const byte FIRST_MOVES[POKEMON_ARRAY_SIZE] = {
// Data obtained through PokeAPI
0, // Offset the list to remove "off by one" errors
@ -4966,13 +4965,19 @@ const u8 TYPES[POKEMON_ARRAY_SIZE][2]{
void generate_pokemon_data()
{
u8 optimized_movesets[MOVESETS_size];
// printf("Optimizing movesets table...");
optimize_moveset_result optimize_moveset_status = optimize_movesets(optimized_movesets, (const uint8_t*)(MOVESETS), MOVESETS_size);
// printf("done!\n\t-> unique rows: %hu, bytes: %hu\n", optimize_moveset_status.num_unique_rows, optimize_moveset_status.num_bytes);
writeTable("gen_1_charsets.bin", (const uint8_t*)gen_1_charsets, sizeof(gen_1_charsets));
writeTable("gen_2_charsets.bin", (const uint8_t*)gen_2_charsets, sizeof(gen_2_charsets));
writeTable("gen_3_charsets.bin", (const uint8_t*)gen_3_charsets, sizeof(gen_3_charsets));
writeTable("EXP_GROUPS.bin", EXP_GROUPS, sizeof(EXP_GROUPS));
writeTable("GENDER_RATIO.bin", GENDER_RATIO, sizeof(GENDER_RATIO));
writeTable("NUM_ABILITIES.bin", (const uint8_t*)(NUM_ABILITIES), sizeof(NUM_ABILITIES));
writeTable("MOVESETS.bin", (const uint8_t*)(MOVESETS), sizeof(MOVESETS));
// writeTable("MOVESETS.bin", (const uint8_t*)(MOVESETS), sizeof(MOVESETS));
writeTable("MOVESETS.bin", optimized_movesets, optimize_moveset_status.num_bytes);
writeTable("FIRST_MOVES.bin", FIRST_MOVES, sizeof(FIRST_MOVES));
writeTable("JPN_NAMES.bin", (const uint8_t*)JPN_NAMES, sizeof(JPN_NAMES));
writeTable("POWER_POINTS.bin", POWER_POINTS, sizeof(POWER_POINTS));