Better sanitize names

This commit is contained in:
Lorenzooone 2023-02-28 06:30:04 +01:00
parent cc47b4e53b
commit 334c741d68
17 changed files with 330 additions and 197 deletions

View File

@ -20,7 +20,8 @@ u8 get_gender_thresholds_gen12(u8);
u8 get_gender_useless_atk_ivs_gen12(u8);
u8 get_pokemon_gender_gen2(u8, u8, u8, u8);
u8 get_pokemon_gender_kind_gen2(u8, u8, u8);
const u8* get_pokemon_name_gen2_gen3_enc(int, u8, u8);
const u8* get_pokemon_name_gen2(int, u8, u8, u8*);
const u8* get_trainer_name_gen12_enc3(u8);
const u8* get_default_trainer_name_gen2(u8, u8*);
#endif

View File

@ -38,7 +38,7 @@ struct game_data_priv_t {
struct game_data_t {
struct game_identity game_identifier;
u8 giftRibbons[GIFT_RIBBONS];
u8 trainer_name[OT_NAME_GEN3_SIZE+1];
u8 trainer_name[OT_NAME_GEN3_MAX_SIZE+1];
u8 trainer_gender;
u32 trainer_id;
struct mail_gen3 mails_3[PARTY_SIZE];

View File

@ -1,13 +1,15 @@
#ifndef GEN_CONVERTER__
#define GEN_CONVERTER__
#include "party_handler.h"
void alter_nature(struct gen3_mon_data_unenc*, u8);
void set_alter_data(struct gen3_mon_data_unenc*, struct alternative_data_gen3*);
void preload_if_fixable(struct gen3_mon_data_unenc*);
void sanitize_ot_name_gen3_to_gen12(u8*, u8*, u8, u8);
void sanitize_ot_name_gen12_to_gen3(u8*, u8*, u8);
u8 gen3_to_gen2(struct gen2_mon*, struct gen3_mon_data_unenc*, u32);
u8 gen3_to_gen1(struct gen1_mon*, struct gen3_mon_data_unenc*, u32);
u8 gen2_to_gen3(struct gen2_mon_data*, struct gen3_mon_data_unenc*, u8, u8*, u8*, u8);

View File

@ -135,6 +135,10 @@
#define STRING_GEN2_INT_CAP (STRING_GEN2_INT_SIZE-1)
#define STRING_GEN2_JP_CAP (STRING_GEN2_JP_SIZE-1)
#define NICKNAME_GEN3_MAX_SIZE ((NICKNAME_GEN3_SIZE > NICKNAME_JP_GEN3_SIZE) ? NICKNAME_GEN3_SIZE : NICKNAME_JP_GEN3_SIZE)
#define OT_NAME_GEN3_MAX_SIZE ((OT_NAME_GEN3_SIZE > OT_NAME_JP_GEN3_SIZE) ? OT_NAME_GEN3_SIZE : OT_NAME_JP_GEN3_SIZE)
#define STRING_GEN2_MAX_SIZE ((STRING_GEN2_INT_SIZE > STRING_GEN2_JP_SIZE) ? STRING_GEN2_INT_SIZE : STRING_GEN2_JP_SIZE)
#define GEN2_EGG 253
#define GEN2_NO_MON 255
@ -163,7 +167,6 @@
#define GET_LANGUAGE_IS_JAPANESE(x) ((x) == JAPANESE_LANGUAGE)
#define GET_LANGUAGE_NICKNAME_LIMIT(x) (GET_LANGUAGE_IS_JAPANESE(x) ? NICKNAME_JP_GEN3_SIZE : NICKNAME_GEN3_SIZE)
#define GET_LANGUAGE_OT_NAME_LIMIT(x) (GET_LANGUAGE_IS_JAPANESE(x) ? OT_NAME_JP_GEN3_SIZE : OT_NAME_GEN3_SIZE)
#define GET_LANGUAGE_OT_NAME_LIMIT_DIRECT(x) ((x) ? OT_NAME_JP_GEN3_SIZE : OT_NAME_GEN3_SIZE)
#define SYS_LANGUAGE ENGLISH_LANGUAGE
#define IS_SYS_LANGUAGE_JAPANESE GET_LANGUAGE_IS_JAPANESE(SYS_LANGUAGE)
@ -187,7 +190,7 @@ struct alternative_data_gen3 {
struct mail_gen3 {
u16 words[MAIL_WORDS_SIZE];
u8 ot_name[OT_NAME_GEN3_SIZE+1];
u8 ot_name[OT_NAME_GEN3_MAX_SIZE+1];
u32 ot_id;
u16 species;
u16 item;
@ -270,13 +273,13 @@ struct gen3_mon_data_unenc {
struct gen3_mon {
u32 pid;
u32 ot_id;
u8 nickname[NICKNAME_GEN3_SIZE];
u8 nickname[NICKNAME_GEN3_MAX_SIZE];
u8 language;
u8 is_bad_egg : 1;
u8 has_species : 1;
u8 use_egg_name : 1;
u8 unused : 5;
u8 ot_name[OT_NAME_GEN3_SIZE];
u8 ot_name[OT_NAME_GEN3_MAX_SIZE];
u8 marks;
u16 checksum;
u16 unk;
@ -410,6 +413,7 @@ u8 get_hidden_power_power_gen3(struct gen3_mon_misc*);
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);
char get_nature_symbol(u32, u8);
const u8* get_move_name_raw(u16);
const u8* get_move_name_gen3(struct gen3_mon_attacks*, u8);
@ -428,5 +432,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);
#endif

View File

@ -17,7 +17,7 @@
#define NUM_SIZES 4
#define SIZE_STOP 0xFFFF
#define NUM_EXTRA_PADDING_BYTES_GEN3 0x1F
#define NUM_EXTRA_PADDING_BYTES_GEN3 0x1C
#define OWN_BUFFER 0
#define OTHER_BUFFER 1
@ -135,11 +135,9 @@ struct gen3_trade_data {
u32 checksum_mail;
struct gen3_party party_3;
u32 checksum_party;
u8 game_main_code : 4;
u8 game_sub_code : 2;
u8 game_is_jp : 2;
struct game_identity game_identifier;
u8 giftRibbons[GIFT_RIBBONS];
u8 trainer_name[OT_NAME_GEN3_SIZE+1];
u8 trainer_name[OT_NAME_GEN3_MAX_SIZE+1];
u8 trainer_gender;
u8 extra_tmp_padding[NUM_EXTRA_PADDING_BYTES_GEN3];
u32 trainer_id;

View File

@ -62,4 +62,9 @@ void text_gen3_to_gen12(const u8*, u8*, size_t, size_t, u8, u8);
u8 is_gen12_trainer(const u8*);
void text_gen12_to_gen3(const u8*, u8*, size_t, size_t, u8, u8);
void sanitize_name_gen12_to_gen3(const u8*, u8*, const u8*, size_t, size_t);
void sanitize_name_gen3_to_gen12(const u8*, u8*, const u8*, size_t, size_t);
void sanitize_name_gen3(u8*, const u8*, const u8*, size_t, size_t);
void limit_name_gen3(u8*, size_t, size_t);
#endif

View File

@ -1,6 +1,8 @@
#ifndef VERSION_IDENTIFIER__
#define VERSION_IDENTIFIER__
#include "useful_qualifiers.h"
#define UNDETERMINED 0xFF
#define NUMBER_OF_GAMES 5
#define RS_MAIN_GAME_CODE 0x0
@ -21,10 +23,13 @@
#define LG_VERSION_ID (FR_VERSION_ID+1)
struct game_identity {
u8 game_is_jp;
u8 language;
u8 game_main_version;
u8 game_sub_version;
};
u8 language_is_sys : 1;
u8 game_sub_version_undetermined : 1;
u8 padding : 6;
} PACKED ALIGNED(4);
void init_game_identifier(struct game_identity*);
u8 is_trainer_name_japanese(u8*);

View File

@ -2,7 +2,6 @@
#include "gen12_methods.h"
#include "party_handler.h"
#include "text_handler.h"
#include "bin_table_handler.h"
#include "fast_pokemon_methods.h"
#include "gen3_to_1_conv_table_bin.h"
@ -10,7 +9,8 @@
#include "pokemon_gender_bin.h"
#include "pokemon_stats_gen1_bin.h"
#include "pokemon_stats_bin.h"
#include "trainer_names_bin.h"
const u8* set_buffer_with_gen2(const u8*, u8, u8*);
u8 stat_index_conversion_gen2[] = {0, 1, 2, 5, 3, 4};
u8 gender_thresholds_gen12[TOTAL_GENDER_KINDS] = {8, 0, 2, 4, 12, 14, 16, 17, 0, 16};
@ -50,10 +50,6 @@ u8 get_ivs_gen2(u16 ivs, u8 stat_index) {
}
}
const u8* get_trainer_name_gen12_enc3(u8 language) {
return get_table_pointer(trainer_names_bin, get_valid_language(language));
}
u8 get_unown_letter_gen2(u16 ivs){
return get_unown_letter_gen2_fast(ivs);
}
@ -173,7 +169,17 @@ u8 get_pokemon_gender_kind_gen2(u8 index, u8 is_egg, u8 curr_gen) {
return pokemon_gender_bin[get_mon_index_gen2(index, is_egg)];
}
const u8* get_pokemon_name_gen2(int index, u8 is_egg, u8 language, u8* buffer) {
const u8* get_pokemon_name_gen2_gen3_enc(int index, u8 is_egg, u8 language) {
u16 mon_index = get_mon_index_gen2(index, is_egg);
if (mon_index == MR_MIME_SPECIES)
mon_index = MR_MIME_OLD_NAME_POS;
if (mon_index == UNOWN_SPECIES)
mon_index = UNOWN_REAL_NAME_POS;
return get_pokemon_name_language(mon_index, language);
}
const u8* set_buffer_with_gen2(const u8* src_gen3_enc, u8 language, u8* buffer) {
u8 string_cap = STRING_GEN2_INT_CAP;
u8 is_jp = 0;
if(language == JAPANESE_LANGUAGE) {
@ -181,16 +187,18 @@ const u8* get_pokemon_name_gen2(int index, u8 is_egg, u8 language, u8* buffer) {
is_jp = 1;
}
u16 mon_index = get_mon_index_gen2(index, is_egg);
if (mon_index == MR_MIME_SPECIES)
mon_index = MR_MIME_OLD_NAME_POS;
if (mon_index == UNOWN_SPECIES)
mon_index = UNOWN_REAL_NAME_POS;
text_gen3_to_gen12(get_pokemon_name_language(mon_index, language), buffer, string_cap, string_cap, is_jp, is_jp);
text_gen3_to_gen12(src_gen3_enc, buffer, string_cap, string_cap, is_jp, is_jp);
return buffer;
}
const u8* get_pokemon_name_gen2(int index, u8 is_egg, u8 language, u8* buffer) {
return set_buffer_with_gen2(get_pokemon_name_gen2_gen3_enc(index, is_egg, language), language, buffer);
}
const u8* get_default_trainer_name_gen2(u8 language, u8* buffer) {
return set_buffer_with_gen2(get_default_trainer_name(language), language, buffer);
}
u8 get_pokemon_gender_gen2(u8 index, u8 atk_ivs, u8 is_egg, u8 curr_gen) {
u8 gender_kind = get_pokemon_gender_kind_gen2(index, is_egg, curr_gen);
switch(gender_kind){

View File

@ -576,54 +576,48 @@ u8 exists_record_mix_tv_slot(struct tv_show_t* tv_shows, u8 kind, u8 clear, u16
return 0;
}
void try_airing_world_of_masters_show(struct tv_show_t* tv_shows, u32 steps, u16 tid, u8* name, u8 is_jp) {
void try_airing_world_of_masters_show(struct tv_show_t* tv_shows, u32 steps, u16 tid, u8* name, u8 language) {
int curr_slot = find_first_empty_record_mix_tv_slot(tv_shows);
if((curr_slot != -1) && (!exists_record_mix_tv_slot(tv_shows, TV_SHOW_WOM_ID, 0, tid))) {
copy_tv_show(&tv_shows[TV_SHOW_WOM_POS], &tv_shows[curr_slot]);
struct tv_show_wom_t* wom_show = (struct tv_show_wom_t*)&tv_shows[curr_slot];
wom_show->is_active = 0; // Show is not active until passed via Record Mix
wom_show->steps = steps - wom_show->steps;
text_gen3_copy(name, wom_show->name, OT_NAME_GEN3_SIZE, OT_NAME_GEN3_SIZE+1);
text_gen3_copy(name, wom_show->name, OT_NAME_GEN3_MAX_SIZE, OT_NAME_GEN3_MAX_SIZE+1);
store_tid_tv_show((struct tv_show_t*)wom_show, tid);
if(is_jp)
wom_show->language = JAPANESE_LANGUAGE;
else
wom_show->language = ENGLISH_LANGUAGE;
wom_show->language = language;
}
}
void try_airing_number_one_show(struct tv_show_t* tv_shows, u8 index, u16 value, u16 tid, u8* name, u8 is_jp) {
void try_airing_number_one_show(struct tv_show_t* tv_shows, u8 index, u16 value, u16 tid, u8* name, u8 language) {
exists_record_mix_tv_slot(tv_shows, TV_SHOW_NUMO_ID, 1, tid);
int curr_slot = find_first_empty_record_mix_tv_slot(tv_shows);
if(curr_slot != -1) {
struct tv_show_numo_t* numo_show = (struct tv_show_numo_t*)&tv_shows[curr_slot];
numo_show->kind = TV_SHOW_NUMO_ID;
numo_show->is_active = 0; // Show is not active until passed via Record Mix
text_gen3_copy(name, numo_show->name, OT_NAME_GEN3_SIZE, OT_NAME_GEN3_SIZE+1);
text_gen3_copy(name, numo_show->name, OT_NAME_GEN3_MAX_SIZE, OT_NAME_GEN3_MAX_SIZE+1);
numo_show->index = index;
numo_show->value = value;
store_tid_tv_show((struct tv_show_t*)numo_show, tid);
if(is_jp)
numo_show->language = JAPANESE_LANGUAGE;
else
numo_show->language = ENGLISH_LANGUAGE;
numo_show->language = language;
}
}
void schedule_world_of_masters_show(struct tv_show_t* tv_shows, u32 steps, u16 tid, u8* name, u8 is_jp) {
void schedule_world_of_masters_show(struct tv_show_t* tv_shows, u32 steps, u16 tid, u8* name, u8 language) {
if(tv_shows[TV_SHOW_WOM_POS].kind == TV_SHOW_WOM_ID) {
struct tv_show_wom_t* wom_show = (struct tv_show_wom_t*)&tv_shows[TV_SHOW_WOM_POS];
if(wom_show->num_caught >= MIN_CAUGHT_WOM)
try_airing_world_of_masters_show(tv_shows, steps, tid, name, is_jp);
try_airing_world_of_masters_show(tv_shows, steps, tid, name, language);
clear_single_tv_show(&tv_shows[TV_SHOW_WOM_POS]);
}
}
void schedule_number_one_show(struct tv_show_t* tv_shows, u16* daily_show_vars, u16 tid, u8* name, u8 is_jp) {
void schedule_number_one_show(struct tv_show_t* tv_shows, u16* daily_show_vars, u16 tid, u8* name, u8 language) {
for(int i = 0; i < TOTAL_DAILY_SHOW_VARS; i++) {
if(daily_show_vars[i] >= daily_show_thresholds[i]) {
try_airing_number_one_show(tv_shows, i, daily_show_thresholds[i], tid, name, is_jp);
try_airing_number_one_show(tv_shows, i, daily_show_thresholds[i], tid, name, language);
break;
}
}
@ -676,9 +670,9 @@ void update_tv_shows(struct game_data_t* game_data, struct clock_events_t* clock
update_outbreak_tv(clock_events->tv_shows, &clock_events->outbreak, days_increase);
update_outbreak(&clock_events->outbreak, days_increase);
update_news(clock_events->news, is_game_cleared, days_increase);
schedule_world_of_masters_show(clock_events->tv_shows, clock_events->steps_stat, game_data->trainer_id & 0xFFFF, game_data->trainer_name, game_data->game_identifier.game_is_jp);
schedule_world_of_masters_show(clock_events->tv_shows, clock_events->steps_stat, game_data->trainer_id & 0xFFFF, game_data->trainer_name, game_data->game_identifier.language);
if(game_data->game_identifier.game_main_version == E_MAIN_GAME_CODE)
schedule_number_one_show(clock_events->tv_shows, clock_events->daily_show_vars, game_data->trainer_id & 0xFFFF, game_data->trainer_name, game_data->game_identifier.game_is_jp);
schedule_number_one_show(clock_events->tv_shows, clock_events->daily_show_vars, game_data->trainer_id & 0xFFFF, game_data->trainer_name, game_data->game_identifier.language);
}
void update_weather(struct clock_events_t* clock_events, u16 days_increase) {

View File

@ -108,7 +108,7 @@ void init_game_data(struct game_data_t* game_data) {
game_data->party_3.total = 0;
for(size_t i = 0; i < (OT_NAME_GEN3_SIZE+1); i++)
for(size_t i = 0; i < (OT_NAME_GEN3_MAX_SIZE+1); i++)
game_data->trainer_name[i] = GEN3_EOL;
for(gen3_party_total_t i = 0; i < PARTY_SIZE; i++) {
@ -167,7 +167,7 @@ void read_game_data_trainer_info(int slot, struct game_data_t* game_data, struct
for(int i = 0; i < SECTION_TOTAL; i++)
if(read_section_id(slot, i) == SECTION_TRAINER_INFO_ID) {
copy_save_to_ram((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + TRAINER_NAME_POS, game_data->trainer_name, OT_NAME_GEN3_SIZE+1);
copy_save_to_ram((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + TRAINER_NAME_POS, game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1);
game_data->trainer_gender = read_byte_save((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + TRAINER_GENDER_POS);
game_data->trainer_id = read_int_save((slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE) + TRAINER_ID_POS);
determine_game_with_save(&game_data->game_identifier, slot, i, summable_bytes[SECTION_TRAINER_INFO_ID]);
@ -354,9 +354,16 @@ void read_party(int slot, struct game_data_t* game_data, struct game_data_priv_t
slot = 1;
read_game_data_trainer_info(slot, game_data, game_data_priv);
if(game_data->game_identifier.game_is_jp == UNDETERMINED)
game_data->game_identifier.game_is_jp = is_trainer_name_japanese(game_data->trainer_name);
if(game_data->game_identifier.language == UNDETERMINED) {
if(is_trainer_name_japanese(game_data->trainer_name))
game_data->game_identifier.language = JAPANESE_LANGUAGE;
else {
game_data->game_identifier.language = SYS_LANGUAGE;
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);
u8 game_id = game_data->game_identifier.game_main_version;
for(int i = 0; i < SECTION_TOTAL; i++) {

View File

@ -67,8 +67,8 @@ void set_ivs(struct gen3_mon_misc*, u32);
void preset_alter_data(struct gen3_mon_data_unenc*, struct alternative_data_gen3*);
void set_origin_pid_iv(struct gen3_mon*, struct gen3_mon_data_unenc*, u16, u16, u8, u8, u8, u8);
u8 are_trainers_same(struct gen3_mon*, u8);
void fix_name_change_from_gen3(struct gen3_mon*, u16, u8*, u8, u8, u8);
void fix_name_change_to_gen3(struct gen3_mon*, u8);
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);
@ -800,7 +800,7 @@ void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_data_unenc* data_ds
u8 are_trainers_same(struct gen3_mon* dst, u8 is_jp) {
struct game_data_t* trainer_data = get_own_game_data();
u8 trainer_is_jp = trainer_data->game_identifier.game_is_jp;
u8 trainer_is_jp = GET_LANGUAGE_IS_JAPANESE(trainer_data->game_identifier.language);
u32 trainer_id = trainer_data->trainer_id;
u8* trainer_name = trainer_data->trainer_name;
@ -813,125 +813,163 @@ u8 are_trainers_same(struct gen3_mon* dst, u8 is_jp) {
return 0;
// Return whether the OT names are the same
return text_gen3_is_same(dst->ot_name, trainer_name, OT_NAME_GEN3_SIZE, OT_NAME_GEN3_SIZE);
return text_gen3_is_same(dst->ot_name, trainer_name, OT_NAME_GEN3_MAX_SIZE, OT_NAME_GEN3_MAX_SIZE);
}
void fix_name_change_from_gen3(struct gen3_mon* src, u16 species, u8* nickname, u8 is_egg, u8 is_gen2, u8 language) {
u8 tmp_text_buffer[STRING_GEN2_INT_SIZE];
void fix_name_change_from_gen3(const u8* src, u16 species, u8* dst, u8 language) {
u8 tmp_text_buffer[STRING_GEN2_MAX_SIZE];
u8 is_jp = language == JAPANESE_LANGUAGE;
u8 name_cap = STRING_GEN2_INT_CAP;
if(is_jp)
name_cap = STRING_GEN2_JP_CAP;
// If it's the same, update the nickname with the new one
if(text_gen3_is_same(src->nickname, get_pokemon_name_pure(species, is_egg, language), NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE)) {
text_gen2_copy(get_pokemon_name_gen2(species, is_egg, language, tmp_text_buffer), nickname, name_cap, name_cap);
// Gen 1 used the wrong dot symbol
if(!is_gen2)
text_gen2_replace(nickname, name_cap, GEN2_DOT, GEN1_DOT);
u8 gen3_nickname_cap = NICKNAME_GEN3_SIZE;
u8 gen2_name_cap = STRING_GEN2_INT_CAP;
if(is_jp) {
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
}
}
void fix_name_change_to_gen3(struct gen3_mon* dst, u8 species) {
u8 tmp_text_buffer[STRING_GEN2_INT_SIZE];
u8 tmp_text_buffer2[NICKNAME_GEN3_SIZE];
u8 language = dst->language;
u8 is_jp = language == JAPANESE_LANGUAGE;
u8 name_cap = STRING_GEN2_INT_CAP;
if(is_jp)
name_cap = STRING_GEN2_JP_CAP;
// Get the string to compare to
text_gen12_to_gen3(get_pokemon_name_gen2(species, 0, language, tmp_text_buffer), tmp_text_buffer2, name_cap, NICKNAME_GEN3_SIZE, 0, 0);
// If it's the same, update the nickname with the new one
if(text_gen3_is_same(dst->nickname, tmp_text_buffer2, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE))
text_gen3_copy(get_pokemon_name_pure(species, 0, language), dst->nickname, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE);
if(text_gen3_is_same(src, get_pokemon_name_pure(species, 0, language), gen3_nickname_cap, gen3_nickname_cap))
text_gen2_copy(get_pokemon_name_gen2(species, 0, language, tmp_text_buffer), dst, gen2_name_cap, gen2_name_cap);
}
void fix_name_change_to_gen3(u8* dst, u8 species, u8 language) {
u8 is_jp = language == JAPANESE_LANGUAGE;
u8 gen3_nickname_cap = NICKNAME_GEN3_SIZE;
if(is_jp)
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
// If it's the same, update the nickname with the new one
if(text_gen3_is_same(dst, get_pokemon_name_gen2_gen3_enc(species, 0, language), gen3_nickname_cap, gen3_nickname_cap))
text_gen3_copy(get_pokemon_name_pure(species, 0, language), dst, gen3_nickname_cap, gen3_nickname_cap);
}
void sanitize_ot_name_gen3_to_gen12(u8* src, u8* dst, u8 gen3_language, u8 gen2_language) {
u8 gen2_buffer[STRING_GEN2_MAX_SIZE];
u8 gen2_name_cap = STRING_GEN2_INT_CAP;
u8 gen3_ot_name_cap = OT_NAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(gen2_language))
gen2_name_cap = STRING_GEN2_JP_CAP;
if(GET_LANGUAGE_IS_JAPANESE(gen3_language))
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
sanitize_name_gen3_to_gen12(src, dst, get_default_trainer_name_gen2(gen2_language, gen2_buffer), gen3_ot_name_cap, gen2_name_cap);
}
void sanitize_ot_name_gen12_to_gen3(u8* src, u8* dst, u8 language) {
u8 gen2_name_cap = STRING_GEN2_INT_CAP;
u8 gen3_ot_name_cap = OT_NAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(language)) {
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
}
if(is_gen12_trainer(src))
text_gen3_copy(get_default_trainer_name(language), dst, gen3_ot_name_cap, gen3_ot_name_cap);
sanitize_name_gen12_to_gen3(src, dst, get_default_trainer_name(language), gen2_name_cap, gen3_ot_name_cap);
}
void convert_strings_of_gen3(struct gen3_mon* src, u16 species, u8* ot_name, u8* ot_name_jp, u8* nickname, u8* nickname_jp, u8 is_egg, u8 is_gen2) {
u8 gen2_buffer[STRING_GEN2_INT_SIZE];
u8 gen2_buffer[STRING_GEN2_MAX_SIZE];
u8 is_jp = (src->language == JAPANESE_LANGUAGE);
u8 gen3_nickname_cap = NICKNAME_GEN3_SIZE;
u8 gen3_ot_name_cap = OT_NAME_GEN3_SIZE;
if(is_jp) {
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
}
// Text conversions
text_gen2_terminator_fill(ot_name, STRING_GEN2_INT_SIZE);
text_gen2_terminator_fill(ot_name_jp, STRING_GEN2_JP_SIZE);
text_gen2_terminator_fill(nickname, STRING_GEN2_INT_SIZE);
text_gen2_terminator_fill(nickname_jp, STRING_GEN2_JP_SIZE);
text_gen3_to_gen12(src->ot_name, ot_name, OT_NAME_GEN3_SIZE, STRING_GEN2_INT_CAP, is_jp, 0);
text_gen3_to_gen12(src->ot_name, ot_name_jp, OT_NAME_GEN3_SIZE, STRING_GEN2_JP_CAP, is_jp, 1);
text_gen3_to_gen12(src->nickname, nickname, NICKNAME_GEN3_SIZE, STRING_GEN2_INT_CAP, is_jp, 0);
text_gen3_to_gen12(src->nickname, nickname_jp, NICKNAME_GEN3_SIZE, STRING_GEN2_JP_CAP, is_jp, 1);
text_gen3_to_gen12(src->ot_name, ot_name, gen3_ot_name_cap, STRING_GEN2_INT_CAP, is_jp, 0);
text_gen3_to_gen12(src->ot_name, ot_name_jp, gen3_ot_name_cap, STRING_GEN2_JP_CAP, is_jp, 1);
text_gen3_to_gen12(src->nickname, nickname, gen3_nickname_cap, STRING_GEN2_INT_CAP, is_jp, 0);
text_gen3_to_gen12(src->nickname, nickname_jp, gen3_nickname_cap, STRING_GEN2_JP_CAP, is_jp, 1);
// Fix text up
// "MR.MIME" gen 2 == "MR. MIME" gen 3
// In French, "M.MIME" == "M. MIME"
if((species == MR_MIME_SPECIES) && !is_egg)
fix_name_change_from_gen3(src, species, nickname, is_egg, is_gen2, target_int_language);
if((species == MR_MIME_SPECIES) && (!is_egg)) {
fix_name_change_from_gen3(src->nickname, species, nickname, target_int_language);
fix_name_change_from_gen3(src->nickname, species, nickname_jp, JAPANESE_LANGUAGE);
}
// Put the "EGG" name
if(is_gen2 && is_egg) {
text_gen2_copy(get_pokemon_name_gen2(species, is_egg, target_int_language, gen2_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP);
text_gen2_copy(get_pokemon_name_gen2(species, is_egg, JAPANESE_LANGUAGE, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP);
}
// Handle bad naming conversions (? >= half the name) and empty names
size_t question_marks_count = text_gen2_count_question(nickname, STRING_GEN2_INT_CAP) - text_gen3_count_question(src->nickname, NICKNAME_GEN3_SIZE);
if((question_marks_count >= (text_gen2_size(nickname, STRING_GEN2_INT_CAP) >> 1)) || (text_gen2_size(nickname, STRING_GEN2_INT_CAP) == 0))
text_gen2_copy(get_pokemon_name_gen2(species, is_egg, target_int_language, gen2_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP);
// For the japanese nickname too
question_marks_count = text_gen2_count_question(nickname_jp, STRING_GEN2_JP_CAP) - text_gen3_count_question(src->nickname, NICKNAME_GEN3_SIZE);
if((question_marks_count >= (text_gen2_size(nickname_jp, STRING_GEN2_JP_CAP) >> 1)) || (text_gen2_size(nickname_jp, STRING_GEN2_JP_CAP) == 0))
text_gen2_copy(get_pokemon_name_gen2(species, is_egg, JAPANESE_LANGUAGE, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP);
sanitize_name_gen3_to_gen12(src->nickname, nickname, get_pokemon_name_gen2(species, is_egg, target_int_language, gen2_buffer), gen3_nickname_cap, STRING_GEN2_INT_CAP);
sanitize_name_gen3_to_gen12(src->nickname, nickname_jp, get_pokemon_name_gen2(species, is_egg, JAPANESE_LANGUAGE, gen2_buffer), gen3_nickname_cap, STRING_GEN2_JP_CAP);
sanitize_ot_name_gen3_to_gen12(src->ot_name, ot_name, src->language, target_int_language);
sanitize_ot_name_gen3_to_gen12(src->ot_name, ot_name_jp, src->language, JAPANESE_LANGUAGE);
// Gen 1 used the wrong dot symbol
// Removed because in gen 1, Mr. Mime is trade-only
/*if(!is_gen2) {
text_gen2_replace(nickname, STRING_GEN2_INT_CAP, GEN2_DOT, GEN1_DOT);
text_gen2_replace(nickname_jp, STRING_GEN2_JP_CAP, GEN2_DOT, GEN1_DOT);
text_gen2_replace(ot_name, STRING_GEN2_INT_CAP, GEN2_DOT, GEN1_DOT);
text_gen2_replace(ot_name_jp, STRING_GEN2_JP_CAP, GEN2_DOT, GEN1_DOT);
}*/
}
void convert_strings_of_gen12(struct gen3_mon* dst, u8 species, u8* ot_name, u8* nickname, u8 is_egg) {
u8 gen2_buffer[STRING_GEN2_INT_SIZE];
u8 is_jp = (dst->language == JAPANESE_LANGUAGE);
u8 name_cap = STRING_GEN2_INT_CAP;
if(is_jp)
name_cap = STRING_GEN2_JP_CAP;
u8 gen2_name_cap = STRING_GEN2_INT_CAP;
u8 gen3_nickname_cap = NICKNAME_GEN3_SIZE;
u8 gen3_ot_name_cap = OT_NAME_GEN3_SIZE;
if(is_jp) {
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
}
// Text conversions
text_gen3_terminator_fill(dst->nickname, NICKNAME_GEN3_SIZE);
text_gen3_terminator_fill(dst->ot_name, OT_NAME_GEN3_SIZE);
text_gen12_to_gen3(nickname, dst->nickname, name_cap, NICKNAME_GEN3_SIZE, is_jp, is_jp);
text_gen12_to_gen3(ot_name, dst->ot_name, name_cap, OT_NAME_GEN3_SIZE, is_jp, is_jp);
text_gen3_terminator_fill(dst->nickname, NICKNAME_GEN3_MAX_SIZE);
text_gen3_terminator_fill(dst->ot_name, OT_NAME_GEN3_MAX_SIZE);
text_gen12_to_gen3(nickname, dst->nickname, gen2_name_cap, gen3_nickname_cap, is_jp, is_jp);
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) {
dst->language = JAPANESE_LANGUAGE;
text_gen12_to_gen3(nickname, dst->nickname, name_cap, NICKNAME_JP_GEN3_SIZE, is_jp, 1);
text_gen12_to_gen3(ot_name, dst->ot_name, name_cap, OT_NAME_JP_GEN3_SIZE, is_jp, 1);
name_cap = STRING_GEN2_JP_CAP;
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
text_gen12_to_gen3(nickname, dst->nickname, gen2_name_cap, gen3_nickname_cap, is_jp, 1);
text_gen12_to_gen3(ot_name, dst->ot_name, gen2_name_cap, gen3_ot_name_cap, is_jp, 1);
is_jp = 1;
}
if(is_gen12_trainer(ot_name))
text_gen3_copy(get_trainer_name_gen12_enc3(dst->language), dst->ot_name, name_cap, OT_NAME_GEN3_SIZE);
// Fix text up
// "MR.MIME" gen 2 == "MR. MIME" gen 3
// In French, "M.MIME" == "M. MIME"
if((species == MR_MIME_SPECIES) && !is_egg && !is_jp)
fix_name_change_to_gen3(dst, species);
if((species == MR_MIME_SPECIES) && (!is_egg))
fix_name_change_to_gen3(dst->nickname, species, dst->language);
// Put the "EGG" name
if(is_egg) {
dst->language = JAPANESE_LANGUAGE;
text_gen3_copy(get_pokemon_name_pure(species, 1, JAPANESE_LANGUAGE), dst->nickname, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE);
}
else {
// Handle bad naming conversions (? >= half the name) and empty names
size_t question_marks_count = text_gen3_count_question(dst->nickname, NICKNAME_GEN3_SIZE) - text_gen2_count_question(nickname, name_cap);
if((question_marks_count >= (text_gen3_size(dst->nickname, NICKNAME_GEN3_SIZE) >> 1)) || (text_gen3_size(dst->nickname, NICKNAME_GEN3_SIZE) == 0))
text_gen12_to_gen3(get_pokemon_name_gen2(species, 0, dst->language, gen2_buffer), dst->nickname, name_cap, NICKNAME_GEN3_SIZE, is_jp, is_jp);
gen2_name_cap = STRING_GEN2_JP_CAP;
gen3_nickname_cap = NICKNAME_JP_GEN3_SIZE;
gen3_ot_name_cap = OT_NAME_JP_GEN3_SIZE;
text_gen3_copy(get_pokemon_name_pure(species, 1, JAPANESE_LANGUAGE), dst->nickname, gen3_nickname_cap, gen3_nickname_cap);
text_gen12_to_gen3(ot_name, dst->ot_name, gen2_name_cap, gen3_ot_name_cap, is_jp, 1);
is_jp = 1;
}
sanitize_name_gen12_to_gen3(nickname, dst->nickname, get_pokemon_name_pure(species, is_egg, dst->language), gen2_name_cap, gen3_nickname_cap);
sanitize_ot_name_gen12_to_gen3(ot_name, dst->ot_name, dst->language);
}
u8 gen3_to_gen2(struct gen2_mon* dst_data, struct gen3_mon_data_unenc* data_src, u32 trainer_id) {

View File

@ -116,11 +116,11 @@ void print_trade_menu(struct game_data_t* game_data, u8 update, u8 curr_gen, u8
num_parties = 1;
if(is_own)
PRINT_FUNCTION("\x05 - Gen \x03\n", game_data[0].trainer_name, GET_LANGUAGE_OT_NAME_LIMIT_DIRECT(game_data[0].game_identifier.game_is_jp), game_data[0].game_identifier.game_is_jp, curr_gen);
PRINT_FUNCTION("\x05 - Gen \x03\n", game_data[0].trainer_name, GET_LANGUAGE_OT_NAME_LIMIT(game_data[0].game_identifier.language), GET_LANGUAGE_IS_JAPANESE(game_data[0].game_identifier.language), curr_gen);
else {
for(int i = 0; i < num_parties; i++) {
set_text_x(SCREEN_HALF_X * i);
PRINT_FUNCTION("\x05 - \x01", game_data[i].trainer_name, GET_LANGUAGE_OT_NAME_LIMIT_DIRECT(game_data[i].game_identifier.game_is_jp), game_data[i].game_identifier.game_is_jp, person_strings[i]);
PRINT_FUNCTION("\x05 - \x01", game_data[i].trainer_name, GET_LANGUAGE_OT_NAME_LIMIT(game_data[i].game_identifier.language), GET_LANGUAGE_IS_JAPANESE(game_data[i].game_identifier.language), person_strings[i]);
}
}

View File

@ -44,6 +44,7 @@
#include "learnset_evos_gen3_bin.h"
#include "dex_conversion_bin.h"
#include "pokemon_moves_pp_bin.h"
#include "trainer_names_bin.h"
#define UNOWN_B_START 415
#define INITIAL_MAIL_GEN3 121
@ -74,7 +75,6 @@ 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);
void sanitize_ot_name(u8*, u8);
// Order is G A E M. Initialized by init_enc_positions
u8 enc_positions[PID_POSITIONS];
@ -865,6 +865,10 @@ void place_and_encrypt_gen3_data(struct gen3_mon_data_unenc* src, struct gen3_mo
encrypt_data(dst);
}
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) {
language = get_valid_language(language);
u8 kind = language_keyboard_kind[language];
@ -885,50 +889,23 @@ void sanitize_nickname(u8* nickname, u8 language, u8 is_egg, u16 species) {
if(GET_LANGUAGE_IS_JAPANESE(language))
name_limit = NICKNAME_JP_GEN3_SIZE;
for(size_t i = name_limit; i < NICKNAME_GEN3_SIZE; i++)
if(i == name_limit)
nickname[i] = GEN3_EOL;
else
nickname[i] = 0;
if(!is_egg) {
u8 found_illegal_char = 0;
for(size_t i = 0; i < name_limit; i++) {
u8 selected_char = nickname[i];
if(selected_char == GEN3_EOL)
break;
if(!(validity_keyboard[selected_char>>3] & (1<<(selected_char&7)))) {
found_illegal_char = 1;
break;
}
}
if(found_illegal_char)
text_gen3_copy(get_pokemon_name_pure(species, 0, language), nickname, name_limit, name_limit);
}
else
sanitize_name_gen3(nickname, get_pokemon_name_pure(species, 0, language), validity_keyboard, NICKNAME_GEN3_MAX_SIZE, name_limit);
if(is_egg)
text_gen3_copy(get_pokemon_name_pure(species, 1, JAPANESE_LANGUAGE), nickname, NICKNAME_JP_GEN3_SIZE, name_limit);
limit_name_gen3(nickname, NICKNAME_GEN3_MAX_SIZE, name_limit);
}
void sanitize_ot_name(u8* ot_name, u8 language) {
void sanitize_ot_name(u8* ot_name, u8 max_size, u8 language) {
language = get_valid_language(language);
const u8* validity_keyboard = get_validity_keyboard(language);
size_t name_limit = OT_NAME_GEN3_SIZE;
if(GET_LANGUAGE_IS_JAPANESE(language))
name_limit = OT_NAME_JP_GEN3_SIZE;
for(size_t i = name_limit; i < OT_NAME_GEN3_SIZE; i++)
if(i == name_limit)
ot_name[i] = GEN3_EOL;
else
ot_name[i] = 0;
for(size_t i = 0; i < name_limit; i++) {
u8 selected_char = ot_name[i];
if(selected_char == GEN3_EOL)
break;
if(!(validity_keyboard[selected_char>>3] & (1<<(selected_char&7))))
ot_name[i] = GEN3_QUESTION;
}
sanitize_name_gen3(ot_name, get_default_trainer_name(language), validity_keyboard, max_size, name_limit);
limit_name_gen3(ot_name, max_size, name_limit);
}
void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8 main_version, u8 sub_version) {
@ -1037,12 +1014,12 @@ void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8
// Fix Nincada evolving to Shedinja in a Japanese game
if((!dst->is_egg) && (growth->species == SHEDINJA_SPECIES))
if((src->language != JAPANESE_LANGUAGE) && text_gen3_is_same(src->nickname, get_pokemon_name_pure(SHEDINJA_SPECIES, 0, JAPANESE_LANGUAGE), NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE))
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);
// Sanitize text to avoid crashes in-game
sanitize_nickname(src->nickname, src->language, dst->is_egg, growth->species);
sanitize_ot_name(src->ot_name, src->language);
sanitize_ot_name(src->ot_name, OT_NAME_GEN3_MAX_SIZE, src->language);
// Set the new "cleaned" data
place_and_encrypt_gen3_data(dst, src);
@ -1059,7 +1036,7 @@ void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8
void clean_mail_gen3(struct mail_gen3* mail, struct gen3_mon* mon){
for(size_t i = 0; i < MAIL_WORDS_SIZE; i++)
mail->words[i] = 0;
for(size_t i = 0; i < OT_NAME_GEN3_SIZE+1; i++)
for(size_t i = 0; i < (OT_NAME_GEN3_MAX_SIZE+1); i++)
mail->ot_name[i] = GEN3_EOL;
mail->ot_id = 0;
mail->species = BULBASAUR_SPECIES;

View File

@ -307,7 +307,7 @@ MAX_OPTIMIZE u32 generate_ot(u16 tid, u8* name) {
u16 sid = 0;
seed = get_next_seed(seed);
for(size_t i = 0; i < OT_NAME_GEN3_SIZE; i++) {
for(size_t i = 0; i < OT_NAME_GEN3_MAX_SIZE; i++) {
if(name[i] == GEN3_EOL)
break;
seed += name[i];

View File

@ -134,8 +134,15 @@ void load_names_gen12(struct game_data_t* game_data, struct gen2_party* party_2,
curr_gen = 2;
if(party_1 != NULL)
curr_gen = 1;
text_gen3_to_gen12(game_data->trainer_name, trainer_name, OT_NAME_GEN3_SIZE+1, size, game_data->game_identifier.game_is_jp, is_jp);
// TODO: Change this to using the specified language
u8 language = SYS_LANGUAGE;
if(is_jp)
language = JAPANESE_LANGUAGE;
text_gen3_to_gen12(game_data->trainer_name, trainer_name, OT_NAME_GEN3_MAX_SIZE+1, size, GET_LANGUAGE_IS_JAPANESE(game_data->game_identifier.language), is_jp);
sanitize_ot_name_gen3_to_gen12(game_data->trainer_name, trainer_name, game_data->game_identifier.language, language);
for(size_t i = 0; i < size; i++)
if((trainer_name[i] == NO_ACTION_BYTE) || (trainer_name[i] == (NO_ACTION_BYTE-1)))
trainer_name[i] = NO_ACTION_BYTE-2;
@ -368,17 +375,14 @@ void prepare_gen3_trade_data(struct game_data_t* game_data, u32* buffer, size_t*
td->checksum_party = checksum;
checksum = 0;
td->game_main_code = game_data->game_identifier.game_main_version;
td->game_sub_code = game_data->game_identifier.game_sub_version;
td->game_is_jp = game_data->game_identifier.game_is_jp;
copy_bytes(&game_data->game_identifier, &td->game_identifier, sizeof(struct game_identity), 0, 0);
copy_bytes(game_data->giftRibbons, td->giftRibbons, GIFT_RIBBONS, 0, 0);
copy_bytes(game_data->trainer_name, td->trainer_name, OT_NAME_GEN3_SIZE+1, 0, 0);
copy_bytes(game_data->trainer_name, td->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, 0, 0);
td->trainer_gender = game_data->trainer_gender;
for(int i = 0; i < NUM_EXTRA_PADDING_BYTES_GEN3; i++) {
for(int i = 0; i < NUM_EXTRA_PADDING_BYTES_GEN3; i++)
td->extra_tmp_padding[i] = 0;
}
td->trainer_id = game_data->trainer_id;
@ -440,14 +444,18 @@ void read_gen12_trade_data(struct game_data_t* game_data, u32* buffer, u8 curr_g
}
init_game_data(game_data);
game_data->game_identifier.game_is_jp = is_jp;
// TODO: Change this to using the specified language
game_data->game_identifier.language = SYS_LANGUAGE;
if(is_jp)
game_data->game_identifier.language = JAPANESE_LANGUAGE;
copy_bytes(default_gift_ribbons_bin, game_data->giftRibbons, GIFT_RIBBONS, 0, 0);
game_data->trainer_gender = 0;
apply_patch_set(patch_target, patch_set, target_size-(names_size + MON_INDEX_SIZE), names_size + MON_INDEX_SIZE, PATCH_SET_SIZE, PATCH_SET_BASE_POS);
text_gen12_to_gen3(trainer_name, game_data->trainer_name, names_size, OT_NAME_GEN3_SIZE+1, is_jp, is_jp);
text_gen12_to_gen3(trainer_name, game_data->trainer_name, names_size, OT_NAME_GEN3_MAX_SIZE+1, is_jp, is_jp);
sanitize_ot_name_gen12_to_gen3(trainer_name, game_data->trainer_name, game_data->game_identifier.language);
if(curr_gen == 2)
game_data->trainer_id = ((party_info2->trainer_id & 0xFF) << 8) | (party_info2->trainer_id >> 8);
@ -489,13 +497,10 @@ void read_gen3_trade_data(struct game_data_t* game_data, u32* buffer) {
copy_bytes(&td->mails_3[i], &game_data->mails_3[i], sizeof(struct mail_gen3), 0, 0);
copy_bytes(&td->party_3, &game_data->party_3, sizeof(struct gen3_party), 0, 0);
game_data->game_identifier.game_main_version = td->game_main_code;
game_data->game_identifier.game_sub_version = td->game_sub_code;
game_data->game_identifier.game_is_jp = td->game_is_jp;
copy_bytes(&td->game_identifier, &game_data->game_identifier, sizeof(struct game_identity), 0, 0);
copy_bytes(td->giftRibbons, game_data->giftRibbons, GIFT_RIBBONS, 0, 0);
copy_bytes(td->trainer_name, game_data->trainer_name, OT_NAME_GEN3_SIZE+1, 0, 0);
copy_bytes(td->trainer_name, game_data->trainer_name, OT_NAME_GEN3_MAX_SIZE+1, 0, 0);
game_data->trainer_gender = td->trainer_gender;
game_data->trainer_id = td->trainer_id;
@ -515,7 +520,7 @@ void read_gen3_trade_data(struct game_data_t* game_data, u32* buffer) {
}
void load_comm_buffer(struct game_data_t* game_data, struct gen2_party* party_2, struct gen1_party* party_1, int curr_gen, u8 is_jp) {
for(int i = 0; i < NUM_SIZES; i++)
buffer_sizes[i] = SIZE_STOP;
@ -534,7 +539,7 @@ void load_comm_buffer(struct game_data_t* game_data, struct gen2_party* party_2,
}
void read_comm_buffer(struct game_data_t* game_data, int curr_gen, u8 is_jp) {
switch(curr_gen) {
case 1:
read_gen12_trade_data(game_data, communication_buffers[OTHER_BUFFER], 1, is_jp);
@ -546,4 +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);
}

View File

@ -28,6 +28,9 @@ void text_general_copy(const u8*, u8*, size_t, size_t, u8);
void text_general_concat(const u8*, const u8*, u8*, size_t, size_t, size_t, u8);
void text_general_replace(u8*, size_t, u8, u8, u8);
void text_general_terminator_fill(u8*, size_t, u8);
void limit_name_general(u8*, size_t, size_t, u8);
void sanitize_name_general(u8*, const u8*, const u8*, size_t, size_t, u8);
void sanitize_name_general_to_general(const u8*, u8*, const u8*, size_t, size_t, u8, u8, u8, u8);
size_t text_general_count_question(const u8* src, size_t src_size, u8 terminator, u8 question) {
size_t counter = 0;
@ -131,6 +134,43 @@ void text_general_terminator_fill(u8* src, size_t src_size, u8 terminator) {
src[i] = terminator;
}
void limit_name_general(u8* src, size_t src_size, size_t name_limit, u8 terminator) {
for(size_t i = name_limit; i < src_size; i++)
if(i == name_limit)
src[i] = terminator;
else
src[i] = 0;
}
void sanitize_name_general(u8* src, const u8* default_name, const u8* validity_keyboard, size_t src_size, size_t name_limit, u8 terminator) {
limit_name_general(src, src_size, name_limit, terminator);
u8 found_illegal_char = 0;
size_t name_size = 0;
for(name_size = 0; name_size < name_limit; name_size++) {
u8 selected_char = src[name_size];
if(selected_char == terminator)
break;
if(!(validity_keyboard[selected_char>>3] & (1<<(selected_char&7)))) {
found_illegal_char = 1;
break;
}
}
if((found_illegal_char) || (!name_size))
text_general_copy(default_name, src, name_limit, name_limit, terminator);
}
void sanitize_name_general_to_general(const u8* src, u8* dst, const u8* default_name, size_t src_size, size_t dst_size, u8 src_terminator, u8 dst_terminator, u8 src_question_mark, u8 dst_question_mark) {
// Handle bad naming conversions (? >= half the name) and empty name
size_t question_marks_count_dst = text_general_count_question(dst, dst_size, dst_terminator, dst_question_mark);
size_t question_marks_count_src = text_general_count_question(src, src_size, src_terminator, src_question_mark);
size_t question_marks_count = question_marks_count_dst - question_marks_count_src;
if(question_marks_count_src > question_marks_count_dst)
question_marks_count = 0;
if((question_marks_count >= (text_general_size(dst, dst_size, dst_terminator) >> 1)) || (!text_general_size(dst, dst_size, dst_terminator)))
text_general_copy(default_name, dst, dst_size, dst_size, dst_terminator);
}
void text_generic_concat(const u8* src, const u8* src2, u8* dst, size_t src_size, size_t src2_size, size_t dst_size) {
text_general_concat(src, src2, dst, src_size, src2_size, dst_size, GENERIC_EOL);
}
@ -252,3 +292,19 @@ void text_gen12_to_gen3(const u8* src, u8* dst, size_t src_size, size_t dst_size
else
text_general_conversion(src, dst, src_size, dst_size, GEN2_EOL, GEN3_EOL, text_gen12_to_gen3_int_bin);
}
void sanitize_name_gen12_to_gen3(const u8* src, u8* dst, const u8* default_name_gen3, size_t src_size, size_t dst_size) {
sanitize_name_general_to_general(src, dst, default_name_gen3, src_size, dst_size, GEN2_EOL, GEN3_EOL, GEN2_QUESTION, GEN3_QUESTION);
}
void sanitize_name_gen3_to_gen12(const u8* src, u8* dst, const u8* default_name_gen12, size_t src_size, size_t dst_size) {
sanitize_name_general_to_general(src, dst, default_name_gen12, src_size, dst_size, GEN3_EOL, GEN2_EOL, GEN3_QUESTION, GEN2_QUESTION);
}
void sanitize_name_gen3(u8* src, const u8* default_name, const u8* validity_keyboard, size_t src_size, size_t name_limit) {
sanitize_name_general(src, default_name, validity_keyboard, src_size, name_limit, GEN3_EOL);
}
void limit_name_gen3(u8* src, size_t src_size, size_t name_limit) {
limit_name_general(src, src_size, name_limit, GEN3_EOL);
}

View File

@ -9,8 +9,14 @@
#define GAME_STRING_POS (ROM+0xA0)
#define GAME_STRING_SIZE 0xC
#define JAPANESE_ID_POS (ROM+0xAF)
#define LANGUAGE_ID_POS (ROM+0xAF)
#define JAPANESE_ID 0x4A
#define ENGLISH_ID_0 0x45
#define ENGLISH_ID_1 0x50
#define GERMAN_ID 0x44
#define FRENCH_ID 0x46
#define ITALIAN_ID 0x49
#define SPANISH_ID 0x53
#define SECTION_GAME_CODE 0xAC
#define FRLG_GAME_CODE 0x1
@ -24,11 +30,14 @@ const u8 sub_identifiers[NUMBER_OF_GAMES] = {R_SUB_GAME_CODE,S_SUB_GAME_CODE,FR_
void init_game_identifier(struct game_identity* identifier) {
identifier->game_main_version = UNDETERMINED;
identifier->game_sub_version = UNDETERMINED;
identifier->game_is_jp = UNDETERMINED;
identifier->language = UNDETERMINED;
identifier->language_is_sys = 0;
identifier->game_sub_version_undetermined = 0;
identifier->padding = 0;
}
u8 is_trainer_name_japanese(u8* buffer) {
for(size_t i = OT_NAME_JP_GEN3_SIZE+2; i < OT_NAME_GEN3_SIZE+1; i++)
for(size_t i = OT_NAME_JP_GEN3_SIZE+2; i < OT_NAME_GEN3_MAX_SIZE+1; i++)
if(buffer[i])
return 0;
return 1;
@ -41,15 +50,36 @@ void get_game_id(struct game_identity* identifier){
if(text_generic_is_same((const u8*)game_identifier_strings[i], (u8*)GAME_STRING_POS, GAME_STRING_SIZE, GAME_STRING_SIZE)) {
identifier->game_main_version = main_identifiers[i];
identifier->game_sub_version = sub_identifiers[i];
if((*(u8*)JAPANESE_ID_POS) == JAPANESE_ID)
identifier->game_is_jp = 1;
else
identifier->game_is_jp = 0;
u8 language_char = *((u8*)LANGUAGE_ID_POS);
switch(language_char) {
case JAPANESE_ID:
identifier->language = JAPANESE_LANGUAGE;
break;
case ENGLISH_ID_0:
case ENGLISH_ID_1:
identifier->language = ENGLISH_LANGUAGE;
break;
case FRENCH_ID:
identifier->language = FRENCH_LANGUAGE;
break;
case ITALIAN_ID:
identifier->language = ITALIAN_LANGUAGE;
break;
case GERMAN_ID:
identifier->language = GERMAN_LANGUAGE;
break;
case SPANISH_ID:
identifier->language = SPANISH_LANGUAGE;
break;
default:
identifier->language = SYS_LANGUAGE;
identifier->language_is_sys = 1;
break;
}
}
}
u8 id_to_version(struct game_identity* identifier){
u8 base_game = S_VERSION_ID;
if(identifier->game_main_version == FRLG_GAME_CODE)
base_game = FR_VERSION_ID;
@ -116,5 +146,6 @@ void determine_game_with_save(struct game_identity* identifier, u8 slot, u8 sect
identifier->game_main_version = E_MAIN_GAME_CODE;
break;
}
identifier->game_sub_version_undetermined = 1;
}
}