Poke_Transporter_GB/source/pokemon.cpp
Philippe Symons 4c93ff869c 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!)
2025-04-29 22:22:38 +02:00

1005 lines
31 KiB
C++

#include <tonc.h>
#include "libstd_replacements.h"
#include "pokemon.h"
#include "pokemon_data.h"
#include "random.h"
#include "save_data_manager.h"
#include "debug_mode.h"
#include "text_engine.h"
#include "zx0_decompressor.h"
#include "JPN_NAMES_zx0_bin.h"
Pokemon::Pokemon() {};
// TODO: Rewrite this with two different classes/structs that have arrays as input/output
// GBpkmn and GBApkmn
// A lot of the event Pokemon script is reused. Really should be split into many different functions
// Endian-ness too is all over the place... :/
void Pokemon::load_data(int index, const byte *party_data, int game, int lang)
{
language = lang;
if (lang == JPN_ID)
{
switch (game)
{
case GREEN_ID:
case RED_ID:
case BLUE_ID:
case YELLOW_ID:
gen = 1;
pkmn_size = 44;
ot_size = 6;
nickname_size = 6;
box_size = 30;
break;
case GOLD_ID:
case SILVER_ID:
case CRYSTAL_ID:
gen = 2;
pkmn_size = 32;
ot_size = 6;
nickname_size = 6;
box_size = 30;
break;
}
}
else
{
switch (game)
{
case RED_ID:
case BLUE_ID:
case YELLOW_ID:
gen = 1;
pkmn_size = 33;
ot_size = 11;
nickname_size = 11;
box_size = 20;
break;
case GOLD_ID:
case SILVER_ID:
case CRYSTAL_ID:
gen = 2;
pkmn_size = 32;
ot_size = 11;
nickname_size = 11;
box_size = 20;
break;
}
}
int party_species_offset =
1 + // the num pkmn byte
(1 * index); // the pkmn index we're looking for
int box_struct_offset =
1 + // the num of pkmn byte
(1 * box_size) + 1 + // list of pkmn in box and terminator
(pkmn_size * index); // the pokemon we're looking for
int ot_offset =
1 + // the num of pkmn byte
(1 * box_size) + 1 + // list of pkmn in box and terminator
(pkmn_size * box_size) + // the pokemon structs
(ot_size * index); // the ot we're looking for
int nickname_offset =
1 + // the num of pkmn byte
(1 * box_size) + 1 + // list of pkmn in box and terminator
(pkmn_size * box_size) + // the pokemon structs
(ot_size * box_size) + // the ots
(nickname_size * index); // the nickname we're looking for
num_in_box = party_data[0];
index_in_box = index;
switch (gen)
{
case 1:
// ptgb_write(ptgb::to_string(party_data[1121]));
// while (true){};
species_index_party = party_data[party_species_offset];
species_index_struct = party_data[box_struct_offset + 0x00];
met_level = party_data[box_struct_offset + 0x03];
copy_from_to(&party_data[box_struct_offset + 0x08], &moves[0], 4, false);
copy_from_to(&party_data[box_struct_offset + 0x0C], &trainer_id[0], 2, false);
exp = 0;
for (int i = 0; i < 3; i++)
{
exp += party_data[box_struct_offset + 0x0E + i];
}
copy_from_to(&party_data[box_struct_offset + 0x1B], &dvs[0], 2, false);
copy_from_to(&party_data[box_struct_offset + 0x1D], &pp_values[0], 4, false);
copy_from_to(&party_data[nickname_offset], &nickname[0], 10, false);
copy_from_to(&party_data[ot_offset], &trainer_name[0], 7, false);
// Data not in gen 1
pokerus = 0x00;
caught_data[0] = 0x00;
caught_data[1] = 0x00;
item = 0;
break;
case 2:
species_index_party = party_data[party_species_offset];
species_index_struct = party_data[box_struct_offset + 0x00];
item = party_data[box_struct_offset + 0x01];
copy_from_to(&party_data[box_struct_offset + 0x02], &moves[0], 4, false);
copy_from_to(&party_data[box_struct_offset + 0x06], &trainer_id[0], 2, false);
exp = 0;
for (int i = 0; i < 3; i++)
{
exp += party_data[box_struct_offset + 0x08 + i] << (8 * (2 - i));
}
copy_from_to(&party_data[box_struct_offset + 0x15], &dvs[0], 2, false);
copy_from_to(&party_data[box_struct_offset + 0x17], &pp_values[0], 4, false);
pokerus = party_data[box_struct_offset + 0x1C];
copy_from_to(&party_data[box_struct_offset + 0x1D], &caught_data[0], 2, false);
met_level = party_data[box_struct_offset + 0x1F];
copy_from_to(&party_data[nickname_offset], &nickname[0], 10, false);
copy_from_to(&party_data[ot_offset + 0x00], &trainer_name[0], 7, false);
break;
}
// box_struct_offset = 0;
if (SHOW_DATA_PACKETS)
{
tte_set_pos(8, 120);
ptgb_write("struct offset: ");
ptgb_write(ptgb::to_string(box_struct_offset));
ptgb_write("\nbox_size: ");
ptgb_write(ptgb::to_string(box_size));
ptgb_write("\npkmn_size: ");
ptgb_write(ptgb::to_string(pkmn_size));
ptgb_write("\nindex: ");
ptgb_write(ptgb::to_string(index));
ptgb_write(", game: ");
ptgb_write(ptgb::to_string(game));
while (!key_hit(KEY_A))
{
global_next_frame();
}
global_next_frame();
}
}
void Pokemon::convert_to_gen_three(PokemonTables& data_tables, bool simplified, bool stabilize_mythical)
{
// Convert the species indexes
if (gen == 1)
{
if (species_index_struct > 190)
{
species_index_struct = 0;
}
else
{
species_index_struct = gen_1_index_array[species_index_struct];
if (species_index_struct == 0xFF)
{
is_missingno = true;
species_index_struct = 0x89; // Porygon
}
}
species_index_party = species_index_struct;
}
if ( // index_in_box % 4 == 0 ||
(species_index_struct > NUM_POKEMON - (get_treecko_enabled() ? 0 : 1)) || // Checks if the Pokemon is beyond the supported Pokemon
species_index_struct == 0 || // Checks that the Pokemon isn't a blank party space
species_index_struct != species_index_party || // Checks that the Pokemon isn't a hybrid or an egg
index_in_box >= num_in_box || // Checks that we're not reading beyond the Pokemon in the box
item != 0) // Checks that the Pokemon doesn't have an item
{
if (!DONT_HIDE_INVALID_PKMN)
{
is_valid = false;
return;
}
}
is_valid = true;
nature_mod = exp % 25; // save the nature mod in case the level is changed
// Update dex if not simple
if (!simplified && !is_caught(species_index_struct))
{
is_new = true;
set_caught(species_index_struct);
}
// Set nickname
if (language == KOR_ID)
{
u16 JPN_NAMES[POKEMON_ARRAY_SIZE * 6];
gen_3_pkmn[18] = JPN_ID; // Set to JPN
byte new_nickname[10];
byte new_ot[7];
u16 cur_char;
data_tables.load_gen3_charset(language);
// setup the zx0 decompressor to decompress the JPN_NAMES table
zx0_decompressor_start((u8*)JPN_NAMES, JPN_NAMES_zx0_bin);
zx0_decompressor_read(zx0_decompressor_get_decompressed_size());
for (int i = 0; i < 6; i++)
{ // Read the JPN name and convert it
cur_char = JPN_NAMES[species_index_struct * 6];
new_nickname[i] = data_tables.get_gen_3_char(cur_char);
}
if (gen == 1)
{
// レッド (Red)
new_ot[0] = 0x7A; // レ
new_ot[1] = 0xA0; // ッ
new_ot[2] = 0x95; // ド
new_ot[3] = 0xFF;
}
else
{
if (((caught_data[1] & 0b10000000) >> 7) == 1) // Checks if the Gen 2 player is male or female
{
// クリス (Kurisu)
new_ot[0] = 0x58; // ク
new_ot[1] = 0x78; // リ
new_ot[2] = 0x5D; // ス
new_ot[3] = 0xFF;
}
else
{
// ヒビキ (Hibiki)
new_ot[0] = 0x6B; // ヒ
new_ot[1] = 0x97; // ビ
new_ot[2] = 0x57; // キ
new_ot[3] = 0xFF;
}
}
copy_from_to(&new_nickname[0], &gen_3_pkmn[8], 10, false); // Nickname
copy_from_to(&new_ot[0], &gen_3_pkmn[20], 7, false); // OT Name
}
else
{
gen_3_pkmn[18] = language; // Language
data_tables.load_input_charset(gen, language);
data_tables.load_gen3_charset(language);
copy_from_to(convert_text(data_tables, &nickname[0], 10), &gen_3_pkmn[8], 10, false); // Nickname
copy_from_to(convert_text(data_tables, &trainer_name[0], 7), &gen_3_pkmn[20], 7, false); // OT Name
}
// Make sure Level is not over 100 based on EXP
u32 max_exp = data_tables.get_max_exp(species_index_struct);
if (exp > max_exp)
{
exp = max_exp;
}
// Check if shiny
is_shiny =
((dvs[1] == 0b10101010) && // Checks if the Speed and Special DVs equal 10
((dvs[0] & 0xF) == 0b1010) && // Checks if the Defense DVs equal 10
((dvs[0] & 0b00100000) >> 5)); // Checks if the second bit of the Attack DV is true
if (species_index_struct == 52 &&
fnv1a_hash(nickname, 7) == 1515822901 &&
fnv1a_hash(trainer_name, 7) == 1342961308)
{
is_shiny = true;
dvs[0] = 0xFF;
dvs[1] = 0xFF;
}
if (species_index_struct == 201) // Checks if the Pokemon is Unown
{
unown_letter = 0;
unown_letter |= ((dvs[0] >> 5) & 0b11) << 6;
unown_letter |= ((dvs[0] >> 1) & 0b11) << 4;
unown_letter |= ((dvs[1] >> 5) & 0b11) << 2;
unown_letter |= ((dvs[1] >> 1) & 0b11);
unown_letter = unown_letter / 10;
}
else
{
unown_letter = -1;
}
if (simplified)
{
if ((species_index_struct == 151 || species_index_struct == 251) && exp < 560) // Minimum EXP for level 10
{
met_level = 10;
}
return;
}
// Separate the PP Up values from the Move PP values
for (int i = 0; i < 4; i++)
{
pure_pp_values[i] = (pp_values[i] & 0b00111111); // Take only the bottom six bits
pp_bonus[i] = (pp_values[i] >> 6); // Take only the top two bits
}
// Check that the moves are valid
if (is_missingno)
{
moves[0] = 55; // Water Gun
moves[1] = 143; // Sky Attack
moves[2] = 6; // Pay Day
moves[3] = 20; // Bind
for (int i = 0; i < 4; i++)
{
pp_bonus[i] = 0;
}
}
else if ((species_index_struct != 0xEB) && (species_index_struct != 0xFC)) // Ignore Smeargle due to Sketch, Ignore Treecko because Treecko
{
for (int i = 0; i < 4; i++)
{
if ((!data_tables.can_learn_move(species_index_struct, moves[i])) && (moves[i] != 0))
{
moves[i] = 0; // Remove the move
pp_bonus[i] = 0; // Remove the PP bonus
}
}
}
// Make sure it has at least one move
if (moves[0] + moves[1] + moves[2] + moves[3] == 0)
{
moves[0] = data_tables.get_earliest_move(species_index_struct);
}
// Bubble valid moves to the top
int i, j;
bool swapped;
for (i = 0; i < 3; i++)
{
swapped = false;
for (j = 0; j < 3 - i; j++)
{
if ((moves[j] < moves[j + 1]) && moves[j] == 0)
{
// Move the move *and* PP bonus up if there is a blank space
moves[j] = moves[j + 1];
pp_bonus[j] = pp_bonus[j + 1];
moves[j + 1] = 0;
pp_bonus[j + 1] = 0;
swapped = true;
}
}
// If no two elements were swapped
// by inner loop, then break
if (swapped == false)
break;
}
// Restore the PP values
data_tables.load_power_points();
for (int i = 0; i < 4; i++)
{
pure_pp_values[i] = data_tables.POWER_POINTS[moves[i]] + ((data_tables.POWER_POINTS[moves[i]] / 5) * pp_bonus[i]);
}
// This is everything the mythical needs, don't change anything else
if (stabilize_mythical && (species_index_struct == 151 || species_index_struct == 251))
{
set_to_event(data_tables, nature_mod);
return;
}
// Generate PID
disable_auto_random();
u32 n_pid;
if (ENABLE_MATCH_PID)
{
n_pid = generate_pid_iv_match(data_tables, species_index_struct, nature_mod, &dvs[0]);
u16 curr_rand = get_rand_u16();
ivs[0] = (curr_rand >> 0) & 0b11111;
ivs[1] = (curr_rand >> 5) & 0b11111;
ivs[2] = (curr_rand >> 10) & 0b11111;
curr_rand = get_rand_u16();
ivs[3] = (curr_rand >> 0) & 0b11111;
ivs[4] = (curr_rand >> 5) & 0b11111;
ivs[5] = (curr_rand >> 10) & 0b11111;
iv_egg_ability = 0;
for (int i = 0; i < 6; i++)
{
iv_egg_ability |= ((ivs[i] & 0b11111) << (i * 5));
}
}
else
{
n_pid = generate_pid_save_iv(data_tables, species_index_struct, nature_mod, &dvs[0]);
// Convert and set IVs
int hp_iv = 0;
for (int i = 0; i < 4; i++)
{
ivs[i + 1] = (dvs[i / 2] >> (((i + 1) % 2) * 4)) & 0b1111;
hp_iv |= ((ivs[i + 1] & 0x1) << i);
};
ivs[0] = hp_iv;
ivs[5] = ivs[4];
for (int i = 0; i < 6; i++)
{
ivs[i] = (ivs[i] * 2) + 1;
iv_egg_ability |= ((ivs[i] & 0b11111) << (i * 5));
}
}
for (int i = 0; i < 4; i++)
{
pid[i] = (n_pid >> (i * 8)) & 0xFF;
}
enable_auto_random();
// Determine and set Ability
iv_egg_ability |= ((pid[0] & 0x1) ? data_tables.get_num_abilities(species_index_struct) : 0) << 31;
// Origin info
origin_info |= ((caught_data[1] & 0b10000000) << 8); // OT gender - We would shift left 15 bits, but the bit is already shifted over 7
if (is_missingno)
{
origin_info |= (1 << 11); // Master Ball
}
else
{
origin_info |= (4 << 11); // Ball
}
origin_info |= (((gen == 1) ? 4 : 7) << 7); // Game
origin_info |= met_level; // Level met
// Ribbons and Obedience
// ribbons[2] |= 0b00000100; // Artist Ribbon
if (species_index_struct == 151 || species_index_struct == 251) // Pokemon is Mew or Celebi
{
ribbons[3] |= 0b10000000; // Fateful Encounter flag
}
else if (is_missingno)
{
ribbons[3] |= 0b10000000; // Fateful Encounter flag
// ribbons[3] |= 0b00000100; // World Ribbon
}
// Personality Value
copy_from_to(&pid[0], &gen_3_pkmn[0], 4, false);
// Trainer ID
copy_from_to(&trainer_id[0], &gen_3_pkmn[4], 2, true);
// Check if the Pokemon is shiny
if (is_shiny)
{
secret_id[0] = trainer_id[1] ^ pid[0] ^ pid[2] ^ 0x0; // This value at the end should be random between 0 - 15, if that is to be implemented
secret_id[1] = trainer_id[0] ^ pid[1] ^ pid[3] ^ 0x0;
// Randomly shift by 16 (maybe)
}
else // Not shiny, make sure it isn't
{
secret_id[0] = dvs[0];
secret_id[1] = dvs[1];
if (((trainer_id[0] ^ secret_id[0] ^ pid[0] ^ pid[2]) == 0) &&
((trainer_id[1] ^ secret_id[1] ^ pid[1] ^ pid[3]) < 8))
{
secret_id[1] += 8;
}
}
copy_from_to(&secret_id[0], &gen_3_pkmn[6], 2, false); // Set SID
gen_3_pkmn[19] = 0b00000010; // Egg Name (has species sanity flag)
gen_3_pkmn[27] = 0b00000000; // Markings
// Data:
// Reset the data sections (in case the player runs the program twice)
for (int i = 0; i < 12; i++)
{
data_section_G[i] = 0;
data_section_A[i] = 0;
data_section_E[i] = 0;
data_section_M[i] = 0;
}
data_section_G[0] = (species_index_struct != 252 ? species_index_struct : 277); // Treecko check
data_section_G[1] = (species_index_struct != 252 ? 0x00 : 0x01); // Treecko check;
data_section_G[2] = (is_new ? 0x44 : 0x00); // Rare Candy if new
data_section_G[3] = 0x00;
for (int i = 0; i < 3; i++)
{
data_section_G[4 + i] = exp >> (8 * i);
}
data_section_G[8] = (pp_bonus[0] << 0 | pp_bonus[1] << 2 | pp_bonus[2] << 4 | pp_bonus[3] << 6);
data_section_A[0] = moves[0]; // Move 1
data_section_A[2] = moves[1]; // Move 2
data_section_A[4] = moves[2]; // Move 3
data_section_A[6] = moves[3]; // Move 4
copy_from_to(&pure_pp_values[0], &data_section_A[8], 4, false); // PP Values
// Data section E is all zero (EVs and Contest Stats)
data_section_M[0] = pokerus;
data_section_M[1] = 0xFF; // Met location - set to Fateful Encounter (separate from flag), is replaced by Pal Park in gen 4
data_section_M[2] = origin_info & 0x00FF; // Lower origins info
data_section_M[3] = (origin_info >> 8) & 0xFF; // Upper origins info
for (int i = 0; i < 4; i++)
{
data_section_M[i + 4] = (iv_egg_ability >> (i * 8) & 0xFF); // Set IVs, Egg, and Ability
}
copy_from_to(&ribbons[0], &data_section_M[8], 4, false); // Ribbons and Fateful Encounter
// Checksum:
checksum = 0x0000;
for (int i = 0; i < 12; i = i + 2)
{
checksum = checksum + ((data_section_G[i + 1] << 8) | data_section_G[i]);
checksum = checksum + ((data_section_A[i + 1] << 8) | data_section_A[i]);
checksum = checksum + ((data_section_E[i + 1] << 8) | data_section_E[i]);
checksum = checksum + ((data_section_M[i + 1] << 8) | data_section_M[i]);
}
gen_3_pkmn[28] = checksum & 0xFF;
gen_3_pkmn[29] = (checksum & 0xFF00) >> 8;
for (int i = 0; i < 4; i++)
{
encryption_key[i] = gen_3_pkmn[4 + i] ^ pid[i]; // XOR SID and TID with PID
}
for (int i = 0; i < 12; i++)
{
unencrypted_data[i] = data_section_G[i];
data_section_G[i] ^= encryption_key[i % 4];
unencrypted_data[12 + i] = data_section_A[i];
data_section_A[i] ^= encryption_key[i % 4];
unencrypted_data[24 + i] = data_section_E[i];
data_section_E[i] ^= encryption_key[i % 4];
unencrypted_data[36 + i] = data_section_M[i];
data_section_M[i] ^= encryption_key[i % 4];
}
// Puts the four data chunks into their correct locations based on the PID
alocate_data_chunks(data_section_G, data_section_A, data_section_E, data_section_M);
global_next_frame();
}
void Pokemon::copy_from_to(const byte *source, byte *destination, int size, bool reverse_endian)
{
if (reverse_endian)
{
for (int i = 0; i < size; i++)
{
destination[(size - 1) - i] = source[i];
}
}
else
{
for (int i = 0; i < size; i++)
{
destination[i] = source[i];
}
}
}
void Pokemon::alocate_data_chunks(byte *G, byte *A, byte *E, byte *M)
{
word full_pid = (pid[3] << 24 | pid[2] << 16 | pid[1] << 8 | pid[0]);
byte mod_pid = full_pid % 24;
unencrypted_data[48] = mod_pid;
// This is such a stupid way to do this, but I can't for the life of me find a formula for the permutation table.
switch (mod_pid)
{
case 0:
insert_data(G, A, E, M);
break;
case 1:
insert_data(G, A, M, E);
break;
case 2:
insert_data(G, E, A, M);
break;
case 3:
insert_data(G, E, M, A);
break;
case 4:
insert_data(G, M, A, E);
break;
case 5:
insert_data(G, M, E, A);
break;
case 6:
insert_data(A, G, E, M);
break;
case 7:
insert_data(A, G, M, E);
break;
case 8:
insert_data(A, E, G, M);
break;
case 9:
insert_data(A, E, M, G);
break;
case 10:
insert_data(A, M, G, E);
break;
case 11:
insert_data(A, M, E, G);
break;
case 12:
insert_data(E, G, A, M);
break;
case 13:
insert_data(E, G, M, A);
break;
case 14:
insert_data(E, A, G, M);
break;
case 15:
insert_data(E, A, M, G);
break;
case 16:
insert_data(E, M, G, A);
break;
case 17:
insert_data(E, M, A, G);
break;
case 18:
insert_data(M, G, A, E);
break;
case 19:
insert_data(M, G, E, A);
break;
case 20:
insert_data(M, A, G, E);
break;
case 21:
insert_data(M, A, E, G);
break;
case 22:
insert_data(M, E, G, A);
break;
case 23:
insert_data(M, E, A, G);
break;
}
}
void Pokemon::insert_data(byte *first, byte *second, byte *third, byte *fourth)
{
copy_from_to(&first[0], &gen_3_pkmn[32], 12, false);
copy_from_to(&second[0], &gen_3_pkmn[44], 12, false);
copy_from_to(&third[0], &gen_3_pkmn[56], 12, false);
copy_from_to(&fourth[0], &gen_3_pkmn[68], 12, false);
}
byte Pokemon::get_gen_3_data(int index)
{
return gen_3_pkmn[index];
}
byte *Pokemon::get_full_gen_3_array()
{
return gen_3_pkmn;
}
byte Pokemon::get_unencrypted_data(int index)
{
return unencrypted_data[index];
}
byte *Pokemon::convert_text(PokemonTables& data_tables, byte *text_array, int size)
{
for (int i = 0; i < size; i++)
{
text_array[i] = data_tables.get_gen_3_char(data_tables.input_charset[text_array[i]]);
}
return text_array;
}
u32 Pokemon::generate_pid_iv_match(PokemonTables& data_tables, byte pid_species_index, byte nature, byte *pid_dvs)
{
u32 new_pid = 0;
byte new_nature = 0;
byte new_gender = 0;
byte new_letter = 0;
int gen2_gender_threshold = data_tables.get_gender_threshold(pid_species_index, false);
int gen3_gender_threshold = data_tables.get_gender_threshold(pid_species_index, true);
bool gender = (((pid_dvs[0] >> 4) & 0b1111) < gen2_gender_threshold);
do
{
new_pid = get_rand_u16() | (get_rand_u16() << 16);
new_nature = get_nature_from_pid(new_pid);
new_gender = get_gender_from_pid(new_pid);
new_letter = get_letter_from_pid(new_pid);
} while (!(
(unown_letter != -1 ? new_letter == unown_letter : true) &&
new_nature == nature &&
(gen2_gender_threshold != -1
? ((new_gender < gen3_gender_threshold) == gender)
: true)));
return new_pid;
}
u8 Pokemon::get_letter_from_pid(u32 pid)
{
return (
((pid & 0x03000000) >> 18) +
((pid & 0x00030000) >> 12) +
((pid & 0x00000300) >> 6) +
((pid & 0x00000003) >> 0)) %
28;
};
u8 Pokemon::get_nature_from_pid(u32 pid)
{
return (pid % 25);
};
u8 Pokemon::get_gender_from_pid(u32 pid)
{
return (pid & 0xFF);
};
u32 Pokemon::generate_pid_save_iv(PokemonTables &data_tables, byte pid_species_index, byte nature, byte *pid_dvs)
{
// Set Unown Letter
u32 new_pid = 0;
if (pid_species_index == 0xC9) // Checks if the Pokemon is Unown
{
byte letter_mod = rand_reverse_mod(28, unown_letter);
for (int i = 0; i < 4; i++)
{
new_pid |= ((letter_mod >> (i * 2)) & 0b11) << (8 * i);
}
// Randomize rest of PID
new_pid |= get_rand_u32() & 0xFCFCFCFC;
// Set Nature
while ((new_pid % 25) != nature)
{
// Keep adding 0b100 to the PID until the nature matches
// 0b100 ensures that the 2 LSBs are maintained, as they determine the letter
new_pid = (new_pid & 0xFFFFFF00) | ((new_pid + 0b100) & 0xFF);
}
return new_pid;
}
else
{
// Set the correct gender for the Pokemon
new_pid |= get_rand_gender_byte(data_tables, pid_species_index, ((pid_dvs[0] >> 4) & 0b1111));
// Randomize rest of PID
new_pid |= get_rand_u32() & 0xFFFFFF00;
// Set nature
while (new_pid % 25 != nature)
{
new_pid = new_pid + 256;
}
return new_pid;
}
}
byte Pokemon::rand_reverse_mod(byte modulo_divisor, byte target_mod)
{
return (modulo_divisor * get_rand_range(0, (255 - target_mod) / modulo_divisor)) + target_mod;
}
byte Pokemon::get_rand_gender_byte(PokemonTables &data_tables, byte index_num, byte attack_DVs)
{
byte gen2_threshold = data_tables.get_gender_threshold(index_num, false);
byte gen3_threshold = data_tables.get_gender_threshold(index_num, true);
if (gen2_threshold == -1) // Is one gender or is genderless
{
return get_rand_range(0, 256);
}
else if (attack_DVs < gen2_threshold) // Is Female
{
return get_rand_range(0, gen3_threshold);
}
else // Is Male
{
return get_rand_range(gen3_threshold, 256);
}
}
byte Pokemon::get_dex_number()
{
return (is_valid ? species_index_struct : 0);
}
bool Pokemon::get_validity()
{
return is_valid;
}
bool Pokemon::get_is_shiny()
{
return is_shiny;
}
bool Pokemon::get_is_new()
{
return (is_valid ? is_new : false);
}
Simplified_Pokemon Pokemon::get_simple_pkmn()
{
Simplified_Pokemon curr_pkmn;
curr_pkmn.dex_number = get_dex_number();
curr_pkmn.met_level = met_level;
for (int i = 0; i < 10; i++)
{
curr_pkmn.nickname[i] = nickname[i];
}
curr_pkmn.is_valid = get_validity();
curr_pkmn.is_transferred = false;
curr_pkmn.is_shiny = get_is_shiny();
curr_pkmn.unown_letter = unown_letter;
curr_pkmn.is_missingno = is_missingno;
return curr_pkmn;
}
void Pokemon::set_to_event(PokemonTables &data_tables, byte nature)
{
int event_id = 0;
if (species_index_struct == 151)
{
switch (language)
{
case JPN_ID:
case KOR_ID:
event_id = 0;
break;
case ENG_ID:
event_id = 1;
break;
case FRE_ID:
event_id = 2;
break;
case ITA_ID:
event_id = 3;
break;
case GER_ID:
event_id = 4;
break;
case SPA_ID:
event_id = 5;
break;
}
}
else
{
switch (language)
{
case JPN_ID:
case KOR_ID:
event_id = 6;
break;
case ENG_ID:
case FRE_ID:
case ITA_ID:
case GER_ID:
case SPA_ID:
event_id = 7;
break;
}
}
data_tables.load_event_pkmn();
// Load the event into the Pokemon array and unencrypted data array
for (int i = 0; i < 0x20; i++)
{
if (i == 0x08)
{
i += 10; // Skip over the nickname
}
gen_3_pkmn[i] = data_tables.EVENT_PKMN[event_id][i];
}
for (int i = 0; i < 12; i++)
{
data_section_G[i] = data_tables.EVENT_PKMN[event_id][i + 0x20 + 0];
data_section_A[i] = data_tables.EVENT_PKMN[event_id][i + 0x20 + 12];
data_section_E[i] = data_tables.EVENT_PKMN[event_id][i + 0x20 + 24];
data_section_M[i] = data_tables.EVENT_PKMN[event_id][i + 0x20 + 36];
}
// insert moves and PP bonuses
data_section_G[8] = (pp_bonus[0] << 0 | pp_bonus[1] << 2 | pp_bonus[2] << 4 | pp_bonus[3] << 6);
data_section_A[0] = moves[0]; // Move 1
data_section_A[2] = moves[1]; // Move 2
data_section_A[4] = moves[2]; // Move 3
data_section_A[6] = moves[3]; // Move 4
// get a new PID in the BACD_R format, and make sure it isn't shiny
disable_auto_random();
u32 n_pid;
do
{
// Make the seed 16 bits long, per the BACD_R format
rand_set_seed(rand_get_seed() & 0xFFFF);
n_pid = (get_rand_u16() << 16) | get_rand_u16();
for (int i = 0; i < 4; i++)
{
gen_3_pkmn[i] = (n_pid >> (i * 8)) & 0xFF;
pid[i] = (n_pid >> (i * 8)) & 0xFF;
};
} while (((pid[0] ^ pid[2] ^ gen_3_pkmn[4] ^ gen_3_pkmn[6]) < 8) &&
((pid[1] ^ pid[3] ^ gen_3_pkmn[5] ^ gen_3_pkmn[7]) == 0) &&
(n_pid % 25 != nature)); // maintain the nature
// Set and fill the IVs
u16 curr_rand = get_rand_u16();
ivs[0] = (curr_rand >> 0) & 0b11111;
ivs[1] = (curr_rand >> 5) & 0b11111;
ivs[2] = (curr_rand >> 10) & 0b11111;
curr_rand = get_rand_u16();
ivs[3] = (curr_rand >> 0) & 0b11111;
ivs[4] = (curr_rand >> 5) & 0b11111;
ivs[5] = (curr_rand >> 10) & 0b11111;
iv_egg_ability = 0;
for (int i = 0; i < 6; i++)
{
iv_egg_ability |= ((ivs[i] & 0b11111) << (i * 5));
}
enable_auto_random();
// Determine and set Ability
iv_egg_ability |= ((pid[0] & 0x1) ? data_tables.get_num_abilities(species_index_struct) : 0) << 31;
// Set IVs, Egg, and Ability
for (int i = 0; i < 4; i++)
{
data_section_M[i + 4] = (iv_egg_ability >> (i * 8) & 0xFF);
}
// Determine and set OT gender
data_section_M[3] |= (caught_data[1] & 0b10000000);
// Check the level
if (exp < 560) // Minimum EXP for level 10
{
exp = 560;
}
data_section_G[2] = (is_new ? 0x44 : 0x00); // Rare Candy if new
// Update and set the checksum
checksum = 0x0000;
for (int i = 0; i < 12; i = i + 2)
{
checksum = checksum + ((data_section_G[i + 1] << 8) | data_section_G[i]);
checksum = checksum + ((data_section_A[i + 1] << 8) | data_section_A[i]);
checksum = checksum + ((data_section_E[i + 1] << 8) | data_section_E[i]);
checksum = checksum + ((data_section_M[i + 1] << 8) | data_section_M[i]);
}
gen_3_pkmn[28] = checksum & 0xFF;
gen_3_pkmn[29] = (checksum & 0xFF00) >> 8;
// Determine the encryption key
for (int i = 0; i < 4; i++)
{
encryption_key[i] = gen_3_pkmn[4 + i] ^ pid[i]; // XOR SID and TID with PID
}
// Encrypt the data
for (int i = 0; i < 12; i++)
{
unencrypted_data[i] = data_section_G[i];
data_section_G[i] ^= encryption_key[i % 4];
unencrypted_data[12 + i] = data_section_A[i];
data_section_A[i] ^= encryption_key[i % 4];
unencrypted_data[24 + i] = data_section_E[i];
data_section_E[i] ^= encryption_key[i % 4];
unencrypted_data[36 + i] = data_section_M[i];
data_section_M[i] ^= encryption_key[i % 4];
}
// Puts the four data chunks into their correct locations based on the PID
alocate_data_chunks(data_section_G, data_section_A, data_section_E, data_section_M);
return;
}