Add revision 10 changes (#722)

* revision 10 changes

* add rev10 to github actions

* add no-intro entry for leafgreen rev10
This commit is contained in:
Rairii 2026-03-21 21:12:48 +00:00 committed by GitHub
parent 0a86141109
commit 8f00ac8fe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 3103 additions and 79 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

1
firered_switch.sha1 Normal file
View File

@ -0,0 +1 @@
baa452d0b24629dd7782cfc07a8984085dde1311 pokefirered_switch.gba

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

36
include/sloopsvc.h Normal file
View File

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

View File

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

1062
ld_script_rev10.ld Normal file

File diff suppressed because it is too large Load Diff

1
leafgreen_switch.sha1 Normal file
View File

@ -0,0 +1 @@
62b9fc77549dbc67032eb6cbd0ea6ad3b825690f pokeleafgreen_switch.gba

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1512,6 +1512,13 @@ static bool8 RunFieldCallback(void)
return TRUE;
}
#if REVISION >= 0xA
void ClearFieldCallback(void)
{
gFieldCallback = NULL;
}
#endif
void CB2_NewGame(void)
{
FieldClearVBlankHBlankCallbacks();

View File

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

View File

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

View File

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

View File

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

294
src/sloopsvc.c Normal file
View File

@ -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(&params[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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

38
sym_bss_rev10.txt Normal file
View File

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

View File

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

56
sym_common_rev10.txt Normal file
View File

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

137
sym_ewram_rev10.txt Normal file
View File

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