Mark Revision 0xA changes that are actually bug fixes and tested

Things that address UBFixes are marked as such. What addresses BUGFIXES are marked as such.
This commit is contained in:
Mike-Goutokuji
2026-06-15 16:19:54 -04:00
parent 70b76a15df
commit d3cd09a4f4
16 changed files with 111 additions and 95 deletions

View File

@@ -180,7 +180,8 @@ void UpdateEscapeWarp(s16 x, s16 y);
bool8 SetDiveWarpEmerge(u16 x, u16 y);
bool8 SetDiveWarpDive(u16 x, u16 y);
#if REVISION >= 0xA
#if defined(BUGFIX) || REVISION >= 0xA
// Clears stale post-link callback after CB2_LinkError (see link.c).
void ClearFieldCallback(void);
#endif

View File

@@ -819,14 +819,15 @@ static void SetLinkBattleEndCallbacks(void)
void SetBattleEndCallbacks(void)
{
#if REVISION >= 0xA
#else
// BUGFIX: Link battles wait for RFU/cable idle and fade end before standby/close.
// SetLinkStandbyCallback no-ops while gRfu.callback is set, which could skip teardown.
#if !(defined(BUGFIX) || REVISION >= 0xA)
if (!gPaletteFade.active)
#endif
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
#if REVISION >= 0xA
#if REVISION >= 0xA || defined(BUGFIX)
if (!IsLinkTaskFinished() || gPaletteFade.active) return;
#endif
if (gWirelessCommType == 0)

View File

@@ -1160,7 +1160,8 @@ static void CB2_PreInitMultiBattle(void)
}
break;
case 2:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before closing link after multi battle party showcase.
#if defined(BUGFIX) || REVISION >= 0xA
if (IsLinkTaskFinished() && !gPaletteFade.active)
#else
if (!gPaletteFade.active)
@@ -3927,6 +3928,7 @@ static void ReturnFromBattleToOverworld(void)
if (gBattleTypeFlags & BATTLE_TYPE_ROAMER)
{
UpdateRoamerHPStatus(&gEnemyParty[0]);
// BUGFIX: Use == B_OUTCOME_WON, not &. Roar sets outcome to PLAYER_TELEPORTED (5); 5 & 1 is nonzero.
#if defined(BUGFIX) || REVISION >= 0xA
if ((gBattleOutcome == B_OUTCOME_WON) || gBattleOutcome == B_OUTCOME_CAUGHT || gBattleOutcome == B_OUTCOME_DREW)
#else

View File

@@ -718,7 +718,8 @@ static void Task_StartWirelessCableClubBattle(u8 taskId)
tState = 5;
break;
case 5:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before starting cable club battle standby.
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
SetLinkStandbyCallback();
@@ -923,7 +924,8 @@ static void Task_StartWirelessTrade(u8 taskId)
tState++;
break;
case 2:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before trade setup standby.
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
gSelectedTradeMonPositions[TRADE_PLAYER] = 0;

View File

@@ -207,7 +207,8 @@ static void Task_ReturnToFieldRecordMixing(u8 taskId)
switch (task->data[0])
{
case 0:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before wireless return-to-field standby.
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
SetLinkStandbyCallback();

View File

@@ -784,6 +784,7 @@ static void rfu_CB_pollConnectParent(u8 reqCommand, u16 reqResult)
u16 id;
u8 slot;
u8 bm_slot_flag, i;
// UBFIX: Initialize target_p; some failure paths never assign it before use.
#if REVISION >= 0xA || defined(UBFIX)
struct RfuTgtData *target_p = NULL;
#else
@@ -1424,6 +1425,7 @@ static u16 rfu_STC_setSendData_org(u8 ni_or_uni, u8 bmSendSlot, u8 subFrameSize,
{
u8 bm_slot_id, sendSlotFlag;
u8 frameSize;
// UBFIX: llFrameSize_p may be unset if parentChild is neither parent nor child.
#if REVISION >= 0xA || defined(UBFIX)
u8 *llFrameSize_p = NULL;
#else

View File

@@ -1425,7 +1425,9 @@ void CB2_LinkError(void)
{
u8 *tilemapBuffer;
#if REVISION >= 0xA
// BUGFIX: Link error calls ResetTasks() but leaves gFieldCallback set; overworld may
// then run a stale post-link callback on a dead connection (softlock / erratic link state).
#if defined(BUGFIX) || REVISION >= 0xA
ClearFieldCallback();
#endif
SetGpuReg(REG_OFFSET_DISPCNT, 0);

View File

@@ -134,6 +134,8 @@ void AgbMain()
RegisterRamReset(RESET_ALL);
#endif //MODERN
// It is white because the GBA Boot screen is white.
// Sloop does not display this screen, so fade from black instead.
#if REVISION >= 0xA
*(vu16 *)BG_PLTT = RGB_BLACK;
#else
@@ -184,6 +186,8 @@ void AgbMain()
&& (gMain.heldKeysRaw & B_START_SELECT) == B_START_SELECT)
{
rfu_REQ_stopMode();
// Note: Rev10 skips rfu_waitREQComplete for faster Sloop reset; keep the wait on real hardware.
#if REVISION < 0xA
rfu_waitREQComplete();
#endif

View File

@@ -567,12 +567,13 @@ s8 Menu_ProcessInputNoWrapClearOnChoose(void)
void DestroyYesNoMenu(void)
{
#if REVISION >= 0xA
// UBFIX: Guard double-destroy when sYesNoWindowId is already invalid.
#if REVISION >= 0xA || defined(UBFIX)
if (sYesNoWindowId == 0xFF) return;
#endif
ClearStdWindowAndFrameToTransparent(sYesNoWindowId, TRUE);
RemoveWindow(sYesNoWindowId);
#if REVISION >= 0xA
#if REVISION >= 0xA || defined(UBFIX)
sYesNoWindowId = 0xFF;
#endif
}

View File

@@ -1517,7 +1517,7 @@ static bool8 RunFieldCallback(void)
return TRUE;
}
#if REVISION >= 0xA
#if defined(BUGFIX) || REVISION >= 0xA
void ClearFieldCallback(void)
{
gFieldCallback = NULL;

View File

@@ -888,7 +888,8 @@ void Task_LinkFullSave(u8 taskId)
gTasks[taskId].data[0] = 1;
break;
case 1:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before link full-save standby (see also cases 7 and 9).
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
SetLinkStandbyCallback();
@@ -924,7 +925,8 @@ void Task_LinkFullSave(u8 taskId)
gTasks[taskId].data[0] = 7;
break;
case 7:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle between save sectors.
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
ClearContinueGameWarpStatus2();
@@ -942,7 +944,8 @@ void Task_LinkFullSave(u8 taskId)
}
break;
case 9:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before final post-save standby.
#if defined(BUGFIX) || REVISION >= 0xA
if (!IsLinkTaskFinished()) break;
#endif
SetLinkStandbyCallback();

View File

@@ -86,8 +86,8 @@ static void InsertTask(u8 newTaskId)
void DestroyTask(u8 taskId)
{
#if REVISION >= 0xA
// Bounds check on the task ID.
#if REVISION >= 0xA || defined(UBFIX)
// UBFIX: Invalid taskId would read past gTasks[].
if (taskId >= NUM_TASKS) return;
#endif
if (gTasks[taskId].isActive)

View File

@@ -2116,7 +2116,8 @@ static void CB_HandleTradeCanceled(void)
static void CB_InitExitCanceledTrade(void)
{
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before exiting a canceled trade.
#if defined(BUGFIX) || REVISION >= 0xA
if (IsLinkTaskFinished() && !gPaletteFade.active)
#else
if (!gPaletteFade.active)

View File

@@ -525,7 +525,8 @@ static void Task_TryBecomeLinkLeader(u8 taskId)
}
break;
case LL_STATE_MEMBER_LEFT:
#if REVISION >= 0xA
// BUGFIX: Use group size, not activity id, to pick the unavailable-player message.
#if defined(BUGFIX) || REVISION >= 0xA
id = (GROUP_MAX(sPlayerActivityGroupSize) != 2) ? 1 : 0;
#else
id = (GROUP_MAX(sPlayerCurrActivity) == 2) ? 1 : 0;
@@ -619,7 +620,8 @@ 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
// BUGFIX: Use LeaderPrunePlayerList return value to update playerCount.
#if defined(BUGFIX) || REVISION >= 0xA
data->playerCount = LeaderPrunePlayerList(data->playerList);
#else
LeaderPrunePlayerList(data->playerList);
@@ -966,11 +968,13 @@ static bool8 Leader_SetStateIfMemberListChanged(struct WirelessLink_Leader * dat
#endif
break;
case UNION_ROOM_SPAWN_OUT:
#if REVISION >= 0xA
// BUGFIX: Handle pending disconnect (countdown != 0) before player is fully removed.
#if defined(BUGFIX) || REVISION >= 0xA
case UNION_ROOM_SPAWN_OUT_SOON:
#endif
RfuSetStatus(RFU_STATUS_OK, 0);
#if REVISION >= 0xA
// BUGFIX: Prune list when member leaves (or is about to).
#if defined(BUGFIX) || REVISION >= 0xA
data->playerCount = LeaderPrunePlayerList(data->playerList);
#endif
RedrawListMenu(data->listTaskId);
@@ -1006,7 +1010,8 @@ static void ItemPrintFunc_PossibleGroupMembers(u8 windowId, u32 id, u8 y)
static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list)
{
struct WirelessLink_Leader * data = sWirelessLinkMain.leader;
#if REVISION >= 0xA
// BUGFIX: Classify spawn in/out by countdown so SPAWN_OUT_SOON can be handled.
#if defined(BUGFIX) || REVISION >= 0xA
s32 id;
#else
u8 ret = UNION_ROOM_SPAWN_NONE;
@@ -1030,7 +1035,7 @@ static u8 LeaderUpdateGroupMembership(struct RfuPlayerList * list)
{
// No new incoming player
data->playerList->players[i].groupScheduledAnim = UNION_ROOM_SPAWN_OUT;
#if REVISION >= 0xA
#if defined(BUGFIX) || REVISION >= 0xA
#else
ret = UNION_ROOM_SPAWN_OUT;
#endif
@@ -1041,7 +1046,7 @@ 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
#if defined(BUGFIX) || REVISION >= 0xA
id = 1;
{
struct RfuPlayerList* playerList = data->playerList;
@@ -1593,6 +1598,7 @@ static bool32 IsPartnerActivityAcceptable(u32 activity, u32 group)
return TRUE;
#ifdef UBFIX
// UBFIX: group <= ARRAY_COUNT may read one past sAcceptedActivityIds.
if (group < ARRAY_COUNT(sAcceptedActivityIds))
#else
if (group <= ARRAY_COUNT(sAcceptedActivityIds)) // UB: <= may access data outside the array
@@ -1992,7 +1998,8 @@ static void Task_RunScriptAndFadeToActivity(u8 taskId)
}
break;
case 2:
#if REVISION >= 0xA
// BUGFIX: Wait for link idle before activity start standby.
#if defined(BUGFIX) || REVISION >= 0xA
if (IsLinkTaskFinished() && !gPaletteFade.active)
#else
if (!gPaletteFade.active)

View File

@@ -179,7 +179,8 @@ void CB2_UnionRoomBattle(void)
case 50:
if (!UpdatePaletteFade())
{
#if REVISION >= 0xA
// BUGFIX: Defer standby until after fade; extra round syncs link before battle start.
#if REVISION >= 0xA || defined(BUGFIX)
#else
SetLinkStandbyCallback();
#endif
@@ -189,7 +190,7 @@ void CB2_UnionRoomBattle(void)
case 51:
if (IsLinkTaskFinished())
{
#if REVISION >= 0xA
#if REVISION >= 0xA || defined(BUGFIX)
SetLinkStandbyCallback();
gMain.state++;
#else
@@ -197,7 +198,7 @@ void CB2_UnionRoomBattle(void)
#endif
}
break;
#if REVISION >= 0xA
#if REVISION >= 0xA || defined(BUGFIX)
case 52:
if (IsLinkTaskFinished())
{

View File

@@ -144,7 +144,8 @@ 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
// UBFIX: NUM_GROUPTYPES is the array length, not a valid group_type / groupCounts index.
#if defined(UBFIX) || REVISION >= 0xA
{ACTIVITY_POKEMON_JUMP, GROUPTYPE_TOTAL, 0},
{ACTIVITY_BERRY_CRUSH, GROUPTYPE_TOTAL, 0},
{ACTIVITY_BERRY_PICK, GROUPTYPE_TOTAL, 0},
@@ -156,7 +157,8 @@ static const u8 sActivityGroupInfo[][3] = {
{ACTIVITY_SEARCH, GROUPTYPE_NONE, 0},
{ACTIVITY_SPIN_TRADE, GROUPTYPE_TRADE, 0},
{ACTIVITY_ITEM_TRADE, GROUPTYPE_NONE, 0},
#if REVISION >= 0xA
// UBFIX: Same invalid index as Jump/Crush/Pick above.
#if defined(UBFIX) || REVISION >= 0xA
{ACTIVITY_RECORD_CORNER, GROUPTYPE_TOTAL, 0},
#else
{ACTIVITY_RECORD_CORNER, NUM_GROUPTYPES, 0},
@@ -385,58 +387,50 @@ static void WCSS_AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *
AddTextPrinterParameterized4(windowId, fontId, x, y, fontId == FONT_SMALL ? 0 : 1, 0, textColor, TEXT_SKIP_DRAW, str);
}
static u32 CountPlayersInGroupAndGetActivity(struct RfuPlayer * player, u32 * groupCounts)
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;
s32 i, j;
#define group_activity(i) (sActivityGroupInfo[(i)][0])
#define group_type(i) (sActivityGroupInfo[(i)][1])
#define group_players(i) (sActivityGroupInfo[(i)][2])
// UBFIX: Bounds-check group_type before indexing groupCounts.
#if defined(UBFIX) || REVISION >= 0xA
if (player->groupScheduledAnim == UNION_ROOM_SPAWN_IN)
{
for (i = 0; i < ARRAY_COUNT(sActivityGroupInfo); i++)
{
u8 type = group_type(i);
if (type < NUM_GROUPTYPES && activity == group_activity(i))
{
u8 k = group_players(i);
if (k == 0)
{
for (j = 0; j < RFU_CHILD_MAX; j++)
if (player->rfu.data.partnerInfo[j] != 0)
k++;
k++;
}
groupCounts[type] += k;
break;
}
}
}
#else
for (i = 0; i < ARRAY_COUNT(sActivityGroupInfo); i++)
{
if (activity == group_activity(i) && player->groupScheduledAnim == UNION_ROOM_SPAWN_IN)
{
if (group_players(i) == 0)
{
k = 0;
for (j = 0; j < RFU_CHILD_MAX; j++)
if (player->rfu.data.partnerInfo[j] != 0) k++;
s32 k;
for (k = 0, j = 0; j < RFU_CHILD_MAX; j++)
if (player->rfu.data.partnerInfo[j] != 0)
k++;
k++;
groupCounts[group_type(i)] += k;
}
@@ -446,14 +440,13 @@ static u32 CountPlayersInGroupAndGetActivity(struct RfuPlayer * player, u32 * gr
}
}
}
#endif
#undef group_activity
#undef group_type
#undef group_players
#endif
return activity;
}
static bool32 HaveCountsChanged(const u32 * curCounts, const u32 * prevCounts)
@@ -471,52 +464,47 @@ static bool32 HaveCountsChanged(const u32 * curCounts, const u32 * prevCounts)
static bool32 UpdateCommunicationCounts(u32 * groupCounts, u32 * prevGroupCounts, u32 * activities, u8 taskId)
{
bool32 activitiesUpdated = FALSE;
bool32 activitiesChanged = FALSE;
u32 groupCountBuffer[NUM_GROUPTYPES] = {0, 0, 0, 0};
struct WirelessLink_Group * group = (void *)gTasks[taskId].data;
s32 i;
struct WirelessLink_Group *group = (void *)gTasks[taskId].data;
s32 i, activity;
for (i = 0; i < NUM_TASK_DATA; i++)
{
u32 activity = CountPlayersInGroupAndGetActivity(&group->playerList->players[i], groupCountBuffer);
activity = CountPlayersInGroupAndGetActivity(&group->playerList->players[i], groupCountBuffer);
if (activity != activities[i])
{
activities[i] = activity;
activitiesUpdated = TRUE;
activitiesChanged = TRUE;
}
}
#if REVISION >= 0xA
if (HaveCountsChanged(groupCountBuffer, prevGroupCounts))
#else
if (!HaveCountsChanged(groupCountBuffer, prevGroupCounts))
{
if (activitiesUpdated == TRUE)
return TRUE;
else
return FALSE;
}
#endif
{
memcpy(groupCounts, 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]
#if defined(BUGFIX) || REVISION >= 0xA
+ groupCounts[GROUPTYPE_TOTAL] // Missing count for activities not in above groups
#endif
;
// BUGFIX: Include activities counted in GROUPTYPE_TOTAL bucket.
#if defined(BUGFIX) || REVISION >= 0xA
+ groupCounts[GROUPTYPE_TOTAL]
#endif
;
#if REVISION >= 0xA
activitiesUpdated = TRUE;
activitiesChanged = TRUE;
#else
return TRUE;
#endif
}
#if REVISION >= 0xA
return activitiesUpdated;
return activitiesChanged;
#else
return TRUE;
if (activitiesChanged == TRUE)
return TRUE;
return FALSE;
#endif
}