gBattleControllerExecFlags bits now identified via helper macros

Created "exposition" macros to describe operations performed on gBattleControllerExecFlags. Updated the battle engine internals to use them, to more clearly document how battle link communications actually work.
This commit is contained in:
DavidJCobb
2025-04-26 00:45:03 -04:00
parent 9dc48899d3
commit a4370ffcde
4 changed files with 74 additions and 18 deletions

View File

@@ -64,6 +64,47 @@ enum {
REQUEST_TOUGH_RIBBON_BATTLE,
};
// Accessors for gBattleControllerExecFlags.
//
// These are provided for documentation purposes, to make the battle
// controller internals and the link communication internals more
// legible. Several of these have functions that you should call
// (e.g. MarkBattlerForControllerExec) instead of using these macros
// directly.
#define MARK_BATTLE_CONTROLLER_ACTIVE_ON_LOCAL(battlerId) \
do { gBattleControllerExecFlags |= gBitTable[battlerId] } while (0)
#define MARK_BATTLE_CONTROLLER_IDLE_ON_LOCAL(battlerId) \
do { gBattleControllerExecFlags &= ~gBitTable(battlerId) } while (0)
#define IS_BATTLE_CONTROLLER_ACTIVE_ON_LOCAL(battlerId) \
(gBattleControllerExecFlags & gBitTable[battlerId])
#define MARK_BATTLE_CONTROLLER_MESSAGE_OUTBOUND_OVER_LINK(battlerId) \
do { gBattleControllerExecFlags |= gBitTable[battlerId] << 28; } while (0)
#define MARK_BATTLE_CONTROLLER_MESSAGE_SYNCHRONIZED_OVER_LINK(battlerId) \
do { gBattleControllerExecFlags &= ~((1 << 28) << (battlerId)); }
#define MARK_BATTLE_CONTROLLER_ACTIVE_FOR_PLAYER(battlerId, playerId) \
do { gBattleControllerExecFlags |= gBitTable[battlerId] << ((playerId) << 2); } while (0)
#define MARK_BATTLE_CONTROLLER_IDLE_FOR_PLAYER(battlerId, playerId) \
do { gBattleControllerExecFlags &= ~(gBitTable[battlerId] << ((playerId) * 4)); } while (0)
#define IS_BATTLE_CONTROLLER_ACTIVE_FOR_PLAYER(battlerId, playerId) \
(gBattleControllerExecFlags & (gBitTable[battlerId] << ((playerId) * 4)))
#define IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(battlerId) \
(gBattleControllerExecFlags & ( \
(gBitTable[battlerId]) \
| (0xF << 28) \
| (gBitTable[battlerId] << 4) \
| (gBitTable[battlerId] << 8) \
| (gBitTable[battlerId] << 12) \
)
// Special arguments for Battle Controller functions.
enum {

View File

@@ -855,6 +855,13 @@ static void Task_HandleSendLinkBuffersData(u8 taskId)
}
// We have received a message. Place it into the "receive" buffer.
//
// Counterintuitively, we also "receive" the outbound messages that
// we send to other players. The GBA basically stores communicated
// data for all four players, so inbound and outbound data can be
// handled uniformly unless a game specifically decides to do
// otherwise. Pokemon, evidently, did not specifically decide to do
// otherwise.
void TryReceiveLinkBattleData(void)
{
u8 i;
@@ -916,7 +923,7 @@ static void Task_HandleCopyReceivedLinkBuffersData(u8 taskId)
switch (BYTE_TO_RECEIVE(0))
{
case BATTLELINKMSGTYPE_ENGINE_TO_CONTROLLER:
if (gBattleControllerExecFlags & gBitTable[battlerId])
if (IS_BATTLE_CONTROLLER_ACTIVE_ON_LOCAL(battlerId))
return;
memcpy(gBattleBufferA[battlerId], &BYTE_TO_RECEIVE(LINK_BUFF_DATA), blockSize);
@@ -935,7 +942,7 @@ static void Task_HandleCopyReceivedLinkBuffersData(u8 taskId)
break;
case BATTLELINKMSGTYPE_CONTROLLER_BECOMING_IDLE:
playerId = BYTE_TO_RECEIVE(LINK_BUFF_DATA);
gBattleControllerExecFlags &= ~(gBitTable[battlerId] << (playerId * 4));
MARK_BATTLE_CONTROLLER_IDLE_FOR_PLAYER(battlerId, playerId);
break;
}

View File

@@ -4173,7 +4173,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case STATE_WAIT_ACTION_CHOSEN: // Try to perform an action.
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
RecordedBattle_SetBattlerAction(gActiveBattler, gBattleBufferB[gActiveBattler][1]);
gChosenActionByBattler[gActiveBattler] = gBattleBufferB[gActiveBattler][1];
@@ -4352,7 +4352,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case STATE_WAIT_ACTION_CASE_CHOSEN:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
switch (gChosenActionByBattler[gActiveBattler])
{
@@ -4456,11 +4456,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case STATE_WAIT_ACTION_CONFIRMED_STANDBY:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler])
| (0xF << 28)
| (gBitTable[gActiveBattler] << 4)
| (gBitTable[gActiveBattler] << 8)
| (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
if (AllAtActionConfirmed())
i = TRUE;
@@ -4482,7 +4478,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case STATE_WAIT_ACTION_CONFIRMED:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
gBattleCommunication[ACTIONS_CONFIRMED_COUNT]++;
}
@@ -4496,7 +4492,7 @@ static void HandleTurnActionSelectionState(void)
{
gBattlerAttacker = gActiveBattler;
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBattler];
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
@@ -4504,7 +4500,7 @@ static void HandleTurnActionSelectionState(void)
}
break;
case STATE_WAIT_SET_BEFORE_ACTION:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
}
@@ -4528,7 +4524,7 @@ static void HandleTurnActionSelectionState(void)
{
gBattlerAttacker = gActiveBattler;
gBattlescriptCurrInstr = gSelectionBattleScripts[gActiveBattler];
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF << 28) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 12))))
if (!IS_BATTLE_CONTROLLER_ACTIVE_OR_PENDING_SYNC_ANYWHERE(gActiveBattler))
{
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}

View File

@@ -839,26 +839,38 @@ static void UNUSED MarkAllBattlersForControllerExec(void)
else
{
for (i = 0; i < gBattlersCount; i++)
gBattleControllerExecFlags |= gBitTable[i];
MARK_BATTLE_CONTROLLER_ACTIVE_ON_LOCAL(i);
}
}
// Called when the battle engine dispatches a message to a battle controller.
//
// During a singleplayer battle, we just immediately mark the controller as
// active. During a multiplayer link, we do things a little differently. We
// set a bit indicating that we're sending a message over the link. That
// message will be received by all other players... *and* by us, the player
// sending it, at which point we'll invoke MarkBattlerReceivedLinkData,
// below, to clear the "we're sending a message" bit and set the "controller
// is now active" bit.
void MarkBattlerForControllerExec(u8 battlerId)
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
gBattleControllerExecFlags |= gBitTable[battlerId] << (32 - MAX_BATTLERS_COUNT);
MARK_BATTLE_CONTROLLER_MESSAGE_OUTBOUND_OVER_LINK(battlerId);
else
gBattleControllerExecFlags |= gBitTable[battlerId];
MARK_BATTLE_CONTROLLER_ACTIVE_ON_LOCAL(battlerId);
}
// Called when a message dispatched from the battle engine to a battle
// controller is received over link communications. All players assume
// that if they've received the message, everyone else has as well.
void MarkBattlerReceivedLinkData(u8 battlerId)
{
s32 i;
for (i = 0; i < GetLinkPlayerCount(); i++)
gBattleControllerExecFlags |= gBitTable[battlerId] << (i << 2);
MARK_BATTLE_CONTROLLER_ACTIVE_FOR_PLAYER(battlerId, i);
gBattleControllerExecFlags &= ~((1 << 28) << battlerId);
MARK_BATTLE_CONTROLLER_MESSAGE_SYNCHRONIZED_OVER_LINK(battlerId);
}
void CancelMultiTurnMoves(u8 battler)