diff --git a/include/animations_handler.h b/include/animations_handler.h index 420e814..7fd48b4 100644 --- a/include/animations_handler.h +++ b/include/animations_handler.h @@ -4,6 +4,6 @@ void setup_trade_animation(struct gen3_mon_data_unenc*, struct gen3_mon_data_unenc*, u8, u8); void setup_evolution_animation(struct gen3_mon_data_unenc*, u8); void advance_trade_animation(void); -u8 get_animation_state(void); +u8 has_animation_completed(void); #endif diff --git a/include/gen3_save.h b/include/gen3_save.h index 8674a1a..3eb2f58 100644 --- a/include/gen3_save.h +++ b/include/gen3_save.h @@ -26,7 +26,7 @@ struct game_data_t { }; void init_game_data(struct game_data_t*); -void init_save_sections(void); +void init_save_data(void); u8 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(void); diff --git a/include/input_handler.h b/include/input_handler.h index e375f1c..135d842 100644 --- a/include/input_handler.h +++ b/include/input_handler.h @@ -7,6 +7,9 @@ #define CANCEL_INFO 0xFF #define CANCEL_TRADING 0xFF #define CANCEL_IV_FIX 0xFF +#define DENIED_LEARNING 0xFF +#define DO_NOT_FORGET_MOVE 0xFF +#define ENTER_LEARN_MENU 1 #define CONFIRM_IV_FIX 1 #define CANCEL_NATURE 0xFF #define CONFIRM_NATURE 3 @@ -22,6 +25,8 @@ #define FIRST_PAGE 1 u8 handle_input_multiboot_menu(u16); +u8 handle_input_learnable_message_moves_menu(u16, u8*); +u8 handle_input_learnable_moves_menu(u16, u8*); u8 handle_input_info_menu(struct game_data_t*, u8*, u8, u16, u8*, u8, u8*); u8 handle_input_offer_info_menu(struct game_data_t*, u8*, const u8**, u16, u8*); u8 handle_input_trading_menu(u8*, u8*, u16, u8, u8); diff --git a/include/menu_text_handler.h b/include/menu_text_handler.h index eaeaa8e..d681ae0 100644 --- a/include/menu_text_handler.h +++ b/include/menu_text_handler.h @@ -5,11 +5,15 @@ #include "gen3_save.h" #include "multiboot_handler.h" +enum MOVES_PRINTING_TYPE{LEARNT_P, DID_NOT_LEARN_P, LEARNABLE_P}; + +void print_learnable_move(struct gen3_mon_data_unenc*, u16, enum MOVES_PRINTING_TYPE); void print_game_info(struct game_data_t*, int); void print_trade_menu(struct game_data_t*, u8, u8, u8, u8); void print_trade_menu_cancel(u8); void print_trade_animation_send(struct gen3_mon_data_unenc*); void print_trade_animation_recv(struct gen3_mon_data_unenc*); +void print_learnable_moves_menu(struct gen3_mon_data_unenc*, u16); void print_set_nature(u8, struct gen3_mon_data_unenc*); void print_iv_fix(struct gen3_mon_data_unenc*); void print_pokemon_pages(u8, u8, struct gen3_mon_data_unenc*, u8); diff --git a/include/multiboot_handler.h b/include/multiboot_handler.h index 4a044ff..53b4780 100644 --- a/include/multiboot_handler.h +++ b/include/multiboot_handler.h @@ -1,8 +1,10 @@ #ifndef MULTIBOOT_HANDLER__ #define MULTIBOOT_HANDLER__ +#define MULTIBOOT_MAX_SIZE 0x3FF40 + enum MULTIBOOT_RESULTS {MB_SUCCESS, MB_NO_INIT_SYNC, MB_WRONG_ANSWER, MB_HEADER_ISSUE, MB_SWI_FAILURE}; enum MULTIBOOT_RESULTS multiboot_normal(u16*, u16*); -#endif \ No newline at end of file +#endif diff --git a/include/party_handler.h b/include/party_handler.h index 9ad27d4..817a691 100644 --- a/include/party_handler.h +++ b/include/party_handler.h @@ -133,6 +133,7 @@ #define GEN2_NO_MON 255 #define POKEBALL_ID 4 +#define HIDDEN_POWER_ID 237 #define ENIGMA_BERRY_ID 0x00AF #define EVERSTONE_ID 0x00C3 @@ -148,6 +149,8 @@ typedef u32 gen3_party_total_t; +enum LEARNABLE_MOVES_RETVAL {LEARNT, SKIPPED, LEARNABLE, COMPLETED}; + struct alternative_data_gen3 { u8 met_location; u16 origins_info; @@ -378,6 +381,7 @@ const u8* get_hidden_power_type_name_gen3_pure(u32); const u8* get_hidden_power_type_name_gen3(struct gen3_mon_misc*); const u8* get_nature_name(u32); char get_nature_symbol(u32, u8); +const u8* get_move_name_raw(u16); 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); @@ -389,5 +393,7 @@ u8 get_pokemon_gender_kind_gen3_raw(struct gen3_mon_data_unenc*); 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*, u8); +enum LEARNABLE_MOVES_RETVAL learn_if_possible(struct gen3_mon_data_unenc*, u32); +u8 forget_and_learn_move(struct gen3_mon_data_unenc*, u32, u32); #endif diff --git a/include/print_system.h b/include/print_system.h index 1ce2116..2957ad2 100644 --- a/include/print_system.h +++ b/include/print_system.h @@ -37,6 +37,8 @@ void default_reset_screen(void); void reset_screen(u8); void set_text_x(u8); void set_text_y(u8); +u8 get_text_x(void); +u8 get_text_y(void); void swap_screen_enabled_state(u8); void enable_screen(u8); void disable_screen(u8); diff --git a/include/sprite_handler.h b/include/sprite_handler.h index f294915..8a9ebf9 100644 --- a/include/sprite_handler.h +++ b/include/sprite_handler.h @@ -2,6 +2,7 @@ #define SPRITE_HANDLER__ #include "print_system.h" +#include "party_handler.h" #include "graphics_handler.h" #define TOP_SCREEN_SPRITE_POS SCREEN_REAL_HEIGHT @@ -43,6 +44,14 @@ #define BASE_X_CURSOR_INCREMENT_TRADE_OPTIONS (SCREEN_HALF_X << 3) #define BASE_Y_CURSOR_TRADE_OPTIONS (SCREEN_HEIGHT-8) +#define BASE_X_CURSOR_LEARN_MOVE_MESSAGE_YES 18 +#define BASE_X_CURSOR_LEARN_MOVE_MESSAGE_NO (((SCREEN_WIDTH-16)>>1) + BASE_X_CURSOR_LEARN_MOVE_MESSAGE_YES) +#define BASE_Y_CURSOR_LEARN_MOVE_MESSAGE (SCREEN_HEIGHT-16) + +#define BASE_X_CURSOR_LEARN_MOVE_MENU 2 +#define BASE_Y_CURSOR_INCREMENT_LEARN_MOVE_MENU 16 +#define BASE_Y_CURSOR_LEARN_MOVE_MENU (SCREEN_HEIGHT-8-(BASE_Y_CURSOR_INCREMENT_LEARN_MOVE_MENU*(MOVES_SIZE-1+1))) + #define BASE_Y_SPRITE_OFFER_MENU 0 #define BASE_X_SPRITE_OFFER_MENU 0 #define BASE_X_CURSOR_INCREMENT_OFFER_OPTIONS 64 @@ -69,7 +78,7 @@ void reset_sprites(u8); 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_cursor(u8); void reset_sprites_to_party(void); void fade_all_sprites_to_white(u16); void remove_fade_all_sprites(void); diff --git a/include/window_handler.h b/include/window_handler.h index 6df58fb..d804cae 100644 --- a/include/window_handler.h +++ b/include/window_handler.h @@ -22,6 +22,12 @@ #define TRADE_ANIMATION_RECV_WINDOW_Y (TOTAL_Y_SIZE-1-TRADE_ANIMATION_RECV_WINDOW_Y_SIZE) #define TRADE_ANIMATION_RECV_WINDOW_X_SIZE (TOTAL_X_SIZE-TRADE_ANIMATION_RECV_WINDOW_X-1) +#define LEARN_MOVE_MESSAGE_WINDOW_SCREEN 1 +#define LEARN_MOVE_MESSAGE_WINDOW_X 1 +#define LEARN_MOVE_MESSAGE_WINDOW_Y_SIZE 6 +#define LEARN_MOVE_MESSAGE_WINDOW_Y (TOTAL_Y_SIZE-1-LEARN_MOVE_MESSAGE_WINDOW_Y_SIZE) +#define LEARN_MOVE_MESSAGE_WINDOW_X_SIZE (TOTAL_X_SIZE-LEARN_MOVE_MESSAGE_WINDOW_X-1) + #define EVOLUTION_ANIMATION_WINDOW_SCREEN 3 #define EVOLUTION_ANIMATION_WINDOW_X 1 #define EVOLUTION_ANIMATION_WINDOW_Y_SIZE 3 @@ -73,6 +79,9 @@ void clear_offer_options_window(void); void init_waiting_window(void); void clear_waiting_window(void); +void init_learn_move_message_window(void); +void clear_learn_move_message_window(void); + void init_trade_animation_send_window(void); void clear_trade_animation_send_window(void); diff --git a/source/animations_handler.c b/source/animations_handler.c index 1d58c53..e2c64cb 100644 --- a/source/animations_handler.c +++ b/source/animations_handler.c @@ -61,7 +61,7 @@ void setup_trade_animation(struct gen3_mon_data_unenc* own_mon, struct gen3_mon_ is_animating_evolution = 0; } -u8 get_animation_state() { +u8 has_animation_completed() { return animation_completed; } diff --git a/source/gen3_save.c b/source/gen3_save.c index 112309d..6f527c2 100644 --- a/source/gen3_save.c +++ b/source/gen3_save.c @@ -56,7 +56,6 @@ u8 pre_update_save(struct game_data_t*, u8, enum SAVING_KIND); u8 complete_save(u8); static u8 get_next_slot(u8); -u8 sections_freed[SECTION_TOTAL]; 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}; @@ -330,11 +329,6 @@ u8 pre_update_save(struct game_data_t* game_data, u8 base_slot, enum SAVING_KIND { if(target_section >= SECTION_TOTAL) target_section -= SECTION_TOTAL; - - if(!sections_freed[target_section]) { - erase_sector((target_slot * SAVE_SLOT_SIZE) + (target_section * SECTION_SIZE)); - sections_freed[target_section] = 1; - } u16 section_id = read_section_id(base_slot, i); @@ -383,8 +377,8 @@ u8 pre_update_save(struct game_data_t* game_data, u8 base_slot, enum SAVING_KIND buffer_16[CHECKSUM_POS>>1] = checksum; // Copy to new slot + erase_sector((target_slot * SAVE_SLOT_SIZE) + (target_section * SECTION_SIZE)); copy_ram_to_save(buffer_8, (target_slot * SAVE_SLOT_SIZE) + (target_section * SECTION_SIZE), SECTION_SIZE); - sections_freed[target_section] = 0; // Verify everything went accordingly if(!is_save_correct(buffer_8, (target_slot * SAVE_SLOT_SIZE) + (target_section * SECTION_SIZE), SECTION_SIZE)) return 0; @@ -400,10 +394,8 @@ u8 pre_update_save(struct game_data_t* game_data, u8 base_slot, enum SAVING_KIND u8 complete_save(u8 base_slot) { u8 target_slot = get_next_slot(base_slot); - for(int i = 0; i < SECTION_TOTAL; i++) { + for(int i = 0; i < SECTION_TOTAL; i++) erase_sector((base_slot * SAVE_SLOT_SIZE) + (i * SECTION_SIZE)); - sections_freed[i] = 1; - } if(get_slot() != target_slot) return 0; @@ -439,9 +431,7 @@ u8 get_slot(){ return slot; } -void init_save_sections(){ - for(int i = 0; i < SECTION_TOTAL; i++) - sections_freed[i] = 0; +void init_save_data(){ } u8 read_gen_3_data(struct game_data_t* game_data){ diff --git a/source/input_handler.c b/source/input_handler.c index eb4d193..e46633c 100644 --- a/source/input_handler.c +++ b/source/input_handler.c @@ -165,7 +165,11 @@ u8 handle_input_trading_menu(u8* cursor_y_pos, u8* cursor_x_pos, u16 keys, u8 UN return options[cursor_x][cursor_y]+1; } - if(keys & KEY_LEFT) { + if(keys & KEY_B) { + cursor_x = 0; + cursor_y = PARTY_SIZE; + } + else if(keys & KEY_LEFT) { cursor_x = 0; if(cursor_y >= num_options[0]) cursor_y = num_options[0]-1; @@ -366,6 +370,48 @@ u8 handle_input_iv_fix_menu(u16 keys) { return 0; } +u8 handle_input_learnable_message_moves_menu(u16 keys, u8* cursor_x_pos) { + + if(keys & KEY_A) { + if(*cursor_x_pos) + return DENIED_LEARNING; + return ENTER_LEARN_MENU; + } + + if(keys & KEY_B) + *cursor_x_pos = 1; + else if((keys & KEY_LEFT) || (keys & KEY_RIGHT)) + *cursor_x_pos ^= 1; + + return 0; +} + +u8 handle_input_learnable_moves_menu(u16 keys, u8* cursor_y_pos) { + + if(keys & KEY_A) { + if((*cursor_y_pos) >= MOVES_SIZE) + return DO_NOT_FORGET_MOVE; + return 1+(*cursor_y_pos); + } + + if(keys & KEY_B) + *cursor_y_pos = MOVES_SIZE; + else if(keys & KEY_UP) { + if(!(*cursor_y_pos)) + *cursor_y_pos = MOVES_SIZE; + else + *cursor_y_pos -= 1; + } + else if(keys & KEY_DOWN) { + if((*cursor_y_pos) >= MOVES_SIZE) + *cursor_y_pos = 0; + else + *cursor_y_pos += 1; + } + + return 0; +} + u8 handle_input_offer_options(u16 keys, u8* cursor_y_pos, u8* cursor_x_pos) { if(keys & KEY_B) diff --git a/source/main.c b/source/main.c index c8578c8..5dd070d 100644 --- a/source/main.c +++ b/source/main.c @@ -20,6 +20,7 @@ #include "vcount_basic.h" #include "animations_handler.h" #include +#include "timing_basic.h" //#include "save.h" #include "ewram_speed_check_bin.h" @@ -31,7 +32,10 @@ #define WORST_CASE_EWRAM 1 #define MIN_WAITCYCLE 1 +#define WAITING_TIME_MOVE_MESSAGES (2*FPS) + #define BASE_SCREEN 0 +#define LEARNABLE_MOVES_MENU_SCREEN 2 #define TRADE_CANCEL_SCREEN 1 #define INFO_SCREEN 3 #define NATURE_SCREEN 2 @@ -40,10 +44,13 @@ void vblank_update_function(void); void find_optimal_ewram_settings(void); u8 init_cursor_y_pos_main_menu(void); +void cursor_update_learnable_move_message_menu(u8); +void cursor_update_learnable_move_menu(u8); 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 handle_learnable_moves_message(struct game_data_t*, u8, u8*, u32*, enum MOVES_PRINTING_TYPE); void change_nature(struct game_data_t*, u8, u8, u8*, u8); void check_bad_trade_received(struct game_data_t*, u8, u8, u8, u8, u8, u8*); void trade_cancel_print_screen(u8); @@ -62,11 +69,14 @@ void main_menu_init(struct game_data_t*, u8, u8, u8, u8*); void info_menu_init(struct game_data_t*, u8, u8, u8*, u8); void nature_menu_init(struct game_data_t*, u8, u8, u8*); void iv_fix_menu_init(struct game_data_t*, u8, u8); +void learnable_moves_message_init(struct game_data_t*, u8); +void learnable_move_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*); +void wait_frames(int); int main(void); -enum STATE {MAIN_MENU, MULTIBOOT, TRADING_MENU, INFO_MENU, START_TRADE, WAITING_DATA, TRADE_OPTIONS, NATURE_SETTING, OFFER_MENU, TRADING_ANIMATION, OFFER_INFO_MENU, IV_FIX_MENU}; +enum STATE {MAIN_MENU, MULTIBOOT, TRADING_MENU, INFO_MENU, START_TRADE, WAITING_DATA, TRADE_OPTIONS, NATURE_SETTING, OFFER_MENU, TRADING_ANIMATION, OFFER_INFO_MENU, IV_FIX_MENU, LEARNABLE_MOVES_MESSAGE, LEARNABLE_MOVES_MESSAGE_MENU, LEARNABLE_MOVES_MENU}; enum STATE curr_state; u32 counter = 0; u32 input_counter = 0; @@ -158,6 +168,19 @@ void cursor_update_main_menu(u8 cursor_y_pos) { update_cursor_y(BASE_Y_CURSOR_MAIN_MENU + (BASE_Y_CURSOR_INCREMENT_MAIN_MENU * cursor_y_pos)); } +void cursor_update_learnable_move_menu(u8 cursor_y_pos) { + update_cursor_base_x(BASE_X_CURSOR_LEARN_MOVE_MENU); + update_cursor_y(BASE_Y_CURSOR_LEARN_MOVE_MENU + (cursor_y_pos*BASE_Y_CURSOR_INCREMENT_LEARN_MOVE_MENU)); +} + +void cursor_update_learnable_move_message_menu(u8 cursor_x_pos) { + if(cursor_x_pos) + update_cursor_base_x(BASE_X_CURSOR_LEARN_MOVE_MESSAGE_NO + (LEARN_MOVE_MESSAGE_WINDOW_X<<3)); + else + update_cursor_base_x(BASE_X_CURSOR_LEARN_MOVE_MESSAGE_YES + (LEARN_MOVE_MESSAGE_WINDOW_X<<3)); + update_cursor_y(BASE_Y_CURSOR_LEARN_MOVE_MESSAGE); +} + void cursor_update_trade_options(u8 cursor_x_pos) { update_cursor_base_x(BASE_X_CURSOR_TRADE_OPTIONS + (cursor_x_pos * BASE_X_CURSOR_INCREMENT_TRADE_OPTIONS)); } @@ -167,6 +190,32 @@ void cursor_update_offer_options(u8 cursor_y_pos, u8 cursor_x_pos) { update_cursor_y(BASE_Y_CURSOR_OFFER_OPTIONS + (BASE_Y_CURSOR_INCREMENT_OFFER_OPTIONS * cursor_y_pos)); } +void wait_frames(int num_frames) { + int wait_counter = 0; + while(wait_counter < num_frames) { + VBlankIntrWait(); + wait_counter++; + } +} + +void handle_learnable_moves_message(struct game_data_t* game_data, u8 own_mon, u8* cursor_x_pos, u32* curr_move, enum MOVES_PRINTING_TYPE moves_printing_type) { + if(!game_data[0].party_3_undec[own_mon].is_egg) { + print_learnable_move(&game_data[0].party_3_undec[own_mon], *curr_move, moves_printing_type); + enable_screen(LEARN_MOVE_MESSAGE_WINDOW_SCREEN); + if(moves_printing_type == LEARNABLE_P) { + *cursor_x_pos = 0; + cursor_update_learnable_move_message_menu(*cursor_x_pos); + } + prepare_flush(); + if(moves_printing_type != LEARNABLE_P) { + wait_frames(WAITING_TIME_MOVE_MESSAGES); + *curr_move += 1; + } + } + else + *curr_move += 1; +} + void change_nature(struct game_data_t* game_data, u8 cursor_x_pos, u8 curr_mon, u8* wanted_nature, u8 is_change_inc) { if((!game_data[cursor_x_pos].party_3_undec[curr_mon].is_valid_gen3) || (game_data[cursor_x_pos].party_3_undec[curr_mon].is_egg)) return; @@ -329,7 +378,7 @@ void start_trade_init(struct game_data_t* game_data, u8 target, u8 region, u8 ma set_bg_pos(BASE_SCREEN, 0, 0); print_start_trade(); disable_all_screens_but_current(); - reset_sprites_to_cursor(); + reset_sprites_to_cursor(1); disable_all_cursors(); prepare_flush(); start_transfer(master, curr_gen); @@ -345,7 +394,7 @@ void main_menu_init(struct game_data_t* game_data, u8 target, u8 region, u8 mast set_bg_pos(BASE_SCREEN, 0, 0); print_main_menu(1, target, region, master); disable_all_screens_but_current(); - reset_sprites_to_cursor(); + reset_sprites_to_cursor(1); disable_all_cursors(); *cursor_y_pos = init_cursor_y_pos_main_menu(); update_cursor_base_x(BASE_X_CURSOR_MAIN_MENU); @@ -386,6 +435,32 @@ void iv_fix_menu_init(struct game_data_t* game_data, u8 cursor_x_pos, u8 curr_mo prepare_flush(); } +void learnable_move_menu_init(struct game_data_t* game_data, u8 curr_mon, u8 curr_move, u8* cursor_y_pos) { + curr_state = LEARNABLE_MOVES_MENU; + set_screen(LEARNABLE_MOVES_MENU_SCREEN); + disable_all_screens_but_current(); + disable_all_cursors(); + reset_sprites_to_cursor(0); + print_learnable_moves_menu(&game_data[0].party_3_undec[curr_mon], curr_move); + enable_screen(LEARNABLE_MOVES_MENU_SCREEN); + *cursor_y_pos = 0; + cursor_update_learnable_move_menu(*cursor_y_pos); + prepare_flush(); +} + +void learnable_moves_message_init(struct game_data_t* game_data, u8 curr_mon) { + curr_state = LEARNABLE_MOVES_MESSAGE; + set_screen(BASE_SCREEN); + disable_all_screens_but_current(); + disable_all_cursors(); + reset_sprites_to_cursor(0); + default_reset_screen(); + load_pokemon_sprite_raw(&game_data[0].party_3_undec[curr_mon], 0, BASE_Y_SPRITE_TRADE_ANIMATION_SEND, BASE_X_SPRITE_TRADE_ANIMATION); + set_screen(LEARN_MOVE_MESSAGE_WINDOW_SCREEN); + enable_screen(BASE_SCREEN); + prepare_flush(); +} + void conclude_trade(struct game_data_t* game_data, u8 target, u8 region, u8 master, u8* cursor_y_pos) { stop_transfer(master); main_menu_init(game_data, target, region, master, cursor_y_pos); @@ -433,7 +508,7 @@ int main(void) irqEnable(IRQ_VBLANK); irqDisable(IRQ_SERIAL); - init_save_sections(); + init_save_data(); read_gen_3_data(&game_data[0]); init_item_icon(); @@ -443,6 +518,7 @@ int main(void) u8 evolved = 0; u8 learnable_moves = 0; u8 returned_val; + u8 move_go_on = 0; u8 update = 0; u8 target = 1; u8 region = 0; @@ -455,6 +531,7 @@ int main(void) u8 submenu_cursor_x_pos = 0; u8 prev_val = 0; u8 curr_mon = 0; + u32 curr_move = 0; u8 success = 0; u8 other_mon = 0; u8 curr_page = 0; @@ -485,7 +562,7 @@ int main(void) else print_start_trade(); } - if(curr_state == WAITING_DATA) { + else if(curr_state == WAITING_DATA) { if(get_trading_state() == RECEIVED_OFFER) { keys = 0; result = get_received_trade_offer(); @@ -517,12 +594,61 @@ int main(void) curr_state = TRADING_ANIMATION; learnable_moves = game_data[0].party_3_undec[curr_mon].learnable_moves != NULL; success = pre_write_gen_3_data(&game_data[0], !learnable_moves); - process_party_data(&game_data[0]); + if(!success) { + //TODO: Handle bad save + } } else return_to_trade_menu(game_data, target, region, master, curr_gen, own_menu, &cursor_y_pos, &cursor_x_pos); } } + else if(curr_state == TRADING_ANIMATION) { + if(has_animation_completed()) { + keys = 0; + + if(learnable_moves) { + learnable_moves_message_init(game_data, curr_mon); + curr_move = 0; + } + else { + //TODO: Handle done + } + //process_party_data(&game_data[0]); + } + } + else if(curr_state == LEARNABLE_MOVES_MESSAGE) { + keys = 0; + move_go_on = 0; + while(!move_go_on) { + switch(learn_if_possible(&game_data[0].party_3_undec[curr_mon], curr_move)) { + case SKIPPED: + curr_move++; + break; + case LEARNT: + handle_learnable_moves_message(game_data, curr_mon, &cursor_x_pos, &curr_move, LEARNT_P); + break; + case LEARNABLE: + curr_state = LEARNABLE_MOVES_MESSAGE_MENU; + move_go_on = 1; + handle_learnable_moves_message(game_data, curr_mon, &cursor_x_pos, &curr_move, LEARNABLE_P); + break; + case COMPLETED: + success = pre_write_updated_moves_gen_3_data(&game_data[0]); + if(!success) { + //TODO: Handle bad save + } + disable_screen(LEARN_MOVE_MESSAGE_WINDOW_SCREEN); + prepare_flush(); + move_go_on = 1; + //TODO: Handle done + curr_state = MAIN_MENU; + break; + default: + curr_move++; + break; + } + } + } } while ((!(keys & KEY_LEFT)) && (!(keys & KEY_RIGHT)) && (!(keys & KEY_A)) && (!(keys & KEY_B)) && (!(keys & KEY_UP)) && (!(keys & KEY_DOWN))); input_counter++; @@ -536,7 +662,7 @@ int main(void) sio_stop_irq_slave(); irqDisable(IRQ_SERIAL); disable_cursor(); - print_multiboot(multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + 0x3FF40))); + print_multiboot(multiboot_normal((u16*)EWRAM, (u16*)(EWRAM + MULTIBOOT_MAX_SIZE))); } else if(returned_val > VIEW_OWN_PARTY && returned_val <= VIEW_OWN_PARTY + TOTAL_GENS) { curr_gen = returned_val - VIEW_OWN_PARTY; @@ -678,6 +804,37 @@ int main(void) break; case TRADING_ANIMATION: break; + case LEARNABLE_MOVES_MESSAGE: + break; + case LEARNABLE_MOVES_MESSAGE_MENU: + returned_val = handle_input_learnable_message_moves_menu(keys, &cursor_x_pos); + if(returned_val) { + if(returned_val == DENIED_LEARNING) { + learnable_moves_message_init(game_data, curr_mon); + handle_learnable_moves_message(game_data, curr_mon, &cursor_x_pos, &curr_move, DID_NOT_LEARN_P); + } + else + learnable_move_menu_init(game_data, curr_mon, curr_move, &cursor_y_pos); + } + else + cursor_update_learnable_move_message_menu(cursor_x_pos); + break; + case LEARNABLE_MOVES_MENU: + returned_val = handle_input_learnable_moves_menu(keys, &cursor_y_pos); + if(returned_val) { + if(returned_val == DO_NOT_FORGET_MOVE) { + learnable_moves_message_init(game_data, curr_mon); + handle_learnable_moves_message(game_data, curr_mon, &cursor_x_pos, &curr_move, DID_NOT_LEARN_P); + } + else { + forget_and_learn_move(&game_data[0].party_3_undec[curr_mon], curr_move, returned_val-1); + learnable_moves_message_init(game_data, curr_mon); + handle_learnable_moves_message(game_data, curr_mon, &cursor_x_pos, &curr_move, LEARNT_P); + } + } + else + cursor_update_learnable_move_menu(cursor_y_pos); + break; default: main_menu_init(&game_data[0], target, region, master, &cursor_y_pos); break; diff --git a/source/menu_text_handler.c b/source/menu_text_handler.c index 62dbce1..7267669 100644 --- a/source/menu_text_handler.c +++ b/source/menu_text_handler.c @@ -96,7 +96,7 @@ void print_trade_menu(struct game_data_t* game_data, u8 update, u8 curr_gen, u8 } if(load_sprites) - reset_sprites_to_cursor(); + reset_sprites_to_cursor(1); u8* options[2]; for(int i = 0; i < 2; i++) @@ -130,6 +130,53 @@ void print_trade_menu_cancel(u8 update) { PRINT_FUNCTION("Cancel"); } +void print_learnable_move(struct gen3_mon_data_unenc* mon, u16 index, enum MOVES_PRINTING_TYPE moves_printing_type) { + reset_screen(BLANK_FILL); + + init_learn_move_message_window(); + clear_learn_move_message_window(); + + if((!mon->is_valid_gen3) || (mon->is_egg)) + return; + + if(mon->learnable_moves == NULL) + return; + + u16 move = mon->learnable_moves[1+index]; + + set_text_y(LEARN_MOVE_MESSAGE_WINDOW_Y); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + + switch(moves_printing_type) { + case LEARNT_P: + PRINT_FUNCTION("\x01 learnt\n\n", get_pokemon_name_raw(mon)); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("\x01!", get_move_name_raw(move)); + break; + case DID_NOT_LEARN_P: + PRINT_FUNCTION("\x01 did not\n\n", get_pokemon_name_raw(mon)); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("learn \x01!", get_move_name_raw(move)); + break; + case LEARNABLE_P: + PRINT_FUNCTION("\x01 wants to\n", get_pokemon_name_raw(mon)); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("learn \x01!\n", get_move_name_raw(move)); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("Would you like to replace\n", get_pokemon_name_raw(mon)); + set_text_x(LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("an existing move with it?", get_move_name_raw(move)); + set_text_y(BASE_Y_CURSOR_LEARN_MOVE_MESSAGE>>3); + set_text_x((BASE_X_CURSOR_LEARN_MOVE_MESSAGE_YES>>3)+2+LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("Yes"); + set_text_x((BASE_X_CURSOR_LEARN_MOVE_MESSAGE_NO>>3)+2+LEARN_MOVE_MESSAGE_WINDOW_X); + PRINT_FUNCTION("No"); + break; + default: + break; + } +} + void print_offer_screen(struct game_data_t* game_data, u8 own_mon, u8 other_mon) { default_reset_screen(); init_offer_window(); @@ -419,6 +466,51 @@ void print_iv_fix(struct gen3_mon_data_unenc* mon) { PRINT_FUNCTION("A: Confirm - B: Go Back"); } +void print_learnable_moves_menu(struct gen3_mon_data_unenc* mon, u16 index) { + default_reset_screen(); + + if((!mon->is_valid_gen3) || (mon->is_egg)) + return; + + if(mon->learnable_moves == NULL) + return; + + u16 move = mon->learnable_moves[1+index]; + + print_pokemon_base_data(1, mon, BASE_Y_SPRITE_IV_FIX_PAGE, BASE_X_SPRITE_IV_FIX_PAGE); + + u8 base_x = 0; + u8 base_y = get_text_y() + 1; + set_text_y(base_y); + for(int i = 0; i < GEN2_STATS_TOTAL; i++) { + set_text_x(base_x); + PRINT_FUNCTION("\x11: \x09\x02\n", stat_strings[i], 3, calc_stats_gen3_raw(mon,i), 4, get_nature_symbol(mon->src->pid, i)); + if(i == ((GEN2_STATS_TOTAL-1)>>1)) { + set_text_y(base_y); + base_x += X_LIMIT>>1; + } + } + PRINT_FUNCTION("Ability: \x01", get_ability_name_raw(mon)); + PRINT_FUNCTION("\nHidden Power: \x01 \x03", get_hidden_power_type_name_gen3(&mon->misc), get_hidden_power_power_gen3(&mon->misc)); + PRINT_FUNCTION("\nWhich move will be forgotten?\n"); + set_text_x((BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2); + PRINT_FUNCTION("MOVES"); + set_text_x(X_LIMIT-11+(BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2); + PRINT_FUNCTION("PP UP"); + for(size_t i = 0; i < MOVES_SIZE; i++){ + set_text_y((BASE_Y_CURSOR_LEARN_MOVE_MENU + (BASE_Y_CURSOR_INCREMENT_LEARN_MOVE_MENU*i))>>3); + set_text_x((BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2); + PRINT_FUNCTION("\x01", get_move_name_gen3(&mon->attacks, i)); + set_text_x((X_LIMIT-11+(BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2)+2); + PRINT_FUNCTION("\x03", (mon->growth.pp_bonuses >> (2*i)) & 3); + } + set_text_y((BASE_Y_CURSOR_LEARN_MOVE_MENU + (BASE_Y_CURSOR_INCREMENT_LEARN_MOVE_MENU*MOVES_SIZE))>>3); + set_text_x((BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2); + PRINT_FUNCTION("\x01", get_move_name_raw(move)); + set_text_x((X_LIMIT-11+(BASE_X_CURSOR_LEARN_MOVE_MENU>>3)+2)+1); + PRINT_FUNCTION("NEW"); +} + void print_pokemon_base_data(u8 load_sprites, struct gen3_mon_data_unenc* mon, u8 y, u8 x) { u8 is_shiny = is_shiny_gen3_raw(mon, 0); u8 has_pokerus = has_pokerus_gen3_raw(mon); diff --git a/source/party_handler.c b/source/party_handler.c index cf42653..03f25b6 100644 --- a/source/party_handler.c +++ b/source/party_handler.c @@ -319,11 +319,7 @@ void load_pokemon_sprite_raw(struct gen3_mon_data_unenc* data_src, u8 show_item, load_pokemon_sprite(data_src->growth.species, data_src->src->pid, data_src->is_egg, data_src->deoxys_form, has_item_raw(data_src) & show_item, has_mail_raw(data_src) & show_item, y, x); } -const u8* get_move_name_gen3(struct gen3_mon_attacks* attacks, u8 slot){ - if(slot >= MOVES_SIZE) - slot = MOVES_SIZE-1; - - u16 move = attacks->moves[slot]; +const u8* get_move_name_raw(u16 move){ if(move > LAST_VALID_GEN_3_MOVE) move = 0; @@ -331,6 +327,13 @@ const u8* get_move_name_gen3(struct gen3_mon_attacks* attacks, u8 slot){ return get_table_pointer(move_names_bin, move); } +const u8* get_move_name_gen3(struct gen3_mon_attacks* attacks, u8 slot){ + if(slot >= MOVES_SIZE) + slot = MOVES_SIZE-1; + + return get_move_name_raw(attacks->moves[slot]); +} + u8 make_moves_legal_gen3(struct gen3_mon_attacks* attacks){ u8 previous_moves[MOVES_SIZE]; u8 curr_slot = 0; @@ -924,3 +927,73 @@ u8 trade_evolve(struct gen3_mon* mon, struct gen3_mon_data_unenc* mon_data, u8 c return 1; } + +enum LEARNABLE_MOVES_RETVAL learn_if_possible(struct gen3_mon_data_unenc* mon, u32 index) { + if(mon->learnable_moves == NULL) { + place_and_encrypt_gen3_data(mon, mon->src); + return COMPLETED; + } + + u16 num_moves = mon->learnable_moves[0]; + if(index >= num_moves) { + place_and_encrypt_gen3_data(mon, mon->src); + return COMPLETED; + } + + u16 move = mon->learnable_moves[1+index]; + + if(move > LAST_VALID_GEN_3_MOVE) + move = 0; + + if(!move) + return SKIPPED; + + struct gen3_mon_attacks* attacks = &mon->attacks; + + for(size_t i = 0; i < MOVES_SIZE; i++) + if(attacks->moves[i] == move) + return SKIPPED; + + for(size_t i = 0; i < MOVES_SIZE; i++) + if((attacks->moves[i] == 0) || (attacks->moves[i] > LAST_VALID_GEN_3_MOVE)) { + attacks->moves[i] = move; + return LEARNT; + } + + if(mon->is_egg) { + for(size_t i = 0; i < MOVES_SIZE-1; i++) + attacks->moves[i] = attacks->moves[i+1]; + attacks->moves[MOVES_SIZE-1] = move; + return LEARNT; + } + + return LEARNABLE; +} + +u8 forget_and_learn_move(struct gen3_mon_data_unenc* mon, u32 index, u32 forget_index) { + if(mon->learnable_moves == NULL) + return 0; + + u16 num_moves = mon->learnable_moves[0]; + if(index >= num_moves) + return 0; + + if(forget_index >= MOVES_SIZE) + return 0; + + u16 move = mon->learnable_moves[1+index]; + + if(move > LAST_VALID_GEN_3_MOVE) + move = 0; + + if(!move) + return 0; + + struct gen3_mon_attacks* attacks = &mon->attacks; + + // Do not limit HMs' replaceability for better user experience, + // even though normal games do it + attacks->moves[forget_index] = move; + + return 1; +} diff --git a/source/print_system.c b/source/print_system.c index 04cfad5..5ee936a 100644 --- a/source/print_system.c +++ b/source/print_system.c @@ -310,6 +310,14 @@ void set_text_y(u8 new_y){ x_pos = 0; } +u8 get_text_x(){ + return x_pos; +} + +u8 get_text_y(){ + return y_pos; +} + void new_line(){ x_pos = 0; y_pos += 1; diff --git a/source/sio_buffers.c b/source/sio_buffers.c index a96f412..0d2e1f1 100644 --- a/source/sio_buffers.c +++ b/source/sio_buffers.c @@ -462,9 +462,12 @@ void read_gen12_trade_data(struct game_data_t* game_data, u32* buffer, u8 curr_g else conversion_success = gen1_to_gen3(&party_info1->mons_data[i], &game_data->party_3_undec[i], party_info1->mons_index[i], ot_names + (i*names_size), nicknames + (i*names_size), is_jp); if(conversion_success) { + const u16* learnable_moves = game_data->party_3_undec[i].learnable_moves; 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) + if(game_data->party_3_undec[i].is_valid_gen3) { + game_data->party_3_undec[i].learnable_moves = learnable_moves; found = 1; + } } } if (!found) diff --git a/source/sprite_handler.c b/source/sprite_handler.c index 36efb3f..34dd55e 100644 --- a/source/sprite_handler.c +++ b/source/sprite_handler.c @@ -285,9 +285,10 @@ void set_attributes(u16 obj_attr_0, u16 obj_attr_1, u16 obj_attr_2) { shadow_oam[position].attr2 = obj_attr_2; } -void reset_sprites_to_cursor(){ +void reset_sprites_to_cursor(u8 reset_ovram){ wait_for_vblank_if_needed(); - __sprite_counter = cursor_sprite+1; + if(reset_ovram) + __sprite_counter = cursor_sprite+1; __inner_sprite_counter = inner_cursor_sprite+1; reset_sprites(__inner_sprite_counter); } diff --git a/source/window_handler.c b/source/window_handler.c index c57f399..0c1bb12 100644 --- a/source/window_handler.c +++ b/source/window_handler.c @@ -33,6 +33,14 @@ void clear_waiting_window() { reset_window(WAITING_WINDOW_X, WAITING_WINDOW_Y, WAITING_WINDOW_X_SIZE, WAITING_WINDOW_Y_SIZE, WAITING_WINDOW_SCREEN); } +void init_learn_move_message_window() { + create_window(LEARN_MOVE_MESSAGE_WINDOW_X, LEARN_MOVE_MESSAGE_WINDOW_Y, LEARN_MOVE_MESSAGE_WINDOW_X_SIZE, LEARN_MOVE_MESSAGE_WINDOW_Y_SIZE, LEARN_MOVE_MESSAGE_WINDOW_SCREEN); +} + +void clear_learn_move_message_window() { + reset_window(LEARN_MOVE_MESSAGE_WINDOW_X, LEARN_MOVE_MESSAGE_WINDOW_Y, LEARN_MOVE_MESSAGE_WINDOW_X_SIZE, LEARN_MOVE_MESSAGE_WINDOW_Y_SIZE, LEARN_MOVE_MESSAGE_WINDOW_SCREEN); +} + void init_trade_animation_send_window() { create_window(TRADE_ANIMATION_SEND_WINDOW_X, TRADE_ANIMATION_SEND_WINDOW_Y, TRADE_ANIMATION_SEND_WINDOW_X_SIZE, TRADE_ANIMATION_SEND_WINDOW_Y_SIZE, TRADE_ANIMATION_SEND_WINDOW_SCREEN); }