diff --git a/.gitignore b/.gitignore index feeb999..dbe237b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ build/ *.gba *.sav *.py -__pychache__/ +settings.sh +__pycache__/ diff --git a/Makefile b/Makefile index 33831b9..b51485d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .SUFFIXES: #--------------------------------------------------------------------------------- ifeq ($(strip $(DEVKITARM)),) -$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif include $(DEVKITARM)/gba_rules @@ -29,7 +29,10 @@ INCLUDES := include #--------------------------------------------------------------------------------- ARCH := -mthumb -mthumb-interwork -CFLAGS := -g -Wall -save-temps -Os -s\ +CFLAGS := -g -Wall -Wstrict-overflow=5 -Wextra\ + -Wpointer-arith -Wpedantic -Wcast-qual -Wswitch-default\ + -Wstrict-prototypes -Wmissing-prototypes\ + -Wshadow -Wwrite-strings -save-temps -Os -s\ -mcpu=arm7tdmi -mtune=arm7tdmi\ -fomit-frame-pointer\ -ffast-math \ diff --git a/build_proper_warnings.sh b/build_proper_warnings.sh new file mode 100755 index 0000000..c9351af --- /dev/null +++ b/build_proper_warnings.sh @@ -0,0 +1,9 @@ + +if [ -z "$DEVKITARM" ]; +then + echo "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM"; +else + make 2>&1 >/dev/null | grep ^$(pwd); +fi + + diff --git a/source/bin_table_handler.c b/source/bin_table_handler.c index 8076b34..7ee3ee8 100644 --- a/source/bin_table_handler.c +++ b/source/bin_table_handler.c @@ -2,7 +2,7 @@ #include "bin_table_handler.h" const u8* get_table_pointer(const u8* table, u16 entry){ - u16* table_16 = (u16*)table; + const u16* table_16 = (const u16*)table; u16 initial_offset; u32 offset = 0; u8 offset_table_pos = 2; @@ -30,7 +30,7 @@ const u8* get_table_pointer(const u8* table, u16 entry){ } const u8* search_table_for_index(const u8* table, u16 index){ - u16* table_16 = (u16*)table; + const u16* table_16 = (const u16*)table; u16 initial_offset; u32 offset = 0; u8 offset_table_pos = 2; diff --git a/source/communicator.c b/source/communicator.c index 69ff464..d525a6b 100644 --- a/source/communicator.c +++ b/source/communicator.c @@ -4,6 +4,7 @@ #include "sio_buffers.h" #include "vcount_basic.h" #include "print_system.h" +#include "useful_qualifiers.h" #define GEN2_ENTER_STATES_NUM 4 #define GEN2_START_STATES_NUM 5 @@ -17,6 +18,25 @@ #define NUMBER_OF_ENTITIES 2 +void set_start_state(enum START_TRADE_STATE); +void init_received_gen3(void); +u16 get_pos_bytes_from_index(u16); +u16 get_index_from_pos_bytes(u8, u8); +u8 set_received_gen3(u16); +u16 get_first_not_received_gen3(void); +u16 get_not_received_length_gen3(u16); +int increment_last_tranfer(void); +void reset_transfer_data_between_sync(void); +void init_transfer_data(void); +u8 get_offer(u8, u8, u8); +u8 get_accept(u8, u8); +int communicate_buffer(u8, u8); +int check_if_continue(u8, const u8*, const u8*, u32, int, int, u8); +int process_data_arrived_gen1(u8, u8); +int process_data_arrived_gen2(u8, u8); +u32 prepare_out_data_gen3(void); +void process_in_data_gen3(u32); + const u8 gen2_start_trade_enter_room[NUMBER_OF_ENTITIES][GEN2_ENTER_STATES_NUM] = { {ENTER_TRADE_SLAVE, 0x61, 0xD1, 0x00}, {ENTER_TRADE_MASTER, 0x61, 0xD1, 0x00} @@ -61,8 +81,8 @@ u8 syn_transmitted; u8 has_transmitted_syn; volatile u8 next_long_pause = 0; int last_transfer_counter; -int buffer_counter; -int buffer_counter_out; +u32 buffer_counter; +u32 buffer_counter_out; u8 start_state_updated; enum START_TRADE_STATE start_state; enum TRADING_STATE trading_state; @@ -135,7 +155,7 @@ u16 get_transferred(u8 index) { } void init_received_gen3() { - for(int i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) + for(u32 i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) received_gen3[i] = 0; buffer_counter = 0; own_end_gen3 = -1; @@ -171,7 +191,7 @@ u8 set_received_gen3(u16 index) { } u16 get_first_not_received_gen3() { - for(int i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) + for(u32 i = 0; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) for(int j = 0; j < 8; j++) { if(((i<<3) + j) >= (sizeof(struct gen3_trade_data)>>1)) return sizeof(struct gen3_trade_data)>>1; @@ -188,7 +208,7 @@ u16 get_not_received_length_gen3(u16 index) { int j_pos = index & 7; int j = j_pos; int total = 0; - for(int i = i_pos; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) { + for(u32 i = i_pos; i < ((sizeof(struct gen3_trade_data) >> 4)+1); i++) { for(; j < 8; j++) { if(((i<<3) + j) >= (sizeof(struct gen3_trade_data)>>1)) return total; @@ -243,7 +263,8 @@ void init_start_state() { IWRAM_CODE u8 get_offer(u8 data, u8 trade_offer_start, u8 end_trade_value) { next_long_pause = 1; - if(((data >= trade_offer_start) && (data < trade_offer_start + PARTY_SIZE)) || (data == end_trade_value)) { + u8 limit_trade_offer = trade_offer_start + PARTY_SIZE; + if(((data >= trade_offer_start) && (data < limit_trade_offer)) || (data == end_trade_value)) { trade_offer_in = data - trade_offer_start; trading_state = RECEIVED_OFFER; } @@ -259,7 +280,7 @@ IWRAM_CODE u8 get_accept(u8 data, u8 trade_offer_start) { return trade_offer_start + trade_offer_out; } -IWRAM_CODE __attribute__((optimize(3))) void set_next_vcount_interrupt(void){ +IWRAM_CODE MAX_OPTIMIZE void set_next_vcount_interrupt(void){ int next_stop = REG_VCOUNT + VCOUNT_WAIT_LINES; if(next_stop >= SCANLINES) next_stop -= SCANLINES; @@ -300,7 +321,7 @@ IWRAM_CODE int communicate_buffer(u8 data, u8 is_master) { in_buffer[buffer_counter + base_pos] = data; last_transfer_counter = 0; buffer_counter++; - if((buffer_counter == (transfer_sizes[sizes_index])) || ((!is_master) && (sizes_index == get_number_of_buffers()-1) && (buffer_counter == transfer_sizes[sizes_index]-base_pos_out))) { + if((buffer_counter == (transfer_sizes[sizes_index])) || ((!is_master) && (sizes_index == get_number_of_buffers()-1) && (buffer_counter == ((u32)(transfer_sizes[sizes_index]-base_pos_out))))) { base_pos += transfer_sizes[sizes_index]; sizes_index++; reset_transfer_data_between_sync(); @@ -321,7 +342,7 @@ IWRAM_CODE int communicate_buffer(u8 data, u8 is_master) { return out_buffer[buffer_counter_out - 1 + base_pos]; } -IWRAM_CODE int check_if_continue(u8 data, const u8* sends, const u8* recvs, int size, int new_state, int new_send, u8 filter) { +IWRAM_CODE int check_if_continue(u8 data, const u8* sends, const u8* recvs, u32 size, int new_state, int new_send, u8 filter) { if((filter) && (data >= 0x10)) data = data & 0xF0; if(data == recvs[buffer_counter]) { @@ -341,7 +362,7 @@ IWRAM_CODE int process_data_arrived_gen1(u8 data, u8 is_master) { if(start_state != START_TRADE_DON) switch(start_state) { case START_TRADE_ENT: - return check_if_continue(data, gen1_start_trade_enter_room[is_master], gen1_start_trade_enter_room_next[is_master], GEN1_ENTER_STATES_NUM, START_TRADE_WAI, (START_TRADE_BYTE_GEN1 | 1), 1); + return check_if_continue(data, gen1_start_trade_enter_room[is_master], gen1_start_trade_enter_room_next[is_master], GEN1_ENTER_STATES_NUM, START_TRADE_WAI, START_TRADE_BYTE_GEN1 | 1, 1); case START_TRADE_STA: return check_if_continue(data, gen1_start_trade_start_trade_procedure[is_master], gen1_start_trade_start_trade_procedure_next[is_master], GEN1_START_STATES_NUM, START_TRADE_SYN, SEND_NO_INFO, 1); case START_TRADE_PAR: @@ -374,7 +395,7 @@ IWRAM_CODE int process_data_arrived_gen1(u8 data, u8 is_master) { } if((!is_master) && (filtered_data == START_TRADE_BYTE_GEN1)) { buffer_counter++; - if(buffer_counter == MAX_WAIT_FOR_SYN) { + if(buffer_counter >= MAX_WAIT_FOR_SYN) { buffer_counter = 0; last_filtered = 0; init_transfer_data(); @@ -383,7 +404,7 @@ IWRAM_CODE int process_data_arrived_gen1(u8 data, u8 is_master) { } if((!is_master) && (filtered_data == CHOICE_BYTE_GEN1)) { buffer_counter++; - if(buffer_counter == MAX_WAIT_FOR_SYN) { + if(buffer_counter >= MAX_WAIT_FOR_SYN) { buffer_counter = 0; last_filtered = 0; set_start_state(START_TRADE_STA); @@ -405,7 +426,7 @@ IWRAM_CODE int process_data_arrived_gen1(u8 data, u8 is_master) { if(is_master) { if(start_state == START_TRADE_UNK) return gen1_start_trade_enter_room[is_master][0]; - return (START_TRADE_BYTE_GEN1 | 1); + return START_TRADE_BYTE_GEN1 | 1; } return SEND_NO_INFO; } @@ -591,7 +612,7 @@ void process_in_data_gen3(u32 data) { } } -IWRAM_CODE __attribute__((optimize(3))) void slave_routine(void) { +IWRAM_CODE MAX_OPTIMIZE void slave_routine(void) { if(!(REG_IF & IRQ_SERIAL)){ REG_IF |= IRQ_SERIAL; int value; @@ -613,7 +634,7 @@ IWRAM_CODE __attribute__((optimize(3))) void slave_routine(void) { } } -IWRAM_CODE __attribute__((optimize(3))) void master_routine_gen3(void) { +IWRAM_CODE MAX_OPTIMIZE void master_routine_gen3(void) { REG_IF |= IRQ_VCOUNT; int data; u8 success = 0; @@ -629,7 +650,7 @@ IWRAM_CODE __attribute__((optimize(3))) void master_routine_gen3(void) { set_next_vcount_interrupt(); } -IWRAM_CODE __attribute__((optimize(3))) void master_routine_gen12(void) { +IWRAM_CODE MAX_OPTIMIZE void master_routine_gen12(void) { REG_IF |= IRQ_VCOUNT; int data; diff --git a/source/communicator.h b/source/communicator.h index a10de97..80fa0ee 100644 --- a/source/communicator.h +++ b/source/communicator.h @@ -38,22 +38,23 @@ enum START_TRADE_STATE {START_TRADE_UNK, START_TRADE_ENT, START_TRADE_STA, START_TRADE_END, START_TRADE_WAI, START_TRADE_PAR, START_TRADE_SYN, START_TRADE_DON, START_TRADE_NO_UPDATE}; enum TRADING_STATE {NO_INFO, HAVE_OFFER, RECEIVED_OFFER, HAVE_ACCEPT, RECEIVED_ACCEPT, DURING_TRADE, COMPLETED_TRADE}; -void try_to_end_trade(); +void try_to_end_trade(void); void try_to_offer(u8); -void try_to_accept_offer(); -void try_to_decline_offer(); -int get_received_trade_offer(); -int has_accepted_offer(); +void try_to_accept_offer(void); +void try_to_decline_offer(void); +int get_received_trade_offer(void); +int has_accepted_offer(void); void start_transfer(u8, u8); -void set_next_vcount_interrupt(); +void set_next_vcount_interrupt(void); void stop_transfer(u8); -int increment_last_tranfer(); -void init_start_state(); -enum TRADING_STATE get_trading_state(); -enum START_TRADE_STATE get_start_state(); -enum START_TRADE_STATE get_start_state_raw(); +int increment_last_tranfer(void); +void init_start_state(void); +enum TRADING_STATE get_trading_state(void); +enum START_TRADE_STATE get_start_state(void); +enum START_TRADE_STATE get_start_state_raw(void); u16 get_transferred(u8); void slave_routine(void); void master_routine_gen12(void); +void master_routine_gen3(void); #endif diff --git a/source/fast_pokemon_methods.h b/source/fast_pokemon_methods.h index d84a629..e46aecb 100644 --- a/source/fast_pokemon_methods.h +++ b/source/fast_pokemon_methods.h @@ -3,19 +3,24 @@ #include "optimized_swi.h" #include "party_handler.h" +#include "useful_qualifiers.h" -static __attribute__((optimize(3), always_inline)) inline u8 get_nature_fast(u32 pid){ +static u8 get_nature_fast(u32); +static u8 get_unown_letter_gen3_fast(u32); +static u8 get_unown_letter_gen2_fast(u16); + +ALWAYS_INLINE MAX_OPTIMIZE u8 get_nature_fast(u32 pid){ // Make use of modulo properties to get this to positives while(pid >= 0x80000000) pid -= 0x7FFFFFE9; return SWI_DivMod(pid, NUM_NATURES); } -static __attribute__((optimize(3), always_inline)) inline u8 get_unown_letter_gen3_fast(u32 pid){ +ALWAYS_INLINE MAX_OPTIMIZE u8 get_unown_letter_gen3_fast(u32 pid){ return SWI_DivMod((pid & 3) + (((pid >> 8) & 3) << 2) + (((pid >> 16) & 3) << 4) + (((pid >> 24) & 3) << 6), NUM_UNOWN_LETTERS_GEN3); } -static __attribute__((optimize(3), always_inline)) inline u8 get_unown_letter_gen2_fast(u16 ivs){ +ALWAYS_INLINE MAX_OPTIMIZE u8 get_unown_letter_gen2_fast(u16 ivs){ u8 atk_ivs = ((ivs>>4) & 0xF); u8 def_ivs = ((ivs) & 0xF); u8 spe_ivs = ((ivs>>12) & 0xF); diff --git a/source/gen12_methods.c b/source/gen12_methods.c new file mode 100644 index 0000000..ef233a1 --- /dev/null +++ b/source/gen12_methods.c @@ -0,0 +1,199 @@ +#include +#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" +#include "gen1_to_3_conv_table_bin.h" +#include "pokemon_gender_bin.h" +#include "pokemon_names_bin.h" +#include "gen2_names_jap_bin.h" +#include "pokemon_stats_gen1_bin.h" +#include "pokemon_stats_bin.h" + +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}; + +const struct stats_gen_23* stats_table_gen2 = (const struct stats_gen_23*)pokemon_stats_bin; +const struct stats_gen_1* stats_table_gen1 = (const struct stats_gen_1*)pokemon_stats_gen1_bin; + +u8 has_legal_moves_gen12(u8* moves, u8 is_gen2) { + u8 last_valid_move = LAST_VALID_GEN_1_MOVE; + if(is_gen2) + last_valid_move = LAST_VALID_GEN_2_MOVE; + + u8 previous_moves[MOVES_SIZE]; + u8 curr_slot = 0; + for(int i = 0; i < MOVES_SIZE; i++) { + if((moves[i] != 0) && (moves[i] <= last_valid_move)) { + for(int j = 0; j < curr_slot; j++) + if(moves[i] == previous_moves[j]) + return 0; + previous_moves[curr_slot++] = moves[i]; + } + } + + if(curr_slot) + return 1; + return 0; +} + +u8 get_ivs_gen2(u16 ivs, u8 stat_index) { + u8 atk_ivs = (ivs >> 4) & 0xF; + u8 def_ivs = ivs & 0xF; + u8 spe_ivs = (ivs >> 12) & 0xF; + u8 spa_ivs = (ivs >> 8) & 0xF; + switch(stat_index) { + case HP_STAT_INDEX: + return ((atk_ivs & 1) << 3) | ((def_ivs & 1) << 2) | ((spe_ivs & 1) << 1) | (spa_ivs & 1); + case ATK_STAT_INDEX: + return atk_ivs; + case DEF_STAT_INDEX: + return def_ivs; + case SPE_STAT_INDEX: + return spe_ivs; + default: + return spa_ivs; + } +} + +u8 get_unown_letter_gen2(u16 ivs){ + return get_unown_letter_gen2_fast(ivs); +} + +s32 get_proper_exp_gen2(u16 mon_index, u8 level, u8* given_exp) { + s32 exp = (given_exp[0]<<0x10) + (given_exp[1]<<0x8) + (given_exp[2]<<0); + s32 min_exp = get_level_exp_mon_index(mon_index, level); + s32 max_exp = min_exp; + if(level == MAX_LEVEL) + exp = min_exp; + else + max_exp = get_level_exp_mon_index(mon_index, level+1)-1; + if(exp < min_exp) + exp = min_exp; + if(exp > max_exp) + exp = max_exp; + if(exp < 0) + exp = 0; + + return exp; +} +u8 is_shiny_gen2(u8 atk_ivs, u8 def_ivs, u8 spa_ivs, u8 spe_ivs) { + if((atk_ivs & 2) == 2 && def_ivs == 10 && spa_ivs == 10 && spe_ivs == 10) + return 1; + return 0; +} + +u8 is_shiny_gen2_unfiltered(u16 ivs) { + return is_shiny_gen2((ivs >> 4) & 0xF, ivs & 0xF, (ivs >> 8) & 0xF, (ivs >> 12) & 0xF); +} + +u8 is_shiny_gen2_raw(struct gen2_mon_data* src) { + return is_shiny_gen2_unfiltered(src->ivs); +} + +u16 get_mon_index_gen1(int index) { + if(index > LAST_VALID_GEN_1_MON) + return 0; + return gen3_to_1_conv_table_bin[index]; +} + + +u16 get_mon_index_gen2_1(int index) { + if(index > LAST_VALID_GEN_1_MON) + return 0; + return index; +} + +u16 get_mon_index_gen2(int index, u8 is_egg) { + if(index > LAST_VALID_GEN_2_MON) + return 0; + if(is_egg) + return GEN2_EGG; + return index; +} + +u16 get_mon_index_gen1_to_3(u8 index){ + return gen1_to_3_conv_table_bin[index]; +} + +u16 calc_stats_gen1(u16 species, u8 stat_index, u8 level, u8 iv, u16 stat_exp) { + if(species > LAST_VALID_GEN_1_MON) + species = 0; + species = get_mon_index_gen1(species); + if(stat_index >= GEN1_STATS_TOTAL) + stat_index = GEN1_STATS_TOTAL-1; + u16 base = 5; + if(stat_index == HP_STAT_INDEX) + base = level + 10; + u16 stat_exp_contribution = Sqrt(stat_exp); + // Bulbapedia error... + //if((stat_exp_contribution * stat_exp_contribution) < stat_exp) + // stat_exp_contribution += 1; + return base + Div((((stats_table_gen1[species].stats[stat_index] + iv)*2) + (stat_exp_contribution >> 2)) * level, 100); +} + +u16 calc_stats_gen2(u16 species, u32 pid, u8 stat_index, u8 level, u8 iv, u16 stat_exp) { + if(species > LAST_VALID_GEN_2_MON) + species = 0; + if(stat_index >= GEN2_STATS_TOTAL) + stat_index = GEN2_STATS_TOTAL-1; + + u16 mon_index = get_mon_index(species, pid, 0, 0); + + stat_index = stat_index_conversion_gen2[stat_index]; + u16 base = 5; + if(stat_index == HP_STAT_INDEX) + base = level + 10; + u16 stat_exp_contribution = Sqrt(stat_exp); + // Bulbapedia error... + //if((stat_exp_contribution * stat_exp_contribution) < stat_exp) + // stat_exp_contribution += 1; + return base + Div((((stats_table_gen2[mon_index].stats[stat_index] + iv)*2) + (stat_exp_contribution >> 2)) * level, 100); +} + +u8 get_gender_thresholds_gen12(u8 gender_kind) { + if(gender_kind >= TOTAL_GENDER_KINDS) + gender_kind = 0; + return gender_thresholds_gen12[gender_kind]; +} + +u8 get_pokemon_gender_kind_gen2(u8 index, u8 is_egg, u8 curr_gen) { + if(curr_gen == 1) + return pokemon_gender_bin[get_mon_index_gen2_1(index)]; + return pokemon_gender_bin[get_mon_index_gen2(index, is_egg)]; +} + +const u8* get_pokemon_name_gen2(int index, u8 is_egg, u8 is_jp, u8* buffer) { + if(is_jp) + return &(gen2_names_jap_bin[get_mon_index_gen2(index, is_egg)*STRING_GEN2_JP_CAP]); + u8 buffer_two[STRING_GEN2_INT_SIZE]; + 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_generic_to_gen3(get_table_pointer(pokemon_names_bin, mon_index), buffer_two, NAME_SIZE, STRING_GEN2_INT_CAP, 0, 0); + text_gen3_to_gen12(buffer_two, buffer, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP, 0, 0); + return 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){ + case M_INDEX: + case NIDORAN_M_GENDER_INDEX: + return M_GENDER; + case F_INDEX: + case NIDORAN_F_GENDER_INDEX: + return F_GENDER; + case U_INDEX: + return U_GENDER; + default: + if(atk_ivs >= get_gender_thresholds_gen12(gender_kind)) + return M_GENDER; + return F_GENDER; + } +} diff --git a/source/gen12_methods.h b/source/gen12_methods.h new file mode 100644 index 0000000..8dd38f0 --- /dev/null +++ b/source/gen12_methods.h @@ -0,0 +1,24 @@ +#ifndef GEN12_METHODS__ +#define GEN12_METHODS__ + +#include "party_handler.h" + +u8 has_legal_moves_gen12(u8*, u8); +u8 get_ivs_gen2(u16, u8); +u8 get_unown_letter_gen2(u16); +s32 get_proper_exp_gen2(u16, u8, u8*); +u8 is_shiny_gen2(u8, u8, u8, u8); +u8 is_shiny_gen2_unfiltered(u16); +u8 is_shiny_gen2_raw(struct gen2_mon_data*); +u16 get_mon_index_gen1(int); +u16 get_mon_index_gen2_1(int); +u16 get_mon_index_gen2(int, u8); +u16 get_mon_index_gen1_to_3(u8); +u16 calc_stats_gen1(u16, u8, u8, u8, u16); +u16 calc_stats_gen2(u16, u32, u8, u8, u8, u16); +u8 get_gender_thresholds_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(int, u8, u8, u8*); + +#endif diff --git a/source/gen3_save.c b/source/gen3_save.c index d83948b..fd06305 100644 --- a/source/gen3_save.c +++ b/source/gen3_save.c @@ -1,6 +1,7 @@ #include #include "save.h" #include "gen3_save.h" +#include "gen_converter.h" #include "text_handler.h" #define MAGIC_NUMBER 0x08012025 @@ -25,6 +26,16 @@ #define VALID_MAPS 36 +u32 read_section_id(int, int); +void read_game_data_trainer_info(int, struct game_data_t*); +void register_dex_entry(struct game_data_t*, struct gen3_mon_data_unenc*); +void handle_mail_trade(struct game_data_t*, u8, u8); +void process_party_data(struct game_data_t*); +void read_party(int, struct game_data_t*); +u32 read_slot_index(int); +u8 validate_slot(int); +u8 get_slot(void); + const u16 summable_bytes[SECTION_TOTAL] = {3884, 3968, 3968, 3968, 3848, 3968, 3968, 3968, 3968, 3968, 3968, 3968, 3968, 2000}; const u16 pokedex_extra_pos_1 [] = {0x938, 0x5F8, 0x988}; const u16 pokedex_extra_pos_2 [] = {0xC0C, 0xB98, 0xCA4}; @@ -51,7 +62,7 @@ void init_game_data(struct game_data_t* game_data) { } u32 read_section_id(int slot, int section_pos) { - if(slot != 0) + if(slot) slot = 1; if(section_pos < 0) section_pos = 0; @@ -62,7 +73,7 @@ u32 read_section_id(int slot, int section_pos) { } void read_game_data_trainer_info(int slot, struct game_data_t* game_data) { - if(slot != 0) + if(slot) slot = 1; for(int i = 0; i < SECTION_TOTAL; i++) @@ -97,7 +108,7 @@ void handle_mail_trade(struct game_data_t* game_data, u8 own_mon, u8 other_mon) mail_id = get_mail_id_raw(&game_data[1].party_3_undec[other_mon]); if((mail_id != GEN3_NO_MAIL) && (mail_id < PARTY_SIZE)) { u8 is_mail_free[PARTY_SIZE] = {1,1,1,1,1,1}; - for(int i = 0; i < game_data[0].party_3.total; i++) { + for(u32 i = 0; i < game_data[0].party_3.total; i++) { u8 inner_mail_id = get_mail_id_raw(&game_data[0].party_3_undec[i]); if((inner_mail_id != GEN3_NO_MAIL) && (inner_mail_id < PARTY_SIZE)) is_mail_free[inner_mail_id] = 0; @@ -110,7 +121,7 @@ void handle_mail_trade(struct game_data_t* game_data, u8 own_mon, u8 other_mon) } u8* dst = (u8*)&game_data[0].mails_3[target]; u8* src = (u8*)&game_data[1].mails_3[mail_id]; - for(int i = 0; i < sizeof(struct mail_gen3); i++) + for(u32 i = 0; i < sizeof(struct mail_gen3); i++) dst[i] = src[i]; game_data[1].party_3_undec[other_mon].src->mail_id = target; } @@ -123,11 +134,11 @@ u8 trade_mons(struct game_data_t* game_data, u8 own_mon, u8 other_mon, const u16 u8* dst = (u8*)&game_data[0].party_3.mons[own_mon]; u8* src = (u8*)&game_data[1].party_3.mons[other_mon]; - for(int i = 0; i < sizeof(struct gen3_mon); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon); i++) dst[i] = src[i]; dst = (u8*)&game_data[0].party_3_undec[own_mon]; src = (u8*)&game_data[1].party_3_undec[other_mon]; - for(int i = 0; i < sizeof(struct gen3_mon_data_unenc); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_data_unenc); i++) dst[i] = src[i]; game_data[0].party_3_undec[own_mon].src = &game_data[0].party_3.mons[own_mon]; for(int i = 0; i < GIFT_RIBBONS; i++) @@ -164,14 +175,14 @@ void process_party_data(struct game_data_t* game_data) { game_data->party_3.total = PARTY_SIZE; u8 curr_slot = 0; u8 found = 0; - for(int i = 0; i < game_data->party_3.total; i++) { + for(u32 i = 0; i < game_data->party_3.total; i++) { process_gen3_data(&game_data->party_3.mons[i], &game_data->party_3_undec[i], game_data->game_identifier.game_main_version, game_data->game_identifier.game_sub_version); if(game_data->party_3_undec[i].is_valid_gen3) found = 1; } if (!found) game_data->party_3.total = 0; - for(int i = 0; i < game_data->party_3.total; i++) + for(u32 i = 0; i < game_data->party_3.total; i++) if(gen3_to_gen2(&game_data->party_2.mons[curr_slot], &game_data->party_3_undec[i], game_data->trainer_id)) { curr_slot++; game_data->party_3_undec[i].is_valid_gen2 = 1; @@ -180,7 +191,7 @@ void process_party_data(struct game_data_t* game_data) { game_data->party_3_undec[i].is_valid_gen2 = 0; game_data->party_2.total = curr_slot; curr_slot = 0; - for(int i = 0; i < game_data->party_3.total; i++) + for(u32 i = 0; i < game_data->party_3.total; i++) if(gen3_to_gen1(&game_data->party_1.mons[curr_slot], &game_data->party_3_undec[i], game_data->trainer_id)) { curr_slot++; game_data->party_3_undec[i].is_valid_gen1 = 1; @@ -191,7 +202,7 @@ void process_party_data(struct game_data_t* game_data) { } void read_party(int slot, struct game_data_t* game_data) { - if(slot != 0) + if(slot) slot = 1; read_game_data_trainer_info(slot, game_data); @@ -214,14 +225,14 @@ void read_party(int slot, struct game_data_t* game_data) { } u32 read_slot_index(int slot) { - if(slot != 0) + if(slot) slot = 1; return read_int_save((slot * SAVE_SLOT_SIZE) + SAVE_SLOT_INDEX_POS); } u8 validate_slot(int slot) { - if(slot != 0) + if(slot) slot = 1; u16 valid_sections = 0; diff --git a/source/gen3_save.h b/source/gen3_save.h index 70dcb79..242cf04 100644 --- a/source/gen3_save.h +++ b/source/gen3_save.h @@ -25,7 +25,7 @@ struct game_data_t { void init_game_data(struct game_data_t*); void read_gen_3_data(struct game_data_t*); void process_party_data(struct game_data_t* game_data); -struct game_data_t* get_own_game_data(); +struct game_data_t* get_own_game_data(void); u8 trade_mons(struct game_data_t*, u8, u8, const u16**, u8); u8 is_invalid_offer(struct game_data_t*, u8, u8); diff --git a/source/gen_converter.c b/source/gen_converter.c new file mode 100644 index 0000000..3b956db --- /dev/null +++ b/source/gen_converter.c @@ -0,0 +1,960 @@ +#include +#include "party_handler.h" +#include "gen12_methods.h" +#include "gen_converter.h" +#include "text_handler.h" +#include "version_identifier.h" +#include "bin_table_handler.h" +#include "gen3_save.h" +#include "rng.h" +#include "pid_iv_tid.h" +#include "fast_pokemon_methods.h" +#include "optimized_swi.h" +#include "useful_qualifiers.h" + +#include "pokemon_moves_pp_bin.h" +#include "item_gen3_to_12_bin.h" +#include "item_gen12_to_3_bin.h" +#include "pokemon_types_gen1_bin.h" +#include "encounter_types_bin.h" +#include "egg_locations_bin.h" +#include "encounters_static_bin.h" +#include "encounters_roamers_bin.h" +#include "encounters_unown_bin.h" +#include "encounter_types_gen2_bin.h" +#include "special_encounters_gen2_bin.h" + +#define MF_7_1_INDEX 2 +#define UNOWN_EX_LETTER 26 +#define UNOWN_I_LETTER 8 +#define UNOWN_V_LETTER 21 + +u16 swap_endian_short(u16); +u32 swap_endian_int(u32); +u8 validate_converting_mon_of_gen1(u8, struct gen1_mon_data*); +u8 validate_converting_mon_of_gen2(u8, struct gen2_mon_data*, u8*); +u8 validate_converting_mon_of_gen3(struct gen3_mon*, struct gen3_mon_growth*, u8, u8, u8, u8, u8); +u8 convert_moves_of_gen3(struct gen3_mon_attacks*, u8, u8*, u8*, u8); +u8 convert_moves_to_gen3(struct gen3_mon_attacks*, struct gen3_mon_growth*, u8*, u8*, u8); +u8 convert_item_of_gen3(u16); +u16 convert_item_to_gen3(u16); +void convert_exp_nature_of_gen3(struct gen3_mon*, struct gen3_mon_growth*, u8*, u8*, u8); +u8 get_exp_nature(struct gen3_mon*, struct gen3_mon_growth*, u8, u8*); +void convert_evs_of_gen3(struct gen3_mon_evs*, u16*); +void convert_evs_to_gen3(struct gen3_mon_evs*, u16*); +u16 convert_ivs_of_gen3(struct gen3_mon_misc*, u16, u32, u8, u8, u8, u8); +void set_ivs(struct gen3_mon_misc*, u32); +void set_origin_pid_iv(struct gen3_mon*, struct gen3_mon_misc*, 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); +void fix_name_change_to_gen3(struct gen3_mon*, 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); + +u16 swap_endian_short(u16 shrt) { + return ((shrt & 0xFF00) >> 8) | ((shrt & 0xFF) << 8); +} + +u32 swap_endian_int(u32 integer) { + return ((integer & 0xFF000000) >> 24) | ((integer & 0xFF) << 24) | ((integer & 0xFF0000) >> 8) | ((integer & 0xFF00) << 8); +} + +u8 validate_converting_mon_of_gen1(u8 index, struct gen1_mon_data* src) { + + // Check for matching index to species + if(index != src->species) + return 0; + + u8 conv_species = get_mon_index_gen1_to_3(src->species); + + // Is this a valid mon + if((conv_species > LAST_VALID_GEN_1_MON) || (conv_species == 0)) + return 0; + + // Does it have a valid movepool + if(!has_legal_moves_gen12(src->moves, 0)) + return 0; + + // Check for valid types + u8 matched[2] = {0,0}; + for(int i = 0; i < 2; i++) { + if((src->type[i] == pokemon_types_gen1_bin[(2*src->species)]) && (!matched[0])) + matched[0] = 1; + else if((src->type[i] == pokemon_types_gen1_bin[(2*src->species)+1]) && (!matched[1])) + matched[1] = 1; + } + for(int i = 0; i < 2; i++) + if(!matched[i]) + return 0; + + return 1; +} + +u8 validate_converting_mon_of_gen2(u8 index, struct gen2_mon_data* src, u8* is_egg) { + if(index == GEN2_EGG) + *is_egg = 1; + else + *is_egg = 0; + + // Check for matching index to species + if((!(*is_egg)) && (index != src->species)) + return 0; + + // Is this a valid mon + if((src->species > LAST_VALID_GEN_2_MON) || (src->species == 0)) + return 0; + + // Does it have a valid movepool + if(!has_legal_moves_gen12(src->moves, 1)) + return 0; + + return 1; +} + +u8 validate_converting_mon_of_gen3(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 is_shiny, u8 gender, u8 gender_kind, u8 is_egg, u8 is_gen2) { + u8 last_valid_mon = LAST_VALID_GEN_1_MON; + if(is_gen2) + last_valid_mon = LAST_VALID_GEN_2_MON; + + // Bad egg checks + if(src->is_bad_egg) + return 0; + + // Item checks + if(has_mail(src, growth, is_egg)) + return 0; + + // Validity checks + if((growth->species > last_valid_mon) || (growth->species == 0)) + return 0; + + // These Pokemon cannot be both female and shiny in gen 1/2 + if(is_shiny && (gender == F_GENDER) && (gender_kind == MF_7_1_INDEX)) + return 0; + + // Unown ! and ? did not exist in gen 2 + // Not only that, but only Unown I and V can be shiny + if(is_gen2 && (growth->species == UNOWN_SPECIES)) { + u8 letter = get_unown_letter_gen3(src->pid); + if(letter >= UNOWN_EX_LETTER) + return 0; + if(is_shiny && (letter != UNOWN_I_LETTER) && (letter != UNOWN_V_LETTER)) + return 0; + } + + // Eggs cannot be traded to gen 1 + if((!is_gen2) && is_egg) + return 0; + + return 1; +} + +u8 convert_moves_of_gen3(struct gen3_mon_attacks* attacks, u8 pp_bonuses, u8* moves, u8* pps, u8 is_gen2) { + // Start converting moves + u16 last_valid_move = LAST_VALID_GEN_1_MOVE; + if(is_gen2) + last_valid_move = LAST_VALID_GEN_2_MOVE; + + u8 used_slots = 0; + + for(int i = 0; i < MOVES_SIZE; i++) + { + moves[i] = 0; + pps[i] = 0; + } + for(int i = 0; i < MOVES_SIZE; i++) { + u16 move = attacks->moves[i]; + if((move > 0) && (move <= last_valid_move)) { + u8 base_pp = pokemon_moves_pp_bin[move]; + u8 bonus_pp = (pp_bonuses >> (2*i)) & 3; + u8 base_increase_pp = Div(base_pp, 5); + base_pp += (base_increase_pp * bonus_pp); + // Limit the PP to its maximum of 61 + if(base_pp > 61) + base_pp = 61; + base_pp |= (bonus_pp << 6); + pps[used_slots] = base_pp; + moves[used_slots++] = move; + } + } + + return used_slots; +} + +u8 convert_moves_to_gen3(struct gen3_mon_attacks* attacks, struct gen3_mon_growth* growth, u8* moves, u8* pps, u8 is_gen2) { + // Start converting moves + u8 last_valid_move = LAST_VALID_GEN_1_MOVE; + if(is_gen2) + last_valid_move = LAST_VALID_GEN_2_MOVE; + + u8 used_slots = 0; + + for(int i = 0; i < MOVES_SIZE; i++) { + u16 move = moves[i]; + if((move > 0) && (move <= last_valid_move)) { + u8 base_pp = pokemon_moves_pp_bin[move]; + u8 bonus_pp = (pps[i] >> 6) & 3; + u8 base_increase_pp = Div(base_pp, 5); + base_pp += (base_increase_pp * bonus_pp); + + growth->pp_bonuses |= (bonus_pp)<<(2*i); + attacks->pp[used_slots] = base_pp; + attacks->moves[used_slots++] = move; + } + } + + return used_slots; +} + +u8 convert_item_of_gen3(u16 item) { + if(item > LAST_VALID_GEN_3_ITEM) + item = 0; + item = item_gen3_to_12_bin[item]; + if((item == GEN2_NO_ITEM) || (item == GEN2_MAIL)) + item = 0; + return item; +} + +u16 convert_item_to_gen3(u16 item) { + item = item_gen12_to_3_bin[item*2] + (item_gen12_to_3_bin[(item*2)+1]<<8); + if(item == GEN3_NO_ITEM) + item = 0; + return item; +} + +void convert_exp_nature_of_gen3(struct gen3_mon* src, struct gen3_mon_growth* growth, u8* level_ptr, u8* exp_ptr, u8 is_gen2) { + if(((is_gen2) && (growth->species > LAST_VALID_GEN_2_MON)) || ((!is_gen2) && (growth->species > LAST_VALID_GEN_1_MON))) + return; + + // Level handling + u8 level = to_valid_level_gen3(src); + + u16 mon_index = get_mon_index(growth->species, src->pid, 0, 0); + + // Experience handling + s32 exp = get_proper_exp(src, growth, 0); + + s32 max_exp = exp; + if(level < MAX_LEVEL) + max_exp = get_level_exp_mon_index(mon_index, level+1)-1; + + // Save nature in experience, like the Gen I-VII conversion + u8 nature = get_nature(src->pid); + + // Nature handling + u8 exp_nature = DivMod(exp, NUM_NATURES); + if(exp_nature > nature) + nature += NUM_NATURES; + exp += nature - exp_nature; + if (level < MAX_LEVEL) + while (exp > max_exp) { + level++; + if(level == MAX_LEVEL) { + exp = max_exp+1; + break; + } + max_exp = get_level_exp_mon_index(mon_index, level+1)-1; + } + if ((level == MAX_LEVEL) && (exp != get_level_exp_mon_index(mon_index, MAX_LEVEL))){ + level--; + exp -= NUM_NATURES; + } + + // Store exp and level + *level_ptr = level; + for(int i = 0; i < 3; i++) + exp_ptr[2-i] = (exp >> (8*i))&0xFF; +} + +u8 get_exp_nature(struct gen3_mon* dst, struct gen3_mon_growth* growth, u8 level, u8* given_exp) { + // Level handling + level = to_valid_level(level); + + u16 mon_index = get_mon_index_gen2(growth->species, 0); + + // Experience handling + s32 exp = get_proper_exp_gen2(mon_index, level, given_exp); + + // Save nature in experience, like the Gen I-VII conversion + u8 nature = SWI_DivMod(exp, NUM_NATURES); + + // Store exp and level + dst->level = level; + growth->exp = exp; + return nature; +} + +void convert_evs_of_gen3(struct gen3_mon_evs* evs, u16* old_evs) { + // Convert to Gen1/2 EVs + u16 evs_total = 0; + for(int i = 0; i < EVS_TOTAL_GEN3; i++) + evs_total += evs->evs[i]; + if(evs_total >= MAX_USABLE_EVS) + evs_total = MAX_EVS; + u16 new_evs = ((evs_total+1)>>1) * ((evs_total+1)>>1); + for(int i = 0; i < EVS_TOTAL_GEN12; i++) + old_evs[i] = swap_endian_short(new_evs & 0xFFFF); +} + +void convert_evs_to_gen3(struct gen3_mon_evs* evs, u16* UNUSED(old_evs)) { + // A direct conversion is possible, but it would be + // atrocious for competitive/high-level battling... + for(int i = 0; i < EVS_TOTAL_GEN3; i++) + evs->evs[i] = 0; +} + +u16 convert_ivs_of_gen3(struct gen3_mon_misc* misc, u16 species, u32 pid, u8 is_shiny, u8 gender, u8 gender_kind, u8 is_gen2) { + if(((is_gen2) && (species > LAST_VALID_GEN_2_MON)) || ((!is_gen2) && (species > LAST_VALID_GEN_1_MON))) + return 0; + + // Assign IVs + // Keep in mind: Unown letter, gender and shinyness + // Hidden Power calculations are too restrictive + u8 atk_ivs = misc->atk_ivs >> 1; + u8 def_ivs = misc->def_ivs >> 1; + u8 spa_ivs = (misc->spa_ivs + misc->spd_ivs) >> 2; + u8 spe_ivs = misc->spe_ivs >> 1; + + // Handle roamers losing IVs when caught + u8 origin_game = (misc->origins_info>>7)&0xF; + if(((species >= RAIKOU_SPECIES) && (species <= SUICUNE_SPECIES)) && ((origin_game == FR_VERSION_ID) || (origin_game == LG_VERSION_ID))) { + u32 real_ivs = 0; + if(get_roamer_ivs(pid, misc->hp_ivs, misc->atk_ivs, &real_ivs)){ + atk_ivs = ((real_ivs >> 5) & 0x1F) >> 1; + def_ivs = ((real_ivs >> 10) & 0x1F) >> 1; + spa_ivs = (((real_ivs >> 20) & 0x1F) + ((real_ivs >> 25) & 0x1F)) >> 2; + spe_ivs = ((real_ivs >> 15) & 0x1F) >> 1; + } + } + + // Unown letter + if((is_gen2) && (species == UNOWN_SPECIES)) { + u8 letter = get_unown_letter_gen3(pid); + u8 min_iv_sum = letter * 10; + u16 max_iv_sum = ((letter+1) * 10)-1; + if(max_iv_sum >= 0x100) + max_iv_sum = 0xFF; + u8 iv_sum = ((spa_ivs & 0x6) >> 1) | ((spe_ivs & 0x6) << 1) | ((def_ivs & 0x6) << 3) | ((atk_ivs & 0x6) << 5); + if(iv_sum < min_iv_sum) + iv_sum = min_iv_sum; + if(iv_sum > max_iv_sum) + iv_sum = max_iv_sum; + atk_ivs = (atk_ivs & 0x9) | ((iv_sum >> 5) & 0x6); + def_ivs = (def_ivs & 0x9) | ((iv_sum >> 3) & 0x6); + spe_ivs = (spe_ivs & 0x9) | ((iv_sum >> 1) & 0x6); + spa_ivs = (spa_ivs & 0x9) | ((iv_sum << 1) & 0x6); + } + + // Gender + // TODO: Remake this to offer a more fair conversion + if(gender != U_GENDER && gender_kind != M_INDEX && gender_kind != F_INDEX) { + if(gender == F_GENDER && atk_ivs >= get_gender_thresholds_gen12(gender_kind)) + atk_ivs = get_gender_thresholds_gen12(gender_kind) - 1; + else if(gender == M_GENDER && atk_ivs < get_gender_thresholds_gen12(gender_kind)) + atk_ivs = get_gender_thresholds_gen12(gender_kind); + } + + // Shinyness + if(is_shiny) { + atk_ivs = atk_ivs | 2; + def_ivs = 10; + spa_ivs = 10; + spe_ivs = 10; + } + if(!is_shiny && is_shiny_gen2(atk_ivs, def_ivs, spa_ivs, spe_ivs)) + spe_ivs = 11; + + return (atk_ivs << 4) | def_ivs | (spa_ivs << 8) | (spe_ivs << 12); +} + +void set_ivs(struct gen3_mon_misc* misc, u32 ivs) { + misc->hp_ivs = (ivs >> 0) & 0x1F; + misc->atk_ivs = (ivs >> 5) & 0x1F; + misc->def_ivs = (ivs >> 10) & 0x1F; + misc->spe_ivs = (ivs >> 15) & 0x1F; + misc->spa_ivs = (ivs >> 20) & 0x1F; + misc->spd_ivs = (ivs >> 25) & 0x1F; +} + +void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_misc* misc, u16 species, u16 wanted_ivs, u8 wanted_nature, u8 ot_gender, u8 is_egg, u8 no_restrictions) { + struct game_data_t* trainer_data = get_own_game_data(); + u8 trainer_game_version = id_to_version(&trainer_data->game_identifier); + u8 trainer_gender = trainer_data->trainer_gender; + + // Handle eggs separately + u32 ot_id = dst->ot_id; + if(is_egg) + ot_id = trainer_data->trainer_id; + + // Prepare the TSV + u16 tsv = (ot_id & 0xFFFF) ^ (ot_id >> 16); + + u8 chosen_version = FR_VERSION_ID; + if(!no_restrictions) { + chosen_version = trainer_game_version; + ot_gender = trainer_gender; + } + + u8 encounter_type = (encounter_types_bin[species>>2]>>(2*(species&3)))&3; + u8 is_shiny = is_shiny_gen2_unfiltered(wanted_ivs); + u32 ivs = 0; + const u8* searchable_table = egg_locations_bin; + u8 find_in_table = 0; + + // Get PID and IVs + switch(encounter_type) { + case STATIC_ENCOUNTER: + if(!is_shiny) + generate_static_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); + else + generate_static_shiny_info(wanted_nature, tsv, &dst->pid, &ivs); + searchable_table = encounters_static_bin; + find_in_table = 1; + break; + case ROAMER_ENCOUNTER: + if(!is_shiny) + generate_static_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); + else + generate_static_shiny_info(wanted_nature, tsv, &dst->pid, &ivs); + // Roamers only get the first byte of their IVs + ivs &= 0xFF; + searchable_table = encounters_roamers_bin; + find_in_table = 1; + break; + case UNOWN_ENCOUNTER: + if(!is_shiny) + generate_unown_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); + else + generate_unown_shiny_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); + searchable_table = encounters_unown_bin; + find_in_table = 1; + break; + default: + if(!is_shiny) + generate_egg_info(species, wanted_nature, wanted_ivs, tsv, 2, &dst->pid, &ivs); + else + generate_egg_shiny_info(species, wanted_nature, wanted_ivs, tsv, 2, &dst->pid, &ivs); + break; + } + + // Set met location and origins info + u8 met_location = egg_locations_bin[chosen_version]; + u8 met_level = 0; + + if(find_in_table) { + u16 mon_index = get_mon_index(species, dst->pid, 0, 0); + const u8* possible_met_data = search_table_for_index(searchable_table, mon_index); + if(possible_met_data != NULL) { + u8 num_elems = possible_met_data[0]; + u8 chosen_entry = 0; + for(int i = 0; i < num_elems; i++) + if(possible_met_data[1+(3*i)] == chosen_version) + chosen_entry = i; + chosen_version = possible_met_data[1+(3*chosen_entry)]; + met_location = possible_met_data[2+(3*chosen_entry)]; + met_level = possible_met_data[3+(3*chosen_entry)]; + } + } + misc->met_location = met_location; + misc->origins_info = ((ot_gender&1)<<15) | ((POKEBALL_ID&0xF)<<11) | ((chosen_version&0xF)<<7) | ((met_level&0x7F)<<0); + + // Set IVs + set_ivs(misc, ivs); + + // Set ability + if(dst->pid & 1) { + u16 abilities = get_possible_abilities_pokemon(species, dst->pid, 0, 0); + u8 abilities_same = (abilities&0xFF) == ((abilities>>8)&0xFF); + if(!abilities_same) + misc->ability = 1; + } +} + +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; + u32 trainer_id = trainer_data->trainer_id; + u8* trainer_name = trainer_data->trainer_name; + + // Languages do not match + if(is_jp ^ trainer_is_jp) + return 0; + + // IDs do not match + if((trainer_id & 0xFFFF) != (dst->ot_id & 0xFFFF)) + 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); + +} + +void fix_name_change_from_gen3(struct gen3_mon* src, u16 species, u8* nickname, u8 is_egg, u8 is_gen2) { + u8 tmp_text_buffer[NAME_SIZE]; + + // Get the string to compare to + text_generic_to_gen3(get_pokemon_name(species, src->pid, is_egg, 0), tmp_text_buffer, NAME_SIZE, NICKNAME_GEN3_SIZE, 0, 0); + + // If it's the same, update the nickname with the new one + if(text_gen3_is_same(src->nickname, tmp_text_buffer, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE)) { + text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 0, tmp_text_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP); + // Gen 1 used the wrong dot symbol + if(!is_gen2) + text_gen2_replace(nickname, STRING_GEN2_INT_CAP, GEN2_DOT, GEN1_DOT); + } +} + +void fix_name_change_to_gen3(struct gen3_mon* dst, u8 species) { + u8 tmp_text_buffer[STRING_GEN2_INT_CAP]; + u8 tmp_text_buffer2[NICKNAME_GEN3_SIZE]; + + // Get the string to compare to + text_gen12_to_gen3(get_pokemon_name_gen2(species, 0, 0, tmp_text_buffer), tmp_text_buffer2, STRING_GEN2_INT_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_generic_to_gen3(get_pokemon_name(species, 0, 0, 0), dst->nickname, NAME_SIZE, NICKNAME_GEN3_SIZE, 0, 0); +} + +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 is_jp = (src->language == JAPANESE_LANGUAGE); + + // 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); + + // Fix text up + // "MR.MIME" gen 2 == "MR. MIME" gen 3 + // Idk if something similar happens in Jap... + // Maybe there are some French things with accents... + if((species == MR_MIME_SPECIES) && !is_egg) + fix_name_change_from_gen3(src, species, nickname, is_egg, is_gen2); + + // Put the "EGG" name + if(is_gen2 && is_egg) { + text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 0, gen2_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP); + text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 1, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP); + } + + // Handle bad naming conversions (? >= half the name) and empty names + s32 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, 0, 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, 1, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP); + +} + +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; + + // 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); + + // 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; + is_jp = 1; + } + + // Fix text up + // "MR.MIME" gen 2 == "MR. MIME" gen 3 + // Idk if something similar happens in Jap... + // Maybe there are some French things with accents... + if((species == MR_MIME_SPECIES) && !is_egg && !is_jp) + fix_name_change_to_gen3(dst, species); + + // Put the "EGG" name + if(is_egg) { + dst->language = JAPANESE_LANGUAGE; + text_gen12_to_gen3(get_pokemon_name_gen2(species, 1, 1, gen2_buffer), dst->nickname, STRING_GEN2_JP_CAP, NICKNAME_GEN3_SIZE, 1, 1); + } + else { + // Handle bad naming conversions (? >= half the name) and empty names + s32 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, is_jp, gen2_buffer), dst->nickname, name_cap, NICKNAME_GEN3_SIZE, is_jp, is_jp); + } +} + +u8 gen3_to_gen2(struct gen2_mon* dst_data, struct gen3_mon_data_unenc* data_src, u32 trainer_id) { + + struct gen3_mon* src = data_src->src; + struct gen2_mon_data* dst = &dst_data->data; + + if(!data_src->is_valid_gen3) + return 0; + + struct gen3_mon_growth* growth = &data_src->growth; + struct gen3_mon_attacks* attacks = &data_src->attacks; + struct gen3_mon_evs* evs = &data_src->evs; + struct gen3_mon_misc* misc = &data_src->misc; + + // Get shinyness and gender for checks + u8 is_shiny = is_shiny_gen3_raw(data_src, trainer_id); + u8 gender = get_pokemon_gender_gen3(growth->species, src->pid, 0, data_src->deoxys_form); + u8 gender_kind = get_pokemon_gender_kind_gen3(growth->species, src->pid, 0, data_src->deoxys_form); + + // Check that the mon can be traded + if(!validate_converting_mon_of_gen3(src, growth, is_shiny, gender, gender_kind, data_src->is_egg, 1)) + return 0; + + // Reset data structure + for(u32 i = 0; i < sizeof(struct gen2_mon); i++) + ((u8*)dst_data)[i] = 0; + + // Start setting data + dst->species = growth->species; + + // Convert moves, and check if no valid moves were found + if(convert_moves_of_gen3(attacks, growth->pp_bonuses, dst->moves, dst->pps, 1) == 0) + return 0; + + // Item handling + dst->item = convert_item_of_gen3(growth->item); + + // OT handling + dst->ot_id = swap_endian_short(src->ot_id & 0xFFFF); + + // Assign level and experience + convert_exp_nature_of_gen3(src, growth, &dst->level, dst->exp, 1); + + // Convert EVs + u16 evs_container[EVS_TOTAL_GEN12]; + convert_evs_of_gen3(evs, evs_container); + for(int i = 0; i < EVS_TOTAL_GEN12; i++) + dst->evs[i] = evs_container[i]; + + // Assign IVs + dst->ivs = convert_ivs_of_gen3(misc, growth->species, src->pid, is_shiny, gender, gender_kind, 1); + + // Is this really how it works...? + dst->pokerus = misc->pokerus; + + // Defaults + dst->friendship = BASE_FRIENDSHIP; + dst->status = 0; + dst->unused = 0; + + // Handle met location data + dst->time = 1; + dst->ot_gender = (misc->origins_info>>15)&1; + + // Handle special mons which cannot breed + const struct special_met_data_gen2* met_data = NULL; + if(encounter_types_gen2_bin[dst->species>>3]&(1<<(dst->species&7))) { + met_data = (const struct special_met_data_gen2*)search_table_for_index(special_encounters_gen2_bin, dst->species); + if(met_data != NULL) { + dst->location = met_data->location; + dst->met_level = met_data->level; + if((dst->location == 0) && (dst->location == dst->met_level)) { + dst->time = 0; + dst->ot_gender = 0; + } + } + } + if(met_data == NULL) { + dst->met_level = 1; + dst->location = 1; + } + + // Extra byte for egg data + dst_data->is_egg = data_src->is_egg; + + // Stats calculations + // Curr HP should be 0 for eggs, otherwise they count as party members + if(!dst_data->is_egg) + dst->curr_hp = swap_endian_short(calc_stats_gen2(growth->species, src->pid, HP_STAT_INDEX, dst->level, get_ivs_gen2(dst->ivs, HP_STAT_INDEX), swap_endian_short(dst->evs[HP_STAT_INDEX]))); + else + dst->curr_hp = 0; + for(int i = 0; i < GEN2_STATS_TOTAL; i++) + dst->stats[i] = swap_endian_short(calc_stats_gen2(growth->species, src->pid, i, dst->level, get_ivs_gen2(dst->ivs, i), swap_endian_short(dst->evs[i >= EVS_TOTAL_GEN12 ? EVS_TOTAL_GEN12-1 : i]))); + + // Store egg cycles + if(dst_data->is_egg) + dst->friendship = growth->friendship; + + // Text conversions + convert_strings_of_gen3(src, growth->species, dst_data->ot_name, dst_data->ot_name_jp, dst_data->nickname, dst_data->nickname_jp, dst_data->is_egg, 1); + + return 1; +} + +u8 gen3_to_gen1(struct gen1_mon* dst_data, struct gen3_mon_data_unenc* data_src, u32 trainer_id) { + + struct gen3_mon* src = data_src->src; + struct gen1_mon_data* dst = &dst_data->data; + + if(!data_src->is_valid_gen3) + return 0; + + struct gen3_mon_growth* growth = &data_src->growth; + struct gen3_mon_attacks* attacks = &data_src->attacks; + struct gen3_mon_evs* evs = &data_src->evs; + struct gen3_mon_misc* misc = &data_src->misc; + + // Get shinyness and gender for checks + u8 is_shiny = is_shiny_gen3_raw(data_src, trainer_id); + u8 gender = get_pokemon_gender_gen3(growth->species, src->pid, 0, data_src->deoxys_form); + u8 gender_kind = get_pokemon_gender_kind_gen3(growth->species, src->pid, 0, data_src->deoxys_form); + + // Check that the mon can be traded + if(!validate_converting_mon_of_gen3(src, growth, is_shiny, gender, gender_kind, data_src->is_egg, 0)) + return 0; + + // Reset data structure + for(u32 i = 0; i < sizeof(struct gen1_mon); i++) + ((u8*)dst_data)[i] = 0; + + // Start setting data + dst->species = get_mon_index_gen1(growth->species); + + // Convert moves, and check if no valid moves were found + if(convert_moves_of_gen3(attacks, growth->pp_bonuses, dst->moves, dst->pps, 0) == 0) + return 0; + + // Item handling + dst->item = convert_item_of_gen3(growth->item); + + // Types handling + dst->type[0] = pokemon_types_gen1_bin[(2*dst->species)]; + dst->type[1] = pokemon_types_gen1_bin[(2*dst->species) + 1]; + + // OT handling + dst->ot_id = swap_endian_short(src->ot_id & 0xFFFF); + + // Assign level and experience + convert_exp_nature_of_gen3(src, growth, &dst->level, dst->exp, 0); + + // Convert EVs + u16 evs_container[EVS_TOTAL_GEN12]; + convert_evs_of_gen3(evs, evs_container); + for(int i = 0; i < EVS_TOTAL_GEN12; i++) + dst->evs[i] = evs_container[i]; + + // Assign IVs + dst->ivs = convert_ivs_of_gen3(misc, growth->species, src->pid, is_shiny, gender, gender_kind, 0); + + // Defaults + dst->bad_level = 0; + dst->status = 0; + + // Stats calculations + dst->curr_hp = swap_endian_short(calc_stats_gen1(growth->species, HP_STAT_INDEX, dst->level, get_ivs_gen2(dst->ivs, HP_STAT_INDEX), swap_endian_short(dst->evs[HP_STAT_INDEX]))); + for(int i = 0; i < GEN1_STATS_TOTAL; i++) + dst->stats[i] = swap_endian_short(calc_stats_gen1(growth->species, i, dst->level, get_ivs_gen2(dst->ivs, i), swap_endian_short(dst->evs[i]))); + + // Text conversions + convert_strings_of_gen3(src, growth->species, dst_data->ot_name, dst_data->ot_name_jp, dst_data->nickname, dst_data->nickname_jp, 0, 0); + + return 1; +} + +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; + u8 is_egg = 0; + + // Reset everything + for(u32 i = 0; i < sizeof(struct gen3_mon); i++) + ((u8*)(dst))[i] = 0; + + data_dst->is_valid_gen3 = 0; + data_dst->is_valid_gen2 = 0; + + // Check if valid + if(!validate_converting_mon_of_gen2(index, src, &is_egg)) + return 0; + + data_dst->is_valid_gen3 = 1; + data_dst->is_valid_gen2 = 1; + + // Set base data + dst->has_species = 1; + dst->mail_id = GEN3_NO_MAIL; + data_dst->is_egg = is_egg; + + if(is_jp) + dst->language = JAPANESE_LANGUAGE; + else + dst->language = ENGLISH_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); + + // Reset everything + for(u32 i = 0; i < sizeof(struct gen3_mon_growth); i++) + ((u8*)(&data_dst->growth))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_attacks); i++) + ((u8*)(&data_dst->attacks))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_evs); i++) + ((u8*)(&data_dst->evs))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_misc); i++) + ((u8*)(&data_dst->misc))[i] = 0; + + // Set species, exp, level and item + data_dst->growth.species = src->species; + u8 wanted_nature = get_exp_nature(dst, &data_dst->growth, src->level, src->exp); + data_dst->growth.item = convert_item_to_gen3(src->item); + + // Convert EVs + u16 evs_container[EVS_TOTAL_GEN12]; + for(int i = 0; i < EVS_TOTAL_GEN12; i++) + evs_container[i] = src->evs[i]; + convert_evs_to_gen3(&data_dst->evs, evs_container); + + // Handle cases in which the nature would be forced + if((dst->level == MAX_LEVEL) || (is_egg)) + wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES); + + // Store egg cycles + if(is_egg) { + data_dst->growth.friendship = src->friendship; + data_dst->misc.is_egg = 1; + dst->use_egg_name = 1; + } + else + data_dst->growth.friendship = BASE_FRIENDSHIP; + + // Set the moves + convert_moves_to_gen3(&data_dst->attacks, &data_dst->growth, src->moves, src->pps, 1); + + data_dst->misc.pokerus = src->pokerus; + + // Special Mew handling + if(data_dst->growth.species == MEW_SPECIES) + data_dst->misc.obedience = 1; + + // Set the PID-Origin-IVs data, they're all connected + set_origin_pid_iv(dst, &data_dst->misc, data_dst->growth.species, src->ivs, wanted_nature, src->ot_gender, is_egg, no_restrictions); + + // Place all the substructures' data + place_and_encrypt_gen3_data(data_dst, dst); + + // Calculate stats + recalc_stats_gen3(data_dst, dst); + + return 1; +} + +u8 gen1_to_gen3(struct gen1_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; + + // Reset everything + for(u32 i = 0; i < sizeof(struct gen3_mon); i++) + ((u8*)(dst))[i] = 0; + + data_dst->is_valid_gen3 = 0; + data_dst->is_valid_gen1 = 0; + + // Check if valid + if(!validate_converting_mon_of_gen1(index, src)) + return 0; + + data_dst->is_valid_gen3 = 1; + data_dst->is_valid_gen1 = 1; + + // Set base data + dst->has_species = 1; + dst->mail_id = GEN3_NO_MAIL; + data_dst->is_egg = 0; + + if(is_jp) + dst->language = JAPANESE_LANGUAGE; + else + dst->language = ENGLISH_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); + + // Reset everything + for(u32 i = 0; i < sizeof(struct gen3_mon_growth); i++) + ((u8*)(&data_dst->growth))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_attacks); i++) + ((u8*)(&data_dst->attacks))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_evs); i++) + ((u8*)(&data_dst->evs))[i] = 0; + for(u32 i = 0; i < sizeof(struct gen3_mon_misc); i++) + ((u8*)(&data_dst->misc))[i] = 0; + + // Set species, exp, level and item + data_dst->growth.species = get_mon_index_gen1_to_3(src->species); + u8 wanted_nature = get_exp_nature(dst, &data_dst->growth, src->level, src->exp); + data_dst->growth.item = convert_item_to_gen3(src->item); + + // Convert EVs + u16 evs_container[EVS_TOTAL_GEN12]; + for(int i = 0; i < EVS_TOTAL_GEN12; i++) + evs_container[i] = src->evs[i]; + convert_evs_to_gen3(&data_dst->evs, evs_container); + + // Handle cases in which the nature would be forced + if(dst->level == MAX_LEVEL) + wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES); + + // Set base friendship + data_dst->growth.friendship = BASE_FRIENDSHIP; + + // Set the moves + convert_moves_to_gen3(&data_dst->attacks, &data_dst->growth, src->moves, src->pps, 1); + + data_dst->misc.pokerus = 0; + + // Special Mew handling + if(data_dst->growth.species == MEW_SPECIES) + data_dst->misc.obedience = 1; + + // Set the PID-Origin-IVs data, they're all connected + set_origin_pid_iv(dst, &data_dst->misc, data_dst->growth.species, src->ivs, wanted_nature, 0, 0, no_restrictions); + + // Place all the substructures' data + place_and_encrypt_gen3_data(data_dst, dst); + + // Calculate stats + recalc_stats_gen3(data_dst, dst); + + return 1; +} diff --git a/source/gen_converter.h b/source/gen_converter.h new file mode 100644 index 0000000..5356844 --- /dev/null +++ b/source/gen_converter.h @@ -0,0 +1,11 @@ +#ifndef GEN_CONVERTER__ +#define GEN_CONVERTER__ + +#include "party_handler.h" + +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); +u8 gen1_to_gen3(struct gen1_mon_data*, struct gen3_mon_data_unenc*, u8, u8*, u8*, u8); + +#endif diff --git a/source/graphics_handler.c b/source/graphics_handler.c index af627ae..092f44e 100644 --- a/source/graphics_handler.c +++ b/source/graphics_handler.c @@ -1,5 +1,6 @@ #include #include "graphics_handler.h" +#include "useful_qualifiers.h" #define MAX_SIZE_POKEMON_SPRITE 0x400 #define GRAPHICS_BUFFER_SHIFT 10 @@ -10,7 +11,7 @@ void convert_3bpp_forward_odd(const u8*, u32*, u16); void convert_3bpp_forward_even(const u8*, u32*, u16); -IWRAM_CODE __attribute__ ((optimize(3))) void load_pokemon_sprite_gfx(const u32* src, u32* dst, u8 is_3bpp, u8 zero_fill, u8 index, u8* colors){ +IWRAM_CODE MAX_OPTIMIZE void load_pokemon_sprite_gfx(const u32* src, u32* dst, u8 is_3bpp, u8 zero_fill, u8 index, u8* colors){ u32 zero = 0; u32 buffer[2][MAX_SIZE_POKEMON_SPRITE>>2]; @@ -70,7 +71,7 @@ void convert_xbpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward, u8 } } -IWRAM_CODE __attribute__ ((optimize(3))) void convert_3bpp_forward_even(const u8* src, u32* dst, u16 src_size) { +IWRAM_CODE MAX_OPTIMIZE void convert_3bpp_forward_even(const u8* src, u32* dst, u16 src_size) { // This is soooo slow, even with all of this. 50k cycles more than 4bpp u16 num_rows = Div(src_size, 3); if(DivMod(src_size, 3)) @@ -88,7 +89,7 @@ IWRAM_CODE __attribute__ ((optimize(3))) void convert_3bpp_forward_even(const u8 } } -IWRAM_CODE __attribute__ ((optimize(3))) void convert_3bpp_forward_odd(const u8* src, u32* dst, u16 src_size) { +IWRAM_CODE MAX_OPTIMIZE void convert_3bpp_forward_odd(const u8* src, u32* dst, u16 src_size) { // This is soooo slow, even with all of this. 50k cycles more than 4bpp u16 num_rows = Div(src_size, 3); if(DivMod(src_size, 3)) diff --git a/source/input_handler.c b/source/input_handler.c index a13ecd6..1c02217 100644 --- a/source/input_handler.c +++ b/source/input_handler.c @@ -2,6 +2,7 @@ #include "input_handler.h" #include "options_handler.h" #include "communicator.h" +#include "useful_qualifiers.h" u8 handle_input_multiboot_menu(u16 keys) { if(keys & KEY_A) @@ -9,7 +10,7 @@ u8 handle_input_multiboot_menu(u16 keys) { return 0; } -u8 handle_input_info_menu(struct game_data_t* game_data, u8* cursor_y_pos, u8 cursor_x_pos, u16 keys, u8* curr_mon, u8 curr_gen, u8* curr_page) { +u8 handle_input_info_menu(struct game_data_t* game_data, u8* cursor_y_pos, u8 cursor_x_pos, u16 keys, u8* curr_mon, u8 UNUSED(curr_gen), u8* curr_page) { u8* options = get_options_trade(cursor_x_pos); u8 num_options = get_options_num_trade(cursor_x_pos); @@ -87,7 +88,7 @@ u8 handle_input_info_menu(struct game_data_t* game_data, u8* cursor_y_pos, u8 cu return 0; } -u8 handle_input_trading_menu(u8* cursor_y_pos, u8* cursor_x_pos, u16 keys, u8 curr_gen, u8 is_own) { +u8 handle_input_trading_menu(u8* cursor_y_pos, u8* cursor_x_pos, u16 keys, u8 UNUSED(curr_gen), u8 is_own) { u8* options[2]; u8 num_options[2]; @@ -324,7 +325,7 @@ u8 handle_input_trade_options(u16 keys, u8* cursor_x_pos) { return 0; } -u8 handle_input_trade_setup(u16 keys, u8 curr_gen) { +u8 handle_input_trade_setup(u16 keys, u8 UNUSED(curr_gen)) { if(keys & KEY_B) { if((get_start_state_raw() != START_TRADE_PAR) || (get_transferred(0) == 0)) { diff --git a/source/main.c b/source/main.c index b4c7506..8a48ca4 100644 --- a/source/main.c +++ b/source/main.c @@ -1,5 +1,3 @@ -#include -#include #include #include "multiboot_handler.h" @@ -35,8 +33,28 @@ #define TRADE_CANCEL_SCREEN 1 #define INFO_SCREEN 3 +void vblank_update_function(void); +void find_optimal_ewram_settings(void); +u8 init_cursor_y_pos_main_menu(void); +void cursor_update_trading_menu(u8, u8); +void cursor_update_main_menu(u8); +void cursor_update_trade_options(u8); +void cursor_update_offer_options(u8, u8); +void offer_init(struct game_data_t*, u8, u8, u8*, u8*); +void waiting_init(void); +void invalid_init(u8); +void waiting_offer_init(u8, u8); +void waiting_accept_init(u8); +void check_bad_trade_received(struct game_data_t*, u8, u8, u8, u8, u8, u8*); +void trade_cancel_print_screen(u8); +void trade_options_init(u8, u8*); +void trade_menu_init(struct game_data_t*, u8, u8, u8, u8, u8, u8*, u8*); +void start_trade_init(struct game_data_t*, u8, u8, u8, u8, u8*); void main_menu_init(struct game_data_t*, u8, u8, u8, u8*); +void info_menu_init(struct game_data_t*, u8, u8, u8*); void conclude_trade(struct game_data_t*, u8, u8, u8, u8*); +void return_to_trade_menu(struct game_data_t*, u8, u8, u8, u8, u8, u8*, u8*); +int main(void); enum STATE {MAIN_MENU, MULTIBOOT, TRADING_MENU, INFO_MENU, START_TRADE, WAITING_DATA, TRADE_OPTIONS, NATURE_SETTING, OFFER_MENU, TRADING_ANIMATION}; enum STATE curr_state; @@ -76,8 +94,8 @@ IWRAM_CODE void vblank_update_function() { } IWRAM_CODE void find_optimal_ewram_settings() { - int size = ewram_speed_check_bin_size>>2; - u32* ewram_speed_check = (u32*) ewram_speed_check_bin; + u32 size = ewram_speed_check_bin_size>>2; + const u32* ewram_speed_check = (const u32*) ewram_speed_check_bin; u32 test_data[size]; // Check for unsupported (DS) @@ -89,7 +107,7 @@ IWRAM_CODE void find_optimal_ewram_settings() { return; // Prepare data to test against - for(int i = 0; i < size; i++) + for(u32 i = 0; i < size; i++) test_data[i] = ewram_speed_check[i]; // Detetmine minimum number of stable waitcycles @@ -97,8 +115,8 @@ IWRAM_CODE void find_optimal_ewram_settings() { REG_MEMORY_CONTROLLER &= ~(0xF<<24); REG_MEMORY_CONTROLLER |= (15-i-MIN_WAITCYCLE)<<24; u8 failed = 0; - for(int j = 0; (!failed) && (j < size); j++) - if(test_data[i] != ewram_speed_check[i]) + for(u32 j = 0; (!failed) && (j < size); j++) + if(test_data[j] != ewram_speed_check[j]) failed = 1; if(!failed) return; @@ -296,9 +314,9 @@ int main(void) input_counter = 0; find_optimal_ewram_settings(); init_text_system(); + init_enc_positions(); init_rng(0,0); u16 keys; - enum MULTIBOOT_RESULTS result; struct game_data_t game_data[2]; init_game_data(&game_data[0]); @@ -325,6 +343,7 @@ int main(void) init_cursor(); const u16** learnset_ptr = NULL; + int result = 0; u8 evolved = 0; u8 returned_val; u8 update = 0; @@ -368,7 +387,7 @@ int main(void) if(curr_state == WAITING_DATA) { if(get_trading_state() == RECEIVED_OFFER) { keys = 0; - int result = get_received_trade_offer(); + result = get_received_trade_offer(); if(result == TRADE_CANCELLED) conclude_trade(&game_data[0], target, region, master, &cursor_y_pos); else if(result == WANTS_TO_CANCEL) @@ -411,8 +430,7 @@ int main(void) sio_stop_irq_slave(); irqDisable(IRQ_SERIAL); disable_cursor(); - result = multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + 0x3FF40)); - print_multiboot(result); + print_multiboot(multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + 0x3FF40))); } else if(returned_val > VIEW_OWN_PARTY && returned_val <= VIEW_OWN_PARTY + TOTAL_GENS) { curr_gen = returned_val - VIEW_OWN_PARTY; diff --git a/source/menu_text_handler.c b/source/menu_text_handler.c index eb75377..f52e5dc 100644 --- a/source/menu_text_handler.c +++ b/source/menu_text_handler.c @@ -16,6 +16,14 @@ #define SUMMARY_LINE_MAX_SIZE 18 #define PRINTABLE_INVALID_STRINGS 3 +void print_pokemon_base_info(u8, struct gen3_mon_data_unenc*, u8); +void print_bottom_info(void); +void print_pokemon_page1(struct gen3_mon_data_unenc*); +void print_pokemon_page2(struct gen3_mon_data_unenc*); +void print_pokemon_page3(struct gen3_mon_data_unenc*); +void print_pokemon_page4(struct gen3_mon_data_unenc*); +void print_pokemon_page5(struct gen3_mon_data_unenc*); + const char* person_strings[] = {"You", "Other"}; const char* game_strings[] = {"RS", "FRLG", "E"}; const char* unidentified_string = "Unidentified"; @@ -32,6 +40,8 @@ const char* offer_strings[] = {" Sending ", "Receiving"}; const char* invalid_strings[][PRINTABLE_INVALID_STRINGS] = {{" TRADE REJECTED!", "The Pokémon offered by the", "other player has issues!"}, {" TRADE REJECTED!", "The trade would leave you", "with no usable Pokémon!"}}; const u8 ribbon_print_pos[NUM_LINES*2] = {0,1,2,3,4,5,6,7,8,9,14,15,13,16,10,0xFF,11,0xFF,12,0xFF}; +typedef void (*print_info_functions_t)(struct gen3_mon_data_unenc*); +print_info_functions_t print_info_functions[PAGES_TOTAL] = {print_pokemon_page1, print_pokemon_page2, print_pokemon_page3, print_pokemon_page4, print_pokemon_page5}; void print_game_info(struct game_data_t* game_data, int index) { PRINT_FUNCTION("\n Game: "); @@ -402,10 +412,6 @@ void print_pokemon_page5(struct gen3_mon_data_unenc* mon) { } } -typedef void (*print_info_functions_t)(struct gen3_mon_data_unenc*); - -print_info_functions_t print_info_functions[PAGES_TOTAL] = {print_pokemon_page1, print_pokemon_page2, print_pokemon_page3, print_pokemon_page4, print_pokemon_page5}; - void print_pokemon_pages(u8 update, u8 load_sprites, struct gen3_mon_data_unenc* mon, u8 page_num) { if(!update) return; diff --git a/source/menu_text_handler.h b/source/menu_text_handler.h index 37304f7..d20e513 100644 --- a/source/menu_text_handler.h +++ b/source/menu_text_handler.h @@ -12,8 +12,8 @@ void print_pokemon_pages(u8, u8, struct gen3_mon_data_unenc*, u8); void print_main_menu(u8, u8, u8, u8); void print_multiboot_mid_process(u8); void print_multiboot(enum MULTIBOOT_RESULTS); -void print_start_trade(); -void print_waiting(); +void print_start_trade(void); +void print_waiting(void); void print_invalid(u8); void print_offer_screen(struct game_data_t*, u8, u8); void print_offer_options_screen(struct game_data_t*, u8, u8); diff --git a/source/optimized_swi.h b/source/optimized_swi.h index d83a850..20a8cd5 100644 --- a/source/optimized_swi.h +++ b/source/optimized_swi.h @@ -1,7 +1,13 @@ #ifndef OPTIMIZED_SWI__ #define OPTIMIZED_SWI__ -static __attribute__((optimize(3), always_inline)) inline s32 SWI_DivMod(const uint32_t dividend, const uint32_t divisor) +#include "useful_qualifiers.h" + +static s32 SWI_DivMod(const uint32_t, const uint32_t); +static s32 SWI_Div(const uint32_t, const uint32_t); +static s32 SWI_DivDivMod(const uint32_t, const uint32_t, int* mod); + +ALWAYS_INLINE MAX_OPTIMIZE s32 SWI_DivMod(const uint32_t dividend, const uint32_t divisor) { register uint32_t divid_ asm("r0") = (uint32_t)dividend; register uint32_t divis_ asm("r1") = (uint32_t)divisor; @@ -15,7 +21,7 @@ static __attribute__((optimize(3), always_inline)) inline s32 SWI_DivMod(const u return divis_; } -static __attribute__((optimize(3), always_inline)) inline s32 SWI_Div(const uint32_t dividend, const uint32_t divisor) +ALWAYS_INLINE MAX_OPTIMIZE s32 SWI_Div(const uint32_t dividend, const uint32_t divisor) { register uint32_t divid_ asm("r0") = (uint32_t)dividend; register uint32_t divis_ asm("r1") = (uint32_t)divisor; @@ -29,7 +35,7 @@ static __attribute__((optimize(3), always_inline)) inline s32 SWI_Div(const uint return divid_; } -static __attribute__((optimize(3), always_inline)) inline s32 SWI_DivDivMod(const uint32_t dividend, const uint32_t divisor, int* mod) +ALWAYS_INLINE MAX_OPTIMIZE s32 SWI_DivDivMod(const uint32_t dividend, const uint32_t divisor, int* mod) { register uint32_t divid_ asm("r0") = (uint32_t)dividend; register uint32_t divis_ asm("r1") = (uint32_t)divisor; diff --git a/source/options_handler.c b/source/options_handler.c index 2b49f8c..1b10cc8 100644 --- a/source/options_handler.c +++ b/source/options_handler.c @@ -1,7 +1,12 @@ #include #include "options_handler.h" -u8 options_main[3]; +void set_valid_options_main(struct game_data_t*); +void fill_options_main_array(struct game_data_t*); +int prepare_trade_options_num(u8*); +void fill_trade_options(u8*, struct game_data_t*, u8); + +u8 options_main[MAIN_OPTIONS_NUM]; u8 valid_options_main; u8 options_trade[2][PARTY_SIZE]; u8 num_options_trade[2]; @@ -12,7 +17,7 @@ u8 is_valid_for_gen(struct game_data_t* game_data, u8 gen) { if(gen == 2) return (game_data->party_2.total > 0); u8 found = 0; - for(int i = 0; i < game_data->party_3.total; i++) + for(u32 i = 0; i < game_data->party_3.total; i++) if(game_data->party_3_undec[i].is_valid_gen3) { found = 1; break; @@ -72,11 +77,13 @@ u8 get_number_of_higher_ordered_options(u8* options, u8 curr_option, u8 limit) { u8 get_number_of_lower_ordered_options(u8* options, u8 curr_option, u8 limit) { u8 curr_num = 0; u8 lowest_found = curr_option; - for(int i = limit-1; i >= 0; i--) - if(options[i] < lowest_found) { - curr_num++; - lowest_found = options[i]; - } + u8 start = limit-1; + if(limit) + for(int i = start; i >= 0; i--) + if(options[i] < lowest_found) { + curr_num++; + lowest_found = options[i]; + } return curr_num; } diff --git a/source/options_handler.h b/source/options_handler.h index 927aa01..3537629 100644 --- a/source/options_handler.h +++ b/source/options_handler.h @@ -16,8 +16,8 @@ u8 get_number_of_lower_ordered_options(u8*, u8, u8); u8 is_valid_for_gen(struct game_data_t*, u8); -u8* get_options_main(); -u8 get_valid_options_main(); +u8* get_options_main(void); +u8 get_valid_options_main(void); void prepare_main_options(struct game_data_t*); u8* get_options_trade(int); diff --git a/source/party_handler.c b/source/party_handler.c index b0ac357..b4cb6ae 100644 --- a/source/party_handler.c +++ b/source/party_handler.c @@ -9,8 +9,8 @@ #include "pid_iv_tid.h" #include "fast_pokemon_methods.h" #include "optimized_swi.h" +#include "useful_qualifiers.h" -#include "pokemon_moves_pp_bin.h" #include "pokemon_gender_bin.h" #include "pokemon_names_bin.h" #include "item_names_bin.h" @@ -22,71 +22,74 @@ #include "ability_names_bin.h" #include "contest_rank_names_bin.h" #include "ribbon_names_bin.h" -#include "gen2_names_jap_bin.h" #include "sprites_cmp_bin.h" #include "sprites_info_bin.h" #include "palettes_references_bin.h" -#include "item_gen3_to_12_bin.h" -#include "item_gen12_to_3_bin.h" -#include "gen3_to_1_conv_table_bin.h" -#include "gen1_to_3_conv_table_bin.h" #include "pokemon_exp_groups_bin.h" #include "exp_table_bin.h" #include "pokemon_stats_bin.h" #include "pokemon_stats_gen1_bin.h" -#include "pokemon_types_gen1_bin.h" #include "pokemon_natures_bin.h" #include "pokemon_abilities_bin.h" -#include "encounter_types_bin.h" -#include "egg_locations_bin.h" -#include "encounters_static_bin.h" -#include "encounters_roamers_bin.h" -#include "encounters_unown_bin.h" -#include "encounter_types_gen2_bin.h" -#include "special_encounters_gen2_bin.h" #include "trade_evolutions_bin.h" #include "learnset_evos_gen1_bin.h" #include "learnset_evos_gen2_bin.h" #include "learnset_evos_gen3_bin.h" #include "dex_conversion_bin.h" -#define MF_7_1_INDEX 2 -#define M_INDEX 1 -#define F_INDEX 6 -#define U_INDEX 7 -#define EGG_NUMBER 412 -#define EGG_NUMBER_GEN2 253 #define UNOWN_B_START 415 -#define UNOWN_EX_LETTER 26 -#define UNOWN_I_LETTER 8 -#define UNOWN_V_LETTER 21 #define INITIAL_MAIL_GEN3 121 #define LAST_MAIL_GEN3 132 #define ACT_AS_GEN1_TRADE 1 -u8 decrypt_data(struct gen3_mon*, u32*); +#define PID_POSITIONS 24 + +const u8* get_pokemon_name_pure(int, u32, u8); +const u8* get_item_name(int, u8); +u8 get_ability_pokemon(int, u32, u8, u8, u8); +u8 is_ability_valid(u16, u32, u8, u8, u8, u8); +const u8* get_pokemon_sprite_pointer(int, u32, u8, u8); +u8 get_pokemon_sprite_info(int, u32, u8, u8); +u8 get_palette_references(int, u32, u8, u8); +void load_pokemon_sprite(int, u32, u8, u8, u8, u8, u16, u16); +u8 make_moves_legal_gen3(struct gen3_mon_attacks*); u8 is_egg_gen3(struct gen3_mon*, struct gen3_mon_misc*); +u8 is_shiny_gen3(u32, u32, u8, u32); +u8 get_mail_id(struct gen3_mon*, struct gen3_mon_growth*, u8); +u8 decrypt_data(struct gen3_mon* src, u32* decrypted_dst); +void encrypt_data(struct gen3_mon* dst); +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*); -// Order is G A E M, or M E A G reversed. These are their indexes. -u8 enc_positions[] = {0b11100100, 0b10110100, 0b11011000, 0b10011100, 0b01111000, 0b01101100, - 0b11100001, 0b10110001, 0b11010010, 0b10010011, 0b01110010, 0b01100011, - 0b11001001, 0b10001101, 0b11000110, 0b10000111, 0b01001110, 0b01001011, - 0b00111001, 0b00101101, 0b00110110, 0b00100111, 0b00011110, 0b00011011}; +// Order is G A E M. Initialized by init_enc_positions +u8 enc_positions[PID_POSITIONS]; -u8 gender_thresholds_gen3[] = {127, 0, 31, 63, 191, 225, 254, 255, 0, 254}; -u8 gender_thresholds_gen12[] = {8, 0, 2, 4, 12, 14, 16, 17, 0, 16}; +u8 gender_thresholds_gen3[TOTAL_GENDER_KINDS] = {127, 0, 31, 63, 191, 225, 254, 255, 0, 254}; +u8 stat_index_conversion_gen3[] = {0, 1, 2, 4, 5, 3}; const u16* pokemon_abilities_bin_16 = (const u16*)pokemon_abilities_bin; const struct exp_level* exp_table = (const struct exp_level*)exp_table_bin; -const struct stats_gen_23* stats_table = (const struct stats_gen_23*)pokemon_stats_bin; -const struct stats_gen_1* stats_table_gen1 = (const struct stats_gen_1*)pokemon_stats_gen1_bin; +const struct stats_gen_23* stats_table_gen3 = (const struct stats_gen_23*)pokemon_stats_bin; + +void init_enc_positions() { + u8 pos = 0; + for(int i = 0; i < 4; i++) + for(int j = 0; j < 4; j++) + if(j != i) + for(int k = 0; k < 4; k++) + if((k != i) && (k != j)) + for(int l = 0; l < 4; l++) + if((l != i) && (l != j) && (l != k)) + enc_positions[pos++] = (0<<(i*2)) | (1<<(j*2)) | (2<<(k*2)) | (3<<(l*2)); +} u8 get_index_key(u32 pid){ // Make use of modulo properties to get this to positives while(pid >= 0x80000000) pid -= 0x7FFFFFF8; - return SWI_DivMod(pid, 24); + return SWI_DivMod(pid, PID_POSITIONS); } u8 get_nature(u32 pid){ @@ -97,15 +100,11 @@ u8 get_unown_letter_gen3(u32 pid){ return get_unown_letter_gen3_fast(pid); } -u8 get_unown_letter_gen2(u16 ivs){ - return get_unown_letter_gen2_fast(ivs); -} - u16 get_mon_index(int index, u32 pid, u8 is_egg, u8 deoxys_form){ if(index > LAST_VALID_GEN_3_MON) return 0; if(is_egg) - return EGG_NUMBER; + return EGG_SPECIES; if(index == UNOWN_SPECIES) { u8 letter = get_unown_letter_gen3(pid); if(!letter) @@ -127,30 +126,6 @@ u16 get_mon_index_raw(struct gen3_mon_data_unenc* data_src){ return get_mon_index(data_src->growth.species, data_src->src->pid, data_src->is_egg, data_src->deoxys_form); } -u16 get_mon_index_gen2(int index, u8 is_egg){ - if(index > LAST_VALID_GEN_2_MON) - return 0; - if(is_egg) - return EGG_NUMBER_GEN2; - return index; -} - -u16 get_mon_index_gen2_1(int index){ - if(index > LAST_VALID_GEN_1_MON) - return 0; - return index; -} - -u16 get_mon_index_gen1(int index){ - if(index > LAST_VALID_GEN_1_MON) - return 0; - return gen3_to_1_conv_table_bin[index]; -} - -u16 get_mon_index_gen1_to_3(u8 index){ - return gen1_to_3_conv_table_bin[index]; -} - const u8* get_pokemon_name(int index, u32 pid, u8 is_egg, u8 deoxys_form){ return get_table_pointer(pokemon_names_bin, get_mon_index(index, pid, is_egg, deoxys_form)); } @@ -171,20 +146,6 @@ const u8* get_pokemon_name_raw(struct gen3_mon_data_unenc* data_src){ return get_pokemon_name(data_src->growth.species, data_src->src->pid, data_src->is_egg, data_src->deoxys_form); } -const u8* get_pokemon_name_gen2(int index, u8 is_egg, u8 is_jp, u8* buffer){ - if(is_jp) - return &(gen2_names_jap_bin[get_mon_index_gen2(index, is_egg)*STRING_GEN2_JP_CAP]); - u8 buffer_two[STRING_GEN2_INT_SIZE]; - 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_generic_to_gen3(get_table_pointer(pokemon_names_bin, mon_index), buffer_two, NAME_SIZE, STRING_GEN2_INT_CAP, 0, 0); - text_gen3_to_gen12(buffer_two, buffer, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP, 0, 0); - return buffer; -} - const u8* get_item_name(int index, u8 is_egg){ if(is_egg) index = 0; @@ -197,7 +158,7 @@ u8 has_item_raw(struct gen3_mon_data_unenc* data_src){ if(!data_src->is_valid_gen3) return 0; - u8 index = data_src->growth.item; + u16 index = data_src->growth.item; u8 is_egg = data_src->is_egg; if(is_egg) @@ -342,7 +303,7 @@ void load_pokemon_sprite_raw(struct gen3_mon_data_unenc* data_src, u16 y, u16 x) if(!data_src->is_valid_gen3) return; - return load_pokemon_sprite(data_src->growth.species, data_src->src->pid, data_src->is_egg, data_src->deoxys_form, has_item_raw(data_src), has_mail_raw(data_src), y, x); + load_pokemon_sprite(data_src->growth.species, data_src->src->pid, data_src->is_egg, data_src->deoxys_form, has_item_raw(data_src), has_mail_raw(data_src), y, x); } const u8* get_move_name_gen3(struct gen3_mon_attacks* attacks, u8 slot){ @@ -382,45 +343,6 @@ u8 make_moves_legal_gen3(struct gen3_mon_attacks* attacks){ return 0; } -u8 has_legal_moves_gen12(u8* moves, u8 is_gen2){ - u8 last_valid_move = LAST_VALID_GEN_1_MOVE; - if(is_gen2) - last_valid_move = LAST_VALID_GEN_2_MOVE; - - u8 previous_moves[MOVES_SIZE]; - u8 curr_slot = 0; - for(int i = 0; i < MOVES_SIZE; i++) { - if((moves[i] != 0) && (moves[i] <= last_valid_move)) { - for(int j = 0; j < curr_slot; j++) - if(moves[i] == previous_moves[j]) - return 0; - previous_moves[curr_slot++] = moves[i]; - } - } - - if(curr_slot) - return 1; - return 0; -} - -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){ - case M_INDEX: - case NIDORAN_M_GENDER_INDEX: - return M_GENDER; - case F_INDEX: - case NIDORAN_F_GENDER_INDEX: - return F_GENDER; - case U_INDEX: - return U_GENDER; - default: - if(atk_ivs >= gender_thresholds_gen12[gender_kind]) - return M_GENDER; - return F_GENDER; - } -} - u8 get_pokemon_gender_gen3(int index, u32 pid, u8 is_egg, u8 deoxys_form){ u8 gender_kind = get_pokemon_gender_kind_gen3(index, pid, is_egg, deoxys_form); switch(gender_kind){ @@ -466,13 +388,7 @@ u8 get_pokemon_gender_kind_gen3(int index, u32 pid, u8 is_egg, u8 deoxys_form){ return pokemon_gender_bin[get_mon_index(index, pid, is_egg, deoxys_form)]; } -u8 get_pokemon_gender_kind_gen2(u8 index, u8 is_egg, u8 curr_gen){ - if(curr_gen == 1) - return pokemon_gender_bin[get_mon_index_gen2_1(index)]; - return pokemon_gender_bin[get_mon_index_gen2(index, is_egg)]; -} - -u8 is_egg_gen3(struct gen3_mon* src, struct gen3_mon_misc* misc){ +u8 is_egg_gen3(struct gen3_mon* UNUSED(src), struct gen3_mon_misc* misc){ // In case it ends up being more complex, for some reason return misc->is_egg; } @@ -512,20 +428,6 @@ u8 is_shiny_gen3_raw(struct gen3_mon_data_unenc* data_src, u32 trainer_id){ return is_shiny_gen3(data_src->src->pid, data_src->src->ot_id, data_src->is_egg, trainer_id); } -u8 is_shiny_gen2(u8 atk_ivs, u8 def_ivs, u8 spa_ivs, u8 spe_ivs){ - if((atk_ivs & 2) == 2 && def_ivs == 10 && spa_ivs == 10 && spe_ivs == 10) - return 1; - return 0; -} - -u8 is_shiny_gen2_unfiltered(u16 ivs){ - return is_shiny_gen2((ivs >> 4) & 0xF, ivs & 0xF, (ivs >> 8) & 0xF, (ivs >> 12) & 0xF); -} - -u8 is_shiny_gen2_raw(struct gen2_mon_data* src){ - return is_shiny_gen2_unfiltered(src->ivs); -} - u8 has_mail(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 is_egg) { if(is_egg) return 0; @@ -564,7 +466,7 @@ u16 get_dex_index_raw(struct gen3_mon_data_unenc* data_src){ if(!data_src->is_valid_gen3) return NO_DEX_INDEX; - u16* dex_conversion_bin_16 = (u16*)dex_conversion_bin; + const u16* dex_conversion_bin_16 = (const u16*)dex_conversion_bin; u16 mon_index = get_mon_index_raw(data_src); return dex_conversion_bin_16[mon_index]; } @@ -599,34 +501,12 @@ void encrypt_data(struct gen3_mon* dst) { dst->enc_data[i] = dst->enc_data[i] ^ key; } -u8 index_conversion_gen2[] = {0, 1, 2, 5, 3, 4}; -u8 index_conversion_gen3[] = {0, 1, 2, 4, 5, 3}; - -u8 get_ivs_gen2(u16 ivs, u8 stat_index) { - u8 atk_ivs = (ivs >> 4) & 0xF; - u8 def_ivs = ivs & 0xF; - u8 spe_ivs = (ivs >> 12) & 0xF; - u8 spa_ivs = (ivs >> 8) & 0xF; - switch(stat_index) { - case HP_STAT_INDEX: - return ((atk_ivs & 1) << 3) | ((def_ivs & 1) << 2) | ((spe_ivs & 1) << 1) | (spa_ivs & 1); - case ATK_STAT_INDEX: - return atk_ivs; - case DEF_STAT_INDEX: - return def_ivs; - case SPE_STAT_INDEX: - return spe_ivs; - default: - return spa_ivs; - } -} - u8 get_ivs_gen3(struct gen3_mon_misc* misc, u8 stat_index) { if(stat_index >= GEN2_STATS_TOTAL) stat_index = GEN2_STATS_TOTAL-1; u32 ivs = (*(((u32*)misc)+1)); - u8 real_stat_index = index_conversion_gen3[stat_index]; + u8 real_stat_index = stat_index_conversion_gen3[stat_index]; return (ivs >> (5*real_stat_index))&0x1F; } @@ -668,30 +548,11 @@ char get_nature_symbol(u32 pid, u8 stat_index) { return ' '; } -u32 get_level_exp_mon_index(u16 mon_index, u8 level) { +s32 get_level_exp_mon_index(u16 mon_index, u8 level) { return exp_table[level].exp_kind[pokemon_exp_groups_bin[mon_index]]; } -u32 get_proper_exp_gen2(u16 mon_index, u8 level, u8* given_exp) { - - s32 exp = (given_exp[0]<<0x10) + (given_exp[1]<<0x8) + (given_exp[2]<<0); - s32 min_exp = get_level_exp_mon_index(mon_index, level); - s32 max_exp = min_exp; - if(level == MAX_LEVEL) - exp = min_exp; - else - max_exp = get_level_exp_mon_index(mon_index, level+1)-1; - if(exp < min_exp) - exp = min_exp; - if(exp > max_exp) - exp = max_exp; - if(exp < 0) - exp = 0; - - return exp; -} - -u32 get_proper_exp(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 deoxys_form) { +s32 get_proper_exp(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 deoxys_form) { u8 level = to_valid_level_gen3(src); u16 mon_index = get_mon_index(growth->species, src->pid, 0, deoxys_form); @@ -713,7 +574,7 @@ u32 get_proper_exp(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 deox return exp; } -u32 get_proper_exp_raw(struct gen3_mon_data_unenc* data_src) { +s32 get_proper_exp_raw(struct gen3_mon_data_unenc* data_src) { if(!data_src->is_valid_gen3) return 0; @@ -747,46 +608,11 @@ u8 get_evs_gen3(struct gen3_mon_evs* evs, u8 stat_index) { sum += own_evs[i]; } - u8 real_stat_index = index_conversion_gen3[stat_index]; + u8 real_stat_index = stat_index_conversion_gen3[stat_index]; return own_evs[real_stat_index]; } -u16 calc_stats_gen1(u16 species, u8 stat_index, u8 level, u8 iv, u16 stat_exp) { - if(species > LAST_VALID_GEN_1_MON) - species = 0; - species = get_mon_index_gen1(species); - if(stat_index >= GEN1_STATS_TOTAL) - stat_index = GEN1_STATS_TOTAL-1; - u16 base = 5; - if(stat_index == HP_STAT_INDEX) - base = level + 10; - u16 stat_exp_contribution = Sqrt(stat_exp); - // Bulbapedia error... - //if((stat_exp_contribution * stat_exp_contribution) < stat_exp) - // stat_exp_contribution += 1; - return base + Div((((stats_table_gen1[species].stats[stat_index] + iv)*2) + (stat_exp_contribution >> 2)) * level, 100); -} - -u16 calc_stats_gen2(u16 species, u32 pid, u8 stat_index, u8 level, u8 iv, u16 stat_exp) { - if(species > LAST_VALID_GEN_2_MON) - species = 0; - if(stat_index >= GEN2_STATS_TOTAL) - stat_index = GEN2_STATS_TOTAL-1; - - u16 mon_index = get_mon_index(species, pid, 0, 0); - - stat_index = index_conversion_gen2[stat_index]; - u16 base = 5; - if(stat_index == HP_STAT_INDEX) - base = level + 10; - u16 stat_exp_contribution = Sqrt(stat_exp); - // Bulbapedia error... - //if((stat_exp_contribution * stat_exp_contribution) < stat_exp) - // stat_exp_contribution += 1; - return base + Div((((stats_table[mon_index].stats[stat_index] + iv)*2) + (stat_exp_contribution >> 2)) * level, 100); -} - u16 calc_stats_gen3(u16 species, u32 pid, u8 stat_index, u8 level, u8 iv, u8 ev, u8 deoxys_form) { if(species > LAST_VALID_GEN_3_MON) species = 0; @@ -801,7 +627,7 @@ u16 calc_stats_gen3(u16 species, u32 pid, u8 stat_index, u8 level, u8 iv, u8 ev, base = level + 10; u8 boosted_stat = pokemon_natures_bin[(2*nature)]; u8 nerfed_stat = pokemon_natures_bin[(2*nature)+1]; - u16 stat = base + Div(((2*stats_table[mon_index].stats[stat_index]) + iv + (ev >> 2)) * level, 100); + u16 stat = base + Div(((2*stats_table_gen3[mon_index].stats[stat_index]) + iv + (ev >> 2)) * level, 100); if(boosted_stat == nerfed_stat) return stat; if(boosted_stat == stat_index) @@ -819,177 +645,6 @@ u16 calc_stats_gen3_raw(struct gen3_mon_data_unenc* data_src, u8 stat_index) { return calc_stats_gen3(data_src->growth.species, data_src->src->pid, stat_index, to_valid_level_gen3(data_src->src), get_ivs_gen3(&data_src->misc, stat_index), get_evs_gen3(&data_src->evs, stat_index), data_src->deoxys_form); } -u16 swap_endian_short(u16 shrt) { - return ((shrt & 0xFF00) >> 8) | ((shrt & 0xFF) << 8); -} - -u32 swap_endian_int(u32 integer) { - return ((integer & 0xFF000000) >> 24) | ((integer & 0xFF) << 24) | ((integer & 0xFF0000) >> 8) | ((integer & 0xFF00) << 8); -} - -u8 validate_converting_mon_of_gen1(u8 index, struct gen1_mon_data* src) { - - // Check for matching index to species - if(index != src->species) - return 0; - - u8 conv_species = get_mon_index_gen1_to_3(src->species); - - // Is this a valid mon - if((conv_species > LAST_VALID_GEN_1_MON) || (conv_species == 0)) - return 0; - - // Does it have a valid movepool - if(!has_legal_moves_gen12(src->moves, 0)) - return 0; - - // Check for valid types - u8 matched[2] = {0,0}; - for(int i = 0; i < 2; i++) { - if((src->type[i] == pokemon_types_gen1_bin[(2*src->species)]) && (!matched[0])) - matched[0] = 1; - else if((src->type[i] == pokemon_types_gen1_bin[(2*src->species)+1]) && (!matched[1])) - matched[1] = 1; - } - for(int i = 0; i < 2; i++) - if(!matched[i]) - return 0; - - return 1; -} - -u8 validate_converting_mon_of_gen2(u8 index, struct gen2_mon_data* src, u8* is_egg) { - if(index == GEN2_EGG) - *is_egg = 1; - else - *is_egg = 0; - - // Check for matching index to species - if((!(*is_egg)) && (index != src->species)) - return 0; - - // Is this a valid mon - if((src->species > LAST_VALID_GEN_2_MON) || (src->species == 0)) - return 0; - - // Does it have a valid movepool - if(!has_legal_moves_gen12(src->moves, 1)) - return 0; - - return 1; -} - -u8 validate_converting_mon_of_gen3(struct gen3_mon* src, struct gen3_mon_growth* growth, u8 is_shiny, u8 gender, u8 gender_kind, u8 is_egg, u8 is_gen2) { - u8 last_valid_mon = LAST_VALID_GEN_1_MON; - if(is_gen2) - last_valid_mon = LAST_VALID_GEN_2_MON; - - // Bad egg checks - if(src->is_bad_egg) - return 0; - - // Item checks - if(has_mail(src, growth, is_egg)) - return 0; - - // Validity checks - if((growth->species > last_valid_mon) || (growth->species == 0)) - return 0; - - // These Pokemon cannot be both female and shiny in gen 1/2 - if(is_shiny && (gender == F_GENDER) && (gender_kind == MF_7_1_INDEX)) - return 0; - - // Unown ! and ? did not exist in gen 2 - // Not only that, but only Unown I and V can be shiny - if(is_gen2 && (growth->species == UNOWN_SPECIES)) { - u8 letter = get_unown_letter_gen3(src->pid); - if(letter >= UNOWN_EX_LETTER) - return 0; - if(is_shiny && (letter != UNOWN_I_LETTER) && (letter != UNOWN_V_LETTER)) - return 0; - } - - // Eggs cannot be traded to gen 1 - if((!is_gen2) && is_egg) - return 0; - - return 1; -} - -u8 convert_moves_of_gen3(struct gen3_mon_attacks* attacks, u8 pp_bonuses, u8* moves, u8* pps, u8 is_gen2) { - // Start converting moves - u16 last_valid_move = LAST_VALID_GEN_1_MOVE; - if(is_gen2) - last_valid_move = LAST_VALID_GEN_2_MOVE; - - u8 used_slots = 0; - - for(int i = 0; i < MOVES_SIZE; i++) - { - moves[i] = 0; - pps[i] = 0; - } - for(int i = 0; i < MOVES_SIZE; i++) { - u16 move = attacks->moves[i]; - if((move > 0) && (move <= last_valid_move)) { - u8 base_pp = pokemon_moves_pp_bin[move]; - u8 bonus_pp = (pp_bonuses >> (2*i)) & 3; - u8 base_increase_pp = Div(base_pp, 5); - base_pp += (base_increase_pp * bonus_pp); - // Limit the PP to its maximum of 61 - if(base_pp > 61) - base_pp = 61; - base_pp |= (bonus_pp << 6); - pps[used_slots] = base_pp; - moves[used_slots++] = move; - } - } - - return used_slots; -} - -u8 convert_moves_to_gen3(struct gen3_mon_attacks* attacks, struct gen3_mon_growth* growth, u8* moves, u8* pps, u8 is_gen2) { - // Start converting moves - u8 last_valid_move = LAST_VALID_GEN_1_MOVE; - if(is_gen2) - last_valid_move = LAST_VALID_GEN_2_MOVE; - - u8 used_slots = 0; - - for(int i = 0; i < MOVES_SIZE; i++) { - u16 move = moves[i]; - if((move > 0) && (move <= last_valid_move)) { - u8 base_pp = pokemon_moves_pp_bin[move]; - u8 bonus_pp = (pps[i] >> 6) & 3; - u8 base_increase_pp = Div(base_pp, 5); - base_pp += (base_increase_pp * bonus_pp); - - growth->pp_bonuses |= (bonus_pp)<<(2*i); - attacks->pp[used_slots] = base_pp; - attacks->moves[used_slots++] = move; - } - } - - return used_slots; -} - -u8 convert_item_of_gen3(u16 item) { - if(item > LAST_VALID_GEN_3_ITEM) - item = 0; - item = item_gen3_to_12_bin[item]; - if((item == GEN2_NO_ITEM) || (item == GEN2_MAIL)) - item = 0; - return item; -} - -u16 convert_item_to_gen3(u16 item) { - item = item_gen12_to_3_bin[item*2] + (item_gen12_to_3_bin[(item*2)+1]<<8); - if(item == GEN3_NO_ITEM) - item = 0; - return item; -} - u8 to_valid_level(u8 level) { if(level < MIN_LEVEL) return MIN_LEVEL; @@ -1002,387 +657,11 @@ u8 to_valid_level_gen3(struct gen3_mon* src) { return to_valid_level(src->level); } -void convert_exp_nature_of_gen3(struct gen3_mon* src, struct gen3_mon_growth* growth, u8* level_ptr, u8* exp_ptr, u8 is_gen2) { - if(((is_gen2) && (growth->species > LAST_VALID_GEN_2_MON)) || ((!is_gen2) && (growth->species > LAST_VALID_GEN_1_MON))) - return; - - // Level handling - u8 level = to_valid_level_gen3(src); - - u16 mon_index = get_mon_index(growth->species, src->pid, 0, 0); - - // Experience handling - s32 exp = get_proper_exp(src, growth, 0); - - s32 max_exp = exp; - if(level < MAX_LEVEL) - max_exp = get_level_exp_mon_index(mon_index, level+1)-1; - - // Save nature in experience, like the Gen I-VII conversion - u8 nature = get_nature(src->pid); - - // Nature handling - u8 exp_nature = DivMod(exp, NUM_NATURES); - if(exp_nature > nature) - nature += NUM_NATURES; - exp += nature - exp_nature; - if (level < MAX_LEVEL) - while (exp > max_exp) { - level++; - if(level == MAX_LEVEL) { - exp = max_exp+1; - break; - } - max_exp = get_level_exp_mon_index(mon_index, level+1)-1; - } - if (level == MAX_LEVEL && exp != get_level_exp_mon_index(mon_index, MAX_LEVEL)){ - level--; - exp -= NUM_NATURES; - } - - // Store exp and level - *level_ptr = level; - for(int i = 0; i < 3; i++) - exp_ptr[2-i] = (exp >> (8*i))&0xFF; -} - -u8 get_exp_nature(struct gen3_mon* dst, struct gen3_mon_growth* growth, u8 level, u8* given_exp) { - // Level handling - level = to_valid_level(level); - - u16 mon_index = get_mon_index_gen2(growth->species, 0); - - // Experience handling - s32 exp = get_proper_exp_gen2(mon_index, level, given_exp); - - // Save nature in experience, like the Gen I-VII conversion - u8 nature = SWI_DivMod(exp, NUM_NATURES); - - // Store exp and level - dst->level = level; - growth->exp = exp; - return nature; -} - -void convert_evs_of_gen3(struct gen3_mon_evs* evs, u16* old_evs) { - // Convert to Gen1/2 EVs - u16 evs_total = 0; - for(int i = 0; i < EVS_TOTAL_GEN3; i++) - evs_total += evs->evs[i]; - if(evs_total >= MAX_USABLE_EVS) - evs_total = MAX_EVS; - u16 new_evs = ((evs_total+1)>>1) * ((evs_total+1)>>1); - for(int i = 0; i < EVS_TOTAL_GEN12; i++) - old_evs[i] = swap_endian_short(new_evs & 0xFFFF); -} - -void convert_evs_to_gen3(struct gen3_mon_evs* evs, u16* old_evs) { - // A direct conversion is possible, but it would be - // atrocious for competitive/high-level battling... - for(int i = 0; i < EVS_TOTAL_GEN3; i++) - evs->evs[i] = 0; -} - -u16 convert_ivs_of_gen3(struct gen3_mon_misc* misc, u16 species, u32 pid, u8 is_shiny, u8 gender, u8 gender_kind, u8 is_gen2) { - if(((is_gen2) && (species > LAST_VALID_GEN_2_MON)) || ((!is_gen2) && (species > LAST_VALID_GEN_1_MON))) - return 0; - - // Assign IVs - // Keep in mind: Unown letter, gender and shinyness - // Hidden Power calculations are too restrictive - u8 atk_ivs = misc->atk_ivs >> 1; - u8 def_ivs = misc->def_ivs >> 1; - u8 spa_ivs = (misc->spa_ivs + misc->spd_ivs) >> 2; - u8 spe_ivs = misc->spe_ivs >> 1; - - // Handle roamers losing IVs when caught - u8 origin_game = (misc->origins_info>>7)&0xF; - if(((species >= RAIKOU_SPECIES) && (species <= SUICUNE_SPECIES)) && ((origin_game == FR_VERSION_ID) || (origin_game == LG_VERSION_ID))) { - u32 real_ivs = 0; - if(get_roamer_ivs(pid, misc->hp_ivs, misc->atk_ivs, &real_ivs)){ - atk_ivs = ((real_ivs >> 5) & 0x1F) >> 1; - def_ivs = ((real_ivs >> 10) & 0x1F) >> 1; - spa_ivs = (((real_ivs >> 20) & 0x1F) + ((real_ivs >> 25) & 0x1F)) >> 2; - spe_ivs = ((real_ivs >> 15) & 0x1F) >> 1; - } - } - - // Unown letter - if((is_gen2) && (species == UNOWN_SPECIES)) { - u8 letter = get_unown_letter_gen3(pid); - u8 min_iv_sum = letter * 10; - u16 max_iv_sum = ((letter+1) * 10)-1; - if(max_iv_sum >= 0x100) - max_iv_sum = 0xFF; - u8 iv_sum = ((spa_ivs & 0x6) >> 1) | ((spe_ivs & 0x6) << 1) | ((def_ivs & 0x6) << 3) | ((atk_ivs & 0x6) << 5); - if(iv_sum < min_iv_sum) - iv_sum = min_iv_sum; - if(iv_sum > max_iv_sum) - iv_sum = max_iv_sum; - atk_ivs = (atk_ivs & 0x9) | ((iv_sum >> 5) & 0x6); - def_ivs = (def_ivs & 0x9) | ((iv_sum >> 3) & 0x6); - spe_ivs = (spe_ivs & 0x9) | ((iv_sum >> 1) & 0x6); - spa_ivs = (spa_ivs & 0x9) | ((iv_sum << 1) & 0x6); - } - - // Gender - if(gender != U_GENDER && gender_kind != M_INDEX && gender_kind != F_INDEX) { - if(gender == F_GENDER && atk_ivs >= gender_thresholds_gen12[gender_kind]) - atk_ivs = gender_thresholds_gen12[gender_kind] - 1; - else if(gender == M_GENDER && atk_ivs < gender_thresholds_gen12[gender_kind]) - atk_ivs = gender_thresholds_gen12[gender_kind]; - } - - // Shinyness - if(is_shiny) { - atk_ivs = atk_ivs | 2; - def_ivs = 10; - spa_ivs = 10; - spe_ivs = 10; - } - if(!is_shiny && is_shiny_gen2(atk_ivs, def_ivs, spa_ivs, spe_ivs)) - spe_ivs = 11; - - return (atk_ivs << 4) | def_ivs | (spa_ivs << 8) | (spe_ivs << 12); -} - -void set_ivs(struct gen3_mon_misc* misc, u32 ivs) { - misc->hp_ivs = (ivs >> 0) & 0x1F; - misc->atk_ivs = (ivs >> 5) & 0x1F; - misc->def_ivs = (ivs >> 10) & 0x1F; - misc->spe_ivs = (ivs >> 15) & 0x1F; - misc->spa_ivs = (ivs >> 20) & 0x1F; - misc->spd_ivs = (ivs >> 25) & 0x1F; -} - -void set_origin_pid_iv(struct gen3_mon* dst, struct gen3_mon_misc* misc, u16 species, u16 wanted_ivs, u8 wanted_nature, u8 ot_gender, u8 is_egg, u8 no_restrictions) { - struct game_data_t* trainer_data = get_own_game_data(); - u8 trainer_game_version = id_to_version(&trainer_data->game_identifier); - u8 trainer_gender = trainer_data->trainer_gender; - - // Handle eggs separately - u32 ot_id = dst->ot_id; - if(is_egg) - ot_id = trainer_data->trainer_id; - - // Prepare the TSV - u16 tsv = (ot_id & 0xFFFF) ^ (ot_id >> 16); - - u8 chosen_version = FR_VERSION_ID; - if(!no_restrictions) { - chosen_version = trainer_game_version; - ot_gender = trainer_gender; - } - - u8 encounter_type = (encounter_types_bin[species>>2]>>(2*(species&3)))&3; - u8 is_shiny = is_shiny_gen2_unfiltered(wanted_ivs); - u32 ivs = 0; - const u8* searchable_table = egg_locations_bin; - u8 find_in_table = 0; - - // Get PID and IVs - switch(encounter_type) { - case STATIC_ENCOUNTER: - if(!is_shiny) - generate_static_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); - else - generate_static_shiny_info(wanted_nature, tsv, &dst->pid, &ivs); - searchable_table = encounters_static_bin; - find_in_table = 1; - break; - case ROAMER_ENCOUNTER: - if(!is_shiny) - generate_static_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); - else - generate_static_shiny_info(wanted_nature, tsv, &dst->pid, &ivs); - // Roamers only get the first byte of their IVs - ivs &= 0xFF; - searchable_table = encounters_roamers_bin; - find_in_table = 1; - break; - case UNOWN_ENCOUNTER: - if(!is_shiny) - generate_unown_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); - else - generate_unown_shiny_info(wanted_nature, wanted_ivs, tsv, &dst->pid, &ivs); - searchable_table = encounters_unown_bin; - find_in_table = 1; - break; - default: - if(!is_shiny) - generate_egg_info(species, wanted_nature, wanted_ivs, tsv, 2, &dst->pid, &ivs); - else - generate_egg_shiny_info(species, wanted_nature, wanted_ivs, tsv, 2, &dst->pid, &ivs); - break; - } - - // Set met location and origins info - u8 met_location = egg_locations_bin[chosen_version]; - u8 met_level = 0; - - if(find_in_table) { - u16 mon_index = get_mon_index(species, dst->pid, 0, 0); - const u8* possible_met_data = search_table_for_index(searchable_table, mon_index); - if(possible_met_data != NULL) { - u8 num_elems = possible_met_data[0]; - u8 chosen_entry = 0; - for(int i = 0; i < num_elems; i++) - if(possible_met_data[1+(3*i)] == chosen_version) - chosen_entry = i; - chosen_version = possible_met_data[1+(3*chosen_entry)]; - met_location = possible_met_data[2+(3*chosen_entry)]; - met_level = possible_met_data[3+(3*chosen_entry)]; - } - } - misc->met_location = met_location; - misc->origins_info = ((ot_gender&1)<<15) | ((POKEBALL_ID&0xF)<<11) | ((chosen_version&0xF)<<7) | ((met_level&0x7F)<<0); - - // Set IVs - set_ivs(misc, ivs); - - // Set ability - if(dst->pid & 1) { - u16 abilities = get_possible_abilities_pokemon(species, dst->pid, 0, 0); - u8 abilities_same = (abilities&0xFF) == ((abilities>>8)&0xFF); - if(!abilities_same) - misc->ability = 1; - } -} - -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; - u32 trainer_id = trainer_data->trainer_id; - u8* trainer_name = trainer_data->trainer_name; - - // Languages do not match - if(is_jp ^ trainer_is_jp) - return 0; - - // IDs do not match - if((trainer_id & 0xFFFF) != (dst->ot_id & 0xFFFF)) - 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); - -} - -void fix_name_change_from_gen3(struct gen3_mon* src, u16 species, u8* nickname, u8 is_egg, u8 is_gen2) { - u8 tmp_text_buffer[NAME_SIZE]; - - // Get the string to compare to - text_generic_to_gen3(get_pokemon_name(species, src->pid, is_egg, 0), tmp_text_buffer, NAME_SIZE, NICKNAME_GEN3_SIZE, 0, 0); - - // If it's the same, update the nickname with the new one - if(text_gen3_is_same(src->nickname, tmp_text_buffer, NICKNAME_GEN3_SIZE, NICKNAME_GEN3_SIZE)) { - text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 0, tmp_text_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP); - // Gen 1 used the wrong dot symbol - if(!is_gen2) - text_gen2_replace(nickname, STRING_GEN2_INT_CAP, GEN2_DOT, GEN1_DOT); - } -} - -void fix_name_change_to_gen3(struct gen3_mon* dst, u8 species) { - u8 tmp_text_buffer[STRING_GEN2_INT_CAP]; - u8 tmp_text_buffer2[NICKNAME_GEN3_SIZE]; - - // Get the string to compare to - text_gen12_to_gen3(get_pokemon_name_gen2(species, 0, 0, tmp_text_buffer), tmp_text_buffer2, STRING_GEN2_INT_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_generic_to_gen3(get_pokemon_name(species, 0, 0, 0), dst->nickname, NAME_SIZE, NICKNAME_GEN3_SIZE, 0, 0); -} - -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 is_jp = (src->language == JAPANESE_LANGUAGE); - - // 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); - - // Fix text up - // "MR.MIME" gen 2 == "MR. MIME" gen 3 - // Idk if something similar happens in Jap... - // Maybe there are some French things with accents... - if((species == MR_MIME_SPECIES) && !is_egg) - fix_name_change_from_gen3(src, species, nickname, is_egg, is_gen2); - - // Put the "EGG" name - if(is_gen2 && is_egg) { - text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 0, gen2_buffer), nickname, STRING_GEN2_INT_CAP, STRING_GEN2_INT_CAP); - text_gen2_copy(get_pokemon_name_gen2(species, is_egg, 1, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP); - } - - // Handle bad naming conversions (? >= half the name) and empty names - s32 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, 0, 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, 1, gen2_buffer), nickname_jp, STRING_GEN2_JP_CAP, STRING_GEN2_JP_CAP); - -} - -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; - - // 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); - - // 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; - is_jp = 1; - } - - // Fix text up - // "MR.MIME" gen 2 == "MR. MIME" gen 3 - // Idk if something similar happens in Jap... - // Maybe there are some French things with accents... - if((species == MR_MIME_SPECIES) && !is_egg && !is_jp) - fix_name_change_to_gen3(dst, species); - - // Put the "EGG" name - if(is_egg) { - dst->language = JAPANESE_LANGUAGE; - text_gen12_to_gen3(get_pokemon_name_gen2(species, 1, 1, gen2_buffer), dst->nickname, STRING_GEN2_JP_CAP, NICKNAME_GEN3_SIZE, 1, 1); - } - else { - // Handle bad naming conversions (? >= half the name) and empty names - s32 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, is_jp, gen2_buffer), dst->nickname, name_cap, NICKNAME_GEN3_SIZE, is_jp, is_jp); - } -} - void recalc_stats_gen3(struct gen3_mon_data_unenc* data_dst, struct gen3_mon* dst) { // Calculate stats dst->curr_hp = calc_stats_gen3_raw(data_dst, HP_STAT_INDEX); for(int i = 0; i < GEN2_STATS_TOTAL; i++) - dst->stats[index_conversion_gen3[i]] = calc_stats_gen3_raw(data_dst, i); + dst->stats[stat_index_conversion_gen3[i]] = calc_stats_gen3_raw(data_dst, i); // Reset the status dst->status = 0; @@ -1392,16 +671,16 @@ void place_and_encrypt_gen3_data(struct gen3_mon_data_unenc* src, struct gen3_mo u8 index = get_index_key(dst->pid); u8 pos_data = (ENC_DATA_SIZE>>2)*((enc_positions[index] >> 0)&3); - for(int i = 0; i < sizeof(struct gen3_mon_growth); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_growth); i++) ((u8*)dst->enc_data)[pos_data+i] = ((u8*)(&src->growth))[i]; pos_data = (ENC_DATA_SIZE>>2)*((enc_positions[index] >> 2)&3); - for(int i = 0; i < sizeof(struct gen3_mon_attacks); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_attacks); i++) ((u8*)dst->enc_data)[pos_data+i] = ((u8*)(&src->attacks))[i]; pos_data = (ENC_DATA_SIZE>>2)*((enc_positions[index] >> 4)&3); - for(int i = 0; i < sizeof(struct gen3_mon_evs); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_evs); i++) ((u8*)dst->enc_data)[pos_data+i] = ((u8*)(&src->evs))[i]; pos_data = (ENC_DATA_SIZE>>2)*((enc_positions[index] >> 6)&3); - for(int i = 0; i < sizeof(struct gen3_mon_misc); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_misc); i++) ((u8*)dst->enc_data)[pos_data+i] = ((u8*)(&src->misc))[i]; encrypt_data(dst); @@ -1422,19 +701,19 @@ void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8 u8 index = get_index_key(src->pid); - // Make the compiler happy + // Makes the compiler happy struct gen3_mon_growth* growth = (struct gen3_mon_growth*)(((u32)decryption)+((ENC_DATA_SIZE>>2)*((enc_positions[index] >> 0)&3))); struct gen3_mon_attacks* attacks = (struct gen3_mon_attacks*)(((u32)decryption)+((ENC_DATA_SIZE>>2)*((enc_positions[index] >> 2)&3))); struct gen3_mon_evs* evs = (struct gen3_mon_evs*)(((u32)decryption)+((ENC_DATA_SIZE>>2)*((enc_positions[index] >> 4)&3)));; struct gen3_mon_misc* misc = (struct gen3_mon_misc*)(((u32)decryption)+((ENC_DATA_SIZE>>2)*((enc_positions[index] >> 6)&3)));; - for(int i = 0; i < sizeof(struct gen3_mon_growth); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_growth); i++) ((u8*)(&dst->growth))[i] = ((u8*)growth)[i]; - for(int i = 0; i < sizeof(struct gen3_mon_attacks); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_attacks); i++) ((u8*)(&dst->attacks))[i] = ((u8*)attacks)[i]; - for(int i = 0; i < sizeof(struct gen3_mon_evs); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_evs); i++) ((u8*)(&dst->evs))[i] = ((u8*)evs)[i]; - for(int i = 0; i < sizeof(struct gen3_mon_misc); i++) + for(u32 i = 0; i < sizeof(struct gen3_mon_misc); i++) ((u8*)(&dst->misc))[i] = ((u8*)misc)[i]; // Species checks @@ -1509,366 +788,6 @@ void process_gen3_data(struct gen3_mon* src, struct gen3_mon_data_unenc* dst, u8 recalc_stats_gen3(dst, src); } -u8 gen3_to_gen2(struct gen2_mon* dst_data, struct gen3_mon_data_unenc* data_src, u32 trainer_id) { - - struct gen3_mon* src = data_src->src; - struct gen2_mon_data* dst = &dst_data->data; - - if(!data_src->is_valid_gen3) - return 0; - - struct gen3_mon_growth* growth = &data_src->growth; - struct gen3_mon_attacks* attacks = &data_src->attacks; - struct gen3_mon_evs* evs = &data_src->evs; - struct gen3_mon_misc* misc = &data_src->misc; - - // Get shinyness and gender for checks - u8 is_shiny = is_shiny_gen3_raw(data_src, trainer_id); - u8 gender = get_pokemon_gender_gen3(growth->species, src->pid, 0, data_src->deoxys_form); - u8 gender_kind = get_pokemon_gender_kind_gen3(growth->species, src->pid, 0, data_src->deoxys_form); - - // Check that the mon can be traded - if(!validate_converting_mon_of_gen3(src, growth, is_shiny, gender, gender_kind, data_src->is_egg, 1)) - return 0; - - // Reset data structure - for(int i = 0; i < sizeof(struct gen2_mon); i++) - ((u8*)dst_data)[i] = 0; - - // Start setting data - dst->species = growth->species; - - // Convert moves, and check if no valid moves were found - if(convert_moves_of_gen3(attacks, growth->pp_bonuses, dst->moves, dst->pps, 1) == 0) - return 0; - - // Item handling - dst->item = convert_item_of_gen3(growth->item); - - // OT handling - dst->ot_id = swap_endian_short(src->ot_id & 0xFFFF); - - // Assign level and experience - convert_exp_nature_of_gen3(src, growth, &dst->level, dst->exp, 1); - - // Convert EVs - u16 evs_container[EVS_TOTAL_GEN12]; - convert_evs_of_gen3(evs, evs_container); - for(int i = 0; i < EVS_TOTAL_GEN12; i++) - dst->evs[i] = evs_container[i]; - - // Assign IVs - dst->ivs = convert_ivs_of_gen3(misc, growth->species, src->pid, is_shiny, gender, gender_kind, 1); - - // Is this really how it works...? - dst->pokerus = misc->pokerus; - - // Defaults - dst->friendship = BASE_FRIENDSHIP; - dst->status = 0; - dst->unused = 0; - - // Handle met location data - dst->time = 1; - dst->ot_gender = (misc->origins_info>>15)&1; - - // Handle special mons which cannot breed - struct special_met_data_gen2* met_data = NULL; - if(encounter_types_gen2_bin[dst->species>>3]&(1<<(dst->species&7))) { - met_data = (struct special_met_data_gen2*)search_table_for_index(special_encounters_gen2_bin, dst->species); - if(met_data != NULL) { - dst->location = met_data->location; - dst->met_level = met_data->level; - if((dst->location == 0) && (dst->location == dst->met_level)) { - dst->time = 0; - dst->ot_gender = 0; - } - } - } - if(met_data == NULL) { - dst->met_level = 1; - dst->location = 1; - } - - // Extra byte for egg data - dst_data->is_egg = data_src->is_egg; - - // Stats calculations - // Curr HP should be 0 for eggs, otherwise they count as party members - if(!dst_data->is_egg) - dst->curr_hp = swap_endian_short(calc_stats_gen2(growth->species, src->pid, HP_STAT_INDEX, dst->level, get_ivs_gen2(dst->ivs, HP_STAT_INDEX), swap_endian_short(dst->evs[HP_STAT_INDEX]))); - else - dst->curr_hp = 0; - for(int i = 0; i < GEN2_STATS_TOTAL; i++) - dst->stats[i] = swap_endian_short(calc_stats_gen2(growth->species, src->pid, i, dst->level, get_ivs_gen2(dst->ivs, i), swap_endian_short(dst->evs[i >= EVS_TOTAL_GEN12 ? EVS_TOTAL_GEN12-1 : i]))); - - // Store egg cycles - if(dst_data->is_egg) - dst->friendship = growth->friendship; - - // Text conversions - convert_strings_of_gen3(src, growth->species, dst_data->ot_name, dst_data->ot_name_jp, dst_data->nickname, dst_data->nickname_jp, dst_data->is_egg, 1); - - return 1; -} - -u8 gen3_to_gen1(struct gen1_mon* dst_data, struct gen3_mon_data_unenc* data_src, u32 trainer_id) { - - struct gen3_mon* src = data_src->src; - struct gen1_mon_data* dst = &dst_data->data; - - if(!data_src->is_valid_gen3) - return 0; - - struct gen3_mon_growth* growth = &data_src->growth; - struct gen3_mon_attacks* attacks = &data_src->attacks; - struct gen3_mon_evs* evs = &data_src->evs; - struct gen3_mon_misc* misc = &data_src->misc; - - // Get shinyness and gender for checks - u8 is_shiny = is_shiny_gen3_raw(data_src, trainer_id); - u8 gender = get_pokemon_gender_gen3(growth->species, src->pid, 0, data_src->deoxys_form); - u8 gender_kind = get_pokemon_gender_kind_gen3(growth->species, src->pid, 0, data_src->deoxys_form); - - // Check that the mon can be traded - if(!validate_converting_mon_of_gen3(src, growth, is_shiny, gender, gender_kind, data_src->is_egg, 0)) - return 0; - - // Reset data structure - for(int i = 0; i < sizeof(struct gen1_mon); i++) - ((u8*)dst_data)[i] = 0; - - // Start setting data - dst->species = get_mon_index_gen1(growth->species); - - // Convert moves, and check if no valid moves were found - if(convert_moves_of_gen3(attacks, growth->pp_bonuses, dst->moves, dst->pps, 0) == 0) - return 0; - - // Item handling - dst->item = convert_item_of_gen3(growth->item); - - // Types handling - dst->type[0] = pokemon_types_gen1_bin[(2*dst->species)]; - dst->type[1] = pokemon_types_gen1_bin[(2*dst->species) + 1]; - - // OT handling - dst->ot_id = swap_endian_short(src->ot_id & 0xFFFF); - - // Assign level and experience - convert_exp_nature_of_gen3(src, growth, &dst->level, dst->exp, 0); - - // Convert EVs - u16 evs_container[EVS_TOTAL_GEN12]; - convert_evs_of_gen3(evs, evs_container); - for(int i = 0; i < EVS_TOTAL_GEN12; i++) - dst->evs[i] = evs_container[i]; - - // Assign IVs - dst->ivs = convert_ivs_of_gen3(misc, growth->species, src->pid, is_shiny, gender, gender_kind, 0); - - // Defaults - dst->bad_level = 0; - dst->status = 0; - - // Stats calculations - dst->curr_hp = swap_endian_short(calc_stats_gen1(growth->species, HP_STAT_INDEX, dst->level, get_ivs_gen2(dst->ivs, HP_STAT_INDEX), swap_endian_short(dst->evs[HP_STAT_INDEX]))); - for(int i = 0; i < GEN1_STATS_TOTAL; i++) - dst->stats[i] = swap_endian_short(calc_stats_gen1(growth->species, i, dst->level, get_ivs_gen2(dst->ivs, i), swap_endian_short(dst->evs[i]))); - - // Text conversions - convert_strings_of_gen3(src, growth->species, dst_data->ot_name, dst_data->ot_name_jp, dst_data->nickname, dst_data->nickname_jp, 0, 0); - - return 1; -} - -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; - u8 is_egg = 0; - - // Reset everything - for(int i = 0; i < sizeof(struct gen3_mon); i++) - ((u8*)(dst))[i] = 0; - - data_dst->is_valid_gen3 = 0; - data_dst->is_valid_gen2 = 0; - - // Check if valid - if(!validate_converting_mon_of_gen2(index, src, &is_egg)) - return 0; - - data_dst->is_valid_gen3 = 1; - data_dst->is_valid_gen2 = 1; - - // Set base data - dst->has_species = 1; - dst->mail_id = GEN3_NO_MAIL; - data_dst->is_egg = is_egg; - - if(is_jp) - dst->language = JAPANESE_LANGUAGE; - else - dst->language = ENGLISH_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); - - // Reset everything - for(int i = 0; i < sizeof(struct gen3_mon_growth); i++) - ((u8*)(&data_dst->growth))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_attacks); i++) - ((u8*)(&data_dst->attacks))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_evs); i++) - ((u8*)(&data_dst->evs))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_misc); i++) - ((u8*)(&data_dst->misc))[i] = 0; - - // Set species, exp, level and item - data_dst->growth.species = src->species; - u8 wanted_nature = get_exp_nature(dst, &data_dst->growth, src->level, src->exp); - data_dst->growth.item = convert_item_to_gen3(src->item); - - // Convert EVs - u16 evs_container[EVS_TOTAL_GEN12]; - for(int i = 0; i < EVS_TOTAL_GEN12; i++) - evs_container[i] = src->evs[i]; - convert_evs_to_gen3(&data_dst->evs, evs_container); - - // Handle cases in which the nature would be forced - if((dst->level == MAX_LEVEL) || (is_egg)) - wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES); - - // Store egg cycles - if(is_egg) { - data_dst->growth.friendship = src->friendship; - data_dst->misc.is_egg = 1; - dst->use_egg_name = 1; - } - else - data_dst->growth.friendship = BASE_FRIENDSHIP; - - // Set the moves - convert_moves_to_gen3(&data_dst->attacks, &data_dst->growth, src->moves, src->pps, 1); - - data_dst->misc.pokerus = src->pokerus; - - // Special Mew handling - if(data_dst->growth.species == MEW_SPECIES) - data_dst->misc.obedience = 1; - - // Set the PID-Origin-IVs data, they're all connected - set_origin_pid_iv(dst, &data_dst->misc, data_dst->growth.species, src->ivs, wanted_nature, src->ot_gender, is_egg, no_restrictions); - - // Place all the substructures' data - place_and_encrypt_gen3_data(data_dst, dst); - - // Calculate stats - recalc_stats_gen3(data_dst, dst); - - return 1; -} - -u8 gen1_to_gen3(struct gen1_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; - - // Reset everything - for(int i = 0; i < sizeof(struct gen3_mon); i++) - ((u8*)(dst))[i] = 0; - - data_dst->is_valid_gen3 = 0; - data_dst->is_valid_gen1 = 0; - - // Check if valid - if(!validate_converting_mon_of_gen1(index, src)) - return 0; - - data_dst->is_valid_gen3 = 1; - data_dst->is_valid_gen1 = 1; - - // Set base data - dst->has_species = 1; - dst->mail_id = GEN3_NO_MAIL; - data_dst->is_egg = 0; - - if(is_jp) - dst->language = JAPANESE_LANGUAGE; - else - dst->language = ENGLISH_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); - - // Reset everything - for(int i = 0; i < sizeof(struct gen3_mon_growth); i++) - ((u8*)(&data_dst->growth))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_attacks); i++) - ((u8*)(&data_dst->attacks))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_evs); i++) - ((u8*)(&data_dst->evs))[i] = 0; - for(int i = 0; i < sizeof(struct gen3_mon_misc); i++) - ((u8*)(&data_dst->misc))[i] = 0; - - // Set species, exp, level and item - data_dst->growth.species = get_mon_index_gen1_to_3(src->species); - u8 wanted_nature = get_exp_nature(dst, &data_dst->growth, src->level, src->exp); - data_dst->growth.item = convert_item_to_gen3(src->item); - - // Convert EVs - u16 evs_container[EVS_TOTAL_GEN12]; - for(int i = 0; i < EVS_TOTAL_GEN12; i++) - evs_container[i] = src->evs[i]; - convert_evs_to_gen3(&data_dst->evs, evs_container); - - // Handle cases in which the nature would be forced - if(dst->level == MAX_LEVEL) - wanted_nature = SWI_DivMod(get_rng(), NUM_NATURES); - - // Set base friendship - data_dst->growth.friendship = BASE_FRIENDSHIP; - - // Set the moves - convert_moves_to_gen3(&data_dst->attacks, &data_dst->growth, src->moves, src->pps, 1); - - data_dst->misc.pokerus = 0; - - // Special Mew handling - if(data_dst->growth.species == MEW_SPECIES) - data_dst->misc.obedience = 1; - - // Set the PID-Origin-IVs data, they're all connected - set_origin_pid_iv(dst, &data_dst->misc, data_dst->growth.species, src->ivs, wanted_nature, 0, 0, no_restrictions); - - // Place all the substructures' data - place_and_encrypt_gen3_data(data_dst, dst); - - // Calculate stats - recalc_stats_gen3(data_dst, dst); - - return 1; -} - void clean_mail_gen3(struct mail_gen3* mail, struct gen3_mon* mon){ for(int i = 0; i < MAIL_WORDS_SIZE; i++) mail->words[i] = 0; diff --git a/source/party_handler.h b/source/party_handler.h index 1c9ea97..a67ac45 100644 --- a/source/party_handler.h +++ b/source/party_handler.h @@ -1,6 +1,8 @@ #ifndef PARTY_HANDLER__ #define PARTY_HANDLER__ +#include "useful_qualifiers.h" + #define TOTAL_GENS 3 #define FIRST_GEN 1 @@ -27,8 +29,12 @@ #define M_GENDER 0 #define F_GENDER 1 #define U_GENDER 2 +#define M_INDEX 1 +#define F_INDEX 6 +#define U_INDEX 7 #define NIDORAN_M_GENDER_INDEX 8 #define NIDORAN_F_GENDER_INDEX 9 +#define TOTAL_GENDER_KINDS 10 #define NO_POKERUS 0 #define HAS_POKERUS 1 @@ -63,6 +69,7 @@ #define RAIKOU_SPECIES 243 #define SUICUNE_SPECIES 245 #define DEOXYS_SPECIES 410 +#define EGG_SPECIES 412 #define DEOXYS_FORMS_POS 442 #define MR_MIME_OLD_NAME_POS 445 @@ -133,7 +140,7 @@ struct mail_gen3 { u16 species; u16 item; u16 unk; -} __attribute__ ((packed)); +} PACKED; struct special_met_data_gen2 { u8 location; @@ -219,7 +226,7 @@ struct gen3_mon { u8 mail_id; u16 curr_hp; u16 stats[GEN2_STATS_TOTAL]; -} __attribute__ ((packed)) __attribute__ ((aligned(4))); +} PACKED ALIGNED(4); struct gen2_mon_data { u8 species; @@ -241,7 +248,7 @@ struct gen2_mon_data { u8 unused; u16 curr_hp; u16 stats[GEN2_STATS_TOTAL]; -} __attribute__ ((packed)); +} PACKED; struct gen2_mon { struct gen2_mon_data data; @@ -267,7 +274,7 @@ struct gen1_mon_data { u8 pps[MOVES_SIZE]; u8 level; u16 stats[GEN1_STATS_TOTAL]; -} __attribute__ ((packed)); +} PACKED; struct gen1_mon { struct gen1_mon_data data; @@ -292,11 +299,22 @@ struct gen1_party { struct gen1_mon mons[PARTY_SIZE]; }; +void init_enc_positions(void); + void process_gen3_data(struct gen3_mon*, struct gen3_mon_data_unenc*, 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); -u8 gen1_to_gen3(struct gen1_mon_data*, struct gen3_mon_data_unenc*, u8, u8*, u8*, u8); + +u8 get_index_key(u32); +u8 get_nature(u32); +u16 get_mon_index(int, u32, u8, u8); +u8 get_unown_letter_gen3(u32); +const u8* get_pokemon_name(int, u32, u8, u8); +u8 has_mail(struct gen3_mon*, struct gen3_mon_growth*, u8); +s32 get_proper_exp(struct gen3_mon*, struct gen3_mon_growth*, u8); +u8 to_valid_level(u8); +u16 get_possible_abilities_pokemon(int, u32, u8, u8); +u8 get_pokemon_gender_gen3(int, u32, u8, u8); +u16 calc_stats_gen3(u16, u32, u8, u8, u8, u8, u8); +void place_and_encrypt_gen3_data(struct gen3_mon_data_unenc*, struct gen3_mon*); const u8* get_pokemon_name_raw(struct gen3_mon_data_unenc*); u16 get_mon_index_raw(struct gen3_mon_data_unenc*); @@ -327,11 +345,10 @@ const u8* get_move_name_gen3(struct gen3_mon_attacks*, u8); const u8* get_ability_name_raw(struct gen3_mon_data_unenc*); const u8* get_ribbon_name(struct gen3_mon_misc*, u8); const u8* get_ribbon_rank_name(struct gen3_mon_misc*, u8); -u32 get_proper_exp_raw(struct gen3_mon_data_unenc*); -u32 get_level_exp_mon_index(u16, u8); -u8 get_pokemon_gender_gen2(u8, u8, u8, u8); +s32 get_proper_exp_raw(struct gen3_mon_data_unenc*); +s32 get_level_exp_mon_index(u16, u8); u8 get_pokemon_gender_kind_gen3(int, u32, u8, u8); -u8 get_pokemon_gender_kind_gen2(u8, u8, u8); +void recalc_stats_gen3(struct gen3_mon_data_unenc*, struct gen3_mon*); void clean_mail_gen3(struct mail_gen3*, struct gen3_mon* mon); u8 trade_evolve(struct gen3_mon*, struct gen3_mon_data_unenc*, const u16**, u8); diff --git a/source/pid_iv_tid.c b/source/pid_iv_tid.c index 8274378..f96cba3 100644 --- a/source/pid_iv_tid.c +++ b/source/pid_iv_tid.c @@ -1,16 +1,15 @@ #include #include "pid_iv_tid.h" #include "rng.h" -#include "party_handler.h" +#include "gen12_methods.h" #include "text_handler.h" #include "fast_pokemon_methods.h" #include "optimized_swi.h" #include "print_system.h" +#include "useful_qualifiers.h" #include "shiny_unown_banned_tsv_bin.h" #include "shiny_unown_banned_tsv_letter_table_bin.h" - -#define ALWAYS_INLINE __attribute__((always_inline)) static inline #define TEST_WORST_CASE 0 @@ -18,6 +17,19 @@ #define NUM_DIFFERENT_PSV (0x10000>>3) #define NUM_DIFFERENT_UNOWN_PSV (0x10000>>5) +static u8 is_bad_tsv(u16); +static void get_letter_valid_natures(u16, u8, u8*); +static u32 get_prev_seed(u32); +static u32 get_next_seed(u32); +void _generate_egg_info(u8, u16, u16, u8, u8, u32*, u32*, u32); +void _generate_egg_shiny_info(u8, u16, u8, u8, u32*, u32*, u32); +void _generate_static_info(u8, u16, u16, u32*, u32*, u32); +void _generate_static_shiny_info(u8, u16, u32*, u32*, u32); +void _generate_unown_info(u8, u8, u8, u16, u32*, u32*, u32); +u8 search_specific_low_pid(u32, u32*, u32*); +u8 search_unown_pid_masks(u32, u8, u32*, u32*); +void _generate_unown_shiny_info(u8, u16, u8, u32*, u32*, u32); + // Nidoran M is special, it has to have 0x8000 set in the lower PID u8 gender_useful_atk_ivs[] = {3, 4, 1, 2, 2, 1, 4, 4, 4, 4}; u16 gender_values[] = {0x7F, 0, 0x1F, 0x3F, 0xBF, 0xDF, 0, 0, 0x7FFF, 0}; @@ -39,17 +51,17 @@ void init_unown_tsv() { } } -ALWAYS_INLINE __attribute__ ((optimize(3))) u8 is_bad_tsv(u16 tsv) { +ALWAYS_INLINE MAX_OPTIMIZE u8 is_bad_tsv(u16 tsv) { tsv = (tsv >> 3) << 3; const u32* shiny_unown_banned_tsv_bin_32 = (const u32*)shiny_unown_banned_tsv_bin; - for(int i = 0; i < (shiny_unown_banned_tsv_bin_size >> 2); i++) { + for(u32 i = 0; i < (shiny_unown_banned_tsv_bin_size >> 2); i++) { if(tsv == (shiny_unown_banned_tsv_bin_32[i] & 0xFFFF)) return 1; } return 0; } -ALWAYS_INLINE __attribute__ ((optimize(3))) void get_letter_valid_natures(u16 tsv, u8 letter, u8* valid_natures) { +ALWAYS_INLINE MAX_OPTIMIZE void get_letter_valid_natures(u16 tsv, u8 letter, u8* valid_natures) { tsv = (tsv >> 3) << 3; for(int i = 0; i < NUM_NATURES; i++) valid_natures[i] = 1; @@ -58,7 +70,7 @@ ALWAYS_INLINE __attribute__ ((optimize(3))) void get_letter_valid_natures(u16 ts if(letter_kind == 0xF) return; const u32* shiny_unown_banned_tsv_bin_32 = (const u32*)shiny_unown_banned_tsv_bin; - for(int i = 0; i < (shiny_unown_banned_tsv_bin_size >> 2); i++) { + for(u32 i = 0; i < (shiny_unown_banned_tsv_bin_size >> 2); i++) { if(tsv == (shiny_unown_banned_tsv_bin_32[i] & 0xFFFF)) { u8 letter_kind_table = (shiny_unown_banned_tsv_bin_32[i]>>0x14)&0xF; u8 letter_dist_table = (shiny_unown_banned_tsv_bin_32[i]>>0x10)&0xF; @@ -73,15 +85,15 @@ ALWAYS_INLINE __attribute__ ((optimize(3))) void get_letter_valid_natures(u16 ts } } -ALWAYS_INLINE __attribute__ ((optimize(3))) u32 get_prev_seed(u32 seed) { +ALWAYS_INLINE MAX_OPTIMIZE u32 get_prev_seed(u32 seed) { return (seed-0x6073) * 0xEEB9EB65; } -ALWAYS_INLINE __attribute__ ((optimize(3))) u32 get_next_seed(u32 seed) { +ALWAYS_INLINE MAX_OPTIMIZE u32 get_next_seed(u32 seed) { return ((seed*0x41C64E6D)+0x6073); } -IWRAM_CODE __attribute__ ((optimize(3))) u32 generate_ot(u16 tid, u8* name) { +IWRAM_CODE MAX_OPTIMIZE u32 generate_ot(u16 tid, u8* name) { // Worst case: ANY // This should NOT be random... // All Pokémon from a trainer should have the same TID/SID! @@ -108,7 +120,7 @@ IWRAM_CODE __attribute__ ((optimize(3))) u32 generate_ot(u16 tid, u8* name) { return (sid << 0x10) | tid; } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_egg_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 gender, u8 gender_kind, u32* dst_pid, u32* dst_ivs, u32 start_seed) { +IWRAM_CODE MAX_OPTIMIZE void _generate_egg_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 gender, u8 gender_kind, u32* dst_pid, u32* dst_ivs, u32 start_seed) { // Worst case: 0, 0x2113, 0, 0, 0, 34 u8 atk_ivs = ((((wanted_ivs>>4) & 0xF)<<(4-gender_useful_atk_ivs[gender_kind])) & 0xF)<<1; u8 def_ivs = ((wanted_ivs) & 0xF)<<1; @@ -201,11 +213,11 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_egg_info(u8 wanted_natur } } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_egg_info(u8 index, u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 curr_gen, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_egg_info(u8 index, u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 curr_gen, u32* dst_pid, u32* dst_ivs) { _generate_egg_info(wanted_nature, wanted_ivs, tsv, get_pokemon_gender_gen2(index, (wanted_ivs>>4)&0xF, 0, curr_gen), get_pokemon_gender_kind_gen2(index, 0, curr_gen), dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_egg_shiny_info(u8 wanted_nature, u16 tsv, u8 gender, u8 gender_kind, u32* dst_pid, u32* dst_ivs, u32 start_seed) { +IWRAM_CODE MAX_OPTIMIZE void _generate_egg_shiny_info(u8 wanted_nature, u16 tsv, u8 gender, u8 gender_kind, u32* dst_pid, u32* dst_ivs, u32 start_seed) { // Worst case: ANY u16 lower_pid = start_seed &0xFFFF; @@ -251,11 +263,11 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_egg_shiny_info(u8 wanted *dst_pid = pid; } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_egg_shiny_info(u8 index, u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 curr_gen, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_egg_shiny_info(u8 index, u8 wanted_nature, u16 wanted_ivs, u16 tsv, u8 curr_gen, u32* dst_pid, u32* dst_ivs) { _generate_egg_shiny_info(wanted_nature, tsv, get_pokemon_gender_gen2(index, (wanted_ivs>>4)&0xF, 0, curr_gen), get_pokemon_gender_kind_gen2(index, 0, curr_gen), dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_static_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 start_seed) { +IWRAM_CODE MAX_OPTIMIZE void _generate_static_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 start_seed) { // Worst case: 6, 12706, 0xA30E, 0 u8 atk_ivs = ((wanted_ivs>>4) & 0xF)<<1; u8 def_ivs = ((wanted_ivs) & 0xF)<<1; @@ -320,11 +332,11 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_static_info(u8 wanted_na } } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_static_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_static_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { _generate_static_info(wanted_nature, wanted_ivs, tsv, dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_static_shiny_info(u8 wanted_nature, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 given_seed) { +IWRAM_CODE MAX_OPTIMIZE void _generate_static_shiny_info(u8 wanted_nature, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 given_seed) { // Worst case: 0, 0x2088, (base_increment = 1, initial_pos = 0x6D0, set TEST_WORST_CASE to 1 to test it, with seed 0x36810000) s32 base_increment; u16 initial_pos; @@ -411,11 +423,11 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_static_shiny_info(u8 wan } } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_static_shiny_info(u8 wanted_nature, u16 tsv, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_static_shiny_info(u8 wanted_nature, u16 tsv, u32* dst_pid, u32* dst_ivs) { _generate_static_shiny_info(wanted_nature, tsv, dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_unown_info(u8 wanted_nature, u8 letter, u8 rest_of_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 start_seed) { +IWRAM_CODE MAX_OPTIMIZE void _generate_unown_info(u8 wanted_nature, u8 letter, u8 rest_of_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs, u32 start_seed) { // Worst case: 15, 4, 0xCE, 0xA021, 0x1AA u8 atk_ivs = (((rest_of_ivs>>0)&1) | (((rest_of_ivs>>0)&2)<<2))<<1; u8 def_ivs = (((rest_of_ivs>>2)&1) | (((rest_of_ivs>>2)&2)<<2))<<1; @@ -472,7 +484,7 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_unown_info(u8 wanted_nat } } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_unown_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_unown_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { u8 atk_ivs = ((wanted_ivs>>4) & 0xF); u8 def_ivs = ((wanted_ivs) & 0xF); u8 spe_ivs = ((wanted_ivs>>12) & 0xF); @@ -482,9 +494,9 @@ IWRAM_CODE __attribute__ ((optimize(3))) void generate_unown_info(u8 wanted_natu _generate_unown_info(wanted_nature, letter, rest_of_ivs, tsv, dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) u8 search_unown_with_mask(u32 mask, u16 new_high, u16 new_low, u32* dst_pid, u32* dst_ivs) { - new_high = new_high ^ (mask>>16); - new_low = new_low ^ (mask&0xFFFF); +IWRAM_CODE MAX_OPTIMIZE u8 search_specific_low_pid(u32 pid, u32* dst_pid, u32* dst_ivs) { + u16 new_high = pid >> 16; + u16 new_low = pid & 0xFFFF; for(int u = 0; u < NUM_SEEDS; u++) { u32 seed = (new_high<<16) | u; @@ -504,7 +516,29 @@ IWRAM_CODE __attribute__ ((optimize(3))) u8 search_unown_with_mask(u32 mask, u16 return 0; } -IWRAM_CODE __attribute__ ((optimize(3))) void _generate_unown_shiny_info(u8 wanted_nature, u16 tsv, u8 letter, u32* dst_pid, u32* dst_ivs, u32 given_seed) { +IWRAM_CODE MAX_OPTIMIZE u8 search_unown_pid_masks(u32 pid, u8 wanted_nature, u32* dst_pid, u32* dst_ivs) { + for(int i = 0; i < 0x20; i++) + for(int j = 0; j < 0x80; j++) { + u32 mask = 0; + if(j&1) + mask +=4; + if(j&2) + mask += 0x40000; + for(int k = 0; k < 5; k++) + if((j>>(2+k))&1) + mask += 0x10001 << (3+k); + for(int k = 0; k < 5; k++) + if((i>>k)&1) + mask += 0x01000100 << (3+k); + u8 xor_mod_change = get_nature_fast(pid ^ mask); + if(xor_mod_change == wanted_nature) + if(search_specific_low_pid(pid ^ mask, dst_pid, dst_ivs)) + return 1; + } + return 0; +} + +IWRAM_CODE MAX_OPTIMIZE void _generate_unown_shiny_info(u8 wanted_nature, u16 tsv, u8 letter, u32* dst_pid, u32* dst_ivs, u32 given_seed) { // Worst case: 5, 0x4FF8, 5, 0x8FC00000 u16 high_pid; u16 low_pid; @@ -578,26 +612,9 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_unown_shiny_info(u8 want new_high = (new_high & 0x0303) | ((new_low) & 0xFCFC); new_low = (new_low & 0x0303) | ((old_new_high) & 0xFCFC); } - - pid = (new_high<<16) | new_low; - for(int i = 0; i < 0x20; i++) - for(int j = 0; j < 0x80; j++) { - u32 mask = 0; - if(j&1) - mask +=4; - if(j&2) - mask += 0x40000; - for(int k = 0; k < 5; k++) - if((j>>(2+k))&1) - mask += 0x10001 << (3+k); - for(int k = 0; k < 5; k++) - if((i>>k)&1) - mask += 0x01000100 << (3+k); - u8 xor_mod_change = get_nature_fast(pid ^ mask); - if(xor_mod_change == wanted_nature) - if(search_unown_with_mask(mask, new_high, new_low, dst_pid, dst_ivs)) - return; - } + + if(search_unown_pid_masks((new_high<<16) | new_low, wanted_nature, dst_pid, dst_ivs)) + return; } } if(pos + base_increment < 0) @@ -617,7 +634,7 @@ IWRAM_CODE __attribute__ ((optimize(3))) void _generate_unown_shiny_info(u8 want } } -IWRAM_CODE __attribute__ ((optimize(3))) void generate_unown_shiny_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE void generate_unown_shiny_info(u8 wanted_nature, u16 wanted_ivs, u16 tsv, u32* dst_pid, u32* dst_ivs) { u8 letter = get_unown_letter_gen2_fast(wanted_ivs); u8 valid_natures[NUM_NATURES]; get_letter_valid_natures(tsv, letter, valid_natures); @@ -627,10 +644,10 @@ IWRAM_CODE __attribute__ ((optimize(3))) void generate_unown_shiny_info(u8 wante if(wanted_nature >= NUM_NATURES) wanted_nature -= NUM_NATURES; } - return _generate_unown_shiny_info(wanted_nature, letter, tsv, dst_pid, dst_ivs, get_rng()); + _generate_unown_shiny_info(wanted_nature, letter, tsv, dst_pid, dst_ivs, get_rng()); } -IWRAM_CODE __attribute__ ((optimize(3))) u8 get_roamer_ivs(u32 pid, u8 hp_ivs, u8 atk_ivs, u32* dst_ivs) { +IWRAM_CODE MAX_OPTIMIZE u8 get_roamer_ivs(u32 pid, u8 hp_ivs, u8 atk_ivs, u32* dst_ivs) { atk_ivs &= 7; for(u32 l = 0; l < NUM_SEEDS; l++) { @@ -655,11 +672,13 @@ IWRAM_CODE __attribute__ ((optimize(3))) u8 get_roamer_ivs(u32 pid, u8 hp_ivs, u return 0; } +#if !(TEST_WORST_CASE) +void worst_case_conversion_tester(u32* UNUSED(counter)) { +#else void worst_case_conversion_tester(u32* counter) { - #if TEST_WORST_CASE - int curr_counter = *counter; - int max_counter = 0; + u32 curr_counter = *counter; + u32 max_counter = 0; u32 pid, ivs; curr_counter = *counter; @@ -730,4 +749,4 @@ void worst_case_conversion_tester(u32* counter) { PRINT_FUNCTION("Max time 4 s: 0x\x04\n", max_counter); #endif -} \ No newline at end of file +} diff --git a/source/pid_iv_tid.h b/source/pid_iv_tid.h index 9582902..a10b071 100644 --- a/source/pid_iv_tid.h +++ b/source/pid_iv_tid.h @@ -1,10 +1,8 @@ #ifndef PID_IV_TID__ #define PID_IV_TID__ -#include - void worst_case_conversion_tester(u32*); -void init_unown_tsv(); +void init_unown_tsv(void); u8 get_roamer_ivs(u32, u8, u8, u32*); void generate_unown_shiny_info(u8, u16, u16, u32*, u32*); @@ -15,4 +13,4 @@ void generate_egg_shiny_info(u8, u8, u16, u16, u8, u32*, u32*); void generate_egg_info(u8, u8, u16, u16, u8, u32*, u32*); u32 generate_ot(u16, u8*); -#endif \ No newline at end of file +#endif diff --git a/source/print_system.c b/source/print_system.c index 07c0d7d..60648aa 100644 --- a/source/print_system.c +++ b/source/print_system.c @@ -5,14 +5,13 @@ #include "text_handler.h" #include "graphics_handler.h" #include "sprite_handler.h" +#include "useful_qualifiers.h" #include "text_gen3_to_general_int_bin.h" #include "amiga_font_c_bin.h" #include "jp_font_c_bin.h" #include "window_graphics_bin.h" -#define ALWAYS_INLINE __attribute__((always_inline)) static inline - #define BASE_COLOUR RGB8(58,110,165) #define FONT_COLOUR RGB5(31,31,31) #define WINDOW_COLOUR_1 RGB5(15,15,15) @@ -39,6 +38,22 @@ #define NUM_DIGITS 12 +void set_arrangements(u8); +void process_arrangements(void); +void enable_screens(void); +void set_screens_positions(void); +static void base_flush(void); +void new_line(void); +u8 write_char(u16); +void write_above_char(u16); +int sub_printf(u8*); +int sub_printf_gen3(u8*, u8, u8); +int prepare_base_10(int, u8*); +int prepare_base_16(int, u8*); +int digits_print(u8*, int, u8, u8); +int write_base_10(int, int, u8); +int write_base_16(int, int, u8); + u8 x_pos; u8 y_pos; u16* screen; @@ -151,8 +166,8 @@ void init_text_system() { convert_1bpp((u8*)buffer, (u32*)JP_FONT_POS, FONT_1BPP_SIZE, colors, 0); // Set window tiles - for(int i = 0; i < (window_graphics_bin_size>>2); i++) - *((u32*)(FONT_POS+(2*TILE_SIZE)+(i<<2))) = ((u32*)window_graphics_bin)[i]; + for(u32 i = 0; i < (window_graphics_bin_size>>2); i++) + *((u32*)(FONT_POS+(2*TILE_SIZE)+(i<<2))) = ((const u32*)window_graphics_bin)[i]; } void set_updated_screen() { diff --git a/source/print_system.h b/source/print_system.h index 88ef5eb..7ee0b07 100644 --- a/source/print_system.h +++ b/source/print_system.h @@ -1,8 +1,6 @@ #ifndef PRINT_SYSTEM__ #define PRINT_SYSTEM__ -#include "gba.h" - #define PRINT_FUNCTION fast_printf #define X_LIMIT (SCREEN_WIDTH>>3) #define Y_LIMIT (SCREEN_HEIGHT>>3) @@ -25,25 +23,25 @@ int fast_printf(const char *, ...); -void init_numbers(); -void default_reset_screen(); +void init_numbers(void); +void default_reset_screen(void); void reset_screen(u8); void set_text_x(u8); void set_text_y(u8); void enable_screen(u8); void disable_screen(u8); -void disable_all_screens_but_current(); +void disable_all_screens_but_current(void); void set_bg_pos(u8, int, int); u16* get_screen(u8 bg_num); -u8 get_screen_num(); +u8 get_screen_num(void); void set_screen(u8); -void init_text_system(); -void prepare_flush(); -void set_updated_screen(); -void flush_screens(); -void wait_for_vblank_if_needed(); +void init_text_system(void); +void prepare_flush(void); +void set_updated_screen(void); +void flush_screens(void); +void wait_for_vblank_if_needed(void); u8 get_bg_priority(u8); -u8 get_curr_priority(); -u8 get_loaded_priority(); +u8 get_curr_priority(void); +u8 get_loaded_priority(void); #endif diff --git a/source/rng.c b/source/rng.c index 39001e3..6efebb2 100644 --- a/source/rng.c +++ b/source/rng.c @@ -1,18 +1,20 @@ #include #include "rng.h" - -#define ALWAYS_INLINE __attribute__((always_inline)) static inline +#include "useful_qualifiers.h" #define FACTOR_0 0x4C957F2D #define FACTOR_1 0x5851F42D #define INCREMENT_0 1 #define INCREMENT_1 0 +static void u64_add(u32*, u32*, u32, u32); +void u64_mul(u32*, u32*, u32, u32); + static u32 curr_seed_0; static u32 curr_seed_1; static u8 advances_enabled; -ALWAYS_INLINE __attribute__((optimize(3))) void u64_add(u32* src0_0_p, u32* src0_1_p, u32 src1_0, u32 src1_1) +ALWAYS_INLINE MAX_OPTIMIZE void u64_add(u32* src0_0_p, u32* src0_1_p, u32 src1_0, u32 src1_1) { u32 src0_0 = *src0_0_p; u32 src0_1 = *src0_1_p; @@ -25,7 +27,7 @@ ALWAYS_INLINE __attribute__((optimize(3))) void u64_add(u32* src0_0_p, u32* src0 } } -IWRAM_CODE __attribute__((target("arm"), noinline)) void u64_mul(u32* src0_0_p, u32* src0_1_p, u32 src1_0, u32 src1_1) +IWRAM_CODE ARM_TARGET MAX_OPTIMIZE void u64_mul(u32* src0_0_p, u32* src0_1_p, u32 src1_0, u32 src1_1) { register uint32_t src0_0_ asm("r0") = (uint32_t)(*src0_0_p); register uint32_t src0_1_ asm("r1") = (uint32_t)(*src0_1_p); @@ -83,4 +85,4 @@ u32 get_rng() { void advance_rng() { if(advances_enabled) get_rng(); -} \ No newline at end of file +} diff --git a/source/rng.h b/source/rng.h index 4798f32..a9ee17f 100644 --- a/source/rng.h +++ b/source/rng.h @@ -1,13 +1,11 @@ #ifndef RNG__ #define RNG__ -#include - void init_rng(u32, u32); -void disable_advances(); -void enable_advances(); -u32 get_rng(); -void advance_rng(); +void disable_advances(void); +void enable_advances(void); +u32 get_rng(void); +void advance_rng(void); void increase_rng(u32, u32); -#endif \ No newline at end of file +#endif diff --git a/source/save.c b/source/save.c index 6e4a36a..81cf7c1 100644 --- a/source/save.c +++ b/source/save.c @@ -8,6 +8,8 @@ #define timeout 0x1000 #define BANK_SIZE 0x10000 +void bank_check(u32); + u8 current_bank; void init_bank(){ @@ -117,4 +119,4 @@ int is_flash_correct(u8* data, int size, int has_banks) { else if(size > BANK_SIZE) return 0; return 1; -} \ No newline at end of file +} diff --git a/source/save.h b/source/save.h index c273960..a0263df 100644 --- a/source/save.h +++ b/source/save.h @@ -12,6 +12,6 @@ int is_flash_correct(u8* data, int size, int has_banks); u32 read_int_save(u32); u16 read_short_save(u32); void copy_save_to_ram(u32, u8*, int); -void init_bank(); +void init_bank(void); -#endif \ No newline at end of file +#endif diff --git a/source/sio.c b/source/sio.c index 1daa759..234436e 100644 --- a/source/sio.c +++ b/source/sio.c @@ -1,6 +1,7 @@ #include #include "sio.h" #include "vcount_basic.h" +#include "useful_qualifiers.h" #define BLANK_LINES_WAIT 13 @@ -50,7 +51,7 @@ void sio_normal_inner_slave() { REG_SIOCNT |= SIO_SO_HIGH; } -IWRAM_CODE __attribute__((optimize(3))) void sio_handle_irq_slave(int next_data) { +IWRAM_CODE MAX_OPTIMIZE void sio_handle_irq_slave(int next_data) { REG_SIOCNT |= SIO_SO_HIGH; REG_SIODATA32 = next_data; @@ -65,7 +66,7 @@ IWRAM_CODE __attribute__((optimize(3))) void sio_handle_irq_slave(int next_data) REG_SIOCNT &= ~SIO_SO_HIGH; } -IWRAM_CODE __attribute__((optimize(3))) int sio_read(u8 is_32) { +IWRAM_CODE MAX_OPTIMIZE int sio_read(u8 is_32) { u32 data = REG_SIODATA8; if(is_32) data = REG_SIODATA32; @@ -94,7 +95,7 @@ void sio_normal_prepare_irq_slave(int data) { REG_SIOCNT &= ~SIO_SO_HIGH; } -IWRAM_CODE __attribute__((optimize(3))) u32 sio_send_if_ready_master(u32 data, u8 is_32, u8* success) { +IWRAM_CODE MAX_OPTIMIZE u32 sio_send_if_ready_master(u32 data, u8 is_32, u8* success) { // - Wait for SI to become LOW (slave ready). (Check timeout here!) REG_SIODATA32 = data; REG_SIODATA8 = (data & 0xFF); @@ -110,7 +111,7 @@ IWRAM_CODE __attribute__((optimize(3))) u32 sio_send_if_ready_master(u32 data, u return sio_read(is_32); } -IWRAM_CODE __attribute__((optimize(3))) u32 sio_send_master(u32 data, u8 is_32) { +IWRAM_CODE MAX_OPTIMIZE u32 sio_send_master(u32 data, u8 is_32) { // - Wait for SI to become LOW (slave ready). (Check timeout here!) REG_SIODATA32 = data; REG_SIODATA8 = (data & 0xFF); diff --git a/source/sio.h b/source/sio.h index 34ff228..30a5405 100644 --- a/source/sio.h +++ b/source/sio.h @@ -14,7 +14,7 @@ int sio_normal(int, int, int, u8*); void sio_normal_prepare_irq_slave(int); int timed_sio_normal_master(int, int, int); void sio_handle_irq_slave(int); -void sio_stop_irq_slave(); +void sio_stop_irq_slave(void); int sio_read(u8); u32 sio_send_if_ready_master(u32, u8, u8*); u32 sio_send_master(u32 data, u8 is_32); diff --git a/source/sio_buffers.c b/source/sio_buffers.c index b69b3ca..98e615a 100644 --- a/source/sio_buffers.c +++ b/source/sio_buffers.c @@ -1,19 +1,39 @@ -#include #include #include "sio_buffers.h" #include "text_handler.h" #include "options_handler.h" #include "party_handler.h" +#include "gen_converter.h" #include "gen3_save.h" #include "default_gift_ribbons_bin.h" +#define EACH_DIFFERENT 1 + +void prepare_number_of_sizes(void); +u8 get_number_of_buffers(void); +void copy_bytes(const void*, void*, int, u8, u8); +void prepare_random_data_gen12(struct random_data_t*); +void prepare_patch_set(u8*, u8*, u32, int, u32, int); +void apply_patch_set(u8*, u8*, u32, int, u32, int); +void prepare_mail_gen2(u8*, int, u8*, u8, u32); +#if !(EACH_DIFFERENT) +void buffer_loader(struct game_data_t*, u32*, u16*, u8); +#else +void load_names_gen12(struct game_data_t*, u8*, u8*, u8*, u8, u8); +void load_party_info_gen2(struct game_data_t*, struct gen2_party_info*); +void load_party_info_gen1(struct game_data_t*, struct gen1_party_info*); +void prepare_gen2_trade_data(struct game_data_t*, u32*, u8, u16*); +void prepare_gen1_trade_data(struct game_data_t*, u32*, u8, u16*); +#endif +void prepare_gen3_trade_data(struct game_data_t*, u32*, u16*); +void read_gen12_trade_data(struct game_data_t*, u32*, u8, u8); +void read_gen3_trade_data(struct game_data_t* game_data, u32* buffer); + u32 communication_buffers[2][BUFFER_SIZE>>2]; u16 buffer_sizes[NUM_SIZES]; u8 number_of_sizes; -#define EACH_DIFFERENT 1 - u32* get_communication_buffer(u8 requested) { if(!requested) return communication_buffers[OWN_BUFFER]; @@ -43,8 +63,8 @@ u16 get_buffer_size(int index) { return buffer_sizes[index]; } -void copy_bytes(void* src, void* dst, int size, u8 src_offset, u8 dst_offset) { - u8* src_data = (u8*)src; +void copy_bytes(const void* src, void* dst, int size, u8 src_offset, u8 dst_offset) { + const u8* src_data = (const u8*)src; u8* dst_data = (u8*)dst; for(int i = 0; i < size; i++) dst_data[dst_offset+i] = src_data[src_offset+i]; @@ -55,14 +75,14 @@ void prepare_random_data_gen12(struct random_data_t* random_data) { random_data->data[i] = DEFAULT_FILLER; } -void prepare_patch_set(u8* buffer, u8* patch_set_buffer, int size, int start_pos, int patch_set_size, int base_pos) { - int cursor_data = base_pos; +void prepare_patch_set(u8* buffer, u8* patch_set_buffer, u32 size, int start_pos, u32 patch_set_size, int base_pos) { + u32 cursor_data = base_pos; - for(int i = 0; i < patch_set_size; i++) + for(u32 i = 0; i < patch_set_size; i++) patch_set_buffer[i] = 0; u32 base = start_pos; - for(int i = 0; i < size; i++) { + for(u32 i = 0; i < size; i++) { if(buffer[start_pos + i] == NO_ACTION_BYTE) { buffer[start_pos + i] = 0xFF; patch_set_buffer[cursor_data++] = start_pos + i + 1 -base; @@ -87,9 +107,9 @@ void prepare_patch_set(u8* buffer, u8* patch_set_buffer, int size, int start_pos patch_set_buffer[cursor_data] = 0xFF; } -void apply_patch_set(u8* buffer, u8* patch_set_buffer, int size, int start_pos, int patch_set_size, int base_pos) { +void apply_patch_set(u8* buffer, u8* patch_set_buffer, u32 size, int start_pos, u32 patch_set_size, int base_pos) { u32 base = 0; - for(int i = base_pos; i < patch_set_size; i++) { + for(u32 i = base_pos; i < patch_set_size; i++) { if(patch_set_buffer[i]) { if(patch_set_buffer[i] == 0xFF) { base += NO_ACTION_BYTE-1; @@ -434,8 +454,8 @@ u8 are_checksum_same_gen3(struct gen3_trade_data* td) { u32 checksum = 0; for(int i = 0; i < PARTY_SIZE; i++) { u32* mail_buf = (u32*)&td->mails_3[i]; - for(int i = 0; i < (sizeof(struct mail_gen3)>>2); i++) - checksum += mail_buf[i]; + for(u32 j = 0; j < (sizeof(struct mail_gen3)>>2); j++) + checksum += mail_buf[j]; } if(td->checksum_mail != checksum) @@ -444,7 +464,7 @@ u8 are_checksum_same_gen3(struct gen3_trade_data* td) { checksum = 0; u32* party_buf = (u32*)&td->party_3; - for(int i = 0; i < (sizeof(struct gen3_party)>>2); i++) + for(u32 i = 0; i < (sizeof(struct gen3_party)>>2); i++) checksum += party_buf[i]; if(td->checksum_party != checksum) @@ -453,7 +473,7 @@ u8 are_checksum_same_gen3(struct gen3_trade_data* td) { checksum = 0; u32* buffer = (u32*)td; - for(int i = 0; i < ((sizeof(struct gen3_trade_data) - 4)>>2); i++) + for(u32 i = 0; i < ((sizeof(struct gen3_trade_data) - 4)>>2); i++) checksum += buffer[i]; if(td->final_checksum != checksum) @@ -469,7 +489,7 @@ void prepare_gen3_trade_data(struct game_data_t* game_data, u32* buffer, u16* si for(int i = 0; i < PARTY_SIZE; i++) { copy_bytes(&game_data->mails_3[i], &td->mails_3[i], sizeof(struct mail_gen3), 0, 0); u32* mail_buf = (u32*)&td->mails_3[i]; - for(int i = 0; i < (sizeof(struct mail_gen3)>>2); i++) + for(u32 j = 0; j < (sizeof(struct mail_gen3)>>2); j++) checksum += mail_buf[i]; } @@ -478,7 +498,7 @@ void prepare_gen3_trade_data(struct game_data_t* game_data, u32* buffer, u16* si copy_bytes(&game_data->party_3, &td->party_3, sizeof(struct gen3_party), 0, 0); u32* party_buf = (u32*)&td->party_3; - for(int i = 0; i < (sizeof(struct gen3_party)>>2); i++) + for(u32 i = 0; i < (sizeof(struct gen3_party)>>2); i++) checksum += party_buf[i]; td->checksum_party = checksum; @@ -498,7 +518,7 @@ void prepare_gen3_trade_data(struct game_data_t* game_data, u32* buffer, u16* si td->trainer_id = game_data->trainer_id; - for(int i = 0; i < ((sizeof(struct gen3_trade_data) - 4)>>2); i++) + for(u32 i = 0; i < ((sizeof(struct gen3_trade_data) - 4)>>2); i++) checksum += buffer[i]; td->final_checksum = checksum; @@ -559,13 +579,13 @@ void read_gen12_trade_data(struct game_data_t* game_data, u32* buffer, u8 curr_g game_data->game_identifier.game_is_jp = is_jp; for(int i = 0; i < PARTY_SIZE; i++) - for(int j = 0; j < sizeof(struct mail_gen3); j++) + for(u32 j = 0; j < sizeof(struct mail_gen3); j++) ((u8*)(&game_data->mails_3[i]))[j] = 0; - for(int i = 0; i < sizeof(struct gen3_party); i++) + for(u32 i = 0; i < sizeof(struct gen3_party); i++) ((u8*)(&game_data->party_3))[i] = 0; - copy_bytes((u8*)default_gift_ribbons_bin, game_data->giftRibbons, GIFT_RIBBONS, 0, 0); + 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); @@ -584,7 +604,7 @@ void read_gen12_trade_data(struct game_data_t* game_data, u32* buffer, u8 curr_g game_data->party_3.total = PARTY_SIZE; u8 found = 0; - for(int i = 0; i < game_data->party_3.total; i++) { + for(u32 i = 0; i < game_data->party_3.total; i++) { game_data->party_3_undec[i].src = &game_data->party_3.mons[i]; u8 conversion_success = 0; if(curr_gen == 2) @@ -624,7 +644,7 @@ void read_gen3_trade_data(struct game_data_t* game_data, u32* buffer) { game_data->party_3.total = PARTY_SIZE; u8 found = 0; - for(int i = 0; i < game_data->party_3.total; i++) { + for(u32 i = 0; i < game_data->party_3.total; i++) { process_gen3_data(&game_data->party_3.mons[i], &game_data->party_3_undec[i], game_data->game_identifier.game_main_version, game_data->game_identifier.game_sub_version); if(game_data->party_3_undec[i].is_valid_gen3) found = 1; diff --git a/source/sio_buffers.h b/source/sio_buffers.h index 67b9c0e..93fc3d8 100644 --- a/source/sio_buffers.h +++ b/source/sio_buffers.h @@ -3,6 +3,7 @@ #include "party_handler.h" #include "gen3_save.h" +#include "useful_qualifiers.h" // We oversize it to have some wiggle room #define BUFFER_SIZE 0x500 @@ -38,20 +39,20 @@ struct random_data_t { u8 data[RANDOM_DATA_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct gen2_party_info { u8 num_mons; u8 mons_index[MON_INDEX_SIZE]; u16 trainer_id; struct gen2_mon_data mons_data[PARTY_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct gen1_party_info { u8 num_mons; u8 mons_index[MON_INDEX_SIZE]; struct gen1_mon_data mons_data[PARTY_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct trainer_data_gen2_int { u8 trainer_name[STRING_GEN2_INT_SIZE]; @@ -59,7 +60,7 @@ struct trainer_data_gen2_int { u8 ot_names[PARTY_SIZE][STRING_GEN2_INT_SIZE]; u8 nicknames[PARTY_SIZE][STRING_GEN2_INT_SIZE]; u8 safety_bytes[SAFETY_BYTES_NUM]; -} __attribute__ ((packed)); +} PACKED; struct trainer_data_gen2_jp { u8 trainer_name[STRING_GEN2_JP_SIZE]; @@ -67,7 +68,7 @@ struct trainer_data_gen2_jp { u8 ot_names[PARTY_SIZE][STRING_GEN2_JP_SIZE]; u8 nicknames[PARTY_SIZE][STRING_GEN2_JP_SIZE]; u8 safety_bytes[SAFETY_BYTES_NUM]; -} __attribute__ ((packed)); +} PACKED; struct trainer_data_gen1_int { u8 trainer_name[STRING_GEN2_INT_SIZE]; @@ -75,7 +76,7 @@ struct trainer_data_gen1_int { u8 ot_names[PARTY_SIZE][STRING_GEN2_INT_SIZE]; u8 nicknames[PARTY_SIZE][STRING_GEN2_INT_SIZE]; u8 safety_bytes[SAFETY_BYTES_NUM]; -} __attribute__ ((packed)); +} PACKED; struct trainer_data_gen1_jp { u8 trainer_name[STRING_GEN2_JP_SIZE]; @@ -83,22 +84,22 @@ struct trainer_data_gen1_jp { u8 ot_names[PARTY_SIZE][STRING_GEN2_JP_SIZE]; u8 nicknames[PARTY_SIZE][STRING_GEN2_JP_SIZE]; u8 safety_bytes[SAFETY_BYTES_NUM]; -} __attribute__ ((packed)); +} PACKED; struct patch_set_trainer_data_gen12 { u8 patch_set[PATCH_SET_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct party_mail_data_gen2_int { u8 gen2_mail_data[MAIL_GEN2_INT_SIZE]; u8 patch_set[MAIL_PATCH_SET_INT_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct party_mail_data_gen2_jp { // Need to look into it, again for the size... u8 gen2_mail_data[MAIL_GEN2_JP_SIZE]; u8 patch_set[MAIL_PATCH_SET_JP_SIZE]; -} __attribute__ ((packed)); +} PACKED; struct gen2_trade_data_int { struct random_data_t random_data; @@ -106,7 +107,7 @@ struct gen2_trade_data_int { struct patch_set_trainer_data_gen12 patch_set; u8 useless_sync[USELESS_SYNC_BYTES]; struct party_mail_data_gen2_int mail; -} __attribute__ ((packed)); +} PACKED; struct gen2_trade_data_jp { struct random_data_t random_data; @@ -114,19 +115,19 @@ struct gen2_trade_data_jp { struct patch_set_trainer_data_gen12 patch_set; u8 useless_sync[USELESS_SYNC_BYTES]; struct party_mail_data_gen2_jp mail; -} __attribute__ ((packed)); +} PACKED; struct gen1_trade_data_int { struct random_data_t random_data; struct trainer_data_gen1_int trainer_info; struct patch_set_trainer_data_gen12 patch_set; -} __attribute__ ((packed)); +} PACKED; struct gen1_trade_data_jp { struct random_data_t random_data; struct trainer_data_gen1_jp trainer_info; struct patch_set_trainer_data_gen12 patch_set; -} __attribute__ ((packed)); +} PACKED; struct gen3_trade_data { struct mail_gen3 mails_3[PARTY_SIZE]; @@ -142,15 +143,15 @@ struct gen3_trade_data { u8 extra_tmp_padding[NUM_EXTRA_PADDING_BYTES_GEN3]; u32 trainer_id; u32 final_checksum; -} __attribute__ ((packed)) __attribute__((aligned(4))); +} PACKED ALIGNED(4); void load_comm_buffer(struct game_data_t*, int, u8); void read_comm_buffer(struct game_data_t*, int, u8); u8 are_checksum_same_gen3(struct gen3_trade_data*); u32* get_communication_buffer(u8); -u8 get_number_of_buffers(); +u8 get_number_of_buffers(void); u16 get_buffer_size(int); -u16* get_buffer_sizes(); +u16* get_buffer_sizes(void); #endif diff --git a/source/sprite_handler.c b/source/sprite_handler.c index 1f587e7..aa373b6 100644 --- a/source/sprite_handler.c +++ b/source/sprite_handler.c @@ -28,6 +28,20 @@ #define OFF_SCREEN_SPRITE SCREEN_HEIGHT u8 check_for_same_address(const u8*); +u32 get_vram_pos(void); +void set_updated_shadow_oam(void); +void inc_inner_sprite_counter(void); +u8 get_sprite_counter(void); +void inc_sprite_counter(void); +void set_attributes(u16, u16, u16); +u8 get_first_variable_palette(void); +u8 get_3bpp_palette(int); +void set_palette_3bpp(u8*, int, int); +u16 get_item_icon_tile(void); +u16 get_mail_icon_tile(void); +void set_item_icon(u16, u16); +void set_mail_icon(u16, u16); +void raw_update_cursor_x(u16); const u16* sprite_cursor_gfx = (const u16*)sprite_cursor_bin; const u16* item_icon_gfx = (const u16*)item_icon_bin; @@ -64,7 +78,7 @@ IWRAM_CODE void update_normal_oam() { if(updated_shadow_oam) { u32* oam_ptr = (u32*)OAM; u32* shadow_oam_ptr = (u32*)shadow_oam; - for(int i = 0; i < ((sizeof(OBJATTR)*OAM_ENTITIES)>>2); i++) + for(u32 i = 0; i < ((sizeof(OBJATTR)*OAM_ENTITIES)>>2); i++) oam_ptr[i] = shadow_oam_ptr[i]; updated_shadow_oam = 0; } @@ -124,12 +138,12 @@ void set_palette_3bpp(u8* colors, int index, int palette) { } void init_cursor(){ - sprite_pointers[__sprite_counter] = (u8*)sprite_cursor_gfx; + sprite_pointers[__sprite_counter] = (const u8*)sprite_cursor_gfx; u16* vram_pos = (u16*)get_vram_pos(); - for(int i = 0; i < (sprite_cursor_bin_size>>1); i++) + for(u32 i = 0; i < (sprite_cursor_bin_size>>1); i++) vram_pos[i] = sprite_cursor_gfx[i]; vram_pos = (u16*)(get_vram_pos() + SPRITE_ALT_DISTANCE); - for(int i = 0; i < (sprite_cursor_bin_size>>1); i++) + for(u32 i = 0; i < (sprite_cursor_bin_size>>1); i++) vram_pos[i] = sprite_cursor_gfx[i]; for(int i = 0; i < TOTAL_BG; i++) { set_attributes(OFF_SCREEN_SPRITE, 0, (32*__sprite_counter) | ((3-i)<<10)); @@ -143,18 +157,18 @@ void init_cursor(){ } void init_oam_palette(){ - for(int i = 0; i < (sprite_palettes_bin_size>>1); i++) + for(u32 i = 0; i < (sprite_palettes_bin_size>>1); i++) SPRITE_PALETTE[i] = sprite_palettes_bin_16[i]; - for(int i = 0; i < (item_icon_palette_bin_size>>1); i++) + for(u32 i = 0; i < (item_icon_palette_bin_size>>1); i++) SPRITE_PALETTE[i+(sprite_palettes_bin_size>>1)] = item_icon_palette_bin_16[i]; } void init_item_icon(){ u16* vram_pos = (u16*)(get_vram_pos() + sprite_cursor_bin_size); - for(int i = 0; i < (item_icon_bin_size>>1); i++) + for(u32 i = 0; i < (item_icon_bin_size>>1); i++) vram_pos[i] = item_icon_gfx[i]; vram_pos = (u16*)(get_vram_pos() + SPRITE_ALT_DISTANCE + sprite_cursor_bin_size); - for(int i = 0; i < (item_icon_bin_size>>1); i++) + for(u32 i = 0; i < (item_icon_bin_size>>1); i++) vram_pos[i] = item_icon_gfx[i]; } diff --git a/source/sprite_handler.h b/source/sprite_handler.h index cf94a6e..1f0346f 100644 --- a/source/sprite_handler.h +++ b/source/sprite_handler.h @@ -32,30 +32,24 @@ #define BASE_X_CURSOR_INCREMENT_OFFER_OPTIONS 64 #define BASE_Y_CURSOR_INCREMENT_OFFER_OPTIONS 16 -void init_sprite_counter(); -u8 get_sprite_counter(); -void inc_sprite_counter(); -u32 get_vram_pos(); -void init_oam_palette(); -void set_attributes(u16, u16, u16); - -void init_sprites(); -void init_item_icon(); -void set_item_icon(u16, u16); +void init_sprites(void); +void init_sprite_counter(void); +void init_oam_palette(void); +void init_item_icon(void); void set_pokemon_sprite(const u8*, u8, u8, u8, u8, u16, u16); -void set_party_sprite_counter(); -void init_cursor(); +void set_party_sprite_counter(void); +void init_cursor(void); void update_cursor_y(u16); void update_cursor_base_x(u16); void move_sprites(u8 counter); void move_cursor_x(u8 counter); -void disable_cursor(); -void disable_all_cursors(); +void disable_cursor(void); +void disable_all_cursors(void); void reset_sprites(u8); -void disable_all_sprites(); -void enable_all_sprites(); -void update_normal_oam(); -void reset_sprites_to_cursor(); -void reset_sprites_to_party(); +void disable_all_sprites(void); +void enable_all_sprites(void); +void update_normal_oam(void); +void reset_sprites_to_cursor(void); +void reset_sprites_to_party(void); #endif diff --git a/source/text_handler.c b/source/text_handler.c index 1a7feeb..531af43 100644 --- a/source/text_handler.c +++ b/source/text_handler.c @@ -1,6 +1,7 @@ #include #include "text_handler.h" #include "bin_table_handler.h" +#include "useful_qualifiers.h" #include "trainer_names_bin.h" #include "text_gen3_to_gen12_int_bin.h" @@ -19,6 +20,15 @@ #define GENERIC_TO_UPPER 0x20 #define GEN12_TRAINER 0x5D +u8 text_general_count_question(const u8*, u8, u8, u8); +u8 text_general_size(const u8*, u8, u8); +void text_general_conversion(const u8*, u8*, u8, u8, u8, u8, const u8*); +u8 text_general_is_same(const u8*, const u8*, u8, u8, u8); +void text_general_copy(const u8*, u8*, u8, u8, u8); +void text_general_concat(const u8*, const u8*, u8*, u8, u8, u8, u8); +void text_general_replace(u8*, u8, u8, u8, u8); +void text_general_terminator_fill(u8*, u8, u8); + u8 text_general_count_question(const u8* src, u8 src_size, u8 terminator, u8 question) { int counter = 0; for(int i = 0; i < src_size; i++) { @@ -205,14 +215,14 @@ u8 text_gen2_size(const u8* src, u8 src_size) { return text_general_size(src, src_size, GEN2_EOL); } -void text_generic_to_gen3(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_src, u8 jp_dst) { +void text_generic_to_gen3(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 UNUSED(jp_src), u8 jp_dst) { if(jp_dst) text_general_conversion(src, dst, src_size, dst_size, GENERIC_EOL, GEN3_EOL, text_general_to_gen3_jp_bin); else text_general_conversion(src, dst, src_size, dst_size, GENERIC_EOL, GEN3_EOL, text_general_to_gen3_int_bin); } -void text_gen3_to_generic(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_src, u8 jp_dst) { +void text_gen3_to_generic(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_src, u8 UNUSED(jp_dst)) { if(jp_src) text_general_conversion(src, dst, src_size, dst_size, GEN3_EOL, GENERIC_EOL, text_gen3_to_general_jp_bin); else @@ -230,7 +240,7 @@ void text_gen3_to_gen12(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_ text_general_conversion(src, dst, src_size, dst_size, GEN3_EOL, GEN2_EOL, text_gen3_to_gen12_int_bin); } -void text_gen12_to_gen3(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_src, u8 jp_dst) { +void text_gen12_to_gen3(const u8* src, u8* dst, u8 src_size, u8 dst_size, u8 jp_src, u8 UNUSED(jp_dst)) { if(src[0] == GEN12_TRAINER) text_gen3_copy(get_table_pointer(trainer_names_bin, jp_src), dst, src_size, dst_size); else { diff --git a/source/useful_qualifiers.h b/source/useful_qualifiers.h new file mode 100644 index 0000000..c881bef --- /dev/null +++ b/source/useful_qualifiers.h @@ -0,0 +1,11 @@ +#ifndef USEFUL_QUALIFIERS__ +#define USEFUL_QUALIFIERS__ + +#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +#define ALWAYS_INLINE __attribute__((always_inline)) static inline +#define MAX_OPTIMIZE __attribute__((optimize(3))) +#define PACKED __attribute__((packed)) +#define ARM_TARGET __attribute__((target("arm"),noinline)) +#define ALIGNED(x) __attribute__((aligned(x))) + +#endif diff --git a/source/window_handler.h b/source/window_handler.h index 3800eec..5baf5bd 100644 --- a/source/window_handler.h +++ b/source/window_handler.h @@ -1,8 +1,6 @@ #ifndef WINDOW_HANDLER__ #define WINDOW_HANDLER__ -#include "gba.h" - #define TOTAL_Y_SIZE (SCREEN_HEIGHT>>3) #define TOTAL_X_SIZE (SCREEN_WIDTH>>3) @@ -36,19 +34,19 @@ #define OFFER_OPTIONS_WINDOW_X_SIZE (TOTAL_X_SIZE - OFFER_OPTIONS_WINDOW_X - 1) #define OFFER_OPTIONS_WINDOW_Y_SIZE (TOTAL_Y_SIZE - OFFER_OPTIONS_WINDOW_Y - 1) -void init_trade_options_window(); -void clear_trade_options_window(); +void init_trade_options_window(void); +void clear_trade_options_window(void); -void init_offer_window(); -void clear_offer_window(); +void init_offer_window(void); +void clear_offer_window(void); -void init_message_window(); -void clear_message_window(); +void init_message_window(void); +void clear_message_window(void); -void init_offer_options_window(); -void clear_offer_options_window(); +void init_offer_options_window(void); +void clear_offer_options_window(void); -void init_waiting_window(); -void clear_waiting_window(); +void init_waiting_window(void); +void clear_waiting_window(void); #endif