Major Refactor

This commit is contained in:
Lorenzooone 2023-02-04 00:35:17 +01:00
parent 3c0d9d19f0
commit 879a0a530b
40 changed files with 1709 additions and 1408 deletions

3
.gitignore vendored
View File

@ -3,5 +3,6 @@ build/
*.gba
*.sav
*.py
__pychache__/
settings.sh
__pycache__/

View File

@ -4,7 +4,7 @@
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>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 \

9
build_proper_warnings.sh Executable file
View File

@ -0,0 +1,9 @@
if [ -z "$DEVKITARM" ];
then
echo "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM";
else
make 2>&1 >/dev/null | grep ^$(pwd);
fi

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

199
source/gen12_methods.c Normal file
View File

@ -0,0 +1,199 @@
#include <gba.h>
#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;
}
}

24
source/gen12_methods.h Normal file
View File

@ -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

View File

@ -1,6 +1,7 @@
#include <gba.h>
#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;

View File

@ -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);

960
source/gen_converter.c Normal file
View File

@ -0,0 +1,960 @@
#include <gba.h>
#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;
}

11
source/gen_converter.h Normal file
View File

@ -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

View File

@ -1,5 +1,6 @@
#include <gba.h>
#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))

View File

@ -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)) {

View File

@ -1,5 +1,3 @@
#include <stdio.h>
#include <string.h>
#include <gba.h>
#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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -1,7 +1,12 @@
#include <gba.h>
#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;
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -1,16 +1,15 @@
#include <gba.h>
#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
}
}

View File

@ -1,10 +1,8 @@
#ifndef PID_IV_TID__
#define PID_IV_TID__
#include <gba.h>
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
#endif

View File

@ -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() {

View File

@ -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

View File

@ -1,18 +1,20 @@
#include <gba.h>
#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();
}
}

View File

@ -1,13 +1,11 @@
#ifndef RNG__
#define RNG__
#include <gba.h>
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
#endif

View File

@ -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;
}
}

View File

@ -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
#endif

View File

@ -1,6 +1,7 @@
#include <gba.h>
#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);

View File

@ -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);

View File

@ -1,19 +1,39 @@
#include <stddef.h>
#include <gba.h>
#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;

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -1,6 +1,7 @@
#include <gba.h>
#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 {

View File

@ -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

View File

@ -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