Add Celebi conversion

This commit is contained in:
Lorenzooone 2023-02-28 12:04:17 +01:00
parent 20c3f2415d
commit ed92a3bb82
8 changed files with 122 additions and 56 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -56,6 +56,7 @@
#define BATTLE_FACILITY 0x3A
#define HIDEOUT 0x42
#define SOUTHERN_ISLAND 0x49
#define DUKING_TRADE_LOCATION 0x74
#define DEEP_COLOSSEUM 0x7D
#define DEPT_STORE 0xC4
#define EMPTY_LOCATION 0xD5
@ -64,6 +65,7 @@
#define DEPT_STORE_ALT 0x102
#define COLOSSEUM_ALT 0x103
#define TRADE_MET 0xFE
#define EVENT_MET 0xFF
#define BULBASAUR_SPECIES 1
#define NIDORAN_F_SPECIES 29
@ -79,6 +81,7 @@
#define SUICUNE_SPECIES 245
#define LUGIA_SPECIES 249
#define HO_OH_SPECIES 250
#define CELEBI_SPECIES 251
#define SHEDINJA_SPECIES 303
#define SPINDA_SPECIES 308
#define LATIAS_SPECIES 407
@ -142,6 +145,8 @@
#define GEN2_EGG 253
#define GEN2_NO_MON 255
#define CELEBI_AGATE_OT_ID 31121
#define POKEBALL_ID 4
#define HIDDEN_POWER_ID 237
@ -414,6 +419,7 @@ const u8* get_hidden_power_type_name_gen3_pure(u32);
const u8* get_hidden_power_type_name_gen3(struct gen3_mon_misc*);
const u8* get_nature_name(u32);
const u8* get_default_trainer_name(u8);
const u8* get_celebi_trainer_name(u8);
char get_nature_symbol(u32, u8);
const u8* get_move_name_raw(u16);
const u8* get_move_name_gen3(struct gen3_mon_attacks*, u8);
@ -432,6 +438,6 @@ u8 forget_and_learn_move(struct gen3_mon_data_unenc*, u32, u32);
void update_pokerus_gen3(struct gen3_mon_data_unenc*, u16);
void give_pokerus_gen3(struct gen3_mon_data_unenc*);
u8 would_update_end_pokerus_gen3(struct gen3_mon_data_unenc*, u16);
void sanitize_ot_name(u8*, u8, u8);
void sanitize_ot_name(u8*, u8, u8, u8);
#endif

View File

@ -377,7 +377,7 @@ void read_party(int slot, struct game_data_t* game_data, struct game_data_priv_t
game_data->game_identifier.language_is_sys = 1;
}
}
sanitize_ot_name(game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, game_data->game_identifier.language);
sanitize_ot_name(game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, game_data->game_identifier.language, 0);
u8 game_id = game_data->game_identifier.game_main_version;

View File

@ -71,6 +71,8 @@ void fix_name_change_from_gen3(const u8*, u16, u8*, u8);
void fix_name_change_to_gen3(u8*, u8, u8);
void convert_strings_of_gen3(struct gen3_mon*, u16, u8*, u8*, u8*, u8*, u8, u8);
void convert_strings_of_gen12(struct gen3_mon*, u8, u8*, u8*, u8);
void special_convert_strings_distribution(struct gen3_mon*, u16);
u8 text_handling_gen12_to_gen3(struct gen3_mon*, u16, u16, u8, u8*, u8*, u8, u8);
u8 target_int_language = ENGLISH_LANGUAGE;
@ -462,7 +464,7 @@ u16 convert_ivs_of_gen3(struct gen3_mon_misc* misc, u16 species, u32 pid, u8 is_
spe_ivs = 10;
}
if(!is_shiny && is_shiny_gen2(atk_ivs, def_ivs, spa_ivs, spe_ivs))
if(!is_shiny && is_shiny_gen2(atk_ivs, def_ivs, spa_ivs, spe_ivs) && (species != CELEBI_SPECIES))
spe_ivs = 11;
return (atk_ivs << 4) | def_ivs | (spa_ivs << 8) | (spe_ivs << 12);
@ -623,7 +625,11 @@ void alter_nature(struct gen3_mon_data_unenc* data_src, u8 wanted_nature) {
switch(encounter_type) {
case STATIC_ENCOUNTER:
case ROAMER_ENCOUNTER:
if(origin_game == COLOSSEUM_CODE) {
if(species == CELEBI_SPECIES) {
generate_generic_genderless_shadow_info_xd(wanted_nature, 0, wanted_ivs, tsv, pid_ptr, ivs_ptr, ability_ptr);
is_ability_set = 1;
}
else if(origin_game == COLOSSEUM_CODE) {
if(!is_shiny) {
if(is_static_in_xd(species))
generate_generic_genderless_shadow_info_xd(wanted_nature, has_prev_check_tsv_in_xd(species), wanted_ivs, tsv, pid_ptr, ivs_ptr, ability_ptr);
@ -702,7 +708,13 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
// Get PID and IVs
switch(encounter_type) {
case STATIC_ENCOUNTER:
if(!is_shiny) {
if(species == CELEBI_SPECIES) {
chosen_version = R_VERSION_ID;
generate_generic_genderless_shadow_info_xd(wanted_nature, 0, wanted_ivs, tsv, &dst->pid, &ivs, &ability);
is_ability_set = 1;
ot_gender = 1;
}
else if(!is_shiny) {
// Prefer Colosseum/XD encounter, if possible
if(is_static_in_xd(species) && are_colo_valid_tid_sid(ot_id & 0xFFFF, ot_id >> 0x10)) {
chosen_version = COLOSSEUM_CODE;
@ -920,6 +932,31 @@ void convert_strings_of_gen3(struct gen3_mon* src, u16 species, u8* ot_name, u8*
}*/
}
void special_convert_strings_distribution(struct gen3_mon* dst, u16 species) {
u8 gen3_nickname_cap = NICKNAME_GEN3_SIZE;
u8 gen3_ot_name_cap = OT_NAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(dst->language)) {
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
}
const u8* mon_name = get_pokemon_name_pure(species, 0, dst->language);
const u8* trainer_name = NULL;
switch(species) {
case CELEBI_SPECIES:
trainer_name = get_celebi_trainer_name(dst->language);
break;
default:
break;
}
if(mon_name)
text_gen3_copy(mon_name, dst->nickname, gen3_nickname_cap, gen3_nickname_cap);
if(trainer_name)
text_gen3_copy(trainer_name, dst->ot_name, gen3_ot_name_cap, gen3_ot_name_cap);
}
void convert_strings_of_gen12(struct gen3_mon* dst, u8 species, u8* ot_name, u8* nickname, u8 is_egg) {
u8 is_jp = (dst->language == JAPANESE_LANGUAGE);
@ -940,7 +977,8 @@ void convert_strings_of_gen12(struct gen3_mon* dst, u8 species, u8* ot_name, u8*
text_gen12_to_gen3(ot_name, dst->ot_name, gen2_name_cap, gen3_ot_name_cap, is_jp, is_jp);
// Handle Mew's special Japanese-only nature
if(species == MEW_SPECIES) {
// TODO: Allow undistributed events...?
if(1 && (species == MEW_SPECIES)) {
dst->language = JAPANESE_LANGUAGE;
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
@ -1147,6 +1185,42 @@ u8 gen3_to_gen1(struct gen1_mon* dst_data, struct gen3_mon_data_unenc* data_src,
return 1;
}
u8 text_handling_gen12_to_gen3(struct gen3_mon* dst, u16 species, u16 swapped_ot_id, u8 is_egg, u8* ot_name, u8* nickname, u8 is_jp, u8 no_restrictions) {
// Specially handle Celebi's event
if(species == CELEBI_SPECIES) {
// TODO: Allow undistributed events...?
if(1 || is_jp)
dst->language = JAPANESE_LANGUAGE;
else
dst->language = target_int_language;
dst->ot_id = CELEBI_AGATE_OT_ID;
special_convert_strings_distribution(dst, species);
return no_restrictions;
}
// TODO: Maybe detect the language, if not set in the settings...?
if(is_jp)
dst->language = JAPANESE_LANGUAGE;
else
dst->language = target_int_language;
// Handle Nickname + OT conversion
convert_strings_of_gen12(dst, species, ot_name, nickname, is_egg);
// Handle OT ID, if same as the game owner, set it to the game owner's
dst->ot_id = swap_endian_short(swapped_ot_id);
if(are_trainers_same(dst, is_jp)) {
dst->ot_id = get_own_game_data()->trainer_id;
no_restrictions = 0;
}
else
dst->ot_id = generate_ot(dst->ot_id, dst->ot_name);
return no_restrictions;
}
u8 gen2_to_gen3(struct gen2_mon_data* src, struct gen3_mon_data_unenc* data_dst, u8 index, u8* ot_name, u8* nickname, u8 is_jp) {
struct gen3_mon* dst = data_dst->src;
u8 no_restrictions = 1;
@ -1175,25 +1249,7 @@ u8 gen2_to_gen3(struct gen2_mon_data* src, struct gen3_mon_data_unenc* data_dst,
dst->mail_id = GEN3_NO_MAIL;
data_dst->is_egg = is_egg;
// TODO: Maybe detect the language, if not set in the settings...?
if(is_jp)
dst->language = JAPANESE_LANGUAGE;
else
dst->language = target_int_language;
// Handle Nickname + OT conversion
convert_strings_of_gen12(dst, src->species, ot_name, nickname, is_egg);
// Handle OT ID, if same as the game owner, set it to the game owner's
dst->ot_id = swap_endian_short(src->ot_id);
if(are_trainers_same(dst, is_jp)) {
no_restrictions = 0;
dst->ot_id = get_own_game_data()->trainer_id;
}
else
dst->ot_id = generate_ot(dst->ot_id, dst->ot_name);
no_restrictions = text_handling_gen12_to_gen3(dst, src->species, src->ot_id, is_egg, ot_name, nickname, is_jp, no_restrictions);
// Reset everything
for(size_t i = 0; i < sizeof(struct gen3_mon_growth); i++)
@ -1218,7 +1274,7 @@ u8 gen2_to_gen3(struct gen2_mon_data* src, struct gen3_mon_data_unenc* data_dst,
// Handle cases in which the nature would be forced
if((dst->level == MAX_LEVEL) || (is_egg))
wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES);
wanted_nature = get_nature(get_rng());
// Store egg cycles
if(is_egg) {
@ -1273,25 +1329,7 @@ u8 gen1_to_gen3(struct gen1_mon_data* src, struct gen3_mon_data_unenc* data_dst,
dst->mail_id = GEN3_NO_MAIL;
data_dst->is_egg = 0;
// TODO: Maybe detect the language, if not set in the settings...?
if(is_jp)
dst->language = JAPANESE_LANGUAGE;
else
dst->language = target_int_language;
// Handle Nickname + OT conversion
convert_strings_of_gen12(dst, get_mon_index_gen1_to_3(src->species), ot_name, nickname, 0);
// Handle OT ID, if same as the game owner, set it to the game owner's
dst->ot_id = swap_endian_short(src->ot_id);
if(are_trainers_same(dst, is_jp)) {
no_restrictions = 0;
dst->ot_id = get_own_game_data()->trainer_id;
}
else
dst->ot_id = generate_ot(dst->ot_id, dst->ot_name);
no_restrictions = text_handling_gen12_to_gen3(dst, get_mon_index_gen1_to_3(src->species), src->ot_id, 0, ot_name, nickname, is_jp, no_restrictions);
// Reset everything
for(size_t i = 0; i < sizeof(struct gen3_mon_growth); i++)
@ -1316,7 +1354,7 @@ u8 gen1_to_gen3(struct gen1_mon_data* src, struct gen3_mon_data_unenc* data_dst,
// Handle cases in which the nature would be forced
if(dst->level == MAX_LEVEL)
wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES);
wanted_nature = get_nature(get_rng());
// Set base friendship
data_dst->growth.friendship = BASE_FRIENDSHIP;

View File

@ -17,6 +17,7 @@
#include "pokemon_names_bin.h"
#include "egg_names_bin.h"
#include "language_names_index_bin.h"
#include "gen3_spanish_special_valid_chars_bin.h"
#include "gen3_german_valid_chars_bin.h"
#include "gen3_int_valid_chars_bin.h"
#include "gen3_jap_valid_chars_bin.h"
@ -45,6 +46,7 @@
#include "dex_conversion_bin.h"
#include "pokemon_moves_pp_bin.h"
#include "trainer_names_bin.h"
#include "trainer_names_celebi_bin.h"
#define UNOWN_B_START 415
#define INITIAL_MAIL_GEN3 121
@ -73,8 +75,9 @@ u8 get_hidden_power_type_gen3_pure(u32);
u8 get_hidden_power_type_gen3(struct gen3_mon_misc*);
void make_evs_legal_gen3(struct gen3_mon_evs*);
u8 to_valid_level_gen3(struct gen3_mon*);
const u8* get_validity_keyboard(u8);
void sanitize_nickname(u8*, u8, u8, u16);
const u8* get_validity_keyboard(u8, u8);
u8 use_special_keyboard(struct gen3_mon_misc*, u8);
void sanitize_nickname(u8*, u8, u8, u16, u8);
// Order is G A E M. Initialized by init_enc_positions
u8 enc_positions[PID_POSITIONS];
@ -869,7 +872,11 @@ const u8* get_default_trainer_name(u8 language) {
return get_table_pointer(trainer_names_bin, get_valid_language(language));
}
const u8* get_validity_keyboard(u8 language) {
const u8* get_celebi_trainer_name(u8 language) {
return get_table_pointer(trainer_names_celebi_bin, get_valid_language(language));
}
const u8* get_validity_keyboard(u8 language, u8 load_special_keyboard) {
language = get_valid_language(language);
u8 kind = language_keyboard_kind[language];
const u8* validity_keyboard = gen3_int_valid_chars_bin;
@ -879,12 +886,26 @@ const u8* get_validity_keyboard(u8 language) {
validity_keyboard = gen3_int_valid_chars_bin;
else if(kind == 2)
validity_keyboard = gen3_german_valid_chars_bin;
if(load_special_keyboard)
validity_keyboard = gen3_spanish_special_valid_chars_bin;
return validity_keyboard;
}
void sanitize_nickname(u8* nickname, u8 language, u8 is_egg, u16 species) {
u8 use_special_keyboard(struct gen3_mon_misc* misc, u8 language) {
if(language != SPANISH_LANGUAGE)
return 0;
// I could make stricter checks,
// but these should be fine for now...
if((misc->met_location == TRADE_MET) || (misc->met_location == EVENT_MET))
return 1;
if((misc->met_location == DUKING_TRADE_LOCATION) && (((misc->origins_info>>7)&0xF) == COLOSSEUM_CODE))
return 1;
return 0;
}
void sanitize_nickname(u8* nickname, u8 language, u8 is_egg, u16 species, u8 load_special_keyboard) {
language = get_valid_language(language);
const u8* validity_keyboard = get_validity_keyboard(language);
const u8* validity_keyboard = get_validity_keyboard(language, load_special_keyboard);
size_t name_limit = NICKNAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(language))
name_limit = NICKNAME_JP_GEN3_SIZE;
@ -897,9 +918,9 @@ void sanitize_nickname(u8* nickname, u8 language, u8 is_egg, u16 species) {
limit_name_gen3(nickname, NICKNAME_GEN3_MAX_SIZE, name_limit);
}
void sanitize_ot_name(u8* ot_name, u8 max_size, u8 language) {
void sanitize_ot_name(u8* ot_name, u8 max_size, u8 language, u8 load_special_keyboard) {
language = get_valid_language(language);
const u8* validity_keyboard = get_validity_keyboard(language);
const u8* validity_keyboard = get_validity_keyboard(language, load_special_keyboard);
size_t name_limit = OT_NAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(language))
name_limit = OT_NAME_JP_GEN3_SIZE;
@ -1017,9 +1038,10 @@ void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8
if((src->language != JAPANESE_LANGUAGE) && text_gen3_is_same(src->nickname, get_pokemon_name_pure(SHEDINJA_SPECIES, 0, JAPANESE_LANGUAGE), NICKNAME_GEN3_MAX_SIZE, NICKNAME_GEN3_MAX_SIZE))
text_gen3_copy(get_pokemon_name_pure(SHEDINJA_SPECIES, 0, src->language), src->nickname, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE);
u8 special_keyboard = use_special_keyboard(misc, src->language);
// Sanitize text to avoid crashes in-game
sanitize_nickname(src->nickname, src->language, dst->is_egg, growth->species);
sanitize_ot_name(src->ot_name, OT_NAME_GEN3_MAX_SIZE, src->language);
sanitize_nickname(src->nickname, src->language, dst->is_egg, growth->species, special_keyboard);
sanitize_ot_name(src->ot_name, OT_NAME_GEN3_MAX_SIZE, src->language, special_keyboard);
// Set the new "cleaned" data
place_and_encrypt_gen3_data(dst, src);

View File

@ -551,5 +551,5 @@ void read_comm_buffer(struct game_data_t* game_data, int curr_gen, u8 is_jp) {
read_gen3_trade_data(game_data, communication_buffers[OTHER_BUFFER]);
break;
}
sanitize_ot_name(game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, game_data->game_identifier.language);
sanitize_ot_name(game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, game_data->game_identifier.language, 0);
}