diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c834234d5..1c7cc6ad3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -55,6 +55,12 @@ jobs: run: | make -j${nproc} all syms + - name: Compare FireRed rev10 + env: + GAME_REVISION: 10 + run: | + make -j${nproc} all syms + - name: Compare LeafGreen env: GAME_VERSION: LEAFGREEN @@ -68,6 +74,13 @@ jobs: run: | make -j${nproc} all syms + - name: Compare LeafGreen rev10 + env: + GAME_VERSION: LEAFGREEN + GAME_REVISION: 10 + run: | + make -j${nproc} all syms + - name: Build Modern env: MODERN: 1 diff --git a/Makefile b/Makefile index ef6a66de7..eb735f814 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ MAKEFLAGS += --no-print-directory # Delete files that weren't built properly .DELETE_ON_ERROR: -ALL_BUILDS := firered firered_rev1 leafgreen leafgreen_rev1 +ALL_BUILDS := firered firered_rev1 firered_rev10 leafgreen leafgreen_rev1 leafgreen_rev10 ALL_BUILDS += $(ALL_BUILDS:%=%_modern) RULES_NO_SCAN += clean clean-assets tidy generated clean-generated @@ -224,13 +224,17 @@ tidy: # "friendly" target names for convenience sake firered: ; @$(MAKE) GAME_VERSION=FIRERED firered_rev1: ; @$(MAKE) GAME_VERSION=FIRERED GAME_REVISION=1 +firered_switch: ; @$(MAKE) GAME_VERSION=FIRERED GAME_REVISION=10 leafgreen: ; @$(MAKE) GAME_VERSION=LEAFGREEN leafgreen_rev1: ; @$(MAKE) GAME_VERSION=LEAFGREEN GAME_REVISION=1 +leafgreen_switch: ; @$(MAKE) GAME_VERSION=LEAFGREEN GAME_REVISION=10 compare_firered: ; @$(MAKE) GAME_VERSION=FIRERED COMPARE=1 compare_firered_rev1: ; @$(MAKE) GAME_VERSION=FIRERED GAME_REVISION=1 COMPARE=1 +compare_firered_switch: ; @$(MAKE) GAME_VERSION=FIRERED GAME_REVISION=10 COMPARE=1 compare_leafgreen: ; @$(MAKE) GAME_VERSION=LEAFGREEN COMPARE=1 compare_leafgreen_rev1: ; @$(MAKE) GAME_VERSION=LEAFGREEN GAME_REVISION=1 COMPARE=1 +compare_leafgreen_switch:; @$(MAKE) GAME_VERSION=LEAFGREEN GAME_REVISION=10 COMPARE=1 firered_modern: ; @$(MAKE) GAME_VERSION=FIRERED MODERN=1 firered_rev1_modern: ; @$(MAKE) GAME_VERSION=FIRERED GAME_REVISION=1 MODERN=1 @@ -348,16 +352,30 @@ endif $(OBJ_DIR)/sym_bss.ld: sym_bss.txt $(RAMSCRGEN) .bss $< ENGLISH > $@ +$(OBJ_DIR)/sym_bss_rev10.ld: sym_bss_rev10.txt + $(RAMSCRGEN) .bss $< ENGLISH > $@ + $(OBJ_DIR)/sym_common.ld: sym_common.txt $(C_OBJS) $(wildcard common_syms/*.txt) $(RAMSCRGEN) COMMON $< ENGLISH -c $(C_BUILDDIR),common_syms > $@ +$(OBJ_DIR)/sym_common_rev10.ld: sym_common_rev10.txt $(C_OBJS) $(wildcard common_syms/*.txt) + $(RAMSCRGEN) COMMON $< ENGLISH -c $(C_BUILDDIR),common_syms > $@ + $(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt $(RAMSCRGEN) ewram_data $< ENGLISH > $@ +$(OBJ_DIR)/sym_ewram_rev10.ld: sym_ewram_rev10.txt + $(RAMSCRGEN) ewram_data $< ENGLISH > $@ + # Linker script ifeq ($(MODERN),0) +ifeq ($(GAME_REVISION),10) +LD_SCRIPT := ld_script_rev10.ld +LD_SCRIPT_DEPS := $(OBJ_DIR)/sym_bss_rev10.ld $(OBJ_DIR)/sym_common_rev10.ld $(OBJ_DIR)/sym_ewram_rev10.ld +else LD_SCRIPT := ld_script.ld LD_SCRIPT_DEPS := $(OBJ_DIR)/sym_bss.ld $(OBJ_DIR)/sym_common.ld $(OBJ_DIR)/sym_ewram.ld +endif else LD_SCRIPT := ld_script_modern.ld LD_SCRIPT_DEPS := diff --git a/README.md b/README.md index 0dc5dee72..819422657 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ It builds the following ROM images: * [**pokeleafgreen.gba**](https://datomatic.no-intro.org/?page=show_record&s=23&n=1617) `sha1: 574fa542ffebb14be69902d1d36f1ec0a4afd71e` * [**pokefirered_rev1.gba**](https://datomatic.no-intro.org/?page=show_record&s=23&n=1672) `sha1: dd5945db9b930750cb39d00c84da8571feebf417` * [**pokeleafgreen_rev1.gba**](https://datomatic.no-intro.org/index.php?page=show_record&s=23&n=1668) `sha1: 7862c67bdecbe21d1d69ce082ce34327e1c6ed5e` +* [**pokefirered_switch.gba**](https://datomatic.no-intro.org/index.php?page=show_record&s=23&n=x550) `sha1: baa452d0b24629dd7782cfc07a8984085dde1311` +* [**pokeleafgreen_switch.gba**](https://datomatic.no-intro.org/index.php?page=show_record&s=23&n=x551) `sha1: 62b9fc77549dbc67032eb6cbd0ea6ad3b825690f` To set up the repository, see [INSTALL.md](INSTALL.md). diff --git a/config.mk b/config.mk index 48421930c..c07d31fc0 100644 --- a/config.mk +++ b/config.mk @@ -43,6 +43,10 @@ ifeq ($(GAME_REVISION),1) BUILD_NAME := $(BUILD_NAME)_rev1 endif +ifeq ($(GAME_REVISION),10) + BUILD_NAME := $(BUILD_NAME)_switch +endif + # Modern GCC ifeq ($(MODERN),1) BUILD_NAME := $(BUILD_NAME)_modern diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 3304833c7..9ae0ed9d1 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -1664,7 +1664,11 @@ RisingWaterHitEffect: Move_EXPLOSION: loadspritegfx ANIM_TAG_EXPLOSION +.if REVISION >= 0xA + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_BG, 8, 9, RGB(26, 8, 8), 8, RGB_BLACK, 5 +.else createsprite gComplexPaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_BG, 8, 9, RGB(26, 8, 8), 8, RGB_BLACK, 8 +.endif createvisualtask AnimTask_ShakeMon2, 5, 4, 8, 0, 40, 1 createvisualtask AnimTask_ShakeMon2, 5, 5, 8, 0, 40, 1 createvisualtask AnimTask_ShakeMon2, 5, 6, 8, 0, 40, 1 diff --git a/firered_switch.sha1 b/firered_switch.sha1 new file mode 100644 index 000000000..715fa7b9c --- /dev/null +++ b/firered_switch.sha1 @@ -0,0 +1 @@ +baa452d0b24629dd7782cfc07a8984085dde1311 pokefirered_switch.gba diff --git a/include/AgbRfu_LinkManager.h b/include/AgbRfu_LinkManager.h index 53c623e5a..6cf18d6c7 100644 --- a/include/AgbRfu_LinkManager.h +++ b/include/AgbRfu_LinkManager.h @@ -23,8 +23,13 @@ #define PCSWITCH_FORCE_SP_START 0x09 // Period for which parent-child switching search specified +#if REVISION >= 0xA +#define PCSWITCH_ALL_PERIOD 180 // Entire cycle 180 frames +#define PCSWITCH_SP_PERIOD 65 // Child period 40 frames +#else #define PCSWITCH_ALL_PERIOD 180 // Entire cycle 180 frames #define PCSWITCH_SP_PERIOD 40 // Child period 40 frames +#endif // Error code returned by Link Manager API (rfu_LMAN_...return value of function) #define LMAN_ERROR_MANAGER_BUSY 1 // Link Manager is already running. @@ -165,6 +170,9 @@ typedef struct linkManagerTag /* 0x014 */ u16 param[2]; /* 0x018 */ u16 NI_failCounter_limit; /* 0x01a */ u16 connect_period; +#if REVISION >= 0xA + /* 0x01c */ u16 connect_period_initial; // pushes next offsets up by 2 +#endif /* 0x01c */ u16 pcswitch_period_bak; /* 0x01e */ u16 work; /* 0x020 */ u16 *acceptable_serialNo_list; @@ -190,6 +198,10 @@ u8 rfu_LMAN_setLinkRecovery(u8 enable_flag, u16 recovery_period); void rfu_LMAN_manager_entity(u32 rand); void rfu_LMAN_syncVBlank(void); u8 rfu_LMAN_initializeManager(void (*LMAN_callback_p)(u8, u8), void (*MSC_callback_p)(u16)); +#if REVISION >= 0xA +void rfu_LMAN_forceChangeSP(bool8 child); +#else void rfu_LMAN_forceChangeSP(void); +#endif #endif //GUARD_LINKMANAGER_H diff --git a/include/config.h b/include/config.h index 956858e2d..db131b271 100644 --- a/include/config.h +++ b/include/config.h @@ -8,12 +8,17 @@ // still has them in the ROM. This is because the developers forgot // to define NDEBUG before release, however this has been changed as // Ruby's actual debug build does not use the AGBPrint features. -// #define NDEBUG + +// Revision 10 disabled asserts in some other way, comment out NDEBUG there to bring them back. +#if REVISION >= 0xA +#define NDEBUG +#endif // Fire Red likely forgot to define NDEBUG/NOAGBPRN before release, leading // to the inclusion of asserts in the retail ROM. +// Revision 10 disabled asserts in some other way, but isagbprint/etc is still present there. -#ifndef NDEBUG +#if !defined(NDEBUG) || REVISION >= 0xA #define PRETTY_PRINT_OFF (0) #define PRETTY_PRINT_MINI_PRINTF (1) #define PRETTY_PRINT_LIBC (2) diff --git a/include/constants/union_room.h b/include/constants/union_room.h index 4016150f0..c3f719dbd 100644 --- a/include/constants/union_room.h +++ b/include/constants/union_room.h @@ -7,9 +7,10 @@ // exceed RFU_CHILD_MAX (4), for a total of 5 including the player. #define MAX_UNION_ROOM_LEADERS 8 -#define UNION_ROOM_SPAWN_NONE 0 -#define UNION_ROOM_SPAWN_IN 1 -#define UNION_ROOM_SPAWN_OUT 2 +#define UNION_ROOM_SPAWN_NONE 0 +#define UNION_ROOM_SPAWN_IN 1 +#define UNION_ROOM_SPAWN_OUT 2 +#define UNION_ROOM_SPAWN_OUT_SOON 3 // Equivalent to SPAWN_OUT in revision 10 - probably SPAWN_OUT means disconnected in a "connection reset" way? #define UNION_ROOM_MAX_LEVEL 30 diff --git a/include/gba/isagbprint.h b/include/gba/isagbprint.h index de14b289e..9c79e03e8 100644 --- a/include/gba/isagbprint.h +++ b/include/gba/isagbprint.h @@ -9,7 +9,7 @@ #define MGBA_LOG_INFO (3) #define MGBA_LOG_DEBUG (4) -#ifdef NDEBUG +#if defined(NDEBUG) && !(REVISION >= 0xA) #define DebugPrintf(pBuf, ...) #define DebugPrintfLevel(level, pBuf, ...) #define MgbaOpen() diff --git a/include/librfu.h b/include/librfu.h index 6981ba2bc..fa57ac4a2 100644 --- a/include/librfu.h +++ b/include/librfu.h @@ -4,7 +4,11 @@ #include "global.h" #include "main.h" +#if REVISION >= 0xA +#define LIBRFU_VERSION 1028 +#else #define LIBRFU_VERSION 1024 +#endif /* TODOs: * - documentation diff --git a/include/link_rfu.h b/include/link_rfu.h index affbebe3d..12412fb97 100644 --- a/include/link_rfu.h +++ b/include/link_rfu.h @@ -294,6 +294,7 @@ bool32 WaitRfuState(bool32 force); bool32 HasTrainerLeftPartnersList(u16 trainerId, const u8 *trainerName); void SendRfuStatusToPartner(u8 status, u16 trainerId, const u8 *name); u32 WaitSendRfuStatusToPartner(u16 trainerId, const u8 *name); +s32 GetJoinGroupStatus(void); void SetHostRfuGameData(u8 activity, u32 partnerInfo, bool32 startedActivity); void InitializeRfuLinkManager_LinkLeader(u32 availSlots); void RequestDisconnectSlotByTrainerNameAndId(const u8 *trainerName, u16 trainerId); @@ -322,6 +323,17 @@ void RfuSetNormalDisconnectMode(void); void SetUnionRoomChatPlayerData(u32 numPlayers); void ClearRecvCommands(void); +void PkmnStrToASCII(u8 *dest, const u8 *src); +void ASCIIToPkmnStr(u8 *dest, const u8 *src); + +#if REVISION >= 0xA +u16 RfuGetErrorInfo(void); +void LinkRfu_ForceChangeSpParent(void); +void DestroyTask_RfuReconnectWithParent(void); +void RfuReloadSave(void); +void RfuSoftReset(void); +#endif + #include "mystery_gift_server.h" extern const struct MysteryGiftServerCmd gServerScript_ClientCanceledCard[]; diff --git a/include/overworld.h b/include/overworld.h index 56e656f07..b4f56bee6 100644 --- a/include/overworld.h +++ b/include/overworld.h @@ -180,6 +180,10 @@ void UpdateEscapeWarp(s16 x, s16 y); bool8 SetDiveWarpEmerge(u16 x, u16 y); bool8 SetDiveWarpDive(u16 x, u16 y); +#if REVISION >= 0xA +void ClearFieldCallback(void); +#endif + extern u16 *gBGTilemapBuffers1; extern u16 *gBGTilemapBuffers2; extern u16 *gBGTilemapBuffers3; diff --git a/include/sloopsvc.h b/include/sloopsvc.h new file mode 100644 index 000000000..1ba777853 --- /dev/null +++ b/include/sloopsvc.h @@ -0,0 +1,36 @@ +#ifndef GUARD_SLOOPSVC_H +#define GUARD_SLOOPSVC_H + +#if REVISION >= 0xA + +#define SVC4B_EXIT_EARLY (1 << 0) +#define SVC4B_RESEED_RNG (1 << 1) + +void svc_40(void); +void svc_41(void); + +void svc_47(void); +void svc_42(void); +u32 svc_49(void); +void svc_45_rfu_link_status(void); +u32 svc_4a(void); +void svc_43(u16 pid); +void svc_44(void); +u32 svc_53(void); +u32 svc_51(void); +u32 svc_4b(void); +void svc_WriteSector(u8 sector, u8* data); +void svc_ReplaceSector(u8 sector, u8* data); +void svc_FinishSave(void); +u32 svc_CommsAllowedByParentalControls(void); +u32 svc_BadWordCheck(u8* str); +void svc_4f(u32 arg); +u32 svc_50(void); +void svc_SetSaveBlock2(struct SaveBlock2* saveBlock2); +void svc_stubbed(void); +void svc_SetStarter(u32 species); +void svc_SetActivity(u32 activity); +void svc_IncrementLinkError(void); + +#endif +#endif \ No newline at end of file diff --git a/ld_script.ld b/ld_script.ld index 6e2edf14f..f7e62c922 100644 --- a/ld_script.ld +++ b/ld_script.ld @@ -64,6 +64,7 @@ SECTIONS { src/window_8bpp.o(.text); src/text.o(.text); src/sprite.o(.text); + src/sloopsvc.o(.text); src/string_util.o(.text); src/link.o(.text); src/multiboot.o(.text); @@ -405,6 +406,7 @@ SECTIONS { src/text.o(.rodata); src/sprite.o(.rodata); src/bg_regs.o(.rodata); + src/sloopsvc.o(.rodata); src/string_util.o(.rodata); src/link.o(.rodata); src/main_menu.o(.rodata); diff --git a/ld_script_rev10.ld b/ld_script_rev10.ld new file mode 100644 index 000000000..60b6f4431 --- /dev/null +++ b/ld_script_rev10.ld @@ -0,0 +1,1062 @@ +gNumMusicPlayers = 4; +gMaxLines = 0; + +MEMORY +{ + EWRAM (rwx) : ORIGIN = 0x2000000, LENGTH = 256K + IWRAM (rwx) : ORIGIN = 0x3000000, LENGTH = 32K + ROM (rx) : ORIGIN = 0x8000000, LENGTH = 32M +} + +SECTIONS { + + ewram 0x2000000 (NOLOAD) : + ALIGN(4) + { + gHeap = .; + + . = 0x1C000; + + INCLUDE "sym_ewram_rev10.ld" + src/*.o(ewram_data); + + *libc.a:impure.o(.data); + *libc.a:locale.o(.data); + *libc.a:mallocr.o(.data); + } > EWRAM + + iwram 0x3000000 (NOLOAD) : + ALIGN(4) + { + /* .bss starts at 0x3000000 */ + INCLUDE "sym_bss_rev10.ld" + src/*.o(.bss); + data/*.o(.bss); + + /* .bss.code starts at 0x30028E0 */ + src/m4a.o(.bss.code); + + /* COMMON starts at 0x30030E0 */ + INCLUDE "sym_common_rev10.ld" + src/*.o(COMMON); + + *libc.a:sbrkr.o(COMMON); + end = .; + } > IWRAM + + /* BEGIN ROM DATA */ + . = 0x8000000; + + .text : + ALIGN(4) + { + src/rom_header.o(.text); + src/rom_header_gf.o(.text*); + src/crt0.o(.text); + src/main.o(.text); + src/gpu_regs.o(.text); + src/dma3_manager.o(.text); + src/bg.o(.text); + src/malloc.o(.text); + src/text_printer.o(.text); + src/window.o(.text); + src/blit.o(.text); + src/window_8bpp.o(.text); + src/librfu_stwi.o(.text); + src/librfu_rfu.o(.text); + src/text.o(.text); + src/sprite.o(.text); + src/sloopsvc.o(.text); + src/string_util.o(.text); + src/link.o(.text); + src/multiboot.o(.text); + src/main_menu.o(.text); + src/battle_controllers.o(.text); + src/decompress.o(.text); + src/battle_bg.o(.text); + src/battle_main.o(.text); + src/battle_util.o(.text); + src/battle_script_commands.o(.text); + src/battle_util2.o(.text); + src/battle_controller_player.o(.text); + src/battle_gfx_sfx_util.o(.text); + src/battle_controller_opponent.o(.text); + src/battle_ai_switch_items.o(.text); + src/battle_controller_link_opponent.o(.text); + src/pokemon.o(.text); + src/trig.o(.text); + src/random.o(.text); + src/util.o(.text); + src/blend_palette.o(.text); + src/daycare.o(.text); + src/battle_interface.o(.text); + src/battle_anim_smokescreen.o(.text); + src/pokeball.o(.text); + src/load_save.o(.text); + src/trade.o(.text); + src/trade_scene.o(.text); + src/play_time.o(.text); + src/new_game.o(.text); + src/overworld.o(.text); + src/fieldmap.o(.text); + src/metatile_behavior.o(.text); + src/field_camera.o(.text); + src/field_door.o(.text); + src/field_player_avatar.o(.text); + src/event_object_movement.o(.text); + src/field_message_box.o(.text); + src/event_object_lock.o(.text); + src/text_window_graphics.o(.text); + src/script.o(.text); + src/scrcmd.o(.text); + src/field_control_avatar.o(.text); + src/event_data.o(.text); + src/coord_event_weather.o(.text); + src/field_tasks.o(.text); + src/start_menu.o(.text); + src/tileset_anims.o(.text); + src/palette.o(.text); + src/sound.o(.text); + src/battle_anim.o(.text); + src/battle_anim_mons.o(.text); + src/task.o(.text); + src/reshow_battle_screen.o(.text); + src/battle_anim_status_effects.o(.text); + src/title_screen.o(.text); + src/reset_save_heap.o(.text); + src/field_weather.o(.text); + src/field_weather_util.o(.text); + src/field_weather_effects.o(.text); + src/field_fadetransition.o(.text); + src/field_screen_effect.o(.text); + src/battle_setup.o(.text); + src/cable_club.o(.text); + src/trainer_see.o(.text); + src/wild_encounter.o(.text); + src/field_effect.o(.text); + src/scanline_effect.o(.text); + src/option_menu.o(.text); + src/pokedex.o(.text); + src/trainer_card.o(.text); + src/pokemon_storage_system.o(.text); + src/pokemon_storage_system_menu.o(.text); + src/pokemon_storage_system_tasks.o(.text); + src/pokemon_storage_system_graphics.o(.text); + src/pokemon_storage_system_data.o(.text); + src/pokemon_storage_system_misc.o(.text); + src/pokemon_icon.o(.text); + src/script_movement.o(.text); + src/fldeff_cut.o(.text); + src/mail_data.o(.text); + src/map_name_popup.o(.text); + src/item_menu_icons.o(.text); + src/battle_anim_mon_movement.o(.text); + src/item.o(.text); + src/shop.o(.text); + src/special_field_anim.o(.text); + src/berry.o(.text); + src/script_menu.o(.text); + src/naming_screen.o(.text); + src/money.o(.text); + src/script_pokemon_util.o(.text); + src/field_poison.o(.text); + src/pokemon_size_record.o(.text); + src/pc_screen_effect.o(.text); + src/fldeff_poison.o(.text); + src/fldeff_berrytree.o(.text); + src/field_special_scene.o(.text); + src/safari_zone.o(.text); + src/item_use.o(.text); + src/battle_anim_effects_1.o(.text); + src/battle_anim_effects_2.o(.text); + src/battle_anim_water.o(.text); + src/battle_anim_fire.o(.text); + src/battle_anim_electric.o(.text); + src/battle_anim_ice.o(.text); + src/battle_anim_fight.o(.text); + src/battle_anim_poison.o(.text); + src/battle_anim_flying.o(.text); + src/battle_anim_psychic.o(.text); + src/battle_anim_bug.o(.text); + src/battle_anim_rock.o(.text); + src/battle_anim_ghost.o(.text); + src/battle_anim_dragon.o(.text); + src/battle_anim_dark.o(.text); + src/battle_anim_ground.o(.text); + src/battle_anim_normal.o(.text); + src/battle_anim_utility_funcs.o(.text); + src/battle_intro.o(.text); + src/bike.o(.text); + src/easy_chat.o(.text); + src/mon_markings.o(.text); + src/mail.o(.text); + src/menu_helpers.o(.text); + src/party_menu_specials.o(.text); + src/heal_location.o(.text); + src/region_map.o(.text); + src/image_processing_effects.o(.text); + src/battle_ai_script_commands.o(.text); + src/fldeff_rocksmash.o(.text); + src/fldeff_dig.o(.text); + src/fldeff_flash.o(.text); + src/post_battle_event_funcs.o(.text); + src/prof_pc.o(.text); + src/hof_pc.o(.text); + src/field_specials.o(.text); + src/battle_records.o(.text); + src/evolution_scene.o(.text); + src/coins.o(.text); + src/fldeff_strength.o(.text); + src/battle_transition.o(.text); + src/battle_controller_link_partner.o(.text); + src/battle_message.o(.text); + src/math_util.o(.text); + src/palette_util.o(.text); + src/cable_car_util.o(.text); + src/save.o(.text); + src/mystery_event_script.o(.text); + src/field_effect_helpers.o(.text); + src/battle_anim_sound_tasks.o(.text); + src/battle_controller_safari.o(.text); + src/fldeff_sweetscent.o(.text); + src/battle_anim_effects_3.o(.text); + src/learn_move.o(.text); + src/fldeff_softboiled.o(.text); + src/battle_tower.o(.text); + src/battle_controller_oak_old_man.o(.text); + src/player_pc.o(.text); + src/intro.o(.text); + src/battle_anim_special.o(.text); + src/hall_of_fame.o(.text); + src/credits.o(.text); + src/diploma.o(.text); + src/save_failed_screen.o(.text); + src/clear_save_data_screen.o(.text); + src/evolution_graphics.o(.text); + src/fldeff_teleport.o(.text); + src/new_menu_helpers.o(.text); + src/tilemap_util.o(.text); + src/save_menu_util.o(.text); + src/map_preview_screen.o(.text); + src/link_rfu_2.o(.text); + src/link_rfu_3.o(.text); + src/AgbRfu_LinkManager.o(.text); + src/easy_chat_2.o(.text); + src/easy_chat_3.o(.text); + src/pokedex_screen.o(.text); + src/list_menu.o(.text); + src/item_menu.o(.text); + src/save_location.o(.text); + src/bag.o(.text); + src/trainer_pokemon_sprites.o(.text); + src/vs_seeker.o(.text); + src/item_pc.o(.text); + src/mailbox_pc.o(.text); + src/menu.o(.text); + src/quest_log.o(.text); + src/help_message.o(.text); + src/trainer_fan_club.o(.text); + src/quest_log_events.o(.text); + src/union_room.o(.text); + src/union_room_player_avatar.o(.text); + src/union_room_battle.o(.text); + src/pokemon_special_anim.o(.text); + src/pokemon_special_anim_scene.o(.text); + src/party_menu.o(.text); + src/union_room_chat.o(.text); + src/union_room_chat_display.o(.text); + src/union_room_chat_objects.o(.text); + src/help_system.o(.text); + src/quest_log_battle.o(.text); + src/fame_checker.o(.text); + src/menu2.o(.text); + src/oak_speech.o(.text); + src/tm_case.o(.text); + src/menu_indicators.o(.text); + src/pokedex_area_markers.o(.text); + src/pokemon_summary_screen.o(.text); + src/help_system_util.o(.text); + src/wild_pokemon_area.o(.text); + src/dynamic_placeholder_text_util.o(.text); + src/berry_pouch.o(.text); + src/itemfinder.o(.text); + src/buy_menu_helpers.o(.text); + src/slot_machine.o(.text); + src/roamer.o(.text); + src/mystery_gift_menu.o(.text); + src/ereader_screen.o(.text); + src/mystery_gift.o(.text); + src/mystery_gift_link.o(.text); + src/mystery_gift_client.o(.text); + src/mystery_gift_server.o(.text); + src/mystery_gift_show_card.o(.text); + src/mystery_gift_show_news.o(.text); + src/wonder_news.o(.text); + src/seagallop.o(.text); + src/pokemon_jump.o(.text); + src/berry_crush.o(.text); + src/wireless_communication_status_screen.o(.text); + src/braille_text.o(.text); + src/text_window.o(.text); + src/quest_log_player.o(.text); + src/dodrio_berry_picking.o(.text); + src/battle_controller_pokedude.o(.text); + src/quest_log_objects.o(.text); + src/dodrio_berry_picking_comm.o(.text); + src/teachy_tv.o(.text); + src/ereader_helpers.o(.text); + src/digit_obj_util.o(.text); + src/ss_anne.o(.text); + src/cereader_tool.o(.text); + src/renewable_hidden_items.o(.text); + src/trainer_tower.o(.text); + src/berry_powder.o(.text); + src/minigame_countdown.o(.text); + src/berry_fix_program.o(.text); + } > ROM =0 + + script_data : + ALIGN(4) + { + data/event_scripts.o(script_data); + data/battle_anim_scripts.o(script_data); + data/battle_scripts_1.o(script_data); + data/field_effect_scripts.o(script_data); + data/battle_scripts_2.o(script_data); + data/battle_ai_scripts.o(script_data); + data/mystery_event_script_cmd_table.o(script_data); + } > ROM =0 + + lib_text : + ALIGN(4) + { + src/libgcnmultiboot.o(.text); + src/m4a_1.o(.text); + src/m4a.o(.text); + src/agb_flash.o(.text); + src/agb_flash_1m.o(.text); + src/agb_flash_mx.o(.text); + src/agb_flash_le.o(.text); + src/librfu_sio32id.o(.text); + src/librfu_intr.o(.text); + src/isagbprn.o(.text); + src/libagbsyscall.o(.text); + *libgcc.a:_call_via_rX.o(.text); + *libgcc.a:_divdi3.o(.text); + *libgcc.a:_divsi3.o(.text); + *libgcc.a:_dvmd_tls.o(.text); + *libgcc.a:_fixunsdfsi.o(.text); + *libgcc.a:_modsi3.o(.text); + *libgcc.a:_muldi3.o(.text); + *libgcc.a:_udivdi3.o(.text); + *libgcc.a:_udivsi3.o(.text); + *libgcc.a:_umodsi3.o(.text); + *libgcc.a:dp-bit.o(.text); + *libgcc.a:fp-bit.o(.text); + *libgcc.a:_lshrdi3.o(.text); + *libgcc.a:_negdi2.o(.text); + *libc.a:memcpy.o(.text); + *libc.a:memset.o(.text); + *libc.a:strcmp.o(.text); + *libc.a:strcpy.o(.text); + *libc.a:impure.o(.text); + *libc.a:vsprintf.o(.text); + *libc.a:vfprintf.o(.text); + *libc.a:wsetup.o(.text); + *libc.a:dtoa.o(.text); + *libc.a:fflush.o(.text); + *libc.a:findfp.o(.text); + *libc.a:freer.o(.text); + *libc.a:mtrim.o(.text); + *libc.a:fvwrite.o(.text); + *libc.a:fwalk.o(.text); + *libc.a:locale.o(.text); + *libc.a:makebuf.o(.text); + *libc.a:mallocr.o(.text); + *libc.a:mbtowc_r.o(.text); + *libc.a:memchr.o(.text); + *libc.a:memmove.o(.text); + *libc.a:mlock.o(.text); + *libc.a:mprec.o(.text); + *libc.a:s_isinf.o(.text); + *libc.a:s_isnan.o(.text); + *libc.a:sbrkr.o(.text); + *libc.a:stdio.o(.text); + *libc.a:strlen.o(.text); + *libc.a:syscalls.o(.text); + *libc.a:writer.o(.text); + *libc.a:callocr.o(.text); + *libc.a:closer.o(.text); + *libc.a:errno.o(.text); + *libc.a:fstatr.o(.text); + *libc.a:libcfunc.o(.text); + *libc.a:lseekr.o(.text); + *libc.a:readr.o(.text); + } > ROM =0 + + .rodata : + SUBALIGN(4) + { + src/main.o(.rodata); + src/bg.o(.rodata); + src/malloc.o(.rodata); + src/malloc.o(.rodata.str1.4); + src/text_printer.o(.rodata); + src/window.o(.rodata); + src/librfu_rfu.o(.rodata); + src/text.o(.rodata); + src/sprite.o(.rodata); + src/bg_regs.o(.rodata); + src/sloopsvc.o(.rodata); + src/string_util.o(.rodata); + src/link.o(.rodata); + src/main_menu.o(.rodata); + src/data.o(.rodata); + src/battle_bg.o(.rodata); + src/battle_main.o(.rodata); + src/battle_util.o(.rodata); + src/battle_script_commands.o(.rodata); + src/battle_controller_player.o(.rodata); + src/battle_anim_smokescreen.o(.rodata); + src/battle_controller_opponent.o(.rodata); + src/battle_controller_link_opponent.o(.rodata); + src/pokemon.o(.rodata); + src/trig.o(.rodata); + src/util.o(.rodata); + src/daycare.o(.rodata); + src/battle_gfx_sfx_util.o(.rodata); + src/battle_interface.o(.rodata); + src/pokeball.o(.rodata); + src/trade.o(.rodata); + src/trade_scene.o(.rodata); + src/overworld.o(.rodata); + src/tilesets.o(.rodata); + data/maps.o(.rodata); + src/fieldmap.o(.rodata); + src/metatile_behavior.o(.rodata); + src/field_door.o(.rodata); + src/field_player_avatar.o(.rodata); + src/event_object_movement.o(.rodata); + src/scrcmd.o(.rodata); + src/coord_event_weather.o(.rodata); + src/field_tasks.o(.rodata); + src/start_menu.o(.rodata); + src/tileset_anims.o(.rodata); + src/palette.o(.rodata); + src/sound.o(.rodata); + src/battle_anim.o(.rodata); + src/battle_anim_mons.o(.rodata); + data/map_events.o(.rodata); + src/battle_anim_status_effects.o(.rodata); + src/title_screen.o(.rodata); + src/field_weather.o(.rodata); + src/field_weather_util.o(.rodata); + src/field_weather_effects.o(.rodata); + src/field_screen_effect.o(.rodata); + src/battle_setup.o(.rodata); + src/cable_club.o(.rodata); + src/trainer_see.o(.rodata); + src/wild_encounter.o(.rodata); + src/field_effect.o(.rodata); + src/option_menu.o(.rodata); + src/trainer_card.o(.rodata); + src/pokemon_storage_system_menu.o(.rodata); + src/pokemon_storage_system_tasks.o(.rodata); + src/pokemon_storage_system_graphics.o(.rodata); + src/pokemon_storage_system_data.o(.rodata); + src/pokemon_storage_system_misc.o(.rodata); + src/pokemon_icon.o(.rodata); + src/fldeff_cut.o(.rodata); + src/map_name_popup.o(.rodata); + src/item_menu_icons.o(.rodata); + src/battle_anim_mon_movement.o(.rodata); + src/item.o(.rodata); + src/shop.o(.rodata); + src/special_field_anim.o(.rodata); + src/berry.o(.rodata); + src/script_menu.o(.rodata); + src/naming_screen.o(.rodata); + src/pokemon_size_record.o(.rodata); + src/item_use.o(.rodata); + src/battle_anim_effects_1.o(.rodata); + src/battle_anim_effects_2.o(.rodata); + src/battle_anim_water.o(.rodata); + src/battle_anim_fire.o(.rodata); + src/battle_anim_electric.o(.rodata); + src/battle_anim_ice.o(.rodata); + src/battle_anim_fight.o(.rodata); + src/battle_anim_poison.o(.rodata); + src/battle_anim_flying.o(.rodata); + src/battle_anim_psychic.o(.rodata); + src/battle_anim_bug.o(.rodata); + src/battle_anim_rock.o(.rodata); + src/battle_anim_ghost.o(.rodata); + src/battle_anim_dragon.o(.rodata); + src/battle_anim_dark.o(.rodata); + src/battle_anim_ground.o(.rodata); + src/battle_anim_normal.o(.rodata); + src/battle_anim_utility_funcs.o(.rodata); + src/battle_intro.o(.rodata); + src/bike.o(.rodata); + src/easy_chat.o(.rodata); + src/mon_markings.o(.rodata); + src/mail.o(.rodata); + src/heal_location.o(.rodata); + src/region_map.o(.rodata); + src/image_processing_effects.o(.rodata); + src/battle_ai_script_commands.o(.rodata); + src/fldeff_flash.o(.rodata); + src/field_specials.o(.rodata); + src/battle_records.o(.rodata); + src/evolution_scene.o(.rodata); + src/battle_transition.o(.rodata); + src/battle_controller_link_partner.o(.rodata); + src/battle_message.o(.rodata); + src/save.o(.rodata); + src/field_effect_helpers.o(.rodata); + src/battle_controller_safari.o(.rodata); + src/battle_anim_effects_3.o(.rodata); + src/learn_move.o(.rodata); + src/battle_tower.o(.rodata); + src/battle_controller_oak_old_man.o(.rodata); + src/player_pc.o(.rodata); + src/intro.o(.rodata); + src/battle_anim_special.o(.rodata); + src/hall_of_fame.o(.rodata); + src/credits.o(.rodata); + src/diploma.o(.rodata); + src/strings.o(.rodata); + src/save_failed_screen.o(.rodata); + src/clear_save_data_screen.o(.rodata); + src/evolution_graphics.o(.rodata); + src/new_menu_helpers.o(.rodata); + src/tilemap_util.o(.rodata); + src/map_preview_screen.o(.rodata); + src/link_rfu_2.o(.rodata); + src/link_rfu_3.o(.rodata); + src/easy_chat_2.o(.rodata); + src/easy_chat_3.o(.rodata); + src/pokedex_screen.o(.rodata); + src/list_menu.o(.rodata); + src/item_menu.o(.rodata); + src/save_location.o(.rodata); + src/bag.o(.rodata); + src/trainer_pokemon_sprites.o(.rodata); + src/vs_seeker.o(.rodata); + src/item_pc.o(.rodata); + src/mailbox_pc.o(.rodata); + src/decoration.o(.rodata); + src/menu.o(.rodata); + src/quest_log.o(.rodata); + src/help_message.o(.rodata); + src/trainer_fan_club.o(.rodata); + src/quest_log_events.o(.rodata); + src/union_room.o(.rodata); + src/union_room_player_avatar.o(.rodata); + src/union_room_battle.o(.rodata); + src/union_room_message.o(.rodata); + src/pokemon_special_anim.o(.rodata); + src/pokemon_special_anim_scene.o(.rodata); + src/party_menu.o(.rodata); + src/union_room_chat.o(.rodata); + src/union_room_chat_display.o(.rodata); + src/union_room_chat_objects.o(.rodata); + src/help_system.o(.rodata); + src/fame_checker.o(.rodata); + src/menu2.o(.rodata); + src/oak_speech.o(.rodata); + src/tm_case.o(.rodata); + src/menu_indicators.o(.rodata); + src/pokedex_area_markers.o(.rodata); + src/pokemon_summary_screen.o(.rodata); + src/help_system_util.o(.rodata); + src/wild_pokemon_area.o(.rodata); + src/dynamic_placeholder_text_util.o(.rodata); + src/berry_pouch.o(.rodata); + src/itemfinder.o(.rodata); + src/buy_menu_helpers.o(.rodata); + src/slot_machine.o(.rodata); + src/roamer.o(.rodata); + src/mystery_gift_menu.o(.rodata); + src/ereader_screen.o(.rodata); + src/mystery_gift.o(.rodata); + src/mystery_gift_link.o(.rodata); + src/mystery_gift_client.o(.rodata); + src/mystery_gift_server.o(.rodata); + src/mystery_gift_show_card.o(.rodata); + src/mystery_gift_show_news.o(.rodata); + src/mystery_gift_scripts.o(.rodata); + src/wonder_news.o(.rodata); + src/wonder_news.o(.rodata.str1.4); + src/seagallop.o(.rodata); + src/pokemon_jump.o(.rodata); + src/berry_crush.o(.rodata); + src/wireless_communication_status_screen.o(.rodata); + src/braille_text.o(.rodata); + src/text_window_graphics.o(.rodata); + src/quest_log_player.o(.rodata); + src/dodrio_berry_picking.o(.rodata); + src/battle_controller_pokedude.o(.rodata); + src/teachy_tv.o(.rodata); + src/digit_obj_util.o(.rodata); + src/ss_anne.o(.rodata); + src/cereader_tool.o(.rodata); + src/renewable_hidden_items.o(.rodata); + src/trainer_tower.o(.rodata); + src/minigame_countdown.o(.rodata); + src/berry_fix_program.o(.rodata); + src/keyboard_text.o(.rodata); + src/trainer_tower_sets.o(.rodata); + src/move_descriptions.o(.rodata); + + /* These should not be moved to C files */ + src/mystery_event_msg.o(.rodata); + data/mystery_event_msg.o(.rodata); + src/m4a_tables.o(.rodata); + data/sound_data.o(.rodata); + } > ROM =0 + + song_data : + ALIGN(4) + { + sound/songs/midi/mus_dummy.o(.rodata); + sound/songs/midi/se_use_item.o(.rodata); + sound/songs/midi/se_pc_login.o(.rodata); + sound/songs/midi/se_pc_off.o(.rodata); + sound/songs/midi/se_pc_on.o(.rodata); + sound/songs/midi/se_select.o(.rodata); + sound/songs/se_win_open.o(.rodata); + sound/songs/se_wall_hit.o(.rodata); + sound/songs/midi/se_rs_door.o(.rodata); + sound/songs/midi/se_exit.o(.rodata); + sound/songs/midi/se_ledge.o(.rodata); + sound/songs/midi/se_bike_bell.o(.rodata); + sound/songs/midi/se_not_effective.o(.rodata); + sound/songs/midi/se_effective.o(.rodata); + sound/songs/midi/se_super_effective.o(.rodata); + sound/songs/midi/se_ball_open.o(.rodata); + sound/songs/midi/se_faint.o(.rodata); + sound/songs/midi/se_flee.o(.rodata); + sound/songs/midi/se_sliding_door.o(.rodata); + sound/songs/midi/se_ship.o(.rodata); + sound/songs/midi/se_bang.o(.rodata); + sound/songs/midi/se_pin.o(.rodata); + sound/songs/midi/se_boo.o(.rodata); + sound/songs/midi/se_ball.o(.rodata); + sound/songs/midi/se_contest_place.o(.rodata); + sound/songs/midi/se_success.o(.rodata); + sound/songs/midi/se_failure.o(.rodata); + sound/songs/midi/se_exp.o(.rodata); + sound/songs/midi/se_bike_hop.o(.rodata); + sound/songs/midi/se_switch.o(.rodata); + sound/songs/midi/se_click.o(.rodata); + sound/songs/midi/se_fu_zaku.o(.rodata); + sound/songs/midi/se_contest_condition_lose.o(.rodata); + sound/songs/midi/se_lavaridge_fall_warp.o(.rodata); + sound/songs/midi/se_ice_stairs.o(.rodata); + sound/songs/midi/se_ice_break.o(.rodata); + sound/songs/midi/se_ice_crack.o(.rodata); + sound/songs/midi/se_fall.o(.rodata); + sound/songs/midi/se_unlock.o(.rodata); + sound/songs/midi/se_warp_in.o(.rodata); + sound/songs/midi/se_warp_out.o(.rodata); + sound/songs/midi/se_repel.o(.rodata); + sound/songs/midi/se_rotating_gate.o(.rodata); + sound/songs/midi/se_truck_move.o(.rodata); + sound/songs/midi/se_truck_stop.o(.rodata); + sound/songs/midi/se_truck_unload.o(.rodata); + sound/songs/midi/se_truck_door.o(.rodata); + sound/songs/midi/se_berry_blender.o(.rodata); + sound/songs/midi/se_save.o(.rodata); + sound/songs/midi/se_ball_bounce_1.o(.rodata); + sound/songs/midi/se_ball_bounce_2.o(.rodata); + sound/songs/midi/se_ball_bounce_3.o(.rodata); + sound/songs/midi/se_ball_bounce_4.o(.rodata); + sound/songs/midi/se_ball_trade.o(.rodata); + sound/songs/midi/se_ball_throw.o(.rodata); + sound/songs/midi/se_note_c.o(.rodata); + sound/songs/midi/se_note_d.o(.rodata); + sound/songs/midi/se_note_e.o(.rodata); + sound/songs/midi/se_note_f.o(.rodata); + sound/songs/midi/se_note_g.o(.rodata); + sound/songs/midi/se_note_a.o(.rodata); + sound/songs/midi/se_note_b.o(.rodata); + sound/songs/midi/se_note_c_high.o(.rodata); + sound/songs/midi/se_puddle.o(.rodata); + sound/songs/midi/se_bridge_walk.o(.rodata); + sound/songs/midi/se_itemfinder.o(.rodata); + sound/songs/midi/se_ding_dong.o(.rodata); + sound/songs/midi/se_balloon_red.o(.rodata); + sound/songs/midi/se_balloon_blue.o(.rodata); + sound/songs/midi/se_balloon_yellow.o(.rodata); + sound/songs/midi/se_breakable_door.o(.rodata); + sound/songs/midi/se_mud_ball.o(.rodata); + sound/songs/midi/se_field_poison.o(.rodata); + sound/songs/midi/se_escalator.o(.rodata); + sound/songs/midi/se_thunderstorm.o(.rodata); + sound/songs/midi/se_thunderstorm_stop.o(.rodata); + sound/songs/midi/se_downpour.o(.rodata); + sound/songs/midi/se_downpour_stop.o(.rodata); + sound/songs/midi/se_rain.o(.rodata); + sound/songs/midi/se_rain_stop.o(.rodata); + sound/songs/midi/se_thunder.o(.rodata); + sound/songs/midi/se_thunder2.o(.rodata); + sound/songs/midi/se_elevator.o(.rodata); + sound/songs/midi/se_low_health.o(.rodata); + sound/songs/midi/se_exp_max.o(.rodata); + sound/songs/midi/se_roulette_ball.o(.rodata); + sound/songs/midi/se_roulette_ball2.o(.rodata); + sound/songs/midi/se_taillow_wing_flap.o(.rodata); + sound/songs/midi/se_rs_shop.o(.rodata); + sound/songs/midi/se_contest_heart.o(.rodata); + sound/songs/midi/se_contest_curtain_rise.o(.rodata); + sound/songs/midi/se_contest_curtain_fall.o(.rodata); + sound/songs/midi/se_contest_icon_change.o(.rodata); + sound/songs/midi/se_contest_icon_clear.o(.rodata); + sound/songs/midi/se_contest_mons_turn.o(.rodata); + sound/songs/midi/se_shiny.o(.rodata); + sound/songs/midi/se_intro_blast.o(.rodata); + sound/songs/midi/se_mugshot.o(.rodata); + sound/songs/midi/se_applause.o(.rodata); + sound/songs/midi/se_vend.o(.rodata); + sound/songs/midi/se_orb.o(.rodata); + sound/songs/se_dex_scroll.o(.rodata); + sound/songs/se_dex_page.o(.rodata); + sound/songs/midi/se_pokenav_on.o(.rodata); + sound/songs/midi/se_pokenav_off.o(.rodata); + sound/songs/midi/se_dex_search.o(.rodata); + sound/songs/midi/se_egg_hatch.o(.rodata); + sound/songs/midi/se_ball_tray_enter.o(.rodata); + sound/songs/midi/se_ball_tray_ball.o(.rodata); + sound/songs/midi/se_ball_tray_exit.o(.rodata); + sound/songs/midi/se_glass_flute.o(.rodata); + sound/songs/se_m_thunderbolt.o(.rodata); + sound/songs/se_m_thunderbolt2.o(.rodata); + sound/songs/se_m_harden.o(.rodata); + sound/songs/se_m_nightmare.o(.rodata); + sound/songs/se_m_vital_throw.o(.rodata); + sound/songs/se_m_vital_throw2.o(.rodata); + sound/songs/se_m_bubble.o(.rodata); + sound/songs/se_m_bubble2.o(.rodata); + sound/songs/se_m_bubble3.o(.rodata); + sound/songs/se_m_rain_dance.o(.rodata); + sound/songs/midi/se_m_cut.o(.rodata); + sound/songs/se_m_string_shot.o(.rodata); + sound/songs/se_m_string_shot2.o(.rodata); + sound/songs/se_m_rock_throw.o(.rodata); + sound/songs/midi/se_m_gust.o(.rodata); + sound/songs/midi/se_m_gust2.o(.rodata); + sound/songs/midi/se_m_double_slap.o(.rodata); + sound/songs/se_m_double_team.o(.rodata); + sound/songs/midi/se_m_razor_wind.o(.rodata); + sound/songs/se_m_icy_wind.o(.rodata); + sound/songs/se_m_thunder_wave.o(.rodata); + sound/songs/midi/se_m_comet_punch.o(.rodata); + sound/songs/midi/se_m_mega_kick.o(.rodata); + sound/songs/midi/se_m_mega_kick2.o(.rodata); + sound/songs/se_m_crabhammer.o(.rodata); + sound/songs/midi/se_m_jump_kick.o(.rodata); + sound/songs/se_m_flame_wheel.o(.rodata); + sound/songs/se_m_flame_wheel2.o(.rodata); + sound/songs/se_m_flamethrower.o(.rodata); + sound/songs/midi/se_m_fire_punch.o(.rodata); + sound/songs/se_m_toxic.o(.rodata); + sound/songs/se_m_sacred_fire.o(.rodata); + sound/songs/se_m_sacred_fire2.o(.rodata); + sound/songs/se_m_ember.o(.rodata); + sound/songs/midi/se_m_take_down.o(.rodata); + sound/songs/se_m_blizzard.o(.rodata); + sound/songs/se_m_blizzard2.o(.rodata); + sound/songs/midi/se_m_scratch.o(.rodata); + sound/songs/midi/se_m_vicegrip.o(.rodata); + sound/songs/midi/se_m_wing_attack.o(.rodata); + sound/songs/midi/se_m_fly.o(.rodata); + sound/songs/midi/se_m_sand_attack.o(.rodata); + sound/songs/midi/se_m_razor_wind2.o(.rodata); + sound/songs/se_m_bite.o(.rodata); + sound/songs/midi/se_m_headbutt.o(.rodata); + sound/songs/se_m_surf.o(.rodata); + sound/songs/se_m_hydro_pump.o(.rodata); + sound/songs/se_m_whirlpool.o(.rodata); + sound/songs/midi/se_m_horn_attack.o(.rodata); + sound/songs/midi/se_m_tail_whip.o(.rodata); + sound/songs/se_m_mist.o(.rodata); + sound/songs/se_m_poison_powder.o(.rodata); + sound/songs/midi/se_m_bind.o(.rodata); + sound/songs/se_m_dragon_rage.o(.rodata); + sound/songs/se_m_sing.o(.rodata); + sound/songs/se_m_perish_song.o(.rodata); + sound/songs/midi/se_m_pay_day.o(.rodata); + sound/songs/se_m_dig.o(.rodata); + sound/songs/se_m_dizzy_punch.o(.rodata); + sound/songs/se_m_self_destruct.o(.rodata); + sound/songs/se_m_explosion.o(.rodata); + sound/songs/se_m_absorb_2.o(.rodata); + sound/songs/se_m_absorb.o(.rodata); + sound/songs/se_m_screech.o(.rodata); + sound/songs/se_m_bubble_beam.o(.rodata); + sound/songs/se_m_bubble_beam2.o(.rodata); + sound/songs/se_m_supersonic.o(.rodata); + sound/songs/se_m_belly_drum.o(.rodata); + sound/songs/se_m_metronome.o(.rodata); + sound/songs/se_m_bonemerang.o(.rodata); + sound/songs/se_m_lick.o(.rodata); + sound/songs/se_m_psybeam.o(.rodata); + sound/songs/se_m_faint_attack.o(.rodata); + sound/songs/midi/se_m_swords_dance.o(.rodata); + sound/songs/midi/se_m_leer.o(.rodata); + sound/songs/se_m_swagger.o(.rodata); + sound/songs/se_m_swagger2.o(.rodata); + sound/songs/se_m_heal_bell.o(.rodata); + sound/songs/se_m_confuse_ray.o(.rodata); + sound/songs/se_m_snore.o(.rodata); + sound/songs/se_m_brick_break.o(.rodata); + sound/songs/se_m_giga_drain.o(.rodata); + sound/songs/se_m_psybeam2.o(.rodata); + sound/songs/se_m_solar_beam.o(.rodata); + sound/songs/se_m_petal_dance.o(.rodata); + sound/songs/se_m_teleport.o(.rodata); + sound/songs/se_m_minimize.o(.rodata); + sound/songs/se_m_sketch.o(.rodata); + sound/songs/se_m_swift.o(.rodata); + sound/songs/se_m_reflect.o(.rodata); + sound/songs/se_m_barrier.o(.rodata); + sound/songs/se_m_detect.o(.rodata); + sound/songs/se_m_lock_on.o(.rodata); + sound/songs/se_m_moonlight.o(.rodata); + sound/songs/se_m_charm.o(.rodata); + sound/songs/se_m_charge.o(.rodata); + sound/songs/se_m_strength.o(.rodata); + sound/songs/se_m_hyper_beam.o(.rodata); + sound/songs/se_m_waterfall.o(.rodata); + sound/songs/se_m_reversal.o(.rodata); + sound/songs/se_m_acid_armor.o(.rodata); + sound/songs/se_m_sandstorm.o(.rodata); + sound/songs/se_m_tri_attack.o(.rodata); + sound/songs/se_m_tri_attack2.o(.rodata); + sound/songs/se_m_encore.o(.rodata); + sound/songs/se_m_encore2.o(.rodata); + sound/songs/se_m_baton_pass.o(.rodata); + sound/songs/se_m_milk_drink.o(.rodata); + sound/songs/se_m_attract.o(.rodata); + sound/songs/se_m_attract2.o(.rodata); + sound/songs/se_m_morning_sun.o(.rodata); + sound/songs/se_m_flatter.o(.rodata); + sound/songs/se_m_sand_tomb.o(.rodata); + sound/songs/se_m_grasswhistle.o(.rodata); + sound/songs/se_m_spit_up.o(.rodata); + sound/songs/se_m_dive.o(.rodata); + sound/songs/se_m_earthquake.o(.rodata); + sound/songs/se_m_twister.o(.rodata); + sound/songs/se_m_sweet_scent.o(.rodata); + sound/songs/se_m_yawn.o(.rodata); + sound/songs/se_m_sky_uppercut.o(.rodata); + sound/songs/se_m_stat_increase.o(.rodata); + sound/songs/se_m_heat_wave.o(.rodata); + sound/songs/se_m_uproar.o(.rodata); + sound/songs/se_m_hail.o(.rodata); + sound/songs/se_m_cosmic_power.o(.rodata); + sound/songs/se_m_teeter_dance.o(.rodata); + sound/songs/se_m_stat_decrease.o(.rodata); + sound/songs/se_m_haze.o(.rodata); + sound/songs/se_m_hyper_beam2.o(.rodata); + sound/songs/midi/se_door.o(.rodata); + sound/songs/se_card_flip.o(.rodata); + sound/songs/se_card_flipping.o(.rodata); + sound/songs/se_card_open.o(.rodata); + sound/songs/se_bag_cursor.o(.rodata); + sound/songs/se_bag_pocket.o(.rodata); + sound/songs/se_ball_click.o(.rodata); + sound/songs/se_shop.o(.rodata); + sound/songs/se_ss_anne_horn.o(.rodata); + sound/songs/se_help_open.o(.rodata); + sound/songs/se_help_close.o(.rodata); + sound/songs/se_help_error.o(.rodata); + sound/songs/se_deoxys_move.o(.rodata); + sound/songs/se_poke_jump_success.o(.rodata); + sound/songs/se_poke_jump_failure.o(.rodata); + sound/songs/midi/mus_heal.o(.rodata); + sound/songs/midi/mus_level_up.o(.rodata); + sound/songs/midi/mus_obtain_item.o(.rodata); + sound/songs/midi/mus_evolved.o(.rodata); + sound/songs/midi/mus_obtain_badge.o(.rodata); + sound/songs/midi/mus_obtain_tmhm.o(.rodata); + sound/songs/midi/mus_obtain_berry.o(.rodata); + sound/songs/midi/mus_evolution_intro.o(.rodata); + sound/songs/midi/mus_evolution.o(.rodata); + sound/songs/midi/mus_rs_vs_gym_leader.o(.rodata); + sound/songs/midi/mus_rs_vs_trainer.o(.rodata); + sound/songs/midi/mus_school.o(.rodata); + sound/songs/midi/mus_slots_jackpot.o(.rodata); + sound/songs/midi/mus_slots_win.o(.rodata); + sound/songs/midi/mus_move_deleted.o(.rodata); + sound/songs/midi/mus_too_bad.o(.rodata); + sound/songs/midi/mus_follow_me.o(.rodata); + sound/songs/midi/mus_game_corner.o(.rodata); + sound/songs/midi/mus_rocket_hideout.o(.rodata); + sound/songs/midi/mus_gym.o(.rodata); + sound/songs/midi/mus_jigglypuff.o(.rodata); + sound/songs/midi/mus_intro_fight.o(.rodata); + sound/songs/midi/mus_title.o(.rodata); + sound/songs/midi/mus_cinnabar.o(.rodata); + sound/songs/midi/mus_lavender.o(.rodata); + sound/songs/midi/mus_heal_unused.o(.rodata); + sound/songs/midi/mus_cycling.o(.rodata); + sound/songs/midi/mus_encounter_rocket.o(.rodata); + sound/songs/midi/mus_encounter_girl.o(.rodata); + sound/songs/midi/mus_encounter_boy.o(.rodata); + sound/songs/midi/mus_hall_of_fame.o(.rodata); + sound/songs/midi/mus_viridian_forest.o(.rodata); + sound/songs/midi/mus_mt_moon.o(.rodata); + sound/songs/midi/mus_poke_mansion.o(.rodata); + sound/songs/midi/mus_credits.o(.rodata); + sound/songs/midi/mus_route1.o(.rodata); + sound/songs/midi/mus_route24.o(.rodata); + sound/songs/midi/mus_route3.o(.rodata); + sound/songs/midi/mus_route11.o(.rodata); + sound/songs/midi/mus_victory_road.o(.rodata); + sound/songs/midi/mus_vs_gym_leader.o(.rodata); + sound/songs/midi/mus_vs_trainer.o(.rodata); + sound/songs/midi/mus_vs_wild.o(.rodata); + sound/songs/midi/mus_vs_champion.o(.rodata); + sound/songs/midi/mus_pallet.o(.rodata); + sound/songs/midi/mus_oak_lab.o(.rodata); + sound/songs/midi/mus_oak.o(.rodata); + sound/songs/midi/mus_poke_center.o(.rodata); + sound/songs/midi/mus_ss_anne.o(.rodata); + sound/songs/midi/mus_surf.o(.rodata); + sound/songs/midi/mus_poke_tower.o(.rodata); + sound/songs/midi/mus_silph.o(.rodata); + sound/songs/midi/mus_fuchsia.o(.rodata); + sound/songs/midi/mus_celadon.o(.rodata); + sound/songs/midi/mus_victory_trainer.o(.rodata); + sound/songs/midi/mus_victory_wild.o(.rodata); + sound/songs/midi/mus_victory_gym_leader.o(.rodata); + sound/songs/midi/mus_vermillion.o(.rodata); + sound/songs/midi/mus_pewter.o(.rodata); + sound/songs/midi/mus_encounter_rival.o(.rodata); + sound/songs/midi/mus_rival_exit.o(.rodata); + sound/songs/midi/mus_dex_rating.o(.rodata); + sound/songs/midi/mus_obtain_key_item.o(.rodata); + sound/songs/midi/mus_caught_intro.o(.rodata); + sound/songs/midi/mus_photo.o(.rodata); + sound/songs/midi/mus_game_freak.o(.rodata); + sound/songs/midi/mus_caught.o(.rodata); + sound/songs/midi/mus_new_game_instruct.o(.rodata); + sound/songs/midi/mus_new_game_intro.o(.rodata); + sound/songs/midi/mus_new_game_exit.o(.rodata); + sound/songs/midi/mus_poke_jump.o(.rodata); + sound/songs/midi/mus_union_room.o(.rodata); + sound/songs/midi/mus_net_center.o(.rodata); + sound/songs/midi/mus_mystery_gift.o(.rodata); + sound/songs/midi/mus_berry_pick.o(.rodata); + sound/songs/midi/mus_sevii_cave.o(.rodata); + sound/songs/midi/mus_teachy_tv_show.o(.rodata); + sound/songs/midi/mus_sevii_route.o(.rodata); + sound/songs/midi/mus_sevii_dungeon.o(.rodata); + sound/songs/midi/mus_sevii_123.o(.rodata); + sound/songs/midi/mus_sevii_45.o(.rodata); + sound/songs/midi/mus_sevii_67.o(.rodata); + sound/songs/midi/mus_poke_flute.o(.rodata); + sound/songs/midi/mus_vs_deoxys.o(.rodata); + sound/songs/midi/mus_vs_mewtwo.o(.rodata); + sound/songs/midi/mus_vs_legend.o(.rodata); + sound/songs/midi/mus_encounter_gym_leader.o(.rodata); + sound/songs/midi/mus_encounter_deoxys.o(.rodata); + sound/songs/midi/mus_trainer_tower.o(.rodata); + sound/songs/midi/mus_slow_pallet.o(.rodata); + sound/songs/midi/mus_teachy_tv_menu.o(.rodata); + } > ROM =0 + + lib_rodata : + SUBALIGN(4) + { + src/agb_flash.o(.rodata); + src/agb_flash_1m.o(.rodata); + src/agb_flash_mx.o(.rodata); + src/agb_flash_le.o(.rodata); + src/librfu_sio32id.o(.rodata); + src/isagbprn.o(.rodata); + *libgcc.a:_divdi3.o(.rodata); + *libgcc.a:_udivdi3.o(.rodata); + *libc.a:memcpy.o(.rodata); + *libc.a:memset.o(.rodata); + *libc.a:strcmp.o(.rodata); + *libc.a:strcpy.o(.rodata); + *libc.a:impure.o(.rodata); + *libc.a:vsprintf.o(.rodata); + *libc.a:vfprintf.o(.rodata); + *libc.a:wsetup.o(.rodata); + *libc.a:dtoa.o(.rodata); + *libc.a:fflush.o(.rodata); + *libc.a:findfp.o(.rodata); + *libc.a:freer.o(.rodata); + *libc.a:mtrim.o(.rodata); + *libc.a:fvwrite.o(.rodata); + *libc.a:fwalk.o(.rodata); + *libc.a:locale.o(.rodata); + *libc.a:makebuf.o(.rodata); + *libc.a:mallocr.o(.rodata); + *libc.a:mbtowc_r.o(.rodata); + *libc.a:memchr.o(.rodata); + *libc.a:memmove.o(.rodata); + *libc.a:mlock.o(.rodata); + *libc.a:mprec.o(.rodata); + *libc.a:s_isinf.o(.rodata); + *libc.a:s_isnan.o(.rodata); + *libc.a:sbrkr.o(.rodata); + *libc.a:stdio.o(.rodata); + *libc.a:strlen.o(.rodata); + *libc.a:syscalls.o(.rodata); + *libc.a:writer.o(.rodata); + *libc.a:callocr.o(.rodata); + *libc.a:closer.o(.rodata); + *libc.a:errno.o(.rodata); + *libc.a:fstatr.o(.rodata); + *libc.a:libcfunc.o(.rodata); + *libc.a:lseekr.o(.rodata); + *libc.a:readr.o(.rodata); + + . = ALIGN(4); + } > ROM =0 + + multiboot_data : + ALIGN(4) + { + data/multiboot_ereader.o(.rodata); + data/multiboot_berry_glitch_fix.o(.rodata); + data/multiboot_pokemon_colosseum.o(.rodata); + } > ROM =0 + + gfx_data 0x08D00000 : + ALIGN(4) + { + src/graphics.o(.rodata); + } > ROM =0 + + extra : + ALIGN(4) + { + src/*.o(.text); + src/*.o(.rodata); + data/*.o(.rodata); + } > ROM =0 + + + /* DWARF 2 sections */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + /* Discard everything not specifically mentioned above. */ + /DISCARD/ : + { + *(*); + } +} diff --git a/leafgreen_switch.sha1 b/leafgreen_switch.sha1 new file mode 100644 index 000000000..2a857a694 --- /dev/null +++ b/leafgreen_switch.sha1 @@ -0,0 +1 @@ +62b9fc77549dbc67032eb6cbd0ea6ad3b825690f pokeleafgreen_switch.gba diff --git a/src/AgbRfu_LinkManager.c b/src/AgbRfu_LinkManager.c index 0f0501393..35317ab86 100644 --- a/src/AgbRfu_LinkManager.c +++ b/src/AgbRfu_LinkManager.c @@ -1,6 +1,7 @@ #include "global.h" #include "librfu.h" #include "AgbRfu_LinkManager.h" +#include "sloopsvc.h" #define RN_ACCEPT 0x01 #define RN_NAME_TIMER_CLEAR 0x02 @@ -176,6 +177,9 @@ u8 rfu_LMAN_establishConnection(u8 parent_child, u16 connect_period, u16 name_ac } lman.parent_child = parent_child; lman.connect_period = connect_period; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif lman.nameAcceptTimer.count_max = name_accept_period; lman.acceptable_serialNo_list = acceptable_serialNo_list; return 0; @@ -222,6 +226,9 @@ u8 rfu_LMAN_CHILD_connectParent(u16 parentId, u16 connect_period) } lman.work = parentId; lman.connect_period = connect_period; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif if (lman.pcswitch_flag != 0) { lman.pcswitch_flag = PCSWITCH_CP; @@ -560,6 +567,9 @@ static void rfu_LMAN_settingPCSWITCH(u32 rand) lman.parent_child = MODE_PARENT; lman.state = LMAN_STATE_START_SEARCH_CHILD; lman.connect_period = lman.pcswitch_period_bak; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif if (lman.connect_period) { lman.pcswitch_flag = PCSWITCH_3RD_SC; @@ -573,8 +583,14 @@ static void rfu_LMAN_settingPCSWITCH(u32 rand) { lman.parent_child = MODE_PARENT; lman.state = LMAN_STATE_START_SEARCH_CHILD; +#if REVISION >= 0xA + lman.connect_period = rand % 285; + lman.pcswitch_period_bak = 285 - lman.connect_period; + lman.connect_period_initial = 0; +#else lman.connect_period = rand % 140; lman.pcswitch_period_bak = 140 - lman.connect_period; +#endif if (lman.connect_period) { lman.pcswitch_flag = PCSWITCH_1ST_SC; @@ -588,6 +604,9 @@ static void rfu_LMAN_settingPCSWITCH(u32 rand) { lman.parent_child = MODE_CHILD; lman.connect_period = PCSWITCH_SP_PERIOD; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif lman.pcswitch_flag = PCSWITCH_2ND_SP; lman.state = LMAN_STATE_START_SEARCH_PARENT; } @@ -632,11 +651,27 @@ static void rfu_LMAN_REQ_callback(u16 reqCommandId, u16 reqResult) } break; case ID_SC_POLL_REQ: +#if REVISION >= 0xA + if (lman.connect_period) + { + if (svc_49() != 0 && lman.connect_period_initial < 300) + { + if (lman.connect_period > 1) lman.connect_period--; + else lman.connect_period_initial++; + } + else if (--lman.connect_period == 0) + { + lman.state = LMAN_STATE_END_SEARCH_CHILD; + lman.next_state = LMAN_STATE_WAIT_RECV_CHILD_NAME; + } + } +#else if (lman.connect_period && --lman.connect_period == 0) { lman.state = LMAN_STATE_END_SEARCH_CHILD; lman.next_state = LMAN_STATE_WAIT_RECV_CHILD_NAME; } +#endif break; case ID_SC_END_REQ: if (reqResult == 0) @@ -679,11 +714,27 @@ static void rfu_LMAN_REQ_callback(u16 reqCommandId, u16 reqResult) lman.fastSearchParent_flag = FSP_ON; } } +#if REVISION >= 0xA + if (lman.connect_period) + { + if (svc_4a() != 0 && lman.connect_period_initial < 300) + { + if (lman.connect_period > 1) lman.connect_period--; + else lman.connect_period_initial++; + } + else if (--lman.connect_period == 0) + { + lman.state = LMAN_STATE_END_SEARCH_PARENT; + lman.next_state = LMAN_STATE_READY; + } + } +#else if (lman.connect_period && --lman.connect_period == 0) { lman.state = LMAN_STATE_END_SEARCH_PARENT; lman.next_state = LMAN_STATE_READY; } +#endif break; case ID_SP_END_REQ: if (reqResult == 0) @@ -1302,15 +1353,30 @@ static void rfu_LMAN_setLMANCallback(void (*func)(u8, u8)) u8 rfu_LMAN_setLinkRecovery(u8 enable_flag, u16 recovery_period) { +#if REVISION >= 0xA + u16 imeNew = 0; +#endif u16 imeBak; +#if REVISION >= 0xA + + imeBak = REG_IME; + REG_IME = imeNew; + + lman.linkRecovery_enable = FALSE; + lman.linkRecoveryTimer.count_max = recovery_period; +#else + if (lman.linkRecovery_enable && enable_flag == 0 && lman.linkRecoveryTimer.active) { return LMAN_ERROR_NOW_LINK_RECOVERY; } + imeBak = REG_IME; REG_IME = 0; + lman.linkRecovery_enable = enable_flag; lman.linkRecoveryTimer.count_max = recovery_period; +#endif REG_IME = imeBak; return 0; } @@ -1367,7 +1433,11 @@ void rfu_LMAN_requestChangeAgbClockMaster(void) } } +#if REVISION >= 0xA +void rfu_LMAN_forceChangeSP(bool8 child) +#else void rfu_LMAN_forceChangeSP(void) +#endif { if (lman.pcswitch_flag) { @@ -1387,10 +1457,22 @@ void rfu_LMAN_forceChangeSP(void) break; case LMAN_STATE_START_SEARCH_PARENT: case LMAN_STATE_POLL_SEARCH_PARENT: +#if REVISION >= 0xA + if (!child) break; +#endif lman.connect_period = PCSWITCH_SP_PERIOD; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif break; case LMAN_STATE_END_SEARCH_PARENT: +#if REVISION >= 0xA + if (!child) break; +#endif lman.connect_period = PCSWITCH_SP_PERIOD; +#if REVISION >= 0xA + lman.connect_period_initial = 0; +#endif lman.state = LMAN_STATE_POLL_SEARCH_PARENT; break; } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 1422fa13b..d8e1fe71e 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -819,10 +819,16 @@ static void SetLinkBattleEndCallbacks(void) void SetBattleEndCallbacks(void) { +#if REVISION >= 0xA +#else if (!gPaletteFade.active) +#endif { if (gBattleTypeFlags & BATTLE_TYPE_LINK) { +#if REVISION >= 0xA + if (!IsLinkTaskFinished() || gPaletteFade.active) return; +#endif if (gWirelessCommType == 0) SetCloseLinkCallback(); else diff --git a/src/battle_main.c b/src/battle_main.c index 4c3e927a0..64c9e59b7 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1160,7 +1160,11 @@ static void CB2_PreInitMultiBattle(void) } break; case 2: +#if REVISION >= 0xA + if (IsLinkTaskFinished() && !gPaletteFade.active) +#else if (!gPaletteFade.active) +#endif { gBattleCommunication[MULTIUSE_STATE]++; if (gWirelessCommType) @@ -3923,8 +3927,8 @@ static void ReturnFromBattleToOverworld(void) if (gBattleTypeFlags & BATTLE_TYPE_ROAMER) { UpdateRoamerHPStatus(&gEnemyParty[0]); -#ifdef BUGFIX - if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) +#if defined(BUGFIX) || REVISION >= 0xA + if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT || gBattleOutcome == B_OUTCOME_DREW) #else if ((gBattleOutcome & B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT) // Bug: When Roar is used by roamer, gBattleOutcome is B_OUTCOME_PLAYER_TELEPORTED (5). #endif // & with B_OUTCOME_WON (1) will return TRUE and deactivates the roamer. diff --git a/src/battle_message.c b/src/battle_message.c index 07c136029..aabbbcb9a 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1789,10 +1789,17 @@ static const u8 *TryGetStatusString(u8 *src) u8 *statusPtr; statusPtr = status; +#if REVISION >= 0xA + for (i = 0; i < 8 && *src != EOS; i++) +#else for (i = 0; i < 8; i++) +#endif { +#if REVISION >= 0xA +#else if (*src == EOS) break; +#endif *statusPtr = *src; src++; statusPtr++; diff --git a/src/cable_club.c b/src/cable_club.c index 23c9b940a..d2f61cdcf 100644 --- a/src/cable_club.c +++ b/src/cable_club.c @@ -718,6 +718,9 @@ static void Task_StartWirelessCableClubBattle(u8 taskId) tState = 5; break; case 5: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif SetLinkStandbyCallback(); tState = 6; break; @@ -920,6 +923,9 @@ static void Task_StartWirelessTrade(u8 taskId) tState++; break; case 2: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif gSelectedTradeMonPositions[TRADE_PLAYER] = 0; gSelectedTradeMonPositions[TRADE_PARTNER] = 0; m4aMPlayAllStop(); @@ -996,7 +1002,11 @@ bool32 GetSeeingLinkPlayerCardMsg(u8 linkPlayerIndex) void Task_WaitForLinkPlayerConnection(u8 taskId) { struct Task *task = &gTasks[taskId]; +#if REVISION >= 0xA + if (++task->tTimer > 480) +#else if (++task->tTimer > 300) +#endif { CloseLink(); SetMainCallback2(CB2_LinkError); diff --git a/src/event_object_movement.c b/src/event_object_movement.c index d2bffe5ec..8110c247a 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -1495,10 +1495,18 @@ static bool8 GetAvailableObjectEventId(u16 localId, u8 mapNum, u8 mapGroup, u8 * { u8 i = 0; +#if REVISION >= 0xA + for (i = 0; i < OBJECT_EVENTS_COUNT && gObjectEvents[i].active; i++) +#else for (i = 0; i < OBJECT_EVENTS_COUNT; i++) +#endif { + +#if REVISION >= 0xA +#else if (!gObjectEvents[i].active) break; +#endif if (gObjectEvents[i].localId == localId && gObjectEvents[i].mapNum == mapNum && gObjectEvents[i].mapGroup == mapGroup) return TRUE; } diff --git a/src/field_fadetransition.c b/src/field_fadetransition.c index 4b0b40bcc..f392a06d5 100644 --- a/src/field_fadetransition.c +++ b/src/field_fadetransition.c @@ -207,6 +207,9 @@ static void Task_ReturnToFieldRecordMixing(u8 taskId) switch (task->data[0]) { case 0: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif SetLinkStandbyCallback(); task->data[0]++; break; diff --git a/src/fldeff_poison.c b/src/fldeff_poison.c index 1e609caf4..f43a9eb77 100644 --- a/src/fldeff_poison.c +++ b/src/fldeff_poison.c @@ -10,7 +10,11 @@ static void Task_FieldPoisonEffect(u8 taskId) switch (data[0]) { case 0: +#if REVISION >= 0xA + data[1] += 2; +#else data[1] += 1; +#endif if (data[1] > 4) data[0]++; break; diff --git a/src/intro.c b/src/intro.c index 3d0caef72..bec0f3144 100644 --- a/src/intro.c +++ b/src/intro.c @@ -922,7 +922,12 @@ static bool8 SetUpCopyrightScreen(void) SetGpuReg(REG_OFFSET_BLDCNT, 0); SetGpuReg(REG_OFFSET_BLDALPHA, 0); SetGpuReg(REG_OFFSET_BLDY, 0); +// "Fade from white" instead is just pure black in Revision 10. +#if REVISION >= 0xA + ((vu16*)PLTT)[0] = RGB_BLACK; +#else ((vu16*)PLTT)[0] = RGB_WHITE; +#endif SetGpuReg(REG_OFFSET_DISPCNT, 0); SetGpuReg(REG_OFFSET_BG0HOFS, 0); SetGpuReg(REG_OFFSET_BG0VOFS, 0); @@ -935,7 +940,11 @@ static bool8 SetUpCopyrightScreen(void) ResetTasks(); ResetSpriteData(); FreeAllSpritePalettes(); +#if REVISION >= 0xA + BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); +#else BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_WHITEALPHA); +#endif SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(7)); EnableInterrupts(INTR_FLAG_VBLANK); SetVBlankCallback(VBlankCB_Copyright); diff --git a/src/isagbprn.c b/src/isagbprn.c index a038814e7..5890e764f 100644 --- a/src/isagbprn.c +++ b/src/isagbprn.c @@ -31,7 +31,8 @@ struct AGBPrintStruct typedef void (*LPFN_PRINT_FLUSH)(void); -#ifndef NDEBUG +// Revision 10 still has this code present, despite only the init function ever being used. +#if !defined(NDEBUG) || REVISION >= 0xA // AGBPrint print functions #if (LOG_HANDLER == LOG_HANDLER_AGB_PRINT) diff --git a/src/librfu_rfu.c b/src/librfu_rfu.c index 0bfa13abb..909903eca 100644 --- a/src/librfu_rfu.c +++ b/src/librfu_rfu.c @@ -1,5 +1,6 @@ #include #include "librfu.h" +#include "sloopsvc.h" struct LLSFStruct { @@ -381,6 +382,9 @@ void rfu_REQ_stopMode(void) REG_SIOCNT = SIO_MULTI_MODE; rfu_STC_REQ_callback(ID_STOP_MODE_REQ, 0); } +#if REVISION >= 0xA + svc_44(); +#endif } } @@ -461,6 +465,9 @@ void rfu_REQ_configGameData(u8 mbootFlag, u16 serialNo, const u8 *gname, const u packet[14] = 0; STWI_set_Callback_M(rfu_CB_configGameData); STWI_send_GameConfigREQ(packet, uname); +#if REVISION >= 0xA + svc_47(); +#endif } static void rfu_CB_configGameData(u8 reqCommand, u16 reqResult) @@ -519,6 +526,9 @@ void rfu_REQ_startSearchChild(void) } STWI_set_Callback_M(rfu_CB_startSearchChild); STWI_send_SC_StartREQ(); +#if REVISION >= 0xA + svc_42(); +#endif } static void rfu_CB_startSearchChild(u8 reqCommand, u16 reqResult) @@ -630,7 +640,11 @@ static void rfu_STC_readChildList(void) gRfuStatic->cidBak[bm_slot_id] = gRfuLinkStatus->partner[bm_slot_id].id; } #else +#if REVISION >= 0xA + gRfuStatic->lsFixedCount[bm_slot_id] = 0x3C; +#else gRfuStatic->lsFixedCount[bm_slot_id] = 0xF0; +#endif gRfuLinkStatus->strength[bm_slot_id] = 16; gRfuLinkStatus->connSlotFlag |= 1 << bm_slot_id; ++gRfuLinkStatus->connCount; @@ -649,6 +663,9 @@ void rfu_REQ_startSearchParent(void) { STWI_set_Callback_M(rfu_CB_startSearchParent); STWI_send_SP_StartREQ(); +#if REVISION >= 0xA + svc_45_rfu_link_status(); +#endif } static void rfu_CB_startSearchParent(u8 reqCommand, u16 reqResult) @@ -703,8 +720,13 @@ static void rfu_STC_readParentCandidateList(void) } if (my_check_sum == check_sum) { +#if REVISION >= 0xA + target = &gRfuLinkStatus->partner[gRfuLinkStatus->findParentCount]; + packet_p -= 28; +#else packet_p -= 28; target = &gRfuLinkStatus->partner[gRfuLinkStatus->findParentCount]; +#endif target->id = *(u16 *)packet_p; packet_p += 2; target->slot = *packet_p; @@ -723,6 +745,9 @@ static void rfu_STC_readParentCandidateList(void) ++gRfuLinkStatus->findParentCount; } } +#if REVISION >= 0xA + svc_45_rfu_link_status(); +#endif } void rfu_REQ_startConnectParent(u16 pid) @@ -738,6 +763,9 @@ void rfu_REQ_startConnectParent(u16 pid) gRfuStatic->tryPid = pid; STWI_set_Callback_M(rfu_STC_REQ_callback); STWI_send_CP_StartREQ(pid); +#if REVISION >= 0xA + svc_43(pid); +#endif } else { @@ -756,7 +784,11 @@ static void rfu_CB_pollConnectParent(u8 reqCommand, u16 reqResult) u16 id; u8 slot; u8 bm_slot_flag, i; +#if REVISION >= 0xA + struct RfuTgtData *target_p = NULL; +#else struct RfuTgtData *target_p; +#endif struct RfuTgtData target_local; if (reqResult == 0) @@ -1392,7 +1424,11 @@ static u16 rfu_STC_setSendData_org(u8 ni_or_uni, u8 bmSendSlot, u8 subFrameSize, { u8 bm_slot_id, sendSlotFlag; u8 frameSize; +#if REVISION >= 0xA + u8 *llFrameSize_p = NULL; +#else u8 *llFrameSize_p; +#endif u8 sending; u8 i; u16 imeBak; diff --git a/src/link.c b/src/link.c index 959264a40..84506bf0e 100644 --- a/src/link.c +++ b/src/link.c @@ -24,6 +24,7 @@ #include "reset_save_heap.h" #include "constants/battle.h" #include "constants/songs.h" +#include "sloopsvc.h" extern u16 gHeldKeyCodeToSend; @@ -67,7 +68,10 @@ COMMON_DATA u32 gLinkDebugSeed = 0; COMMON_DATA struct LinkPlayerBlock gLocalLinkPlayerBlock = {0}; COMMON_DATA bool8 gLinkErrorOccurred = 0; COMMON_DATA u32 gLinkDebugFlags = 0; +#if REVISION >= 0xA +#else COMMON_DATA u32 gLinkFiller1 = 0; +#endif COMMON_DATA bool8 gRemoteLinkPlayersNotReceived[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u8 gBlockReceivedStatus[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u32 gLinkFiller2 = 0; @@ -85,14 +89,21 @@ COMMON_DATA u8 gSavedLinkPlayerCount = 0; COMMON_DATA u16 gSendCmd[CMD_LENGTH] = {0}; COMMON_DATA u8 gSavedMultiplayerId = 0; COMMON_DATA bool8 gReceivedRemoteLinkPlayers = 0; +#if REVISION >= 0xA +// all references to this are gone anyway +#else COMMON_DATA struct LinkTestBGInfo gLinkTestBGInfo = {0}; +#endif COMMON_DATA void (*gLinkCallback)(void) = NULL; COMMON_DATA u8 gShouldAdvanceLinkState = 0; COMMON_DATA u16 gLinkTestBlockChecksums[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u8 gBlockRequestType = 0; COMMON_DATA u32 gLinkFiller3 = 0; // file +#if REVISION >= 0xA +#else COMMON_DATA u32 gLinkFiller4 = 0; // boundary COMMON_DATA u32 gLinkFiller5 = 0; // here? +#endif COMMON_DATA u8 gLastSendQueueCount = 0; COMMON_DATA struct Link gLink = {0}; COMMON_DATA u8 gLastRecvQueueCount = 0; @@ -118,6 +129,9 @@ EWRAM_DATA struct { static EWRAM_DATA u16 sReadyCloseLinkAttempts = 0; // never read static EWRAM_DATA void *sLinkErrorBgTilemapBuffer = NULL; +void Task_WirelessCommunicationScreen(u8 taskId); +void Task_MysteryGift(u8 taskId); + static void InitLocalLinkPlayer(void); static void VBlankCB_LinkError(void); static void CB2_LinkTest(void); @@ -131,7 +145,6 @@ static void LinkCB_BlockSendEnd(void); static void SetBerryBlenderLinkCallback(void); static void SetBlockReceivedFlag(u8 id); static u16 LinkTestCalcBlockChecksum(const u16 *src, u16 size); -static void LinkTest_PrintHex(u32 pos, u8 a0, u8 a1, u8 a2); static void LinkCB_RequestPlayerDataExchange(void); static void Task_PrintTestData(u8 taskId); static void LinkCB_ReadyCloseLink(void); @@ -155,11 +168,19 @@ static void DoSend(void); static void StopTimer(void); static void SendRecvDone(void); +#if REVISION >= 0xA +#else +static void LinkTest_PrintHex(u32 pos, u8 a0, u8 a1, u8 a2); +#endif + static const u16 sWirelessLinkDisplayPal[] = INCBIN_U16("graphics/link/wireless_display.gbapal"); static const u16 sWirelessLinkDisplayGfx[] = INCBIN_U16("graphics/link/wireless_display.4bpp.lz"); static const u16 sWirelessLinkDisplayTilemap[] = INCBIN_U16("graphics/link/wireless_display.bin.lz"); +#if REVISION >= 0xA +#else static const u16 sLinkTestFontPal[] = INCBIN_U16("graphics/link/test_font.gbapal"); static const u16 sLinkTestFontGfx[] = INCBIN_U16("graphics/link/test_font.4bpp"); +#endif static const struct BlockRequest sBlockRequests[] = { [BLOCK_REQ_SIZE_NONE] = { gBlockSendBuffer, 200 }, @@ -169,7 +190,11 @@ static const struct BlockRequest sBlockRequests[] = { [BLOCK_REQ_SIZE_40] = { gBlockSendBuffer, 40 } }; static const char sASCIIGameFreakInc[] = "GameFreak inc."; + +#if REVISION >= 0xA +#else static const char sASCIITestPrint[] = "TEST PRINT\nP0\nP1\nP2\nP3"; +#endif static const struct BgTemplate sLinkErrorBgTemplates[] = { { @@ -240,6 +265,9 @@ void Task_DestroySelf(u8 taskId) DestroyTask(taskId); } +#if REVISION >= 0xA +// Gone in this rev. +#else void InitLinkTestBG(u8 paletteNum, u8 bgNum, u8 screenBaseBlock, u8 charBaseBlock, u16 baseChar) { LoadPalette(sLinkTestFontPal, BG_PLTT_ID(paletteNum), PLTT_SIZE_4BPP); @@ -273,6 +301,7 @@ static void LoadLinkTestBgGfx(u8 paletteNum, u8 bgNum, u8 screenBaseBlock, u8 ch gLinkTestBGInfo.baseChar = 0; SetGpuReg(gBGControlRegOffsets[bgNum], BGCNT_SCREENBASE(screenBaseBlock) | BGCNT_CHARBASE(charBaseBlock)); } +#endif // Unused static void LinkTestScreen(void) @@ -290,7 +319,10 @@ static void LinkTestScreen(void) for (i = 0; i < TRAINER_ID_LENGTH; i++) gSaveBlock2Ptr->playerTrainerId[i] = Random() % 256; +#if REVISION >= 0xA +#else InitLinkTestBG(0, 2, 4, 0, 0); +#endif SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_BG2_ON | DISPCNT_OBJ_ON); CreateTask(Task_DestroySelf, 0); RunTasks(); @@ -400,14 +432,20 @@ static void TestBlockTransfer(u8 unused0, u8 unused1, u8 unused2) if (sLinkTestLastBlockSendPos != sBlockSend.pos) { +#if REVISION >= 0xA +#else LinkTest_PrintHex(sBlockSend.pos, 2, 3, 2); +#endif sLinkTestLastBlockSendPos = sBlockSend.pos; } for (i = 0; i < MAX_LINK_PLAYERS; i++) { if (sLinkTestLastBlockRecvPos[i] != sBlockRecv[i].pos) { +#if REVISION >= 0xA +#else LinkTest_PrintHex(sBlockRecv[i].pos, 2, i + 4, 2); +#endif sLinkTestLastBlockRecvPos[i] = sBlockRecv[i].pos; } } @@ -450,8 +488,11 @@ static void LinkTestProcessKeyInput(void) if (JOY_NEW(SELECT_BUTTON)) SetCloseLinkCallback(); +#if REVISION >= 0xA +#else if (sLinkTestDebugValuesEnabled) SetLinkDebugValues(gMain.vblankCounter2, gLinkCallback ? gLinkVSyncDisabled : gLinkVSyncDisabled | 0x10); +#endif } static void CB2_LinkTest(void) @@ -1025,6 +1066,8 @@ static u16 LinkTestCalcBlockChecksum(const u16 *src, u16 size) return checksum; } +#if REVISION >= 0xA +#else static void LinkTest_PrintNumChar(char val, u8 x, u8 y) { u16 *vAddr; @@ -1080,6 +1123,7 @@ static void LinkTest_PrintString(const char *str, u8 x, u8 y) } } } +#endif static void LinkCB_RequestPlayerDataExchange(void) { @@ -1091,6 +1135,9 @@ static void LinkCB_RequestPlayerDataExchange(void) static void Task_PrintTestData(u8 taskId) { +#if REVISION >= 0xA + // This function performs no operation in this revision. +#else char testTitle[32]; int i; @@ -1113,13 +1160,17 @@ static void Task_PrintTestData(u8 taskId) for (i = 0; i < MAX_LINK_PLAYERS; i++) LinkTest_PrintHex(gLinkTestBlockChecksums[i], 10, 4 + i, 4); +#endif } +#if REVISION >= 0xA +#else void SetLinkDebugValues(u32 seed, u32 flags) { gLinkDebugSeed = seed; gLinkDebugFlags = flags; } +#endif u8 GetSavedLinkPlayerCountAsBitFlags(void) { @@ -1374,6 +1425,9 @@ void CB2_LinkError(void) { u8 *tilemapBuffer; +#if REVISION >= 0xA + ClearFieldCallback(); +#endif SetGpuReg(REG_OFFSET_DISPCNT, 0); m4aMPlayStop(&gMPlayInfo_SE1); m4aMPlayStop(&gMPlayInfo_SE2); @@ -1387,8 +1441,11 @@ void CB2_LinkError(void) ScanlineEffect_Stop(); if (gWirelessCommType) { +#if REVISION >= 0xA +#else if (!sLinkErrorBuffer.disconnected) gWirelessCommType = 3; +#endif ResetLinkRfuGFLayer(); } @@ -1457,7 +1514,15 @@ static void CB2_PrintErrorMessage(void) case 0: // Below is only true for the RFU, so the other error // type is inferred to be from a wired connection +#if REVISION >= 0xA + svc_IncrementLinkError(); +#endif + +#if REVISION >= 0xA + if (sLinkErrorBuffer.disconnected || gWirelessCommType != 0) +#else if (sLinkErrorBuffer.disconnected) +#endif ErrorMsg_MoveCloserToPartner(); else ErrorMsg_CheckConnections(); @@ -1472,7 +1537,11 @@ static void CB2_PrintErrorMessage(void) PlaySE(SE_BOO); break; case 130: +#if REVISION >= 0xA + if (gWirelessCommType == 2 || gWirelessCommType == 3) +#else if (gWirelessCommType == 2) +#endif AddTextPrinterParameterized3(0, FONT_NORMAL_COPY_2, 2, 20, sLinkErrorTextColor, 0, gText_ABtnTitleScreen); else if (gWirelessCommType == 1) AddTextPrinterParameterized3(0, FONT_NORMAL_COPY_2, 2, 20, sLinkErrorTextColor, 0, gText_ABtnRegistrationCounter); @@ -1491,7 +1560,11 @@ static void CB2_PrintErrorMessage(void) ReloadSave(); } } +#if REVISION >= 0xA + else if (gWirelessCommType == 2 || gWirelessCommType == 3) +#else else if (gWirelessCommType == 2) +#endif { if (JOY_NEW(A_BUTTON)) { @@ -1576,8 +1649,33 @@ bool8 HandleLinkConnection(void) } else { +#if REVISION >= 0xA + bool32 reloadOrReset = FALSE; + if (svc_51()) + { +// Documentation issue: +// Rfu_IsMaster supposedly returns bool8, but just returns gRfu.ParentChild +// That value has three states, see librfu.h. One of those states is MODE_NEUTRAL (0xFF) which means init. +// So the last condition basically means "rfu link status is connected, not initialising". +// As in, it's true if value is MODE_CHILD or MODE_PARENT but not MODE_NEUTRAL (because unsigned cmp). + if (!FuncIsActiveTask(Task_WirelessCommunicationScreen) && (InUnionRoom() || gReceivedRemoteLinkPlayers != 0 || Rfu_IsMaster() <= MODE_PARENT)) + { + reloadOrReset = TRUE; + } + CloseLink(); + } +#endif main1Failed = RfuMain1(); // Always returns FALSE main2Failed = RfuMain2(); +#if REVISION >= 0xA + if (reloadOrReset) + { + // If active task is mystery gift then soft reset, otherwise reload the save. + if (FuncIsActiveTask(Task_MysteryGift)) RfuSoftReset(); + else RfuReloadSave(); + } + else +#endif if (IsSendingKeysOverCable() == TRUE) { // This will never be reached. diff --git a/src/link_rfu_2.c b/src/link_rfu_2.c index 2a58279c0..78087d76f 100644 --- a/src/link_rfu_2.c +++ b/src/link_rfu_2.c @@ -11,6 +11,12 @@ #include "task.h" #include "constants/union_room.h" +#include "sloopsvc.h" +#include "help_system.h" +#include "reset_save_heap.h" +#include "m4a.h" +#include "gba/m4a_internal.h" + enum { RFUSTATE_INIT, RFUSTATE_INIT_END, @@ -71,14 +77,25 @@ struct RfuDebug static EWRAM_DATA INIT_PARAM sRfuReqConfig = {}; static EWRAM_DATA struct RfuDebug sRfuDebug = {}; +#if REVISION >= 0xA +#else static u32 sRfuAPIBuffer[RFU_API_BUFF_SIZE_RAM / 4]; +#endif static u8 sResendBlock8[CMD_LENGTH * 2]; static u16 sResendBlock16[CMD_LENGTH]; +#if REVISION >= 0xA +COMMON_DATA u32 sRfuAPIBuffer[RFU_API_BUFF_SIZE_RAM / 4] = {0}; +#endif COMMON_DATA struct RfuGameData gHostRfuGameData = {0}; COMMON_DATA struct RfuManager gRfu = {0}; COMMON_DATA u8 gHostRfuUsername[PLAYER_NAME_LENGTH + 1] = {0}; +#if REVISION >= 0xA +u16 ReadU16(const void* ptr); +#else +static u16 ReadU16(const void *ptr); +#endif static void InitChildRecvBuffers(void); static void InitParentSendData(void); static void MscCallback_Child(u16 REQ_commandID); @@ -92,7 +109,6 @@ static void SendNextBlock(void); static void SendLastBlock(void); static void CallRfuFunc(void); static void UpdateChildStatuses(void); -static s32 GetJoinGroupStatus(void); static void Task_PlayerExchange(u8 taskId); static void ClearSelectedLinkPlayerIds(u16 disconnectMask); static void ValidateAndReceivePokemonSioInfo(void *recvBuffer); @@ -118,8 +134,13 @@ static const INIT_PARAM sRfuReqConfigTemplate = { .userName = gHostRfuUsername, .fastSearchParent_flag = TRUE, .linkRecovery_enable = FALSE, +#if REVISION >= 0xA + .linkRecovery_period = 720, + .NI_failCounter_limit = 480 +#else .linkRecovery_period = 600, .NI_failCounter_limit = 300 +#endif }; static const u8 sAvailSlots[] = { @@ -317,7 +338,11 @@ static void Task_ParentSearchForChildren(u8 taskId) case RFUSTATE_INIT_END: break; case RFUSTATE_PARENT_CONNECT: +#if REVISION >= 0xA + rfu_LMAN_establishConnection(gRfu.parentChild, 0, 360, (u16 *)sAcceptedSerialNos); +#else rfu_LMAN_establishConnection(gRfu.parentChild, 0, 240, (u16 *)sAcceptedSerialNos); +#endif gRfu.state = RFUSTATE_PARENT_CONNECT_END; gTasks[taskId].data[1] = 6; break; @@ -404,7 +429,11 @@ static void Task_ChildSearchForParent(u8 taskId) case RFUSTATE_INIT_END: break; case RFUSTATE_CHILD_CONNECT: +#if REVISION >= 0xA + rfu_LMAN_establishConnection(gRfu.parentChild, 0, 360, (u16 *)sAcceptedSerialNos); +#else rfu_LMAN_establishConnection(gRfu.parentChild, 0, 240, (u16 *)sAcceptedSerialNos); +#endif gRfu.state = RFUSTATE_CHILD_CONNECT_END; gTasks[taskId].data[1] = 7; break; @@ -491,7 +520,11 @@ static void Task_UnionRoomListen(u8 taskId) case RFUSTATE_INIT_END: break; case RFUSTATE_UR_CONNECT: +#if REVISION >= 0xA + rfu_LMAN_establishConnection(MODE_P_C_SWITCH, 0, 360, (u16 *)sAcceptedSerialNos); +#else rfu_LMAN_establishConnection(MODE_P_C_SWITCH, 0, 240, (u16 *)sAcceptedSerialNos); +#endif rfu_LMAN_setMSCCallback(MscCallback_Child); gRfu.state = RFUSTATE_UR_CONNECT_END; break; @@ -532,7 +565,11 @@ static void Task_UnionRoomListen(u8 taskId) void LinkRfu_CreateConnectionAsParent(void) { +#if REVISION >= 0xA + rfu_LMAN_establishConnection(MODE_PARENT, 0, 360, (u16 *)sAcceptedSerialNos); +#else rfu_LMAN_establishConnection(MODE_PARENT, 0, 240, (u16 *)sAcceptedSerialNos); +#endif } void LinkRfu_StopManagerBeforeEnteringChat(void) @@ -540,6 +577,14 @@ void LinkRfu_StopManagerBeforeEnteringChat(void) rfu_LMAN_stopManager(FALSE); } +#if REVISION >= 0xA +void LinkRfu_ForceChangeSpParent(void) +{ + if (gRfu.parentId != 0) return; + rfu_LMAN_forceChangeSP(FALSE); +} +#endif + // Argument is provided by the RFU and is unused. static void MscCallback_Child(u16 REQ_commandID) { @@ -576,6 +621,9 @@ void LinkRfu_Shutdown(void) return; rfu_LMAN_powerDownRFU(); +#if REVISION >= 0xA + svc_44(); +#endif if (gRfu.parentChild == MODE_PARENT) { // Stop parent searching for children @@ -629,7 +677,11 @@ static bool8 CanTryReconnectParent(void) static bool32 TryReconnectParent(void) { +#if REVISION >= 0xA + if (gRfu.state == RFUSTATE_CHILD_CONNECT_END && !rfu_LMAN_CHILD_connectParent(gRfuLinkStatus->partner[gRfu.reconnectParentId].id, 360)) +#else if (gRfu.state == RFUSTATE_CHILD_CONNECT_END && !rfu_LMAN_CHILD_connectParent(gRfuLinkStatus->partner[gRfu.reconnectParentId].id, 240)) +#endif { gRfu.state = RFUSTATE_RECONNECTED; return TRUE; @@ -823,14 +875,25 @@ static bool32 RfuMain2_Parent(void) { if (gRfu.childRecvBuffer[i][1]) { +#if REVISION >= 0xA + u8* childRecvBuffer = gRfu.childRecvBuffer[i]; + u8 newChildRecvId = childRecvBuffer[0] / 32; + u8* oldChildRecvId = &gRfu.childRecvIds[i]; + if (*oldChildRecvId != 0xFF && newChildRecvId != ((*oldChildRecvId + 1) & 7)) +#else if (gRfu.childRecvIds[i] != 0xFF && (gRfu.childRecvBuffer[i][0] >> 5) != ((gRfu.childRecvIds[i] + 1) & 7)) +#endif { if (++gRfu.numChildRecvErrors[i] > 4) RfuSetErrorParams(F_RFU_ERROR_8 | F_RFU_ERROR_1); } else { +#if REVISION >= 0xA + gRfu.childRecvIds[i] = newChildRecvId; +#else gRfu.childRecvIds[i] = gRfu.childRecvBuffer[i][0] / 32; +#endif gRfu.numChildRecvErrors[i] = 0; gRfu.childRecvBuffer[i][0] &= 0x1f; r0 = gRfu.linkPlayerIdx[i]; @@ -1386,6 +1449,9 @@ static void TryDisconnectRfu(void) { rfu_LMAN_requestChangeAgbClockMaster(); gRfu.disconnectMode = RFU_DISCONNECT_NORMAL; +#if REVISION >= 0xA + svc_44(); +#endif } else gRfu.callback = DisconnectRfu; @@ -1396,6 +1462,9 @@ void LinkRfu_FatalError(void) rfu_LMAN_requestChangeAgbClockMaster(); gRfu.disconnectMode = RFU_DISCONNECT_ERROR; gRfu.disconnectSlots = gRfuLinkStatus->connSlotFlag | gRfuLinkStatus->linkLossSlotFlag; +#if REVISION >= 0xA + svc_44(); +#endif } // RFU equivalent of LinkCB_WaitCloseLink @@ -1547,7 +1616,11 @@ u8 Rfu_SetLinkRecovery(bool32 enable) { if (!enable) return rfu_LMAN_setLinkRecovery(FALSE, 0); +#if REVISION >= 0xA + rfu_LMAN_setLinkRecovery(TRUE, 720); +#else rfu_LMAN_setLinkRecovery(TRUE, 600); +#endif return 0; } @@ -1586,8 +1659,11 @@ static bool8 CheckForLeavingGroupMembers(void) bool8 memberLeft = FALSE; for (i = 0; i < RFU_CHILD_MAX; i++) { +#if REVISION >= 0xA +#else if (gRfu.partnerSendStatuses[i] < RFU_STATUS_JOIN_GROUP_OK || gRfu.partnerSendStatuses[i] > RFU_STATUS_JOIN_GROUP_NO) +#endif { if (gRfuSlotStatusNI[i]->recv.state == SLOT_STATE_RECV_SUCCESS || gRfuSlotStatusNI[i]->recv.state == SLOT_STATE_RECV_SUCCESS_AND_SENDSIDE_UNKNOWN) @@ -1596,7 +1672,11 @@ static bool8 CheckForLeavingGroupMembers(void) { gRfu.partnerSendStatuses[i] = RFU_STATUS_LEAVE_GROUP; gRfu.partnerRecvStatuses[i] = RFU_STATUS_CHILD_LEAVE_READY; +#if REVISION >= 0xA + rfu_clearSlot(TYPE_NI_SEND | TYPE_NI_RECV, i); +#else rfu_clearSlot(TYPE_NI_RECV, i); +#endif rfu_NI_setSendData(1 << i, 8, &gRfu.partnerSendStatuses[i], 1); memberLeft = TRUE; } @@ -1624,6 +1704,12 @@ bool32 RfuTryDisconnectLeavingChildren(void) childrenLeaving |= (1 << i); gRfu.partnerRecvStatuses[i] = RFU_STATUS_OK; } +#if REVISION >= 0xA + if (((gRfuLinkStatus->connSlotFlag >> i) & 1) == 0) + { + gRfu.partnerRecvStatuses[i] = RFU_STATUS_OK; + } +#endif } // Disconnect any leaving children @@ -1665,6 +1751,9 @@ void SendLeaveGroupNotice(void) { gRfu.sendStatus = RFU_STATUS_LEAVE_GROUP_NOTICE; rfu_clearSlot(TYPE_NI_SEND, gRfu.childSlot); +#if REVISION >= 0xA + gRfuLinkStatus->remainLLFrameSizeChild[gRfu.childSlot] = 16; +#endif rfu_NI_setSendData(1 << gRfu.childSlot, 8, &gRfu.sendStatus, 1); } @@ -1695,7 +1784,7 @@ static void UpdateChildStatuses(void) } } -static s32 GetJoinGroupStatus(void) +s32 GetJoinGroupStatus(void) { s32 status = RFU_STATUS_OK; if (gRfu.sendStatus == RFU_STATUS_LEAVE_GROUP_NOTICE) @@ -1789,7 +1878,11 @@ static void Task_PlayerExchange(u8 taskId) DestroyTask(taskId); gReceivedRemoteLinkPlayers = TRUE; gRfu.playerExchangeActive = FALSE; +#if REVISION >= 0xA + rfu_LMAN_setLinkRecovery(1, 720); +#else rfu_LMAN_setLinkRecovery(1, 600); +#endif if (gRfu.newChildQueue) { for (i = 0; i < RFU_CHILD_MAX; i++) @@ -2017,6 +2110,12 @@ bool32 RfuMain1(void) { bool32 retval = FALSE; gRfu.parentId = 0; +#if REVISION >= 0xA + if ((svc_4b() & SVC4B_RESEED_RNG) != 0) + { + SeedRng(ReadU16( & GetHostRfuGameData()->compatibility.playerTrainerId )); + } +#endif rfu_LMAN_manager_entity(Random()); if (!gRfu.isShuttingDown) { @@ -2510,6 +2609,13 @@ u8 RfuGetStatus(void) return gRfu.status; } +#if REVISION >= 0xA +u16 RfuGetErrorInfo(void) +{ + return gRfu.errorInfo; +} +#endif + bool32 RfuHasErrored(void) { u32 status = RfuGetStatus(); @@ -2627,15 +2733,23 @@ void InitializeRfuLinkManager_EnterUnionRoom(void) rfu_LMAN_initializeManager(LinkManagerCB_UnionRoom, NULL); sRfuReqConfig = sRfuReqConfigTemplate; sRfuReqConfig.linkRecovery_enable = 0; +#if REVISION >= 0xA + sRfuReqConfig.linkRecovery_period = 720; +#else sRfuReqConfig.linkRecovery_period = 600; +#endif gRfu.searchTaskId = CreateTask(Task_UnionRoomListen, 1); } +#if REVISION >= 0xA +// (what used to be) ReadAsU16 from union_room.c is used instead. +#else static u16 ReadU16(const void *ptr) { const u8 *ptr_ = ptr; return (ptr_[1] << 8) | (ptr_[0]); } +#endif /* * ================================================================ @@ -2775,7 +2889,11 @@ static void Task_RfuReconnectWithParent(u8 taskId) tTime++; } +#if REVISION >= 0xA + if (tTime > 360) +#else if (tTime > 240) +#endif { // Timeout error RfuSetStatus(RFU_STATUS_CONNECTION_ERROR, F_RFU_ERROR_5 | F_RFU_ERROR_6 | F_RFU_ERROR_7); @@ -2797,6 +2915,13 @@ void CreateTask_RfuReconnectWithParent(const u8 *name, u16 trainerId) data[8] = trainerId; } +#if REVISION >= 0xA +void DestroyTask_RfuReconnectWithParent(void) +{ + DestroyTask(FindTaskIdByFunc(Task_RfuReconnectWithParent)); +} +#endif + static bool32 IsPartnerActivityIncompatible(s16 activity, struct RfuGameData *partner) { if (GetHostRfuGameData()->activity == (ACTIVITY_CHAT | IN_UNION_ROOM)) @@ -2841,7 +2966,11 @@ static void Task_TryConnectToUnionRoomParent(u8 taskId) if (gRfu.status == RFU_STATUS_NEW_CHILD_DETECTED) DestroyTask(taskId); +#if REVISION >= 0xA + if (++gTasks[taskId].data[0] > 480) +#else if (++gTasks[taskId].data[0] > 300) +#endif { // Timeout error RfuSetStatus(RFU_STATUS_CONNECTION_ERROR, F_RFU_ERROR_5 | F_RFU_ERROR_6 | F_RFU_ERROR_7); @@ -2859,7 +2988,11 @@ static void Task_TryConnectToUnionRoomParent(u8 taskId) // Parent found, try to connect if (!IsPartnerActivityIncompatible(gTasks[taskId].data[1], (struct RfuGameData *)&gRfuLinkStatus->partner[id].gname)) { +#if REVISION >= 0xA + if (gRfuLinkStatus->partner[id].slot != 0xFF && !rfu_LMAN_CHILD_connectParent(gRfuLinkStatus->partner[id].id, 150)) +#else if (gRfuLinkStatus->partner[id].slot != 0xFF && !rfu_LMAN_CHILD_connectParent(gRfuLinkStatus->partner[id].id, 90)) +#endif { // Succesfully connected to parent gRfu.state = RFUSTATE_CONNECTED; @@ -2884,7 +3017,11 @@ void TryConnectToUnionRoomParent(const u8 *name, struct RfuGameData *parent, u8 gRfu.status = RFU_STATUS_OK; StringCopy(gRfu.parent.uname, name); memcpy(gRfu.parent.gname, parent, RFU_GAME_NAME_LENGTH); +#if REVISION >= 0xA + rfu_LMAN_forceChangeSP(TRUE); +#else rfu_LMAN_forceChangeSP(); +#endif taskId = CreateTask(Task_TryConnectToUnionRoomParent, 2); gTasks[taskId].tActivity = activity; listenTaskId = FindTaskIdByFunc(Task_UnionRoomListen); @@ -2999,6 +3136,27 @@ u32 GetRfuRecvQueueLength(void) return gRfu.recvQueue.count; } +#if REVISION >= 0xA +static inline void RfuReloadCommon(void) { + m4aMPlayStop(&gMPlayInfo_SE1); + m4aMPlayStop(&gMPlayInfo_SE2); + m4aMPlayStop(&gMPlayInfo_SE3); + StopMapMusic(); + gMain.callback1 = NULL; + HelpSystem_Enable(); +} + +void RfuReloadSave(void) { + RfuReloadCommon(); + ReloadSave(); +} + +void RfuSoftReset(void) { + RfuReloadCommon(); + DoSoftReset(); +} +#endif + static void Task_Idle(u8 taskId) { diff --git a/src/link_rfu_3.c b/src/link_rfu_3.c index 078a28ff8..f9164070b 100644 --- a/src/link_rfu_3.c +++ b/src/link_rfu_3.c @@ -35,6 +35,204 @@ static const u16 sWirelessLinkIconPalette[] = INCBIN_U16("graphics/link/wireless static const u32 sWirelessLinkIconPic[] = INCBIN_U32("graphics/link/wireless_icon.4bpp.lz"); // Most of the below two tables won't make sense with ASCII encoding. +#if REVISION >= 0xA +// The tables have been changed to overload some control characters onto ASCII characters. +static const u8 sWireless_ASCIItoRSETable[] = { + EOS, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + [' '] = CHAR_SPACE, + ['!'] = CHAR_EXCL_MARK, + 0xb5, 0xb6, 0xb1, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xb2, 0xf1, 0xfc, + ['-'] = 0xfd, + ['.'] = 0xfe, + ['/'] = CHAR_SLASH, + ['0'] = CHAR_0, + ['1'] = CHAR_1, + ['2'] = CHAR_2, + ['3'] = CHAR_3, + ['4'] = CHAR_4, + ['5'] = CHAR_5, + ['6'] = CHAR_6, + ['7'] = CHAR_7, + ['8'] = CHAR_8, + ['9'] = CHAR_9, + CHAR_CURRENCY, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, CHAR_BLACK_TRIANGLE, + ['A'] = CHAR_A, + ['B'] = CHAR_B, + ['C'] = CHAR_C, + ['D'] = CHAR_D, + ['E'] = CHAR_E, + ['F'] = CHAR_F, + ['G'] = CHAR_G, + ['H'] = CHAR_H, + ['I'] = CHAR_I, + ['J'] = CHAR_J, + ['K'] = CHAR_K, + ['L'] = CHAR_L, + ['M'] = CHAR_M, + ['N'] = CHAR_N, + ['O'] = CHAR_O, + ['P'] = CHAR_P, + ['Q'] = CHAR_Q, + ['R'] = CHAR_R, + ['S'] = CHAR_S, + ['T'] = CHAR_T, + ['U'] = CHAR_U, + ['V'] = CHAR_V, + ['W'] = CHAR_W, + ['X'] = CHAR_X, + ['Y'] = CHAR_Y, + ['Z'] = CHAR_Z, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf0, + ['a'] = CHAR_a, + ['b'] = CHAR_b, + ['c'] = CHAR_c, + ['d'] = CHAR_d, + ['e'] = CHAR_e, + ['f'] = CHAR_f, + ['g'] = CHAR_g, + ['h'] = CHAR_h, + ['i'] = CHAR_i, + ['j'] = CHAR_j, + ['k'] = CHAR_k, + ['l'] = CHAR_l, + ['m'] = CHAR_m, + ['n'] = CHAR_n, + ['o'] = CHAR_o, + ['p'] = CHAR_p, + ['q'] = CHAR_q, + ['r'] = CHAR_r, + ['s'] = CHAR_s, + ['t'] = CHAR_t, + ['u'] = CHAR_u, + ['v'] = CHAR_v, + ['w'] = CHAR_w, + ['x'] = CHAR_x, + ['y'] = CHAR_y, + ['z'] = CHAR_z, + 0x2d, 0x2f, 0x30, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x50, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0xad, 0xb3, 0xb4, 0xb8, 0xaf, 0x7d, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xa0, + 0xae, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7e, 0xb0, 0xac, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2e, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, + 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94 +}; + +static const u8 sWireless_RSEtoASCIITable[] = { + [CHAR_SPACE] = ' ', + 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, + 0x9e, 0x9f, 0xa0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, + 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf0, 0x7b, 0xf1, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x84, + 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, + 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, + 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xa6, 0xdd, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xf2, 0xf3, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff, 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xaf, + [CHAR_0] = '0', + [CHAR_1] = '1', + [CHAR_2] = '2', + [CHAR_3] = '3', + [CHAR_4] = '4', + [CHAR_5] = '5', + [CHAR_6] = '6', + [CHAR_7] = '7', + [CHAR_8] = '8', + [CHAR_9] = '9', + [CHAR_EXCL_MARK] = '!', + 0xdf, 0xa1, 0xb0, 0xa5, 0xde, 0x24, 0x2a, + 0xa2, 0xa3, 0x22, 0x23, ':', 0xa4, 0x20, + [CHAR_SLASH] = '/', + [CHAR_A] = 'A', + [CHAR_B] = 'B', + [CHAR_C] = 'C', + [CHAR_D] = 'D', + [CHAR_E] = 'E', + [CHAR_F] = 'F', + [CHAR_G] = 'G', + [CHAR_H] = 'H', + [CHAR_I] = 'I', + [CHAR_J] = 'J', + [CHAR_K] = 'K', + [CHAR_L] = 'L', + [CHAR_M] = 'M', + [CHAR_N] = 'N', + [CHAR_O] = 'O', + [CHAR_P] = 'P', + [CHAR_Q] = 'Q', + [CHAR_R] = 'R', + [CHAR_S] = 'S', + [CHAR_T] = 'T', + [CHAR_U] = 'U', + [CHAR_V] = 'V', + [CHAR_W] = 'W', + [CHAR_X] = 'X', + [CHAR_Y] = 'Y', + [CHAR_Z] = 'Z', + [CHAR_a] = 'a', + [CHAR_b] = 'b', + [CHAR_c] = 'c', + [CHAR_d] = 'd', + [CHAR_e] = 'e', + [CHAR_f] = 'f', + [CHAR_g] = 'g', + [CHAR_h] = 'h', + [CHAR_i] = 'i', + [CHAR_j] = 'j', + [CHAR_k] = 'k', + [CHAR_l] = 'l', + [CHAR_m] = 'm', + [CHAR_n] = 'n', + [CHAR_o] = 'o', + [CHAR_p] = 'p', + [CHAR_q] = 'q', + [CHAR_r] = 'r', + [CHAR_s] = 's', + [CHAR_t] = 't', + [CHAR_u] = 'u', + [CHAR_v] = 'v', + [CHAR_w] = 'w', + [CHAR_x] = 'x', + [CHAR_y] = 'y', + [CHAR_z] = 'z', + 0x40, 0x60, 0x2b, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + [CHAR_DYNAMIC] = '%', + [CHAR_KEYPAD_ICON] = '&', + [CHAR_EXTRA_SYMBOL] = '\'', + [CHAR_PROMPT_SCROLL] = '(', + [CHAR_PROMPT_CLEAR] = ')', + [EXT_CTRL_CODE_BEGIN] = ',', + [PLACEHOLDER_BEGIN] = '-', + [CHAR_NEWLINE] = '.', + [EOS] = 0 +}; +#else static const u8 sWireless_ASCIItoRSETable[] = { EOS, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x37, @@ -231,6 +429,8 @@ static const u8 sWireless_RSEtoASCIITable[] = { [EOS] = 0 }; +#endif + static const struct OamData sWirelessStatusIndicatorOamData = { .y = 0, @@ -595,7 +795,7 @@ static void PopulateArrayWithSequence(u8 *arr, u8 mode) } } -static void PkmnStrToASCII(u8 *dest, const u8 *src) +void PkmnStrToASCII(u8 *dest, const u8 *src) { s32 i; @@ -604,7 +804,7 @@ static void PkmnStrToASCII(u8 *dest, const u8 *src) dest[i] = 0; } -static void ASCIIToPkmnStr(u8 *dest, const u8 *src) +void ASCIIToPkmnStr(u8 *dest, const u8 *src) { s32 i; diff --git a/src/load_save.c b/src/load_save.c index d71130507..8b723dd04 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -10,6 +10,7 @@ #include "berry_powder.h" #include "overworld.h" #include "quest_log.h" +#include "sloopsvc.h" #define SAVEBLOCK_MOVE_RANGE 128 @@ -125,6 +126,9 @@ void MoveSaveBlocks_ResetHeap(void) encryptionKey = (Random() << 0x10) + (Random()); ApplyNewEncryptionKeyToAllEncryptedData(encryptionKey); gSaveBlock2Ptr->encryptionKey = encryptionKey; +#if REVISION >= 0xA + svc_SetSaveBlock2(gSaveBlock2Ptr); +#endif } u32 UseContinueGameWarp(void) diff --git a/src/main.c b/src/main.c index f2d77a8c2..542b0f5d1 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,7 @@ #include "scanline_effect.h" #include "save_failed_screen.h" #include "quest_log.h" +#include "sloopsvc.h" extern u32 intr_main[]; @@ -24,6 +25,14 @@ static void VCountIntr(void); static void SerialIntr(void); static void IntrDummy(void); +#if REVISION >= 0xA && !MODERN +const char OtherBuildDateTime[] = "2025 12 19 16:01"; +#endif + +#if REVISION >= 0xA +// OtherBuildDateTime is probably in some other file? +__attribute__((aligned(4))) +#endif const u8 gGameVersion = GAME_VERSION; const u8 gGameLanguage = GAME_LANGUAGE; @@ -33,8 +42,10 @@ const char BuildDateTime[] = __DATE__ " " __TIME__; #else #if REVISION == 0 const char BuildDateTime[] = "2004 04 26 11:20"; -#else +#elif REVISION == 1 const char BuildDateTime[] = "2004 07 20 09:30"; +#elif REVISION == 0xA +const char BuildDateTime[] = "2025 12 19 15:38 22afedd9"; #endif //REVISION #endif //MODERN @@ -88,6 +99,9 @@ void EnableVCountIntrAtLine150(void); void AgbMain() { +#if REVISION >= 0xA + svc_stubbed(); +#endif #if MODERN // Modern compilers are liberal with the stack on entry to this function, // so RegisterRamReset may crash if it resets IWRAM. @@ -119,7 +133,12 @@ void AgbMain() #else RegisterRamReset(RESET_ALL); #endif //MODERN + +#if REVISION >= 0xA + *(vu16 *)BG_PLTT = RGB_BLACK; +#else *(vu16 *)BG_PLTT = RGB_WHITE; +#endif InitGpuRegManager(); REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3; InitKeys(); @@ -140,7 +159,8 @@ void AgbMain() SetNotInSaveFailedScreen(); -#ifndef NDEBUG + // Revision 10 has no calls into libisagbprn except this one. +#if !defined(NDEBUG) || REVISION >= 0xA #if (LOG_HANDLER == LOG_HANDLER_MGBA_PRINT) (void) MgbaOpen(); #elif (LOG_HANDLER == LOG_HANDLER_AGB_PRINT) @@ -148,7 +168,7 @@ void AgbMain() #endif #endif -#if REVISION == 1 +#if REVISION >= 1 if (gFlashMemoryPresent != TRUE) SetMainCallback2(NULL); #endif @@ -164,7 +184,9 @@ void AgbMain() && (gMain.heldKeysRaw & B_START_SELECT) == B_START_SELECT) { rfu_REQ_stopMode(); +#if REVISION < 0xA rfu_waitREQComplete(); +#endif DoSoftReset(); } @@ -211,6 +233,9 @@ static void InitMainCallbacks(void) gSaveBlock1Ptr = &gSaveBlock1; gSaveBlock2.encryptionKey = 0; gQuestLogPlaybackState = QL_PLAYBACK_STATE_STOPPED; +#if REVISION >= 0xA + svc_SetSaveBlock2(&gSaveBlock2); +#endif } static void CallCallbacks(void) @@ -375,11 +400,11 @@ static void VBlankIntr(void) gPcmDmaCounter = gSoundInfo.pcmDmaCounter; -#ifndef NDEBUG +#if !defined(NDEBUG) || REVISION >= 0xA sVcountBeforeSound = REG_VCOUNT; #endif m4aSoundMain(); -#ifndef NDEBUG +#if !defined(NDEBUG) || REVISION >= 0xA sVcountAfterSound = REG_VCOUNT; #endif @@ -408,7 +433,7 @@ static void HBlankIntr(void) static void VCountIntr(void) { -#ifndef NDEBUG +#if !defined(NDEBUG) || REVISION >= 0xA sVcountAtIntr = REG_VCOUNT; #endif m4aSoundVSync(); diff --git a/src/menu.c b/src/menu.c index 22e0321bc..9ee9968cb 100644 --- a/src/menu.c +++ b/src/menu.c @@ -567,8 +567,14 @@ s8 Menu_ProcessInputNoWrapClearOnChoose(void) void DestroyYesNoMenu(void) { +#if REVISION >= 0xA + if (sYesNoWindowId == 0xFF) return; +#endif ClearStdWindowAndFrameToTransparent(sYesNoWindowId, TRUE); RemoveWindow(sYesNoWindowId); +#if REVISION >= 0xA + sYesNoWindowId = 0xFF; +#endif } void MultichoiceGrid_PrintItems(u8 windowId, u8 fontId, u8 itemWidth, u8 itemHeight, u8 cols, u8 rows, const struct MenuAction *strs) diff --git a/src/mystery_gift_menu.c b/src/mystery_gift_menu.c index 0c9800146..77c032c1b 100644 --- a/src/mystery_gift_menu.c +++ b/src/mystery_gift_menu.c @@ -27,7 +27,7 @@ EWRAM_DATA u8 sDownArrowCounterAndYCoordIdx[8] = {}; EWRAM_DATA bool8 gGiftIsFromEReader = FALSE; static void CreateMysteryGiftTask(void); -static void Task_MysteryGift(u8 taskId); +void Task_MysteryGift(u8 taskId); extern void CreateEReaderTask(void); static const u16 sTextboxBorder_Pal[] = INCBIN_U16("graphics/interface/mystery_gift_textbox_border.gbapal"); @@ -1110,7 +1110,7 @@ static void CreateMysteryGiftTask(void) data->clientMsg = AllocZeroed(CLIENT_MAX_MSG_SIZE); } -static void Task_MysteryGift(u8 taskId) +void Task_MysteryGift(u8 taskId) { struct MysteryGiftTaskData * data = (void *)gTasks[taskId].data; bool32 successMsg, input; diff --git a/src/naming_screen.c b/src/naming_screen.c index c9d003a97..deef7054a 100644 --- a/src/naming_screen.c +++ b/src/naming_screen.c @@ -24,6 +24,7 @@ #include "constants/help_system.h" #include "constants/songs.h" #include "constants/event_objects.h" +#include "sloopsvc.h" enum { INPUT_NONE, @@ -680,7 +681,15 @@ static bool8 MainState_MoveToOKButton(void) static bool8 MainState_PressedOKButton(void) { +#if REVISION >= 0xA + // If the input text matched against the Switch bad words list, do not use it. + if (!svc_BadWordCheck(sNamingScreen->textBuffer)) + { + SaveInputText(); + } +#else SaveInputText(); +#endif SetInputState(INPUT_STATE_DISABLED); SetCursorFlashing(FALSE); TryStartButtonFlash(BUTTON_COUNT, FALSE, TRUE); diff --git a/src/overworld.c b/src/overworld.c index 1b81b360c..ffce6cecc 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -1512,6 +1512,13 @@ static bool8 RunFieldCallback(void) return TRUE; } +#if REVISION >= 0xA +void ClearFieldCallback(void) +{ + gFieldCallback = NULL; +} +#endif + void CB2_NewGame(void) { FieldClearVBlankHBlankCallbacks(); diff --git a/src/post_battle_event_funcs.c b/src/post_battle_event_funcs.c index cab6d3afe..5679375eb 100644 --- a/src/post_battle_event_funcs.c +++ b/src/post_battle_event_funcs.c @@ -5,7 +5,9 @@ #include "overworld.h" #include "hall_of_fame.h" #include "load_save.h" +#include "item.h" #include "constants/heal_locations.h" +#include "constants/items.h" bool8 EnterHallOfFame(void) { @@ -46,6 +48,20 @@ bool8 EnterHallOfFame(void) { IncrementGameStat(GAME_STAT_RECEIVED_RIBBONS); FlagSet(FLAG_SYS_RIBBON_GET); +#if REVISION >= 0xA + // The player has entered the Hall of Fame for the first time. + // (At least, this is probably what was intended, except giving at least one Champion Ribbon does not imply first Hall of Fame entry) + // Give the event tickets, and the flags for obtaining them, if required. + if (!CheckBagHasItem(ITEM_AURORA_TICKET, 1)) + { + AddBagItem(ITEM_AURORA_TICKET, 1); + FlagSet(FLAG_ENABLE_SHIP_BIRTH_ISLAND); + FlagSet(FLAG_RECEIVED_AURORA_TICKET); + AddBagItem(ITEM_MYSTIC_TICKET, 1); + FlagSet(FLAG_ENABLE_SHIP_NAVEL_ROCK); + FlagSet(FLAG_RECEIVED_MYSTIC_TICKET); + } +#endif } SetMainCallback2(CB2_DoHallOfFameScreen); return FALSE; diff --git a/src/save.c b/src/save.c index 7a4808924..36b960f37 100644 --- a/src/save.c +++ b/src/save.c @@ -9,6 +9,7 @@ #include "fieldmap.h" #include "pokemon_storage_system.h" #include "gba/flash_internal.h" +#include "sloopsvc.h" static u8 HandleWriteSector(u16 sectorId, const struct SaveSectorLocation *locations); static u8 TryWriteSector(u8 sectorNum, u8 *data); @@ -212,6 +213,11 @@ static u8 HandleWriteSectorNBytes(u8 sectorId, u8 *data, u16 size) static u8 TryWriteSector(u8 sectorNum, u8 *data) { +#if REVISION >= 0xA + svc_WriteSector(sectorNum, data); + SetDamagedSectorBits(DISABLE, sectorNum); + return SAVE_STATUS_OK; +#else if (ProgramFlashSectorAndVerify(sectorNum, data)) // is damaged? { SetDamagedSectorBits(ENABLE, sectorNum); // set damaged sector bits. @@ -222,6 +228,7 @@ static u8 TryWriteSector(u8 sectorNum, u8 *data) SetDamagedSectorBits(DISABLE, sectorNum); // unset damaged sector bits. it's safe now. return SAVE_STATUS_OK; } +#endif } static u32 RestoreSaveBackupVarsAndIncrement(const struct SaveSectorLocation *locations) @@ -312,6 +319,11 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveSectorLocation *loc gSaveDataBufferPtr->checksum = CalculateChecksum(data, size); +#if REVISION >= 0xA + svc_ReplaceSector(sectorNum, (u8*)gSaveDataBufferPtr); + SetDamagedSectorBits(DISABLE, sectorNum); + return SAVE_STATUS_OK; +#else // erase old save data EraseFlashSector(sectorNum); @@ -358,6 +370,7 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveSectorLocation *loc return SAVE_STATUS_OK; } } +#endif } static u8 CopySectorSignatureByte(u16 sectorId, const struct SaveSectorLocation *locations) @@ -679,6 +692,9 @@ u8 HandleSavingData(u8 saveType) break; } gMain.vblankCounter1 = backupPtr; +#if REVISION >= 0xA + svc_FinishSave(); +#endif return 0; } @@ -872,6 +888,9 @@ void Task_LinkFullSave(u8 taskId) gTasks[taskId].data[0] = 1; break; case 1: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif SetLinkStandbyCallback(); gTasks[taskId].data[0] = 2; break; @@ -905,6 +924,9 @@ void Task_LinkFullSave(u8 taskId) gTasks[taskId].data[0] = 7; break; case 7: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif ClearContinueGameWarpStatus2(); SetLinkStandbyCallback(); gTasks[taskId].data[0] = 8; @@ -913,10 +935,16 @@ void Task_LinkFullSave(u8 taskId) if (IsLinkTaskFinished()) { LinkFullSave_SetLastSectorSignature(); +#if REVISION >= 0xA + svc_FinishSave(); +#endif gTasks[taskId].data[0] = 9; } break; case 9: +#if REVISION >= 0xA + if (!IsLinkTaskFinished()) break; +#endif SetLinkStandbyCallback(); gTasks[taskId].data[0] = 10; break; diff --git a/src/scrcmd.c b/src/scrcmd.c index f7481f862..97b695ee2 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -37,6 +37,7 @@ #include "constants/event_objects.h" #include "constants/maps.h" #include "constants/sound.h" +#include "sloopsvc.h" extern u16 (*const gSpecials[])(void); extern u16 (*const gSpecialsEnd[])(void); @@ -1732,12 +1733,24 @@ bool8 ScrCmd_bufferboxname(struct ScriptContext * ctx) bool8 ScrCmd_givemon(struct ScriptContext * ctx) { - u16 species = VarGet(ScriptReadHalfword(ctx)); - u8 level = ScriptReadByte(ctx); - u16 item = VarGet(ScriptReadHalfword(ctx)); - u32 unkParam1 = ScriptReadWord(ctx); - u32 unkParam2 = ScriptReadWord(ctx); - u8 unkParam3 = ScriptReadByte(ctx); + u16 species; + u8 level; + u16 item; + u32 unkParam1; + u32 unkParam2; + u8 unkParam3; + species = VarGet(ScriptReadHalfword(ctx)); +#if REVISION >= 0xA + // If the player party count is zero, this "must" be giving the starter. + // Notify the emulator of what starter was picked, for telemetry purposes. + if (gSaveBlock1Ptr->playerPartyCount == 0) + svc_SetStarter(species); +#endif + level = ScriptReadByte(ctx); + item = VarGet(ScriptReadHalfword(ctx)); + unkParam1 = ScriptReadWord(ctx); + unkParam2 = ScriptReadWord(ctx); + unkParam3 = ScriptReadByte(ctx); gSpecialVar_Result = ScriptGiveMon(species, level, item, unkParam1, unkParam2, unkParam3); return FALSE; diff --git a/src/script_menu.c b/src/script_menu.c index 25991e775..41eebd86e 100644 --- a/src/script_menu.c +++ b/src/script_menu.c @@ -338,8 +338,14 @@ static const struct MenuAction sMultichoiceList_TradeCenter_Colosseum[] = { }; static const struct MenuAction sMultichoiceList_Link_Wireless[] = { +#if REVISION >= 0xA + // The default is wireless here as it's always emulated by Sloop + { gText_Wireless }, + { gText_GameLinkCable }, +#else { gText_GameLinkCable }, { gText_Wireless }, +#endif { gOtherText_Exit } }; diff --git a/src/sloopsvc.c b/src/sloopsvc.c new file mode 100644 index 000000000..384ed252f --- /dev/null +++ b/src/sloopsvc.c @@ -0,0 +1,294 @@ +#include "global.h" +#include "librfu.h" +#include "link_rfu.h" +#include "link.h" +#include "sloopsvc.h" + +#if REVISION >= 0xA + +typedef struct _SloopSvc47Params { + // BUGBUG: gHostRfuGameData certainly didn't change size, ResetHostRfuGameData still zeroes 13 bytes + u8 HostRfuGameData[0x10]; + u8 HostRfuUsername[RFU_USER_NAME_LENGTH]; +} SloopSvc47Params; + +static u8 sBadWordAsciiString[256]; + +COMMON_DATA SloopSvc47Params gSvc47Params = {0}; +COMMON_DATA struct RfuLinkStatus *gSloopRfuLinkStatus = NULL; + +// Syscall functions for the extra syscalls handled by the Sloop emulator. +#define SLOOP_SVC_CLOBBERS "r0", "r1", "r2", "r3", "memory" + +// Unreferenced. Sets a flag to true (default true) (svc_41 sets it to false) +void svc_40(void) { + asm volatile("swi 0x40"); +} + +// Unreferenced. Sets a flag to false (default true) (svc_40 sets it to true) +void svc_41(void) { + asm volatile("swi 0x41"); +} + +// Called by rfu_REQ_configGameData. +void svc_47(void) { + u8* params = gSvc47Params.HostRfuGameData; + memcpy(params, &gHostRfuGameData, sizeof(gSvc47Params.HostRfuGameData)); + memcpy(¶ms[sizeof(gSvc47Params.HostRfuGameData)], gHostRfuUsername, sizeof(gSvc47Params.HostRfuUsername)); + asm volatile( + "movs r0, %0 \n" + "swi 0x47 \n" + : + : "l"(params) + : SLOOP_SVC_CLOBBERS + ); + gSloopRfuLinkStatus = gRfuLinkStatus; +} + +// Called by rfu_REQ_startSearchChild. +void svc_42(void) { + asm volatile("swi 0x42"); +} + +// Called from rfu_LMAN_manager_entity. +u32 svc_49(void) { + u32 ret; + asm volatile( + "swi 0x49 \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by rfu_REQ_startSearchParent and rfu_STC_readParentCandidateList. +void svc_45_rfu_link_status(void) { + asm volatile( + "movs r0, %0 \n" + "swi 0x45 \n" + : + : "l"(gRfuLinkStatus) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by rfu_LMAN_REQ_callback +u32 svc_4a(void) { + u32 ret; + asm volatile( + "swi 0x4a \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by rfu_REQ_startConnectParent +void svc_43(u16 pid) { + asm volatile( + "movs r0, %0 \n" + "swi 0x43 \n" + : + : "l"(pid) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by rfu_REQ_stopMode, ... +void svc_44(void) { + asm volatile("swi 0x44"); +} + +// Called by Task_WirelessCommunicationScreen +u32 svc_53(void) { + u32 ret; + asm volatile( + "swi 0x53 \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by HandleLinkConnection +u32 svc_51(void) { + u32 ret; + asm volatile( + "swi 0x51 \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by RfuMain1 and SpawnGroupLeaderAndMembers. +// SpawnGroupLeaderAndMembers will exit early in the SpawnGroupLeader case if retval has bit 0 unset. +// RfuMain1 will reseed the RNG by gHostRfuGameData->compatibility.playerTrainerId if retval has bit 1 set. +u32 svc_4b(void) { + u32 ret; + asm volatile( + "swi 0x4b \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by TryWriteSector. +void svc_WriteSector(u8 sector, u8* data) { + asm volatile( + "movs r0, %0 \n" + "movs r1, %1 \n" + "swi 0x48 \n" + : + : "l"(sector), "l"(data) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by HandleReplaceSector. +void svc_ReplaceSector(u8 sector, u8* data) { + asm volatile( + "movs r0, %0 \n" + "movs r1, %1 \n" + "swi 0x56 \n" + : + : "l"(sector), "l"(data) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by various save-related functions. +// This writes the save out (handler calls a function using fopen/fwrite/fclose) +void svc_FinishSave(void) { + asm volatile("swi 0x4c"); +} + +// Called by Task_RunUnionRoom and ListMenuHandler_AllItemsAvailable. +// This handler calls functions from the parental controls library. +// ListMenuHandler_AllItemsAvailable returns -2 if this returns zero. +// The Task_RunUnionRoom case auto-declines if this returns zero. +// Probably returns zero if "free communication" is denied by parental control settings. +u32 svc_CommsAllowedByParentalControls(void) { + u32 ret; + asm volatile( + "swi 0x54 \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +static inline u32 call_svc_BadWordCheck(u8* string, int arg2) { + u32 ret; + asm volatile( + "movs r0, %1\n" + "movs r1, %2\n" + "swi 0x4d\n" + "movs %0, r0\n" + : "=l" (ret) + : "l" (string), "l" (arg2) + : SLOOP_SVC_CLOBBERS + ); + return ret; +} +// Called by naming screen MainState_PressedOKButton, +// ChatEntryRoutine_SendMessage and union room RegisterTextAtRow. +// This does the bad word checks. +// The text buffer passed in is sanitised, and zero returned if sanitisation occured(?)/badwords present(?) +u32 svc_BadWordCheck(u8* str) { + u32 ret; + PkmnStrToASCII((u8*)sBadWordAsciiString, str); + ret = call_svc_BadWordCheck((u8*)sBadWordAsciiString, 0); + ASCIIToPkmnStr(str, (u8*)sBadWordAsciiString); + return ret; +} + +// Called by various cases of Task_TryJoinLinkGroup and Task_TryBecomeLinkLeader. +void svc_4f(u32 arg) { + asm volatile( + "movs r0, %0 \n" + "swi 0x4f \n" + : + : "l"(arg) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by a wrapper function called by Task_TryBecomeLinkLeader. +// The wrapper function is equivalent to "return !svc_50();" +// Return value is ORed with gReceivedRemoteLinkPlayers. +u32 svc_50(void) { + u32 ret; + asm volatile( + "swi 0x50 \n" + "movs %0, r0 \n" + : "=l"(ret) + : + : SLOOP_SVC_CLOBBERS + ); + return ret; +} + +// Called by InitMainCallbacks and MoveSaveBlocks_ResetHeap. +// Lets the emulator know where SaveBlock2 is located in memory. +// Emulator appears to use this to get saveBlock2->optionsButtonMode to check against L_EQUALS_A. +void svc_SetSaveBlock2(struct SaveBlock2* saveBlock2) { + asm volatile( + "movs r0, %0 \n" + "swi 0x55 \n" + : + : "l"(saveBlock2) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by AgbMain, as its first action before RegisterRamReset. +void svc_stubbed(void) { + // No operation. +} + +// Called by ScrCmd_givemon when the party is empty. +// This lets the emulator know what starter was picked (saved in play report / telemetry data) +void svc_SetStarter(u32 species) { + asm volatile( + "movs r0, %0 \n" + "swi 0x57 \n" + : + : "l"(species) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by Task_StartActivity +// This lets the emulator know the current union room activity. +void svc_SetActivity(u32 activity) { + asm volatile( + "movs r0, %0 \n" + "swi 0x61 \n" + : + : "l"(activity) + : SLOOP_SVC_CLOBBERS + ); +} + +// Called by CB2_PrintErrorMessage. +// This causes the emulator to increment some variable (link error counter, probably). +void svc_IncrementLinkError(void) { + asm volatile("swi 0x62"); +} + + +#endif \ No newline at end of file diff --git a/src/start_menu.c b/src/start_menu.c index 8a372e5af..88cc377ce 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -36,6 +36,7 @@ #include "help_system.h" #include "constants/songs.h" #include "constants/field_weather.h" +#include "sloopsvc.h" enum StartMenuOption { @@ -935,6 +936,9 @@ static void task50_after_link_battle_save(u8 taskId) if (WriteSaveBlock1Sector()) { ClearContinueGameWarpStatus2(); +#if REVISION >= 0xA + svc_FinishSave(); +#endif data[0] = 3; } break; diff --git a/src/string_util.c b/src/string_util.c index 4744e231c..5c26d151a 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -5,7 +5,11 @@ EWRAM_DATA u8 gStringVar1[32] = {}; EWRAM_DATA u8 gStringVar2[20] = {}; EWRAM_DATA u8 gStringVar3[20] = {}; EWRAM_DATA u8 gStringVar4[1000] = {}; +#if REVISION >= 0xA +EWRAM_DATA u8 gUnknownStringVar[12] = {0}; +#else EWRAM_DATA u8 gUnknownStringVar[16] = {0}; +#endif static const u8 sDigits[] = __("0123456789ABCDEF"); diff --git a/src/task.c b/src/task.c index cd9841d06..01503dc7a 100644 --- a/src/task.c +++ b/src/task.c @@ -86,6 +86,10 @@ static void InsertTask(u8 newTaskId) void DestroyTask(u8 taskId) { +#if REVISION >= 0xA + // Bounds check on the task ID. + if (taskId >= NUM_TASKS) return; +#endif if (gTasks[taskId].isActive) { gTasks[taskId].isActive = FALSE; diff --git a/src/title_screen.c b/src/title_screen.c index 334af1f0f..75f0e6743 100644 --- a/src/title_screen.c +++ b/src/title_screen.c @@ -634,12 +634,16 @@ static void SetTitleScreenScene_Run(s16 *data) DestroyTask(FindTaskIdByFunc(Task_TitleScreenMain)); SetMainCallback2(CB2_FadeOutTransitionToSaveClearScreen); } +#if REVISION >= 0xA + // Berry fix trigger has been removed. +#else else if (JOY_HELD(KEYSTROKE_BERRY_FIX) == KEYSTROKE_BERRY_FIX) { DeactivateSlashSprite(tSlashSpriteId); DestroyTask(FindTaskIdByFunc(Task_TitleScreenMain)); SetMainCallback2(CB2_FadeOutTransitionToBerryFix); } +#endif else if (JOY_NEW(A_BUTTON | START_BUTTON)) { SetTitleScreenScene(data, TITLESCREENSCENE_CRY); diff --git a/src/trade.c b/src/trade.c index ea29aedc8..c19360963 100644 --- a/src/trade.c +++ b/src/trade.c @@ -2116,7 +2116,11 @@ static void CB_HandleTradeCanceled(void) static void CB_InitExitCanceledTrade(void) { +#if REVISION >= 0xA + if (IsLinkTaskFinished() && !gPaletteFade.active) +#else if (!gPaletteFade.active) +#endif { if (gWirelessCommType) SetLinkStandbyCallback(); diff --git a/src/trade_scene.c b/src/trade_scene.c index 2c3a0801d..98d129039 100644 --- a/src/trade_scene.c +++ b/src/trade_scene.c @@ -33,6 +33,7 @@ #include "constants/songs.h" #include "constants/region_map_sections.h" #include "constants/moves.h" +#include "sloopsvc.h" // Values for signaling to/from the link partner enum { @@ -2608,25 +2609,37 @@ static void CB2_SaveAndEndTrade(void) MysteryGift_TryIncrementStat(CARD_STAT_NUM_TRADES, gLinkPlayers[GetMultiplayerId() ^ 1].trainerId); SetContinueGameWarpStatusToDynamicWarp(); LinkFullSave_Init(); +#if REVISION >= 0xA + // No need to wait for a save when the emulator does it fast and synchronously + gMain.state = 52; +#else gMain.state++; +#endif sTradeAnim->timer = 0; break; +#if REVISION >= 0xA +#else case 51: if (++sTradeAnim->timer == 5) gMain.state++; break; +#endif case 52: if (LinkFullSave_WriteSector()) { ClearContinueGameWarpStatus2(); gMain.state = 4; } +#if REVISION >= 0xA + // Save delay is gone, just write the next sector if save isn't finished +#else else { // Save isn't finished, delay again sTradeAnim->timer = 0; gMain.state = 51; } +#endif break; case 4: LinkFullSave_ReplaceLastSector(); @@ -2654,6 +2667,26 @@ static void CB2_SaveAndEndTrade(void) sTradeAnim->timer--; } break; +#if REVISION >= 0xA + case 42: + if (IsLinkTaskFinished()) + { + gMain.state = 43; + } + break; + case 43: + SetLinkStandbyCallback(); + gMain.state = 44; + break; + case 44: + if (IsLinkTaskFinished()) + { + LinkFullSave_SetLastSectorSignature(); + svc_FinishSave(); + gMain.state = 5; + } + break; +#else case 42: if (IsLinkTaskFinished()) { @@ -2661,6 +2694,7 @@ static void CB2_SaveAndEndTrade(void) gMain.state = 5; } break; +#endif case 5: if (++sTradeAnim->timer > 60) { diff --git a/src/union_room.c b/src/union_room.c index 282353238..91bd92c99 100644 --- a/src/union_room.c +++ b/src/union_room.c @@ -48,6 +48,7 @@ #include "constants/field_weather.h" #include "constants/trainer_card.h" #include "constants/union_room.h" +#include "sloopsvc.h" // States for Task_RunUnionRoom enum { @@ -143,7 +144,11 @@ enum { LL_STATE_FAILED, LL_STATE_TRY_START_ACTIVITY = 26, LL_STATE_MEMBER_DISCONNECTED = 29, - LL_STATE_CANCEL_WITH_MSG + LL_STATE_CANCEL_WITH_MSG, +#if REVISION >= 0xA + LL_STATE_CONFIRM_MEMBERS_SLOOP, + LL_STATE_DISCONNECT_CHILD_SLOOP +#endif }; // States for Task_TryJoinLinkGroup @@ -205,9 +210,19 @@ EWRAM_DATA u16 gUnionRoomOfferedSpecies = SPECIES_NONE; EWRAM_DATA u8 gUnionRoomRequestedMonType = TYPE_NORMAL; static EWRAM_DATA struct UnionRoomTrade sUnionRoomTrade = {}; +#if REVISION >= 0xA +COMMON_DATA struct WirelessLink_Leader * sLeader = NULL; +COMMON_DATA struct WirelessLink_URoom * sURoom = NULL; +COMMON_DATA struct WirelessLink_Group * sGroup = NULL; +#else static struct WirelessLink_Leader * sLeader; static struct WirelessLink_Group * sGroup; static struct WirelessLink_URoom * sURoom; +#endif + +#if REVISION >= 0xA +static void Leader_DisconnectOnState(struct WirelessLink_Leader * data, u8 state); +#endif static void Task_TryBecomeLinkLeader(u8); static void Leader_DestroyResources(struct WirelessLink_Leader *); @@ -227,7 +242,12 @@ static void Task_SendMysteryGift(u8); static void Task_CardOrNewsWithFriend(u8); static void Task_CardOrNewsOverWireless(u8); static void Task_RunUnionRoom(u8); +#if REVISION >= 0xA +u16 ReadU16(const u8 *); +#define ReadAsU16(x) ReadU16(x) +#else static u16 ReadAsU16(const u8 *); +#endif static void ReceiveUnionRoomActivityPacket(struct WirelessLink_URoom *); static bool32 HandleContactFromOtherPlayer(struct WirelessLink_URoom *); static void Task_InitUnionRoom(u8); @@ -422,6 +442,9 @@ static void Task_TryBecomeLinkLeader(u8 taskId) CopyBgTilemapBufferToVram(0); data->playerCount = 1; data->state = LL_STATE_GET_AWAITING_PLAYERS_TEXT; +#if REVISION >= 0xA + svc_4f(0); +#endif break; case LL_STATE_GET_AWAITING_PLAYERS_TEXT: StringCopy(gStringVar1, sLinkGroupActivityNameTexts[sPlayerCurrActivity]); @@ -439,19 +462,28 @@ static void Task_TryBecomeLinkLeader(u8 taskId) PrintNumPlayersWaitingForMsg(data->nPlayerModeWindowId, sPlayerActivityGroupSize, data->playerCount); data->state = LL_STATE_PRINT_AWAITING_PLAYERS; +#if REVISION >= 0xA + Leader_SetStateIfMemberListChanged(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT, LL_STATE_MEMBER_LEFT); +#endif break; case LL_STATE_PRINT_AWAITING_PLAYERS: if (PrintOnTextbox(&data->textState, gStringVar4)) data->state = LL_STATE_AWAIT_PLAYERS; break; case LL_STATE_AWAIT_PLAYERS: +#if REVISION >= 0xA +#else Leader_SetStateIfMemberListChanged(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT, LL_STATE_MEMBER_LEFT); +#endif if (JOY_NEW(B_BUTTON)) { if (data->playerCount == 1) data->state = LL_STATE_SHUTDOWN_AND_FAIL; +#if REVISION >= 0xA +#else else if (GROUP_MIN2(sPlayerActivityGroupSize) != 0) data->state = LL_STATE_CANCEL_WITH_MSG; +#endif else data->state = LL_STATE_CANCEL_PROMPT; } @@ -462,30 +494,54 @@ static void Task_TryBecomeLinkLeader(u8 taskId) && JOY_NEW(START_BUTTON)) { data->state = LL_STATE_MEMBERS_OK_PROMPT; +#if REVISION >= 0xA +#else LinkRfu_StopManagerAndFinalizeSlots(); +#endif } +#if REVISION >= 0xA + if (data->state == LL_STATE_AWAIT_PLAYERS) + { + Leader_SetStateIfMemberListChanged(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT, LL_STATE_MEMBER_LEFT); + } + Leader_DisconnectOnState(data, LL_STATE_AWAIT_PLAYERS); +#else if (data->state == LL_STATE_AWAIT_PLAYERS && RfuTryDisconnectLeavingChildren()) { // At least 1 group member has left or is trying to leave data->state = LL_STATE_WAIT_DISCONNECT_CHILD; } +#endif break; case LL_STATE_WAIT_DISCONNECT_CHILD: // Resume after ensuring all members trying to leave have left if (!RfuTryDisconnectLeavingChildren()) { data->state = LL_STATE_AWAIT_PLAYERS; +#if REVISION >= 0xA +#else data->playerCount = LeaderPrunePlayerList(data->playerList); +#endif } break; case LL_STATE_MEMBER_LEFT: +#if REVISION >= 0xA + id = (GROUP_MAX(sPlayerActivityGroupSize) != 2) ? 1 : 0; +#else id = (GROUP_MAX(sPlayerCurrActivity) == 2) ? 1 : 0; +#endif if (PrintOnTextbox(&data->textState, gTexts_UR_PlayerUnavailable[id])) { +#if REVISION >= 0xA +#else data->playerCount = LeaderPrunePlayerList(data->playerList); RedrawListMenu(data->listTaskId); +#endif data->state = LL_STATE_GET_AWAITING_PLAYERS_TEXT; } +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_MEMBER_LEFT); +#endif break; case LL_STATE_MEMBER_DISCONNECTED: id = (GROUP_MAX(sPlayerActivityGroupSize) == 2) ? 0 : 1; @@ -495,6 +551,9 @@ static void Task_TryBecomeLinkLeader(u8 taskId) case LL_STATE_ACCEPT_NEW_MEMBER_PROMPT: if (PrintOnTextbox(&data->textState, gStringVar4)) data->state = LL_STATE_ACCEPT_NEW_MEMBER_PROMPT_HANDLE_INPUT; +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT); +#endif break; case LL_STATE_ACCEPT_NEW_MEMBER_PROMPT_HANDLE_INPUT: switch (UnionRoomHandleYesNo(&data->textState, HasTrainerLeftPartnersList( @@ -518,6 +577,9 @@ static void Task_TryBecomeLinkLeader(u8 taskId) data->state = LL_STATE_WAIT_DISCONNECT_CHILD; break; } +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT_HANDLE_INPUT); +#endif break; case LL_STATE_UPDATE_AFTER_JOIN_REQUEST: val = WaitSendRfuStatusToPartner(ReadAsU16(data->playerList->players[data->playerCount].rfu.data.compatibility.playerTrainerId), data->playerList->players[data->playerCount].rfu.name); @@ -542,7 +604,10 @@ static void Task_TryBecomeLinkLeader(u8 taskId) data->state = LL_STATE_ACCEPTED_FINAL_MEMBER; } +#if REVISION >= 0xA +#else LinkRfu_StopManagerAndFinalizeSlots(); +#endif PrintNumPlayersWaitingForMsg(data->nPlayerModeWindowId, sPlayerActivityGroupSize, data->playerCount); } else @@ -554,7 +619,11 @@ static void Task_TryBecomeLinkLeader(u8 taskId) { RequestDisconnectSlotByTrainerNameAndId(data->playerList->players[data->playerCount].rfu.name, ReadAsU16(data->playerList->players[data->playerCount].rfu.data.compatibility.playerTrainerId)); data->playerList->players[data->playerCount].groupScheduledAnim = UNION_ROOM_SPAWN_NONE; +#if REVISION >= 0xA + data->playerCount = LeaderPrunePlayerList(data->playerList); +#else LeaderPrunePlayerList(data->playerList); +#endif RedrawListMenu(data->listTaskId); data->state = LL_STATE_GET_AWAITING_PLAYERS_TEXT; } @@ -570,59 +639,159 @@ static void Task_TryBecomeLinkLeader(u8 taskId) break; case LL_STATE_ACCEPTED_FINAL_MEMBER: if (PrintOnTextbox(&data->textState, gStringVar4)) + { +#if REVISION >= 0xA + data->state = LL_STATE_CONFIRM_MEMBERS_SLOOP; + svc_4f(1); + data->delayTimerAfterOk = 0; +#else data->state = LL_STATE_WAIT_AND_CONFIRM_MEMBERS; +#endif + } +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_ACCEPTED_FINAL_MEMBER); +#endif break; +#if REVISION >= 0xA +#else case LL_STATE_WAIT_AND_CONFIRM_MEMBERS: if (++data->delayTimerAfterOk > 120) data->state = LL_STATE_CONFIRMED_MEMBERS; break; +#endif case LL_STATE_MEMBERS_OK_PROMPT: if (PrintOnTextbox(&data->textState, gText_UR_AreTheseMembersOK)) data->state = LL_STATE_MEMBERS_OK_PROMPT_HANDLE_INPUT; +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_MEMBERS_OK_PROMPT); +#endif break; case LL_STATE_MEMBERS_OK_PROMPT_HANDLE_INPUT: switch (UnionRoomHandleYesNo(&data->textState, FALSE)) { case 0: // YES +#if REVISION >= 0xA + data->state = LL_STATE_CONFIRM_MEMBERS_SLOOP; + svc_4f(1); + data->delayTimerAfterOk = 0; +#else data->state = LL_STATE_CONFIRMED_MEMBERS; +#endif break; case 1: // NO case MENU_B_PRESSED: +#if REVISION >= 0xA + data->state = LL_STATE_CANCEL_PROMPT; +#else if (GROUP_MIN2(sPlayerActivityGroupSize) != 0) data->state = LL_STATE_CANCEL_WITH_MSG; else data->state = LL_STATE_CANCEL_PROMPT; +#endif break; } +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_MEMBERS_OK_PROMPT_HANDLE_INPUT); +#endif break; +#if REVISION >= 0xA + case LL_STATE_CONFIRM_MEMBERS_SLOOP: + switch (LeaderUpdateGroupMembership(data->playerList)) + { + case UNION_ROOM_SPAWN_IN: + data->joinRequestAnswer = RFU_STATUS_CONNECTION_ERROR; + SendRfuStatusToPartner(RFU_STATUS_CONNECTION_ERROR, ReadAsU16(data->playerList->players[data->playerCount].rfu.data.compatibility.playerTrainerId), data->playerList->players[data->playerCount].rfu.name); + data->state = LL_STATE_DISCONNECT_CHILD_SLOOP; + return; + case UNION_ROOM_SPAWN_OUT: + RfuSetStatus(RFU_STATUS_OK, 0); + data->playerCount = LeaderPrunePlayerList(data->playerList); + RedrawListMenu(data->listTaskId); + svc_4f(0); + data->state = LL_STATE_MEMBER_LEFT; + return; + case UNION_ROOM_SPAWN_OUT_SOON: + RfuSetStatus(RFU_STATUS_OK, 0); + data->playerCount = LeaderPrunePlayerList(data->playerList); + RedrawListMenu(data->listTaskId); + return; + } + if (++data->delayTimerAfterOk > 40) + { + data->state = LL_STATE_FINAL_MEMBER_CHECK; + LinkRfu_StopManagerAndFinalizeSlots(); + } + Leader_DisconnectOnState(data, LL_STATE_CONFIRM_MEMBERS_SLOOP); + break; + case LL_STATE_DISCONNECT_CHILD_SLOOP: + val = WaitSendRfuStatusToPartner(ReadAsU16(data->playerList->players[data->playerCount].rfu.data.compatibility.playerTrainerId), data->playerList->players[data->playerCount].rfu.name); + if (val == 1) + { + // Send complete + RequestDisconnectSlotByTrainerNameAndId(data->playerList->players[data->playerCount].rfu.name, ReadAsU16(data->playerList->players[data->playerCount].rfu.data.compatibility.playerTrainerId)); + data->playerList->players[data->playerCount].groupScheduledAnim = UNION_ROOM_SPAWN_NONE; + data->playerCount = LeaderPrunePlayerList(data->playerList); + RedrawListMenu(data->listTaskId); + } else if (val == 2) + { + // Disconnect + RfuSetStatus(RFU_STATUS_OK, 0); + } else break; + data->state = LL_STATE_CONFIRM_MEMBERS_SLOOP; + break; +#endif case LL_STATE_CANCEL_PROMPT: if (PrintOnTextbox(&data->textState, gText_UR_CancelModeWithTheseMembers)) data->state = LL_STATE_CANCEL_PROMPT_HANDLE_INPUT; +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_CANCEL_PROMPT); +#endif break; case LL_STATE_CANCEL_PROMPT_HANDLE_INPUT: switch (UnionRoomHandleYesNo(&data->textState, FALSE)) { case 0: // YES +#if REVISION >= 0xA + data->state = LL_STATE_CANCEL_WITH_MSG; +#else data->state = LL_STATE_SHUTDOWN_AND_FAIL; +#endif break; case 1: // NO case MENU_B_PRESSED: +#if REVISION >= 0xA + if (GROUP_MIN2(sPlayerActivityGroupSize) == 0 && data->playerCount == GROUP_MAX(sPlayerActivityGroupSize)) + data->state = LL_STATE_MEMBERS_OK_PROMPT; +#else if (GROUP_MIN2(sPlayerActivityGroupSize) != 0) data->state = LL_STATE_MEMBERS_OK_PROMPT; else if (data->playerCount == GROUP_MAX(sPlayerActivityGroupSize)) data->state = LL_STATE_MEMBERS_OK_PROMPT; +#endif else data->state = LL_STATE_GET_AWAITING_PLAYERS_TEXT; break; } +#if REVISION >= 0xA + Leader_DisconnectOnState(data, LL_STATE_CANCEL_PROMPT_HANDLE_INPUT); +#endif break; +#if REVISION >= 0xA +#else case LL_STATE_CONFIRMED_MEMBERS: if (!Leader_SetStateIfMemberListChanged(data, LL_STATE_ACCEPT_NEW_MEMBER_PROMPT, LL_STATE_SHUTDOWN_AND_FAIL)) data->state = LL_STATE_FINAL_MEMBER_CHECK; break; +#endif case LL_STATE_FINAL_MEMBER_CHECK: if (LmanAcceptSlotFlagIsNotZero()) { +#if REVISION >= 0xA + if (RfuGetStatus() == RFU_STATUS_CONNECTION_ERROR && RfuGetErrorInfo() == LMAN_MSG_LINK_LOSS_DETECTED_AND_DISCONNECTED) + { + RfuSetStatus(RFU_STATUS_OK, 0); + } +#endif if (WaitRfuState(FALSE)) { data->state = LL_STATE_TRY_START_ACTIVITY; @@ -770,6 +939,18 @@ static void GetGroupLeaderSentAnOKMessage(u8 *dst, u8 caseId) } } +#if REVISION >= 0xA +static void Leader_DisconnectOnState(struct WirelessLink_Leader * data, u8 state) +{ + if (data->state != state) return; + if (!RfuTryDisconnectLeavingChildren()) return; + data->state = LL_STATE_WAIT_DISCONNECT_CHILD; + DestroyYesNoMenu(); + svc_4f(0); + data->textState = 0; +} +#endif + static bool8 Leader_SetStateIfMemberListChanged(struct WirelessLink_Leader * data, u32 joinedState, u32 droppedState) { switch (LeaderUpdateGroupMembership(data->playerList)) @@ -780,11 +961,23 @@ static bool8 Leader_SetStateIfMemberListChanged(struct WirelessLink_Leader * dat CopyAndTranslatePlayerName(gStringVar2, data->playerList->players[data->playerCount]); Leader_GetAcceptNewMemberPrompt(gStringVar4, sPlayerCurrActivity); data->state = joinedState; +#if REVISION >= 0xA + svc_4f(0); +#endif break; case UNION_ROOM_SPAWN_OUT: +#if REVISION >= 0xA + case UNION_ROOM_SPAWN_OUT_SOON: +#endif RfuSetStatus(RFU_STATUS_OK, 0); +#if REVISION >= 0xA + data->playerCount = LeaderPrunePlayerList(data->playerList); +#endif RedrawListMenu(data->listTaskId); data->state = droppedState; +#if REVISION >= 0xA + svc_4f(0); +#endif return TRUE; } @@ -813,9 +1006,13 @@ static void ItemPrintFunc_PossibleGroupMembers(u8 windowId, u32 id, u8 y) static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list) { struct WirelessLink_Leader * data = sWirelessLinkMain.leader; - u8 ret = UNION_ROOM_SPAWN_NONE; - u8 i; +#if REVISION >= 0xA s32 id; +#else + u8 ret = UNION_ROOM_SPAWN_NONE; + s32 id; +#endif + u8 i; for (i = 1; i < MAX_RFU_PLAYERS; i++) { @@ -833,7 +1030,10 @@ static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list) { // No new incoming player data->playerList->players[i].groupScheduledAnim = UNION_ROOM_SPAWN_OUT; +#if REVISION >= 0xA +#else ret = UNION_ROOM_SPAWN_OUT; +#endif } } } @@ -841,6 +1041,31 @@ static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list) for (id = 0; id < RFU_CHILD_MAX; id++) TryAddIncomingPlayerToList(data->playerList->players, &data->incomingPlayerList->players[id], MAX_RFU_PLAYERS); +#if REVISION >= 0xA + id = 1; + { + struct RfuPlayerList* playerList = data->playerList; + // spawning out, and countdown = 0 => SPAWN_OUT + for (; id < MAX_RFU_PLAYERS; id++) + { + if (playerList->players[id].groupScheduledAnim == UNION_ROOM_SPAWN_OUT && playerList->players[id].newPlayerCountdown == 0) + return UNION_ROOM_SPAWN_OUT; + } + // spawning out, and countdown != 0 => SPAWN_OUT_SOON + for (id = 1; id < MAX_RFU_PLAYERS; id++) + { + if (playerList->players[id].groupScheduledAnim == UNION_ROOM_SPAWN_OUT && playerList->players[id].newPlayerCountdown != 0) + return UNION_ROOM_SPAWN_OUT_SOON; + } + // spawning in, and countdown != 0 => SPAWN_IN + for (id = 0; id < MAX_RFU_PLAYERS; id++) + { + if (playerList->players[id].groupScheduledAnim == UNION_ROOM_SPAWN_IN && playerList->players[id].newPlayerCountdown != 0) + return UNION_ROOM_SPAWN_IN; + } + } + return UNION_ROOM_SPAWN_NONE; +#else if (ret != UNION_ROOM_SPAWN_OUT) { for (id = 0; id < MAX_RFU_PLAYERS; id++) @@ -851,6 +1076,7 @@ static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list) } return ret; +#endif } static u8 LeaderPrunePlayerList(struct RfuPlayerList * list) @@ -911,9 +1137,20 @@ void TryJoinLinkGroup(void) gSpecialVar_Result = LINKUP_ONGOING; } +#if REVISION >= 0xA +static u8 svc_50_wrapper() { + return svc_50() == TRUE; +} +#endif + static void Task_TryJoinLinkGroup(u8 taskId) { s32 id; +#if REVISION >= 0xA + u8 RfuStatus; + bool8 RfuStatusIsGroup; + u8 handleYN; +#endif struct WirelessLink_Group * data = sWirelessLinkMain.group; switch (data->state) @@ -1011,7 +1248,10 @@ static void Task_TryJoinLinkGroup(u8 taskId) GetYouAskedToJoinGroupPleaseWaitMessage(gStringVar4, sPlayerCurrActivity); if (PrintOnTextbox(&data->textState, gStringVar4)) { +#if REVISION >= 0xA +#else CopyAndTranslatePlayerName(gStringVar1, data->playerList->players[data->leaderId]); +#endif data->state = LG_STATE_MAIN; } break; @@ -1038,71 +1278,158 @@ static void Task_TryJoinLinkGroup(u8 taskId) break; } } - - switch (RfuGetStatus()) +#if REVISION >= 0xA + else +#endif { - case RFU_STATUS_FATAL_ERROR: - data->state = LG_STATE_RFU_ERROR; - break; - case RFU_STATUS_CONNECTION_ERROR: - case RFU_STATUS_JOIN_GROUP_NO: - case RFU_STATUS_LEAVE_GROUP: - data->state = LG_STATE_DISCONNECTED; - break; - case RFU_STATUS_JOIN_GROUP_OK: - GetGroupLeaderSentAnOKMessage(gStringVar4, sPlayerCurrActivity); - if (PrintOnTextbox(&data->textState, gStringVar4)) - { - RfuSetStatus(RFU_STATUS_WAIT_ACK_JOIN_GROUP, 0); - StringCopy(gStringVar1, sLinkGroupActivityNameTexts[sPlayerCurrActivity]); - StringExpandPlaceholders(gStringVar4, gText_UR_AwaitingOtherMembers); - } - break; - case RFU_STATUS_WAIT_ACK_JOIN_GROUP: - if (data->delayBeforePrint > 240) + + switch (RfuGetStatus()) { + case RFU_STATUS_FATAL_ERROR: + data->state = LG_STATE_RFU_ERROR; + break; + case RFU_STATUS_CONNECTION_ERROR: + case RFU_STATUS_JOIN_GROUP_NO: + case RFU_STATUS_LEAVE_GROUP: + data->state = LG_STATE_DISCONNECTED; + break; + case RFU_STATUS_JOIN_GROUP_OK: +#if REVISION >= 0xA + CopyAndTranslatePlayerName(gStringVar1, data->playerList->players[data->leaderId]); +#endif + GetGroupLeaderSentAnOKMessage(gStringVar4, sPlayerCurrActivity); if (PrintOnTextbox(&data->textState, gStringVar4)) { - RfuSetStatus(RFU_STATUS_ACK_JOIN_GROUP, 0); - data->delayBeforePrint = 0; + RfuSetStatus(RFU_STATUS_WAIT_ACK_JOIN_GROUP, 0); +#if REVISION >= 0xA +#else + StringCopy(gStringVar1, sLinkGroupActivityNameTexts[sPlayerCurrActivity]); + StringExpandPlaceholders(gStringVar4, gText_UR_AwaitingOtherMembers); +#endif + } + break; + case RFU_STATUS_WAIT_ACK_JOIN_GROUP: + if (data->delayBeforePrint > 240) + { +#if REVISION >= 0xA + StringCopy(gStringVar1, sLinkGroupActivityNameTexts[sPlayerCurrActivity]); + StringExpandPlaceholders(gStringVar4, gText_UR_AwaitingOtherMembers); +#endif + if (PrintOnTextbox(&data->textState, gStringVar4)) + { + RfuSetStatus(RFU_STATUS_ACK_JOIN_GROUP, 0); + data->delayBeforePrint = 0; + } + break; } - } - else - { data->delayBeforePrint++; +#if REVISION >= 0xA + // fallthrough, to not duplicate code + case RFU_STATUS_CHILD_LEAVE_READY: + case RFU_STATUS_CHILD_LEAVE: + case RFU_STATUS_ACK_JOIN_GROUP: + default: + if (JOY_NEW(B_BUTTON)) + { + u8 syscallPlayers = svc_50_wrapper(taskId); + bool8 noPlayers = FALSE; + noPlayers = (syscallPlayers | gReceivedRemoteLinkPlayers) == 0; + if (noPlayers) + { + data->state = LG_STATE_ASK_LEAVE_GROUP; + } + } +#endif + break; } - break; } +#if REVISION >= 0xA +#else if (RfuGetStatus() == RFU_STATUS_OK && JOY_NEW(B_BUTTON)) data->state = LG_STATE_ASK_LEAVE_GROUP; +#endif break; case LG_STATE_ASK_LEAVE_GROUP: if (PrintOnTextbox(&data->textState, gText_UR_QuitBeingMember)) data->state = LG_STATE_ASK_LEAVE_GROUP_HANDLE_INPUT; break; case LG_STATE_ASK_LEAVE_GROUP_HANDLE_INPUT: +#if REVISION >= 0xA + RfuStatus = RfuGetStatus(); + RfuStatusIsGroup = (RfuStatus == RFU_STATUS_JOIN_GROUP_OK || RfuStatus == RFU_STATUS_WAIT_ACK_JOIN_GROUP || RfuStatus == RFU_STATUS_ACK_JOIN_GROUP); + handleYN = gReceivedRemoteLinkPlayers | svc_50_wrapper(); + switch (UnionRoomHandleYesNo(&data->textState, handleYN)) +#else switch (UnionRoomHandleYesNo(&data->textState, RfuGetStatus())) +#endif { case 0: // YES - SendLeaveGroupNotice(); - data->state = LG_STATE_WAIT_LEAVE_GROUP; +#if REVISION >= 0xA + if (RfuStatusIsGroup) +#endif + { + SendLeaveGroupNotice(); + data->state = LG_STATE_WAIT_LEAVE_GROUP; +#if REVISION >= 0xA + data->delayBeforePrint = 0; +#endif + } +#if REVISION >= 0xA + else + { + data->state = LG_STATE_CANCEL_CHOOSE_LEADER; + } +#endif RedrawListMenu(data->listTaskId); break; case 1: // NO case MENU_B_PRESSED: - data->state = LG_STATE_ASK_JOIN_GROUP; +#if REVISION >= 0xA + if (RfuStatusIsGroup) + { + data->state = LG_STATE_MAIN; + if (RfuStatus >= RFU_STATUS_WAIT_ACK_JOIN_GROUP) + { + data->delayBeforePrint = -15; + RfuSetStatus(RFU_STATUS_WAIT_ACK_JOIN_GROUP, 0); + } + } + else +#endif + { + data->state = LG_STATE_ASK_JOIN_GROUP; + } RedrawListMenu(data->listTaskId); break; case -3: data->state = LG_STATE_MAIN; +#if REVISION >= 0xA + if (RfuStatus == RFU_STATUS_WAIT_ACK_JOIN_GROUP) + RfuSetStatus(RFU_STATUS_ACK_JOIN_GROUP, 0); +#endif RedrawListMenu(data->listTaskId); break; } break; case LG_STATE_WAIT_LEAVE_GROUP: +#if REVISION >= 0xA + switch (GetJoinGroupStatus()) + { + case RFU_STATUS_LEAVE_GROUP: + data->state = LG_STATE_DISCONNECTED; + break; + case RFU_STATUS_JOIN_GROUP_NO: + data->state = LG_STATE_CANCEL_CHOOSE_LEADER; + break; + } + if (data->delayBeforePrint > 240) + data->state = LG_STATE_CANCEL_CHOOSE_LEADER; + ++data->delayBeforePrint; +#else if (RfuGetStatus()) data->state = LG_STATE_MAIN; +#endif break; case LG_STATE_CANCEL_CHOOSE_LEADER: // next: LG_STATE_CANCELED case LG_STATE_RFU_ERROR: // next: LG_STATE_RFU_ERROR_SHUTDOWN @@ -1155,6 +1482,9 @@ static void Task_TryJoinLinkGroup(u8 taskId) } break; case LG_STATE_SHUTDOWN: +#if REVISION >= 0xA + DestroyTask_RfuReconnectWithParent(); +#endif DestroyTask(taskId); JoinGroup_EnableScriptContexts(); LinkRfu_Shutdown(); @@ -1557,6 +1887,10 @@ static void Task_StartActivity(u8 taskId) break; } +#if REVISION >= 0xA + svc_SetActivity(sPlayerCurrActivity); +#endif + switch (sPlayerCurrActivity) { case ACTIVITY_BATTLE_SINGLE | IN_UNION_ROOM: @@ -1658,7 +1992,11 @@ static void Task_RunScriptAndFadeToActivity(u8 taskId) } break; case 2: +#if REVISION >= 0xA + if (IsLinkTaskFinished() && !gPaletteFade.active) +#else if (!gPaletteFade.active) +#endif { SetLinkStandbyCallback(); data[0]++; @@ -2261,7 +2599,11 @@ void RunUnionRoom(void) ListMenuLoadStdPalAt(BG_PLTT_ID(13), 1); } +#if REVISION >= 0xA +u16 ReadU16(const u8 *ptr) +#else static u16 ReadAsU16(const u8 *ptr) +#endif { return (ptr[1] << 8) | (ptr[0]); } @@ -2281,6 +2623,9 @@ static void ScheduleFieldMessageAndExit(const u8 *src) struct WirelessLink_URoom * uroom = sWirelessLinkMain.uRoom; uroom->state = UR_STATE_PRINT_AND_EXIT; +#if REVISION >= 0xA + uroom->textState = 0; +#endif if (src != gStringVar4) StringExpandPlaceholders(gStringVar4, src); } @@ -2478,21 +2823,37 @@ static void Task_RunUnionRoom(u8 taskId) break; case UR_STATE_TRY_COMMUNICATING: UR_RunTextPrinters(); +#if REVISION >= 0xA + LinkRfu_ForceChangeSpParent(); +#endif switch (RfuGetStatus()) { case RFU_STATUS_NEW_CHILD_DETECTED: HandleCancelActivity(TRUE); uroom->state = UR_STATE_MAIN; +#if REVISION >= 0xA + return; +#else break; +#endif case RFU_STATUS_FATAL_ERROR: case RFU_STATUS_CONNECTION_ERROR: if (IsUnionRoomListenTaskActive() == TRUE) ScheduleFieldMessageAndExit(gText_UR_TrainerAppearsBusy); else + { ScheduleFieldMessageWithFollowupState(UR_STATE_CANCEL_ACTIVITY_LINK_ERROR, gText_UR_TrainerAppearsBusy); +#if REVISION >= 0xA + gReceivedRemoteLinkPlayers = FALSE; +#endif + } sPlayerCurrActivity = IN_UNION_ROOM; +#if REVISION >= 0xA + return; +#else break; +#endif } if (gReceivedRemoteLinkPlayers) @@ -2503,6 +2864,14 @@ static void Task_RunUnionRoom(u8 taskId) } break; case UR_STATE_COMMUNICATING_WAIT_FOR_DATA: +#if REVISION >= 0xA + if (!gReceivedRemoteLinkPlayers || RfuHasErrored()) + { + DestroyTask(FindTaskIdByFunc(Task_ExchangeCards)); + uroom->state = UR_STATE_TRAINER_APPEARS_BUSY; + break; + } +#endif if (!FuncIsActiveTask(Task_ExchangeCards)) { if (sPlayerCurrActivity == (ACTIVITY_TRADE | IN_UNION_ROOM)) @@ -2593,7 +2962,10 @@ static void Task_RunUnionRoom(u8 taskId) case UR_STATE_WAIT_FOR_RESPONSE_TO_REQUEST: if (!gReceivedRemoteLinkPlayers) { +#if REVISION >= 0xA +#else StringCopy(gStringVar4, gText_UR_TrainerBattleBusy); +#endif uroom->state = UR_STATE_TRAINER_APPEARS_BUSY; } else @@ -2625,6 +2997,9 @@ static void Task_RunUnionRoom(u8 taskId) ScheduleFieldMessageWithFollowupState(UR_STATE_HANDLE_DO_SOMETHING_PROMPT_INPUT, gTexts_UR_HiDoSomething[id][playerGender]); break; case UR_STATE_PRINT_CARD_INFO: +#if REVISION >= 0xA + svc_SetActivity(IN_UNION_ROOM | ACTIVITY_CARD); +#endif if (PrintOnTextbox(&uroom->textState, gStringVar4)) { uroom->state = UR_STATE_WAIT_FINISH_READING_CARD; @@ -2653,6 +3028,15 @@ static void Task_RunUnionRoom(u8 taskId) switch (UnionRoomHandleYesNo(&uroom->textState, FALSE)) { case 0: // YES +#if REVISION >= 0xA + // If not allowed by parental controls, act as if user chose No. + if (!svc_CommsAllowedByParentalControls()) + { + playerGender = GetUnionRoomPlayerGender(taskData[1], uroom->playerList); + ScheduleFieldMessageAndExit(gTexts_UR_DeclineChat[playerGender]); + break; + } +#endif CopyBgTilemapBufferToVram(0); sPlayerCurrActivity = ACTIVITY_CHAT | IN_UNION_ROOM; UpdateGameData_SetActivity(ACTIVITY_CHAT | IN_UNION_ROOM, 0, TRUE); @@ -2705,7 +3089,15 @@ static void Task_RunUnionRoom(u8 taskId) if (IsUnionRoomListenTaskActive() == TRUE) ScheduleFieldMessageAndExit(gTexts_UR_ChatDeclined[playerGender]); else + { ScheduleFieldMessageWithFollowupState(UR_STATE_CANCEL_ACTIVITY_LINK_ERROR, gTexts_UR_ChatDeclined[playerGender]); +#if REVISION >= 0xA + gReceivedRemoteLinkPlayers = FALSE; +#endif + } +#if REVISION >= 0xA + break; +#endif } if (gReceivedRemoteLinkPlayers) uroom->state = UR_STATE_START_ACTIVITY_FREE_UROOM; @@ -2760,6 +3152,19 @@ static void Task_RunUnionRoom(u8 taskId) switch (UnionRoomHandleYesNo(&uroom->textState, FALSE)) { case 0: // ACCEPT +#if REVISION >= 0xA + // If this is union room chat: + // Tell the emulator to check if Switch parental controls allow free communication. + // If it is not allowed, then act as if the user selected to deny the request. + if (sPlayerCurrActivity == (IN_UNION_ROOM | ACTIVITY_CHAT) && !svc_CommsAllowedByParentalControls()) + { + uroom->playerSendBuffer[0] = ACTIVITY_DECLINE | IN_UNION_ROOM; + Rfu_SendPacket(uroom->playerSendBuffer); + uroom->state = UR_STATE_DECLINE_ACTIVITY_REQUEST; + GetYouDeclinedTheOfferMessage(gStringVar4, sPlayerCurrActivity); + break; + } +#endif uroom->playerSendBuffer[0] = ACTIVITY_ACCEPT | IN_UNION_ROOM; if (sPlayerCurrActivity == (ACTIVITY_CHAT | IN_UNION_ROOM)) UpdateGameData_SetActivity(sPlayerCurrActivity | IN_UNION_ROOM, GetLinkPlayerInfoFlags(1), FALSE); @@ -3112,6 +3517,9 @@ void InitUnionRoom(void) struct WirelessLink_URoom * data; sUnionRoomPlayerName[0] = EOS; +#if REVISION >= 0xA + // The rest of this function is stubbed out, as if QL_IS_PLAYBACK_STATE is always true. +#else if (QL_IS_PLAYBACK_STATE) return; CreateTask(Task_InitUnionRoom, 0); @@ -3123,6 +3531,7 @@ void InitUnionRoom(void) data->unknown = 0; data->unreadPlayerId = 0; sUnionRoomPlayerName[0] = EOS; +#endif } static void Task_InitUnionRoom(u8 taskId) @@ -3264,9 +3673,13 @@ static u8 HandlePlayerListUpdate(void) } else if (data->playerList->players[j].groupScheduledAnim != UNION_ROOM_SPAWN_OUT) { - // Person may have disconnected. Give them 10 seconds. + // Person may have disconnected. Give them 10 seconds. (15 seconds in rev 10) data->playerList->players[j].timeoutCounter++; +#if REVISION >= 0xA + if (data->playerList->players[j].timeoutCounter >= 900) +#else if (data->playerList->players[j].timeoutCounter >= 600) +#endif { data->playerList->players[j].groupScheduledAnim = UNION_ROOM_SPAWN_OUT; retVal = PLIST_RECENT_UPDATE; @@ -3274,9 +3687,13 @@ static u8 HandlePlayerListUpdate(void) } else if (data->playerList->players[j].groupScheduledAnim == UNION_ROOM_SPAWN_OUT) { - // Person dropped. Wait 15 seconds, then remove them. + // Person dropped. Wait 15 seconds (20 seconds in rev 10), then remove them. data->playerList->players[j].timeoutCounter++; +#if REVISION >= 0xA + if (data->playerList->players[j].timeoutCounter >= 1200) +#else if (data->playerList->players[j].timeoutCounter >= 900) +#endif { ClearRfuPlayerList(&data->playerList->players[j], 1); } @@ -3520,6 +3937,14 @@ static s32 ListMenuHandler_AllItemsAvailable(u8 *state, u8 *windowId, u8 *listMe ClearStdWindowAndFrame(*windowId, TRUE); RemoveWindow(*windowId); *state = 0; +#if REVISION >= 0xA + // If this is the union room chat, and Switch parental controls disallow free communication, + // always act as if Cancel was pressed. + if ((input & 0xFF) == (ACTIVITY_CHAT | IN_UNION_ROOM) && !svc_CommsAllowedByParentalControls()) + { + return LIST_CANCEL; + } +#endif return input; } else if (JOY_NEW(B_BUTTON)) diff --git a/src/union_room_battle.c b/src/union_room_battle.c index 5c31746a9..f680c33ec 100644 --- a/src/union_room_battle.c +++ b/src/union_room_battle.c @@ -179,16 +179,32 @@ void CB2_UnionRoomBattle(void) case 50: if (!UpdatePaletteFade()) { +#if REVISION >= 0xA +#else SetLinkStandbyCallback(); +#endif gMain.state++; } break; case 51: if (IsLinkTaskFinished()) { +#if REVISION >= 0xA + SetLinkStandbyCallback(); + gMain.state++; +#else + SetMainCallback2(SetUpPartiesAndStartBattle); +#endif + } + break; +#if REVISION >= 0xA + case 52: + if (IsLinkTaskFinished()) + { SetMainCallback2(SetUpPartiesAndStartBattle); } break; +#endif case 6: if (!gReceivedRemoteLinkPlayers) { diff --git a/src/union_room_chat.c b/src/union_room_chat.c index aedc57fdc..2a4182a3a 100644 --- a/src/union_room_chat.c +++ b/src/union_room_chat.c @@ -16,6 +16,7 @@ #include "union_room_chat_display.h" #include "keyboard_text.h" #include "constants/songs.h" +#include "sloopsvc.h" #define MESSAGE_BUFFER_NCHAR 15 @@ -806,6 +807,9 @@ static void ChatEntryRoutine_SendMessage(void) switch (sWork->routineState) { case 0: +#if REVISION >= 0xA + svc_BadWordCheck(sWork->messageEntryBuffer); +#endif if (!gReceivedRemoteLinkPlayers) { GoToRoutine(CHATNETRYROUTINE_HANDLE_INPUT); @@ -1162,6 +1166,9 @@ static void RegisterTextAtRow(void) { u8 *src = UnionRoomChat_GetEndOfMessageEntryBuffer(); StringCopy(sWork->registeredTexts[sWork->currentRow], src); +#if REVISION >= 0xA + svc_BadWordCheck(sWork->registeredTexts[sWork->currentRow]); +#endif sWork->changedRegisteredTexts = TRUE; } diff --git a/src/union_room_player_avatar.c b/src/union_room_player_avatar.c index 2cfa38167..9352b8150 100644 --- a/src/union_room_player_avatar.c +++ b/src/union_room_player_avatar.c @@ -9,6 +9,7 @@ #include "constants/event_object_movement.h" #include "constants/union_room.h" #include "constants/event_objects.h" +#include "sloopsvc.h" #define UR_SPRITE_START_ID (MAX_SPRITES - MAX_UNION_ROOM_LEADERS) @@ -513,6 +514,14 @@ static void SpawnGroupLeaderAndMembers(u32 leaderId, struct RfuGameData * gameDa { case ACTIVITY_NONE | IN_UNION_ROOM: case ACTIVITY_PLYRTALK | IN_UNION_ROOM: +#if REVISION >= 0xA + if ((svc_4b() & SVC4B_EXIT_EARLY) != 0) + { + DespawnGroupLeader(leaderId); + AssembleGroup(leaderId, gameData); + break; + } +#endif SpawnGroupLeader(leaderId, gameData->playerGender, gameData->compatibility.playerTrainerId[0]); for (i = 0; i < MAX_RFU_PLAYERS; i++) DespawnGroupMember(leaderId, i); diff --git a/src/wireless_communication_status_screen.c b/src/wireless_communication_status_screen.c index 693e22052..28b0993bc 100644 --- a/src/wireless_communication_status_screen.c +++ b/src/wireless_communication_status_screen.c @@ -13,6 +13,7 @@ #include "union_room.h" #include "constants/songs.h" #include "constants/union_room.h" +#include "sloopsvc.h" enum { COLOR_NONE, @@ -41,8 +42,8 @@ static struct u8 filler[10]; } * sStatusScreen; +void Task_WirelessCommunicationScreen(u8 taskId); static void CB2_InitWirelessCommunicationScreen(void); -static void Task_WirelessCommunicationScreen(u8 taskId); static void WCSS_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 * str, u8 x, u8 y, u8 palIdx); static bool32 UpdateCommunicationCounts(u32 * counts, u32 * lastCounts, u32 * activities, u8 taskId); @@ -134,7 +135,7 @@ static const u8 *const sHeaderTexts[NUM_GROUPTYPES + 1] = { // Activity, group type, number of players // 0 players means the number of players can change and should be counted dynamically // GROUPTYPE_TOTAL have no unique group and are simply counted in the total of "people communicating". -// A handful use NUM_GROUPTYPES, which is invalid, and are changed to GROUPTYPE_TOTAL in Emerald. +// A handful use NUM_GROUPTYPES, which is invalid, and are changed to GROUPTYPE_TOTAL in Emerald (and Revision 10) // UB: GROUPTYPE_NONE (-1) can potentially be used as an index into a u8[4] in CountPlayersInGroupAndGetActivity. static const u8 sActivityGroupInfo[][3] = { {ACTIVITY_BATTLE_SINGLE, GROUPTYPE_BATTLE, 2}, @@ -143,13 +144,23 @@ static const u8 sActivityGroupInfo[][3] = { {ACTIVITY_TRADE, GROUPTYPE_TRADE, 2}, {ACTIVITY_WONDER_CARD, GROUPTYPE_TOTAL, 2}, {ACTIVITY_WONDER_NEWS, GROUPTYPE_TOTAL, 2}, +#if REVISION >= 0xA + {ACTIVITY_POKEMON_JUMP, GROUPTYPE_TOTAL, 0}, + {ACTIVITY_BERRY_CRUSH, GROUPTYPE_TOTAL, 0}, + {ACTIVITY_BERRY_PICK, GROUPTYPE_TOTAL, 0}, +#else {ACTIVITY_POKEMON_JUMP, NUM_GROUPTYPES, 0}, {ACTIVITY_BERRY_CRUSH, NUM_GROUPTYPES, 0}, {ACTIVITY_BERRY_PICK, NUM_GROUPTYPES, 0}, +#endif {ACTIVITY_SEARCH, GROUPTYPE_NONE, 0}, {ACTIVITY_SPIN_TRADE, GROUPTYPE_TRADE, 0}, {ACTIVITY_ITEM_TRADE, GROUPTYPE_NONE, 0}, +#if REVISION >= 0xA + {ACTIVITY_RECORD_CORNER, GROUPTYPE_TOTAL, 0}, +#else {ACTIVITY_RECORD_CORNER, NUM_GROUPTYPES, 0}, +#endif {ACTIVITY_BERRY_BLENDER, GROUPTYPE_NONE, 0}, {ACTIVITY_NONE | IN_UNION_ROOM, GROUPTYPE_UNION, 1}, {ACTIVITY_BATTLE_SINGLE | IN_UNION_ROOM, GROUPTYPE_UNION, 2}, @@ -278,7 +289,7 @@ static void PrintHeaderTexts(void) #define tState data[0] -static void Task_WirelessCommunicationScreen(u8 taskId) +void Task_WirelessCommunicationScreen(u8 taskId) { s32 i; switch (gTasks[taskId].tState) @@ -313,7 +324,11 @@ static void Task_WirelessCommunicationScreen(u8 taskId) PutWindowTilemap(2); CopyWindowToVram(2, COPYWIN_FULL); } +#if REVISION >= 0xA + if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON) || svc_53()) +#else if (JOY_NEW(A_BUTTON) || JOY_NEW(B_BUTTON)) +#endif { PlaySE(SE_SELECT); gTasks[sStatusScreen->rfuTaskId].data[15] = 0xFF; @@ -372,6 +387,40 @@ static void WCSS_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 * static u32 CountPlayersInGroupAndGetActivity(struct RfuPlayer * player, u32 * groupCounts) { +#if REVISION >= 0xA + u32 activity = player->rfu.data.activity; + if (player->groupScheduledAnim == UNION_ROOM_SPAWN_IN) + { + + u32 i = 0; + const u8 * group_info = &sActivityGroupInfo[0][0]; + const u8 * group_players = &group_info[2]; + const u8 * group_activity = group_info; + s32 offset = 0; + for (; i < ARRAY_COUNT(sActivityGroupInfo); i++) + { + const u8 * group_type = &group_info[1]; + u8 type = ((u8*)offset)[(u32)group_type]; // needed to match, but nobody would write this??? + if (type < MAX_LINK_PLAYERS && activity == *group_activity) + { + u8 k = *group_players; + if (k == 0) + { + s32 j; + for (j = 0; j < RFU_CHILD_MAX; j++) + if (player->rfu.data.partnerInfo[j] != 0) k++; + k++; + } + groupCounts[type] += k; + break; + } + group_players += sizeof(sActivityGroupInfo[0]); + group_activity += sizeof(sActivityGroupInfo[0]); + offset += (u8)sizeof(sActivityGroupInfo[0]); + } + + } +#else u32 activity = player->rfu.data.activity; s32 i, j, k; @@ -398,11 +447,13 @@ static u32 CountPlayersInGroupAndGetActivity(struct RfuPlayer * player, u32 * gr } } - return activity; - #undef group_activity #undef group_type #undef group_players +#endif + + return activity; + } static bool32 HaveCountsChanged(const u32 * curCounts, const u32 * prevCounts) @@ -435,6 +486,9 @@ static bool32 UpdateCommunicationCounts(u32 * groupCounts, u32 * prevGroupCounts } } +#if REVISION >= 0xA + if (HaveCountsChanged(groupCountBuffer, prevGroupCounts)) +#else if (!HaveCountsChanged(groupCountBuffer, prevGroupCounts)) { if (activitiesUpdated == TRUE) @@ -442,16 +496,27 @@ static bool32 UpdateCommunicationCounts(u32 * groupCounts, u32 * prevGroupCounts else return FALSE; } +#endif + { + memcpy(groupCounts, groupCountBuffer, sizeof(groupCountBuffer)); + memcpy(prevGroupCounts, groupCountBuffer, sizeof(groupCountBuffer)); - memcpy(groupCounts, groupCountBuffer, sizeof(groupCountBuffer)); - memcpy(prevGroupCounts, groupCountBuffer, sizeof(groupCountBuffer)); - - groupCounts[GROUPTYPE_TOTAL] = groupCounts[GROUPTYPE_TRADE] - + groupCounts[GROUPTYPE_BATTLE] - + groupCounts[GROUPTYPE_UNION] - #ifdef BUGFIX - + groupCounts[GROUPTYPE_TOTAL] // Missing count for activities not in above groups - #endif - ; + groupCounts[GROUPTYPE_TOTAL] = groupCounts[GROUPTYPE_TRADE] + + groupCounts[GROUPTYPE_BATTLE] + + groupCounts[GROUPTYPE_UNION] + #if defined(BUGFIX) || REVISION >= 0xA + + groupCounts[GROUPTYPE_TOTAL] // Missing count for activities not in above groups + #endif + ; + +#if REVISION >= 0xA + activitiesUpdated = TRUE; +#endif + } + +#if REVISION >= 0xA + return activitiesUpdated; +#else return TRUE; +#endif } diff --git a/sym_bss.txt b/sym_bss.txt index 00c7b1dc6..81e7e2051 100644 --- a/sym_bss.txt +++ b/sym_bss.txt @@ -4,6 +4,7 @@ .include "src/malloc.o" .include "src/text_printer.o" .include "src/sprite.o" + .include "src/sloopsvc.o" .include "src/link.o" .include "src/multiboot.o" .include "src/daycare.o" diff --git a/sym_bss_rev10.txt b/sym_bss_rev10.txt new file mode 100644 index 000000000..1a90ebb38 --- /dev/null +++ b/sym_bss_rev10.txt @@ -0,0 +1,38 @@ + .include "src/gpu_regs.o" + .include "src/dma3_manager.o" + .include "src/bg.o" + .include "src/malloc.o" + .include "src/text_printer.o" + .include "src/librfu_stwi.o" + .include "src/librfu_rfu.o" + .include "src/sprite.o" + .include "src/sloopsvc.o" + .include "src/link.o" + .include "src/multiboot.o" + .include "src/daycare.o" + .include "src/trade.o" + .include "src/play_time.o" + .include "src/overworld.o" + .include "src/field_camera.o" + .include "src/script.o" + .include "src/start_menu.o" + .include "src/tileset_anims.o" + .include "src/sound.o" + .include "src/field_effect.o" + .include "src/pokemon_storage_system_misc.o" + .include "src/easy_chat.o" + .include "src/link_rfu_2.o" + .include "src/link_rfu_3.o" + .include "src/quest_log.o" + .include "src/union_room.o" + .include "src/pokemon_special_anim_scene.o" + .include "src/wireless_communication_status_screen.o" + .include "src/dodrio_berry_picking.o" + .include "src/ereader_helpers.o" + .include "src/digit_obj_util.o" + .include "src/m4a_1.o" + .include "data/sound_data.o" + .include "src/agb_flash.o" + .include "*libgcc.a:dp-bit.o" + .include "*libgcc.a:fp-bit.o" + .include "*libc.a:syscalls.o" diff --git a/sym_common.txt b/sym_common.txt index 1e57985da..9798689ad 100644 --- a/sym_common.txt +++ b/sym_common.txt @@ -5,6 +5,7 @@ .include "window.o" .include "text.o" .include "sprite.o" + .include "sloopsvc.o" .include "link.o" .align 4 .include "battle_main.o" diff --git a/sym_common_rev10.txt b/sym_common_rev10.txt new file mode 100644 index 000000000..ce4a446c3 --- /dev/null +++ b/sym_common_rev10.txt @@ -0,0 +1,56 @@ + .include "main.o" + .include "bg.o" + .include "text_printer.o" + .align 4 + .include "window.o" + .include "librfu_stwi.o" + .align 4 + .include "librfu_rfu.o" + .include "text.o" + .include "sprite.o" + .align 4 + .include "sloopsvc.o" + .include "link.o" + .align 4 + .include "battle_main.o" + .include "random.o" + .include "load_save.o" + .include "overworld.o" + .align 4 + .include "fieldmap.o" + .align 4 + .include "field_camera.o" + .include "scrcmd.o" + .include "field_control_avatar.o" + .include "event_data.o" + .include "sound.o" + .include "task.o" + .include "cable_club.o" + .include "image_processing_effects.o" + .include "field_specials.o" + .include "evolution_scene.o" + .include "save.o" + .include "battle_anim_special.o" + .include "save_failed_screen.o" + .align 4 + .include "link_rfu_2.o" + .align 4 + .include "AgbRfu_LinkManager.o" + .align 4 + .include "list_menu.o" + .include "quest_log.o" + .include "union_room.o" + .include "party_menu.o" + .include "help_system.o" + .align 4 + .include "fame_checker.o" + .include "help_system_util.o" + .align 4 + .include "ereader_screen.o" + .align 4 + .include "battle_controller_pokedude.o" + .align 4 + .include "berry_fix_program.o" + .include "m4a.o" + .include "agb_flash.o" + .include "librfu_sio32id.o" diff --git a/sym_ewram_rev10.txt b/sym_ewram_rev10.txt new file mode 100644 index 000000000..cee4e8281 --- /dev/null +++ b/sym_ewram_rev10.txt @@ -0,0 +1,137 @@ + .include "src/main.o" + .include "src/malloc.o" + .include "src/text_printer.o" + .include "src/window.o" + .include "src/window_8bpp.o" + .include "src/sprite.o" + .include "src/string_util.o" + .include "src/link.o" + .space 8 + .include "src/battle_controllers.o" + .include "src/battle_main.o" + .include "src/pokemon.o" + .include "src/daycare.o" + .include "src/load_save.o" + .include "src/trade.o" + .include "src/trade_scene.o" + .include "src/new_game.o" + .include "src/overworld.o" + .include "src/fieldmap.o" + .include "src/field_camera.o" + .include "src/field_player_avatar.o" + .include "src/event_object_movement.o" + .include "src/field_message_box.o" + .include "src/script.o" + .include "src/scrcmd.o" + .include "src/event_data.o" + .include "src/start_menu.o" + .include "src/tileset_anims.o" + .include "src/palette.o" + .include "src/sound.o" + .include "src/battle_anim.o" + .include "src/battle_anim_mons.o" + .include "src/title_screen.o" + .include "src/field_weather.o" + .include "src/battle_setup.o" + .include "src/wild_encounter.o" + .include "src/field_effect.o" + .include "src/scanline_effect.o" + .include "src/option_menu.o" + .include "src/trainer_card.o" + .include "src/pokemon_storage_system_menu.o" + .include "src/pokemon_storage_system_tasks.o" + .include "src/pokemon_storage_system_data.o" + .include "src/pokemon_storage_system_misc.o" + .include "src/script_movement.o" + .include "src/fldeff_cut.o" + .include "src/item_menu_icons.o" + .include "src/item.o" + .include "src/shop.o" + .include "src/special_field_anim.o" + .include "src/script_menu.o" + .include "src/naming_screen.o" + .include "src/money.o" + .include "src/safari_zone.o" + .include "src/item_use.o" + .include "src/battle_anim_effects_1.o" + .include "src/battle_anim_dragon.o" + .include "src/battle_anim_utility_funcs.o" + .include "src/battle_intro.o" + .include "src/easy_chat.o" + .include "src/mon_markings.o" + .include "src/mail.o" + .include "src/menu_helpers.o" + .include "src/region_map.o" + .include "src/battle_ai_script_commands.o" + .include "src/fldeff_rocksmash.o" + .include "src/field_specials.o" + .include "src/battle_records.o" + .include "src/evolution_scene.o" + .include "src/coins.o" + .include "src/battle_transition.o" + .include "src/battle_message.o" + .include "src/save.o" + .include "src/mystery_event_script.o" + .include "src/fldeff_sweetscent.o" + .include "src/learn_move.o" + .include "src/battle_tower.o" + .include "src/player_pc.o" + .include "src/intro.o" + .include "src/hall_of_fame.o" + .include "src/credits.o" + .include "src/diploma.o" + .include "src/save_failed_screen.o" + .include "src/clear_save_data_screen.o" + .include "src/new_menu_helpers.o" + .include "src/tilemap_util.o" + .include "src/map_preview_screen.o" + .include "src/link_rfu_2.o" + .include "src/link_rfu_3.o" + .include "src/easy_chat_2.o" + .include "src/easy_chat_3.o" + .include "src/pokedex_screen.o" + .include "src/list_menu.o" + .include "src/item_menu.o" + .include "src/bag.o" + .include "src/trainer_pokemon_sprites.o" + .include "src/vs_seeker.o" + .include "src/item_pc.o" + .include "src/mailbox_pc.o" + .include "src/menu.o" + .include "src/quest_log.o" + .include "src/help_message.o" + .include "src/quest_log_events.o" + .include "src/union_room.o" + .include "src/union_room_player_avatar.o" + .include "src/union_room_battle.o" + .include "src/pokemon_special_anim.o" + .include "src/party_menu.o" + .include "src/union_room_chat.o" + .include "src/union_room_chat_display.o" + .include "src/union_room_chat_objects.o" + .include "src/help_system.o" + .include "src/fame_checker.o" + .include "src/oak_speech.o" + .include "src/tm_case.o" + .include "src/menu_indicators.o" + .include "src/pokemon_summary_screen.o" + .include "src/help_system_util.o" + .include "src/dynamic_placeholder_text_util.o" + .include "src/berry_pouch.o" + .include "src/slot_machine.o" + .include "src/roamer.o" + .include "src/mystery_gift_menu.o" + .include "src/mystery_gift.o" + .include "src/mystery_gift_link.o" + .include "src/mystery_gift_client.o" + .include "src/mystery_gift_server.o" + .include "src/mystery_gift_show_card.o" + .include "src/mystery_gift_show_news.o" + .include "src/seagallop.o" + .include "src/pokemon_jump.o" + .include "src/berry_crush.o" + .include "src/dodrio_berry_picking.o" + .include "src/teachy_tv.o" + .include "src/digit_obj_util.o" + .include "src/trainer_tower.o" + .include "src/berry_powder.o"