I want to avoid the word "message" since PRET has already chosen "battle message" as the term for predefined strings usable in the battle scripts and UI.
I was considering the term "battle link packet" instead, but the library for wireless communications already uses the word "packet" even though GBATEK does not. I'm going with "battle link communication type" instead. For this particular context, I don't think we need a compound noun ("X type"); the singular noun "type" is fine enough.
3148 lines
119 KiB
C
3148 lines
119 KiB
C
#include "global.h"
|
|
#include "battle.h"
|
|
#include "battle_anim.h"
|
|
#include "battle_arena.h"
|
|
#include "battle_controllers.h"
|
|
#include "battle_dome.h"
|
|
#include "battle_interface.h"
|
|
#include "battle_message.h"
|
|
#include "battle_setup.h"
|
|
#include "battle_tv.h"
|
|
#include "bg.h"
|
|
#include "data.h"
|
|
#include "item.h"
|
|
#include "item_menu.h"
|
|
#include "link.h"
|
|
#include "main.h"
|
|
#include "m4a.h"
|
|
#include "palette.h"
|
|
#include "party_menu.h"
|
|
#include "pokeball.h"
|
|
#include "pokemon.h"
|
|
#include "random.h"
|
|
#include "recorded_battle.h"
|
|
#include "reshow_battle_screen.h"
|
|
#include "sound.h"
|
|
#include "string_util.h"
|
|
#include "task.h"
|
|
#include "text.h"
|
|
#include "util.h"
|
|
#include "window.h"
|
|
#include "constants/battle_anim.h"
|
|
#include "constants/items.h"
|
|
#include "constants/moves.h"
|
|
#include "constants/party_menu.h"
|
|
#include "constants/songs.h"
|
|
#include "constants/trainers.h"
|
|
#include "constants/rgb.h"
|
|
|
|
static void PlayerHandleGetMonData(void);
|
|
static void PlayerHandleSetMonData(void);
|
|
static void PlayerHandleSetRawMonData(void);
|
|
static void PlayerHandleLoadMonSprite(void);
|
|
static void PlayerHandleSwitchInAnim(void);
|
|
static void PlayerHandleReturnMonToBall(void);
|
|
static void PlayerHandleDrawTrainerPic(void);
|
|
static void PlayerHandleTrainerSlide(void);
|
|
static void PlayerHandleTrainerSlideBack(void);
|
|
static void PlayerHandleFaintAnimation(void);
|
|
static void PlayerHandlePaletteFade(void);
|
|
static void PlayerHandleSuccessBallThrowAnim(void);
|
|
static void PlayerHandleBallThrowAnim(void);
|
|
static void PlayerHandlePause(void);
|
|
static void PlayerHandleMoveAnimation(void);
|
|
static void PlayerHandlePrintString(void);
|
|
static void PlayerHandlePrintSelectionString(void);
|
|
static void PlayerHandleChooseAction(void);
|
|
static void PlayerHandleYesNoBox(void);
|
|
static void PlayerHandleChooseMove(void);
|
|
static void PlayerHandleChooseItem(void);
|
|
static void PlayerHandleChoosePokemon(void);
|
|
static void PlayerHandleCmd23(void);
|
|
static void PlayerHandleHealthBarUpdate(void);
|
|
static void PlayerHandleExpUpdate(void);
|
|
static void PlayerHandleStatusIconUpdate(void);
|
|
static void PlayerHandleStatusAnimation(void);
|
|
static void PlayerHandleStatusXor(void);
|
|
static void PlayerHandleDataTransfer(void);
|
|
static void PlayerHandleDMA3Transfer(void);
|
|
static void PlayerHandlePlayBGM(void);
|
|
static void PlayerHandleCmd32(void);
|
|
static void PlayerHandleTwoReturnValues(void);
|
|
static void PlayerHandleChosenMonReturnValue(void);
|
|
static void PlayerHandleOneReturnValue(void);
|
|
static void PlayerHandleOneReturnValue_Duplicate(void);
|
|
static void PlayerHandleClearUnkVar(void);
|
|
static void PlayerHandleSetUnkVar(void);
|
|
static void PlayerHandleClearUnkFlag(void);
|
|
static void PlayerHandleToggleUnkFlag(void);
|
|
static void PlayerHandleHitAnimation(void);
|
|
static void PlayerHandleCantSwitch(void);
|
|
static void PlayerHandlePlaySE(void);
|
|
static void PlayerHandlePlayFanfareOrBGM(void);
|
|
static void PlayerHandleFaintingCry(void);
|
|
static void PlayerHandleIntroSlide(void);
|
|
static void PlayerHandleIntroTrainerBallThrow(void);
|
|
static void PlayerHandleDrawPartyStatusSummary(void);
|
|
static void PlayerHandleHidePartyStatusSummary(void);
|
|
static void PlayerHandleEndBounceEffect(void);
|
|
static void PlayerHandleSpriteInvisibility(void);
|
|
static void PlayerHandleBattleAnimation(void);
|
|
static void PlayerHandleLinkStandbyMsg(void);
|
|
static void PlayerHandleResetActionMoveSelection(void);
|
|
static void PlayerHandleEndLinkBattle(void);
|
|
static void PlayerCmdEnd(void);
|
|
|
|
static void PlayerBufferRunCommand(void);
|
|
static void HandleInputChooseTarget(void);
|
|
static void HandleInputChooseMove(void);
|
|
static void MoveSelectionCreateCursorAt(u8, u8);
|
|
static void MoveSelectionDestroyCursorAt(u8);
|
|
static void MoveSelectionDisplayPpNumber(void);
|
|
static void MoveSelectionDisplayPpString(void);
|
|
static void MoveSelectionDisplayMoveType(void);
|
|
static void MoveSelectionDisplayMoveNames(void);
|
|
static void HandleMoveSwitching(void);
|
|
static void SwitchIn_HandleSoundAndEnd(void);
|
|
static void WaitForMonSelection(void);
|
|
static void CompleteWhenChoseItem(void);
|
|
static void Task_LaunchLvlUpAnim(u8);
|
|
static void Task_PrepareToGiveExpWithExpBar(u8);
|
|
static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8);
|
|
static void Task_GiveExpWithExpBar(u8);
|
|
static void Task_UpdateLvlInHealthbox(u8);
|
|
static void PrintLinkStandbyMsg(void);
|
|
static u32 CopyPlayerMonData(u8, u8 *);
|
|
static void SetPlayerMonData(u8);
|
|
static void StartSendOutAnim(u8, bool8);
|
|
static void DoSwitchOutAnimation(void);
|
|
static void PlayerDoMoveAnimation(void);
|
|
static void Task_StartSendOutAnim(u8);
|
|
static void EndDrawPartyStatusSummary(void);
|
|
|
|
static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(void) =
|
|
{
|
|
[CONTROLLER_GETMONDATA] = PlayerHandleGetMonData,
|
|
[CONTROLLER_GETRAWMONDATA] = PlayerHandleGetRawMonData,
|
|
[CONTROLLER_SETMONDATA] = PlayerHandleSetMonData,
|
|
[CONTROLLER_SETRAWMONDATA] = PlayerHandleSetRawMonData,
|
|
[CONTROLLER_LOADMONSPRITE] = PlayerHandleLoadMonSprite,
|
|
[CONTROLLER_SWITCHINANIM] = PlayerHandleSwitchInAnim,
|
|
[CONTROLLER_RETURNMONTOBALL] = PlayerHandleReturnMonToBall,
|
|
[CONTROLLER_DRAWTRAINERPIC] = PlayerHandleDrawTrainerPic,
|
|
[CONTROLLER_TRAINERSLIDE] = PlayerHandleTrainerSlide,
|
|
[CONTROLLER_TRAINERSLIDEBACK] = PlayerHandleTrainerSlideBack,
|
|
[CONTROLLER_FAINTANIMATION] = PlayerHandleFaintAnimation,
|
|
[CONTROLLER_PALETTEFADE] = PlayerHandlePaletteFade,
|
|
[CONTROLLER_SUCCESSBALLTHROWANIM] = PlayerHandleSuccessBallThrowAnim,
|
|
[CONTROLLER_BALLTHROWANIM] = PlayerHandleBallThrowAnim,
|
|
[CONTROLLER_PAUSE] = PlayerHandlePause,
|
|
[CONTROLLER_MOVEANIMATION] = PlayerHandleMoveAnimation,
|
|
[CONTROLLER_PRINTSTRING] = PlayerHandlePrintString,
|
|
[CONTROLLER_PRINTSTRINGPLAYERONLY] = PlayerHandlePrintSelectionString,
|
|
[CONTROLLER_CHOOSEACTION] = PlayerHandleChooseAction,
|
|
[CONTROLLER_YESNOBOX] = PlayerHandleYesNoBox,
|
|
[CONTROLLER_CHOOSEMOVE] = PlayerHandleChooseMove,
|
|
[CONTROLLER_OPENBAG] = PlayerHandleChooseItem,
|
|
[CONTROLLER_CHOOSEPOKEMON] = PlayerHandleChoosePokemon,
|
|
[CONTROLLER_23] = PlayerHandleCmd23,
|
|
[CONTROLLER_HEALTHBARUPDATE] = PlayerHandleHealthBarUpdate,
|
|
[CONTROLLER_EXPUPDATE] = PlayerHandleExpUpdate,
|
|
[CONTROLLER_STATUSICONUPDATE] = PlayerHandleStatusIconUpdate,
|
|
[CONTROLLER_STATUSANIMATION] = PlayerHandleStatusAnimation,
|
|
[CONTROLLER_STATUSXOR] = PlayerHandleStatusXor,
|
|
[CONTROLLER_DATATRANSFER] = PlayerHandleDataTransfer,
|
|
[CONTROLLER_DMA3TRANSFER] = PlayerHandleDMA3Transfer,
|
|
[CONTROLLER_PLAYBGM] = PlayerHandlePlayBGM,
|
|
[CONTROLLER_32] = PlayerHandleCmd32,
|
|
[CONTROLLER_TWORETURNVALUES] = PlayerHandleTwoReturnValues,
|
|
[CONTROLLER_CHOSENMONRETURNVALUE] = PlayerHandleChosenMonReturnValue,
|
|
[CONTROLLER_ONERETURNVALUE] = PlayerHandleOneReturnValue,
|
|
[CONTROLLER_ONERETURNVALUE_DUPLICATE] = PlayerHandleOneReturnValue_Duplicate,
|
|
[CONTROLLER_CLEARUNKVAR] = PlayerHandleClearUnkVar,
|
|
[CONTROLLER_SETUNKVAR] = PlayerHandleSetUnkVar,
|
|
[CONTROLLER_CLEARUNKFLAG] = PlayerHandleClearUnkFlag,
|
|
[CONTROLLER_TOGGLEUNKFLAG] = PlayerHandleToggleUnkFlag,
|
|
[CONTROLLER_HITANIMATION] = PlayerHandleHitAnimation,
|
|
[CONTROLLER_CANTSWITCH] = PlayerHandleCantSwitch,
|
|
[CONTROLLER_PLAYSE] = PlayerHandlePlaySE,
|
|
[CONTROLLER_PLAYFANFAREORBGM] = PlayerHandlePlayFanfareOrBGM,
|
|
[CONTROLLER_FAINTINGCRY] = PlayerHandleFaintingCry,
|
|
[CONTROLLER_INTROSLIDE] = PlayerHandleIntroSlide,
|
|
[CONTROLLER_INTROTRAINERBALLTHROW] = PlayerHandleIntroTrainerBallThrow,
|
|
[CONTROLLER_DRAWPARTYSTATUSSUMMARY] = PlayerHandleDrawPartyStatusSummary,
|
|
[CONTROLLER_HIDEPARTYSTATUSSUMMARY] = PlayerHandleHidePartyStatusSummary,
|
|
[CONTROLLER_ENDBOUNCE] = PlayerHandleEndBounceEffect,
|
|
[CONTROLLER_SPRITEINVISIBILITY] = PlayerHandleSpriteInvisibility,
|
|
[CONTROLLER_BATTLEANIMATION] = PlayerHandleBattleAnimation,
|
|
[CONTROLLER_LINKSTANDBYMSG] = PlayerHandleLinkStandbyMsg,
|
|
[CONTROLLER_RESETACTIONMOVESELECTION] = PlayerHandleResetActionMoveSelection,
|
|
[CONTROLLER_ENDLINKBATTLE] = PlayerHandleEndLinkBattle,
|
|
[CONTROLLER_TERMINATOR_NOP] = PlayerCmdEnd
|
|
};
|
|
|
|
static const u8 sTargetIdentities[MAX_BATTLERS_COUNT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT};
|
|
|
|
// unknown unused data
|
|
static const u8 sUnused[] = {0x48, 0x48, 0x20, 0x5a, 0x50, 0x50, 0x50, 0x58};
|
|
|
|
void BattleControllerDummy(void)
|
|
{
|
|
}
|
|
|
|
void SetControllerToPlayer(void)
|
|
{
|
|
gBattlerControllerFuncs[gActiveBattler] = PlayerBufferRunCommand;
|
|
gDoingBattleAnim = FALSE;
|
|
gPlayerDpadHoldFrames = 0;
|
|
}
|
|
|
|
static void PlayerBufferExecCompleted(void)
|
|
{
|
|
gBattlerControllerFuncs[gActiveBattler] = PlayerBufferRunCommand;
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
{
|
|
u8 playerId = GetMultiplayerId();
|
|
|
|
PrepareBufferDataTransferLink(BATTLELINKCOMMTYPE_CONTROLLER_BECOMING_IDLE, 4, &playerId);
|
|
gBattleBufferA[gActiveBattler][0] = CONTROLLER_TERMINATOR_NOP;
|
|
}
|
|
else
|
|
{
|
|
gBattleControllerExecFlags &= ~gBitTable[gActiveBattler];
|
|
}
|
|
}
|
|
|
|
static void PlayerBufferRunCommand(void)
|
|
{
|
|
if (gBattleControllerExecFlags & gBitTable[gActiveBattler])
|
|
{
|
|
if (gBattleBufferA[gActiveBattler][0] < ARRAY_COUNT(sPlayerBufferCommands))
|
|
sPlayerBufferCommands[gBattleBufferA[gActiveBattler][0]]();
|
|
else
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void CompleteOnBankSpritePosX_0(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].x2 == 0)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void HandleInputChooseAction(void)
|
|
{
|
|
u16 itemId = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8);
|
|
|
|
DoBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX, 7, 1);
|
|
DoBounceEffect(gActiveBattler, BOUNCE_MON, 7, 1);
|
|
|
|
if (JOY_REPEAT(DPAD_ANY) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A)
|
|
gPlayerDpadHoldFrames++;
|
|
else
|
|
gPlayerDpadHoldFrames = 0;
|
|
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
|
|
switch (gActionSelectionCursor[gActiveBattler])
|
|
{
|
|
case 0: // Top left
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, B_ACTION_USE_MOVE, 0);
|
|
break;
|
|
case 1: // Top right
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, B_ACTION_USE_ITEM, 0);
|
|
break;
|
|
case 2: // Bottom left
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, B_ACTION_SWITCH, 0);
|
|
break;
|
|
case 3: // Bottom right
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, B_ACTION_RUN, 0);
|
|
break;
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else if (JOY_NEW(DPAD_LEFT))
|
|
{
|
|
if (gActionSelectionCursor[gActiveBattler] & 1) // if is B_ACTION_USE_ITEM or B_ACTION_RUN
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]);
|
|
gActionSelectionCursor[gActiveBattler] ^= 1;
|
|
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_RIGHT))
|
|
{
|
|
if (!(gActionSelectionCursor[gActiveBattler] & 1)) // if is B_ACTION_USE_MOVE or B_ACTION_SWITCH
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]);
|
|
gActionSelectionCursor[gActiveBattler] ^= 1;
|
|
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_UP))
|
|
{
|
|
if (gActionSelectionCursor[gActiveBattler] & 2) // if is B_ACTION_SWITCH or B_ACTION_RUN
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]);
|
|
gActionSelectionCursor[gActiveBattler] ^= 2;
|
|
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_DOWN))
|
|
{
|
|
if (!(gActionSelectionCursor[gActiveBattler] & 2)) // if is B_ACTION_USE_MOVE or B_ACTION_USE_ITEM
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
ActionSelectionDestroyCursorAt(gActionSelectionCursor[gActiveBattler]);
|
|
gActionSelectionCursor[gActiveBattler] ^= 2;
|
|
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
}
|
|
else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59)
|
|
{
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
&& GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT
|
|
&& !(gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)])
|
|
&& !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
{
|
|
if (gBattleBufferA[gActiveBattler][1] == B_ACTION_USE_ITEM)
|
|
{
|
|
// Add item to bag if it is a ball
|
|
if (itemId <= LAST_BALL)
|
|
AddBagItem(itemId, 1);
|
|
else
|
|
return;
|
|
}
|
|
PlaySE(SE_SELECT);
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, B_ACTION_CANCEL_PARTNER, 0);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
else if (JOY_NEW(START_BUTTON))
|
|
{
|
|
SwapHpBarsWithHpText();
|
|
}
|
|
}
|
|
|
|
static void UNUSED UnusedEndBounceEffect(void)
|
|
{
|
|
EndBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX);
|
|
EndBounceEffect(gActiveBattler, BOUNCE_MON);
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseTarget;
|
|
}
|
|
|
|
static void HandleInputChooseTarget(void)
|
|
{
|
|
s32 i;
|
|
u8 identities[MAX_BATTLERS_COUNT];
|
|
memcpy(identities, sTargetIdentities, ARRAY_COUNT(sTargetIdentities));
|
|
|
|
DoBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX, 15, 1);
|
|
|
|
// what a weird loop
|
|
i = 0;
|
|
if (gBattlersCount != 0)
|
|
{
|
|
do
|
|
{
|
|
if (i != gMultiUsePlayerCursor)
|
|
EndBounceEffect(i, BOUNCE_HEALTHBOX);
|
|
i++;
|
|
} while (i < gBattlersCount);
|
|
}
|
|
|
|
if (JOY_HELD(DPAD_ANY) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A)
|
|
gPlayerDpadHoldFrames++;
|
|
else
|
|
gPlayerDpadHoldFrames = 0;
|
|
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
|
|
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseMove;
|
|
DoBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX, 7, 1);
|
|
DoBounceEffect(gActiveBattler, BOUNCE_MON, 7, 1);
|
|
EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX);
|
|
}
|
|
else if (JOY_NEW(DPAD_LEFT | DPAD_UP))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
|
|
|
|
do
|
|
{
|
|
u8 currSelIdentity = GetBattlerPosition(gMultiUsePlayerCursor);
|
|
|
|
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
|
{
|
|
if (currSelIdentity == identities[i])
|
|
break;
|
|
}
|
|
do
|
|
{
|
|
if (--i < 0)
|
|
#ifdef UBFIX
|
|
i = MAX_BATTLERS_COUNT - 1;
|
|
#else
|
|
i = MAX_BATTLERS_COUNT; // UB: array out of range
|
|
#endif
|
|
gMultiUsePlayerCursor = GetBattlerAtPosition(identities[i]);
|
|
} while (gMultiUsePlayerCursor == gBattlersCount);
|
|
|
|
i = 0;
|
|
switch (GetBattlerPosition(gMultiUsePlayerCursor))
|
|
{
|
|
case B_POSITION_PLAYER_LEFT:
|
|
case B_POSITION_PLAYER_RIGHT:
|
|
if (gActiveBattler != gMultiUsePlayerCursor)
|
|
i++;
|
|
else if (gBattleMoves[GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler])].target & MOVE_TARGET_USER_OR_SELECTED)
|
|
i++;
|
|
break;
|
|
case B_POSITION_OPPONENT_LEFT:
|
|
case B_POSITION_OPPONENT_RIGHT:
|
|
i++;
|
|
break;
|
|
}
|
|
|
|
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
|
|
i = 0;
|
|
} while (i == 0);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_ShowAsMoveTarget;
|
|
}
|
|
else if (JOY_NEW(DPAD_RIGHT | DPAD_DOWN))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_HideAsMoveTarget;
|
|
|
|
do
|
|
{
|
|
u8 currSelIdentity = GetBattlerPosition(gMultiUsePlayerCursor);
|
|
|
|
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
|
{
|
|
if (currSelIdentity == identities[i])
|
|
break;
|
|
}
|
|
do
|
|
{
|
|
if (++i > 3)
|
|
i = 0;
|
|
gMultiUsePlayerCursor = GetBattlerAtPosition(identities[i]);
|
|
} while (gMultiUsePlayerCursor == gBattlersCount);
|
|
|
|
i = 0;
|
|
switch (GetBattlerPosition(gMultiUsePlayerCursor))
|
|
{
|
|
case B_POSITION_PLAYER_LEFT:
|
|
case B_POSITION_PLAYER_RIGHT:
|
|
if (gActiveBattler != gMultiUsePlayerCursor)
|
|
i++;
|
|
else if (gBattleMoves[GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler])].target & MOVE_TARGET_USER_OR_SELECTED)
|
|
i++;
|
|
break;
|
|
case B_POSITION_OPPONENT_LEFT:
|
|
case B_POSITION_OPPONENT_RIGHT:
|
|
i++;
|
|
break;
|
|
}
|
|
|
|
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
|
|
i = 0;
|
|
} while (i == 0);
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_ShowAsMoveTarget;
|
|
}
|
|
}
|
|
|
|
static void HandleInputChooseMove(void)
|
|
{
|
|
bool32 canSelectTarget = FALSE;
|
|
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleBufferA[gActiveBattler][4]);
|
|
|
|
if (JOY_HELD(DPAD_ANY) && gSaveBlock2Ptr->optionsButtonMode == OPTIONS_BUTTON_MODE_L_EQUALS_A)
|
|
gPlayerDpadHoldFrames++;
|
|
else
|
|
gPlayerDpadHoldFrames = 0;
|
|
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
u8 moveTarget;
|
|
|
|
PlaySE(SE_SELECT);
|
|
if (moveInfo->moves[gMoveSelectionCursor[gActiveBattler]] == MOVE_CURSE)
|
|
{
|
|
if (moveInfo->monTypes[0] != TYPE_GHOST && moveInfo->monTypes[1] != TYPE_GHOST)
|
|
moveTarget = MOVE_TARGET_USER;
|
|
else
|
|
moveTarget = MOVE_TARGET_SELECTED;
|
|
}
|
|
else
|
|
{
|
|
moveTarget = gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].target;
|
|
}
|
|
|
|
if (moveTarget & MOVE_TARGET_USER)
|
|
gMultiUsePlayerCursor = gActiveBattler;
|
|
else
|
|
gMultiUsePlayerCursor = GetBattlerAtPosition(BATTLE_OPPOSITE(GET_BATTLER_SIDE(gActiveBattler)));
|
|
|
|
if (!gBattleBufferA[gActiveBattler][1]) // not a double battle
|
|
{
|
|
if (moveTarget & MOVE_TARGET_USER_OR_SELECTED && !gBattleBufferA[gActiveBattler][2])
|
|
canSelectTarget++;
|
|
}
|
|
else // double battle
|
|
{
|
|
if (!(moveTarget & (MOVE_TARGET_RANDOM | MOVE_TARGET_BOTH | MOVE_TARGET_DEPENDS | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER)))
|
|
canSelectTarget++; // either selected or user
|
|
|
|
if (moveInfo->currentPp[gMoveSelectionCursor[gActiveBattler]] == 0)
|
|
{
|
|
canSelectTarget = FALSE;
|
|
}
|
|
else if (!(moveTarget & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED)) && CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_ACTIVE) <= 1)
|
|
{
|
|
gMultiUsePlayerCursor = GetDefaultMoveTarget(gActiveBattler);
|
|
canSelectTarget = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!canSelectTarget)
|
|
{
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 10, gMoveSelectionCursor[gActiveBattler] | (gMultiUsePlayerCursor << 8));
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseTarget;
|
|
|
|
if (moveTarget & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
|
|
gMultiUsePlayerCursor = gActiveBattler;
|
|
else if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)])
|
|
gMultiUsePlayerCursor = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
|
else
|
|
gMultiUsePlayerCursor = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
|
|
|
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCB_ShowAsMoveTarget;
|
|
}
|
|
}
|
|
else if (JOY_NEW(B_BUTTON) || gPlayerDpadHoldFrames > 59)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 10, 0xFFFF);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else if (JOY_NEW(DPAD_LEFT))
|
|
{
|
|
if (gMoveSelectionCursor[gActiveBattler] & 1)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_RIGHT))
|
|
{
|
|
if (!(gMoveSelectionCursor[gActiveBattler] & 1)
|
|
&& (gMoveSelectionCursor[gActiveBattler] ^ 1) < gNumberOfMovesToChoose)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_UP))
|
|
{
|
|
if (gMoveSelectionCursor[gActiveBattler] & 2)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_DOWN))
|
|
{
|
|
if (!(gMoveSelectionCursor[gActiveBattler] & 2)
|
|
&& (gMoveSelectionCursor[gActiveBattler] ^ 2) < gNumberOfMovesToChoose)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
}
|
|
else if (JOY_NEW(SELECT_BUTTON))
|
|
{
|
|
if (gNumberOfMovesToChoose > 1 && !(gBattleTypeFlags & BATTLE_TYPE_LINK))
|
|
{
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 29);
|
|
|
|
if (gMoveSelectionCursor[gActiveBattler] != 0)
|
|
gMultiUsePlayerCursor = 0;
|
|
else
|
|
gMultiUsePlayerCursor = gMoveSelectionCursor[gActiveBattler] + 1;
|
|
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
|
|
BattlePutTextOnWindow(gText_BattleSwitchWhich, B_WIN_SWITCH_PROMPT);
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleMoveSwitching;
|
|
}
|
|
}
|
|
}
|
|
|
|
static u32 UNUSED HandleMoveInputUnused(void)
|
|
{
|
|
u32 var = 0;
|
|
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
var = 1;
|
|
}
|
|
if (JOY_NEW(B_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
gBattle_BG0_X = 0;
|
|
gBattle_BG0_Y = DISPLAY_HEIGHT * 2;
|
|
var = 0xFF;
|
|
}
|
|
if (JOY_NEW(DPAD_LEFT) && gMoveSelectionCursor[gActiveBattler] & 1)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
if (JOY_NEW(DPAD_RIGHT) && !(gMoveSelectionCursor[gActiveBattler] & 1)
|
|
&& (gMoveSelectionCursor[gActiveBattler] ^ 1) < gNumberOfMovesToChoose)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
if (JOY_NEW(DPAD_UP) && gMoveSelectionCursor[gActiveBattler] & 2)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
if (JOY_NEW(DPAD_DOWN) && !(gMoveSelectionCursor[gActiveBattler] & 2)
|
|
&& (gMoveSelectionCursor[gActiveBattler] ^ 2) < gNumberOfMovesToChoose)
|
|
{
|
|
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
|
gMoveSelectionCursor[gActiveBattler] ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
}
|
|
|
|
return var;
|
|
}
|
|
|
|
static void HandleMoveSwitching(void)
|
|
{
|
|
u8 perMovePPBonuses[MAX_MON_MOVES];
|
|
struct ChooseMoveStruct moveStruct;
|
|
u8 totalPPBonuses;
|
|
|
|
if (JOY_NEW(A_BUTTON | SELECT_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMoveSelectionCursor[gActiveBattler] != gMultiUsePlayerCursor)
|
|
{
|
|
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleBufferA[gActiveBattler][4]);
|
|
s32 i;
|
|
|
|
// swap moves and pp
|
|
i = moveInfo->moves[gMoveSelectionCursor[gActiveBattler]];
|
|
moveInfo->moves[gMoveSelectionCursor[gActiveBattler]] = moveInfo->moves[gMultiUsePlayerCursor];
|
|
moveInfo->moves[gMultiUsePlayerCursor] = i;
|
|
|
|
i = moveInfo->currentPp[gMoveSelectionCursor[gActiveBattler]];
|
|
moveInfo->currentPp[gMoveSelectionCursor[gActiveBattler]] = moveInfo->currentPp[gMultiUsePlayerCursor];
|
|
moveInfo->currentPp[gMultiUsePlayerCursor] = i;
|
|
|
|
i = moveInfo->maxPp[gMoveSelectionCursor[gActiveBattler]];
|
|
moveInfo->maxPp[gMoveSelectionCursor[gActiveBattler]] = moveInfo->maxPp[gMultiUsePlayerCursor];
|
|
moveInfo->maxPp[gMultiUsePlayerCursor] = i;
|
|
|
|
if (gDisableStructs[gActiveBattler].mimickedMoves & gBitTable[gMoveSelectionCursor[gActiveBattler]])
|
|
{
|
|
gDisableStructs[gActiveBattler].mimickedMoves &= (~gBitTable[gMoveSelectionCursor[gActiveBattler]]);
|
|
gDisableStructs[gActiveBattler].mimickedMoves |= gBitTable[gMultiUsePlayerCursor];
|
|
}
|
|
|
|
MoveSelectionDisplayMoveNames();
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
perMovePPBonuses[i] = (gBattleMons[gActiveBattler].ppBonuses & (3 << (i * 2))) >> (i * 2);
|
|
|
|
totalPPBonuses = perMovePPBonuses[gMoveSelectionCursor[gActiveBattler]];
|
|
perMovePPBonuses[gMoveSelectionCursor[gActiveBattler]] = perMovePPBonuses[gMultiUsePlayerCursor];
|
|
perMovePPBonuses[gMultiUsePlayerCursor] = totalPPBonuses;
|
|
|
|
totalPPBonuses = 0;
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
totalPPBonuses |= perMovePPBonuses[i] << (i * 2);
|
|
|
|
gBattleMons[gActiveBattler].ppBonuses = totalPPBonuses;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
gBattleMons[gActiveBattler].moves[i] = moveInfo->moves[i];
|
|
gBattleMons[gActiveBattler].pp[i] = moveInfo->currentPp[i];
|
|
}
|
|
|
|
if (!(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
|
|
{
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
moveStruct.moves[i] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + i);
|
|
moveStruct.currentPp[i] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_PP1 + i);
|
|
}
|
|
|
|
totalPPBonuses = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_PP_BONUSES);
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
perMovePPBonuses[i] = (totalPPBonuses & (3 << (i * 2))) >> (i * 2);
|
|
|
|
i = moveStruct.moves[gMoveSelectionCursor[gActiveBattler]];
|
|
moveStruct.moves[gMoveSelectionCursor[gActiveBattler]] = moveStruct.moves[gMultiUsePlayerCursor];
|
|
moveStruct.moves[gMultiUsePlayerCursor] = i;
|
|
|
|
i = moveStruct.currentPp[gMoveSelectionCursor[gActiveBattler]];
|
|
moveStruct.currentPp[gMoveSelectionCursor[gActiveBattler]] = moveStruct.currentPp[gMultiUsePlayerCursor];
|
|
moveStruct.currentPp[gMultiUsePlayerCursor] = i;
|
|
|
|
totalPPBonuses = perMovePPBonuses[gMoveSelectionCursor[gActiveBattler]];
|
|
perMovePPBonuses[gMoveSelectionCursor[gActiveBattler]] = perMovePPBonuses[gMultiUsePlayerCursor];
|
|
perMovePPBonuses[gMultiUsePlayerCursor] = totalPPBonuses;
|
|
|
|
totalPPBonuses = 0;
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
totalPPBonuses |= perMovePPBonuses[i] << (i * 2);
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + i, &moveStruct.moves[i]);
|
|
SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_PP1 + i, &moveStruct.currentPp[i]);
|
|
}
|
|
|
|
SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_PP_BONUSES, &totalPPBonuses);
|
|
}
|
|
}
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseMove;
|
|
gMoveSelectionCursor[gActiveBattler] = gMultiUsePlayerCursor;
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpString();
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
else if (JOY_NEW(B_BUTTON | SELECT_BUTTON))
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseMove;
|
|
MoveSelectionDisplayPpString();
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
else if (JOY_NEW(DPAD_LEFT))
|
|
{
|
|
if (gMultiUsePlayerCursor & 1)
|
|
{
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 29);
|
|
else
|
|
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
|
|
|
|
gMultiUsePlayerCursor ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
|
|
else
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_RIGHT))
|
|
{
|
|
if (!(gMultiUsePlayerCursor & 1) && (gMultiUsePlayerCursor ^ 1) < gNumberOfMovesToChoose)
|
|
{
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 29);
|
|
else
|
|
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
|
|
|
|
gMultiUsePlayerCursor ^= 1;
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
|
|
else
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_UP))
|
|
{
|
|
if (gMultiUsePlayerCursor & 2)
|
|
{
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 29);
|
|
else
|
|
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
|
|
|
|
gMultiUsePlayerCursor ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
|
|
else
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
|
|
}
|
|
}
|
|
else if (JOY_NEW(DPAD_DOWN))
|
|
{
|
|
if (!(gMultiUsePlayerCursor & 2) && (gMultiUsePlayerCursor ^ 2) < gNumberOfMovesToChoose)
|
|
{
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 29);
|
|
else
|
|
MoveSelectionDestroyCursorAt(gMultiUsePlayerCursor);
|
|
|
|
gMultiUsePlayerCursor ^= 2;
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMultiUsePlayerCursor == gMoveSelectionCursor[gActiveBattler])
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 0);
|
|
else
|
|
MoveSelectionCreateCursorAt(gMultiUsePlayerCursor, 27);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SetLinkBattleEndCallbacks(void)
|
|
{
|
|
if (gWirelessCommType == 0)
|
|
{
|
|
if (gReceivedRemoteLinkPlayers == 0)
|
|
{
|
|
m4aSongNumStop(SE_LOW_HEALTH);
|
|
gMain.inBattle = FALSE;
|
|
gMain.callback1 = gPreBattleCallback1;
|
|
SetMainCallback2(CB2_InitEndLinkBattle);
|
|
if (gBattleOutcome == B_OUTCOME_WON)
|
|
TryPutLinkBattleTvShowOnAir();
|
|
FreeAllWindowBuffers();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (IsLinkTaskFinished())
|
|
{
|
|
m4aSongNumStop(SE_LOW_HEALTH);
|
|
gMain.inBattle = FALSE;
|
|
gMain.callback1 = gPreBattleCallback1;
|
|
SetMainCallback2(CB2_InitEndLinkBattle);
|
|
if (gBattleOutcome == B_OUTCOME_WON)
|
|
TryPutLinkBattleTvShowOnAir();
|
|
FreeAllWindowBuffers();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Despite handling link battles separately, this is only ever used by link battles
|
|
void SetBattleEndCallbacks(void)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
{
|
|
if (IsLinkTaskFinished())
|
|
{
|
|
if (gWirelessCommType == 0)
|
|
SetCloseLinkCallback();
|
|
else
|
|
SetLinkStandbyCallback();
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = SetLinkBattleEndCallbacks;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m4aSongNumStop(SE_LOW_HEALTH);
|
|
gMain.inBattle = FALSE;
|
|
gMain.callback1 = gPreBattleCallback1;
|
|
SetMainCallback2(gMain.savedCallback);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CompleteOnBattlerSpriteCallbackDummy(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void CompleteOnBankSpriteCallbackDummy2(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void FreeTrainerSpriteAfterSlide(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
{
|
|
BattleGfxSfxDummy3(gSaveBlock2Ptr->playerGender);
|
|
FreeSpriteOamMatrix(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void Intro_DelayAndEnd(void)
|
|
{
|
|
if (--gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].introEndDelay == (u8)-1)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].introEndDelay = 0;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void Intro_WaitForShinyAnimAndHealthbox(void)
|
|
{
|
|
bool8 healthboxAnimDone = FALSE;
|
|
|
|
// Check if healthbox has finished sliding in
|
|
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
|
|
{
|
|
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
healthboxAnimDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(gActiveBattler)]].callback == SpriteCallbackDummy)
|
|
healthboxAnimDone = TRUE;
|
|
}
|
|
|
|
// If healthbox and shiny anim are done
|
|
if (healthboxAnimDone && gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim
|
|
&& gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].finishedShinyMonAnim)
|
|
{
|
|
// Reset shiny anim (even if it didn't occur)
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].triedShinyMonAnim = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].finishedShinyMonAnim = FALSE;
|
|
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
|
|
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
|
|
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
|
|
if (IsDoubleBattle())
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(gActiveBattler)]], BATTLE_PARTNER(gActiveBattler));
|
|
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].introEndDelay = 3;
|
|
gBattlerControllerFuncs[gActiveBattler] = Intro_DelayAndEnd;
|
|
}
|
|
}
|
|
|
|
static void Intro_TryShinyAnimShowHealthbox(void)
|
|
{
|
|
bool32 bgmRestored = FALSE;
|
|
bool32 battlerAnimsDone = FALSE;
|
|
|
|
// Start shiny animation if applicable for 1st Pokémon
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive)
|
|
TryShinyAnimation(gActiveBattler, &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]]);
|
|
|
|
// Start shiny animation if applicable for 2nd Pokémon
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].triedShinyMonAnim
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].ballAnimActive)
|
|
TryShinyAnimation(BATTLE_PARTNER(gActiveBattler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(gActiveBattler)]]);
|
|
|
|
// Show healthbox after ball anim
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].ballAnimActive)
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted)
|
|
{
|
|
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
{
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(gActiveBattler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(gActiveBattler)]], HEALTHBOX_ALL);
|
|
StartHealthboxSlideIn(BATTLE_PARTNER(gActiveBattler));
|
|
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(gActiveBattler)]);
|
|
}
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], HEALTHBOX_ALL);
|
|
StartHealthboxSlideIn(gActiveBattler);
|
|
SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
}
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted = TRUE;
|
|
}
|
|
|
|
// Restore bgm after cry has played and healthbox anim is started
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].waitForCry
|
|
&& gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(gActiveBattler)].waitForCry
|
|
&& !IsCryPlayingOrClearCrySongs())
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].bgmRestored)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
m4aMPlayContinue(&gMPlayInfo_BGM);
|
|
else
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
|
|
}
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].bgmRestored = TRUE;
|
|
bgmRestored = TRUE;
|
|
}
|
|
|
|
// Wait for battler anims
|
|
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
|
|
{
|
|
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
{
|
|
battlerAnimsDone = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& gSprites[gBattleControllerData[BATTLE_PARTNER(gActiveBattler)]].callback == SpriteCallbackDummy
|
|
&& gSprites[gBattlerSpriteIds[BATTLE_PARTNER(gActiveBattler)]].callback == SpriteCallbackDummy)
|
|
{
|
|
battlerAnimsDone = TRUE;
|
|
}
|
|
}
|
|
|
|
// Clean up
|
|
if (bgmRestored && battlerAnimsDone)
|
|
{
|
|
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(gActiveBattler)]]);
|
|
DestroySprite(&gSprites[gBattleControllerData[gActiveBattler]]);
|
|
|
|
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].bgmRestored = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].healthboxSlideInStarted = FALSE;
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = Intro_WaitForShinyAnimAndHealthbox;
|
|
}
|
|
}
|
|
|
|
static void SwitchIn_CleanShinyAnimShowSubstitute(void)
|
|
{
|
|
if (gSprites[gHealthboxSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim
|
|
&& gSprites[gBattlerSpriteIds[gActiveBattler]].callback == SpriteCallbackDummy)
|
|
{
|
|
CopyBattleSpriteInvisibility(gActiveBattler);
|
|
|
|
// Reset shiny anim (even if it didn't occur)
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim = FALSE;
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].finishedShinyMonAnim = FALSE;
|
|
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
|
|
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
|
|
|
|
// Check if Substitute should be shown
|
|
if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute)
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_MON_TO_SUBSTITUTE);
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = SwitchIn_HandleSoundAndEnd;
|
|
}
|
|
}
|
|
|
|
static void SwitchIn_HandleSoundAndEnd(void)
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive
|
|
&& !IsCryPlayingOrClearCrySongs())
|
|
{
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void SwitchIn_TryShinyAnimShowHealthbox(void)
|
|
{
|
|
// Start shiny animation if applicable
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].triedShinyMonAnim
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive)
|
|
TryShinyAnimation(gActiveBattler, &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]]);
|
|
|
|
// Wait for ball anim, then show healthbox
|
|
if (gSprites[gBattleControllerData[gActiveBattler]].callback == SpriteCallbackDummy
|
|
&& !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].ballAnimActive)
|
|
{
|
|
DestroySprite(&gSprites[gBattleControllerData[gActiveBattler]]);
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], HEALTHBOX_ALL);
|
|
StartHealthboxSlideIn(gActiveBattler);
|
|
SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
gBattlerControllerFuncs[gActiveBattler] = SwitchIn_CleanShinyAnimShowSubstitute;
|
|
}
|
|
}
|
|
|
|
void Task_PlayerController_RestoreBgmAfterCry(u8 taskId)
|
|
{
|
|
if (!IsCryPlayingOrClearCrySongs())
|
|
{
|
|
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
static void CompleteOnHealthbarDone(void)
|
|
{
|
|
s16 hpValue = MoveBattleBar(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], HEALTH_BAR, 0);
|
|
|
|
SetHealthboxSpriteVisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
|
|
if (hpValue != -1)
|
|
{
|
|
UpdateHpTextInHealthbox(gHealthboxSpriteIds[gActiveBattler], hpValue, HP_CURRENT);
|
|
}
|
|
else
|
|
{
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void CompleteOnInactiveTextPrinter(void)
|
|
{
|
|
if (!IsTextPrinterActive(B_WIN_MSG))
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
#define tExpTask_monId data[0]
|
|
#define tExpTask_gainedExp data[1]
|
|
#define tExpTask_battler data[2]
|
|
#define tExpTask_frames data[10]
|
|
|
|
static void Task_GiveExpToMon(u8 taskId)
|
|
{
|
|
u32 monId = (u8)(gTasks[taskId].tExpTask_monId);
|
|
u8 battlerId = gTasks[taskId].tExpTask_battler;
|
|
s16 gainedExp = gTasks[taskId].tExpTask_gainedExp;
|
|
|
|
if (IsDoubleBattle() == TRUE || monId != gBattlerPartyIndexes[battlerId]) // Give exp without moving the expbar.
|
|
{
|
|
struct Pokemon *mon = &gPlayerParty[monId];
|
|
u16 species = GetMonData(mon, MON_DATA_SPECIES);
|
|
u8 level = GetMonData(mon, MON_DATA_LEVEL);
|
|
u32 currExp = GetMonData(mon, MON_DATA_EXP);
|
|
u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];
|
|
|
|
if (currExp + gainedExp >= nextLvlExp)
|
|
{
|
|
u8 savedActiveBattler;
|
|
|
|
SetMonData(mon, MON_DATA_EXP, &nextLvlExp);
|
|
CalculateMonStats(mon);
|
|
gainedExp -= nextLvlExp - currExp;
|
|
savedActiveBattler = gActiveBattler;
|
|
gActiveBattler = battlerId;
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, RET_VALUE_LEVELED_UP, gainedExp);
|
|
gActiveBattler = savedActiveBattler;
|
|
|
|
if (IsDoubleBattle() == TRUE
|
|
&& ((u16)(monId) == gBattlerPartyIndexes[battlerId] || (u16)(monId) == gBattlerPartyIndexes[BATTLE_PARTNER(battlerId)]))
|
|
gTasks[taskId].func = Task_LaunchLvlUpAnim;
|
|
else
|
|
gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
|
|
}
|
|
else
|
|
{
|
|
currExp += gainedExp;
|
|
SetMonData(mon, MON_DATA_EXP, &currExp);
|
|
gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gTasks[taskId].func = Task_PrepareToGiveExpWithExpBar;
|
|
}
|
|
}
|
|
|
|
static void Task_PrepareToGiveExpWithExpBar(u8 taskId)
|
|
{
|
|
u8 monIndex = gTasks[taskId].tExpTask_monId;
|
|
s32 gainedExp = gTasks[taskId].tExpTask_gainedExp;
|
|
u8 battlerId = gTasks[taskId].tExpTask_battler;
|
|
struct Pokemon *mon = &gPlayerParty[monIndex];
|
|
u8 level = GetMonData(mon, MON_DATA_LEVEL);
|
|
u16 species = GetMonData(mon, MON_DATA_SPECIES);
|
|
u32 exp = GetMonData(mon, MON_DATA_EXP);
|
|
u32 currLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level];
|
|
u32 expToNextLvl;
|
|
|
|
exp -= currLvlExp;
|
|
expToNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1] - currLvlExp;
|
|
SetBattleBarStruct(battlerId, gHealthboxSpriteIds[battlerId], expToNextLvl, exp, -gainedExp);
|
|
PlaySE(SE_EXP);
|
|
gTasks[taskId].func = Task_GiveExpWithExpBar;
|
|
}
|
|
|
|
static void Task_GiveExpWithExpBar(u8 taskId)
|
|
{
|
|
if (gTasks[taskId].tExpTask_frames < 13)
|
|
{
|
|
gTasks[taskId].tExpTask_frames++;
|
|
}
|
|
else
|
|
{
|
|
u8 monId = gTasks[taskId].tExpTask_monId;
|
|
s16 gainedExp = gTasks[taskId].tExpTask_gainedExp;
|
|
u8 battlerId = gTasks[taskId].tExpTask_battler;
|
|
s16 newExpPoints;
|
|
|
|
newExpPoints = MoveBattleBar(battlerId, gHealthboxSpriteIds[battlerId], EXP_BAR, 0);
|
|
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battlerId]);
|
|
if (newExpPoints == -1) // The bar has been filled with given exp points.
|
|
{
|
|
u8 level;
|
|
s32 currExp;
|
|
u16 species;
|
|
s32 expOnNextLvl;
|
|
|
|
m4aSongNumStop(SE_EXP);
|
|
level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
|
|
currExp = GetMonData(&gPlayerParty[monId], MON_DATA_EXP);
|
|
species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES);
|
|
expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];
|
|
|
|
if (currExp + gainedExp >= expOnNextLvl)
|
|
{
|
|
u8 savedActiveBattler;
|
|
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl);
|
|
CalculateMonStats(&gPlayerParty[monId]);
|
|
gainedExp -= expOnNextLvl - currExp;
|
|
savedActiveBattler = gActiveBattler;
|
|
gActiveBattler = battlerId;
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, RET_VALUE_LEVELED_UP, gainedExp);
|
|
gActiveBattler = savedActiveBattler;
|
|
gTasks[taskId].func = Task_LaunchLvlUpAnim;
|
|
}
|
|
else
|
|
{
|
|
currExp += gainedExp;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp);
|
|
gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Task_LaunchLvlUpAnim(u8 taskId)
|
|
{
|
|
u8 battlerId = gTasks[taskId].tExpTask_battler;
|
|
u8 monIndex = gTasks[taskId].tExpTask_monId;
|
|
|
|
if (IsDoubleBattle() == TRUE && monIndex == gBattlerPartyIndexes[BATTLE_PARTNER(battlerId)])
|
|
battlerId ^= BIT_FLANK;
|
|
|
|
InitAndLaunchSpecialAnimation(battlerId, battlerId, battlerId, B_ANIM_LVL_UP);
|
|
gTasks[taskId].func = Task_UpdateLvlInHealthbox;
|
|
}
|
|
|
|
static void Task_UpdateLvlInHealthbox(u8 taskId)
|
|
{
|
|
u8 battlerId = gTasks[taskId].tExpTask_battler;
|
|
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[battlerId].specialAnimActive)
|
|
{
|
|
u8 monIndex = gTasks[taskId].tExpTask_monId;
|
|
|
|
GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value.
|
|
|
|
if (IsDoubleBattle() == TRUE && monIndex == gBattlerPartyIndexes[BATTLE_PARTNER(battlerId)])
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battlerId)], &gPlayerParty[monIndex], HEALTHBOX_ALL);
|
|
else
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[battlerId], &gPlayerParty[monIndex], HEALTHBOX_ALL);
|
|
|
|
gTasks[taskId].func = DestroyExpTaskAndCompleteOnInactiveTextPrinter;
|
|
}
|
|
}
|
|
|
|
static void DestroyExpTaskAndCompleteOnInactiveTextPrinter(u8 taskId)
|
|
{
|
|
u8 monIndex;
|
|
u8 battlerId;
|
|
|
|
monIndex = gTasks[taskId].tExpTask_monId;
|
|
GetMonData(&gPlayerParty[monIndex], MON_DATA_LEVEL); // Unused return value.
|
|
battlerId = gTasks[taskId].tExpTask_battler;
|
|
gBattlerControllerFuncs[battlerId] = CompleteOnInactiveTextPrinter;
|
|
DestroyTask(taskId);
|
|
}
|
|
|
|
static void FreeMonSpriteAfterFaintAnim(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].y + gSprites[gBattlerSpriteIds[gActiveBattler]].y2 > DISPLAY_HEIGHT)
|
|
{
|
|
u16 species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES);
|
|
|
|
BattleGfxSfxDummy2(species);
|
|
FreeOamMatrix(gSprites[gBattlerSpriteIds[gActiveBattler]].oam.matrixNum);
|
|
DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void FreeMonSpriteAfterSwitchOutAnim(void)
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
{
|
|
FreeSpriteOamMatrix(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void CompleteOnInactiveTextPrinter2(void)
|
|
{
|
|
if (!IsTextPrinterActive(B_WIN_MSG))
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void OpenPartyMenuToChooseMon(void)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
{
|
|
u8 caseId;
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = WaitForMonSelection;
|
|
caseId = gTasks[gBattleControllerData[gActiveBattler]].data[0];
|
|
DestroyTask(gBattleControllerData[gActiveBattler]);
|
|
FreeAllWindowBuffers();
|
|
OpenPartyMenuInBattle(caseId);
|
|
}
|
|
}
|
|
|
|
static void WaitForMonSelection(void)
|
|
{
|
|
if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
|
|
{
|
|
if (gPartyMenuUseExitCallback == TRUE)
|
|
BtlController_EmitChosenMonReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, gSelectedMonPartyId, gBattlePartyCurrentOrder);
|
|
else
|
|
BtlController_EmitChosenMonReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, PARTY_SIZE, NULL);
|
|
|
|
if ((gBattleBufferA[gActiveBattler][1] & 0xF) == 1)
|
|
PrintLinkStandbyMsg();
|
|
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void OpenBagAndChooseItem(void)
|
|
{
|
|
if (!gPaletteFade.active)
|
|
{
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteWhenChoseItem;
|
|
ReshowBattleScreenDummy();
|
|
FreeAllWindowBuffers();
|
|
CB2_BagMenuFromBattle();
|
|
}
|
|
}
|
|
|
|
static void CompleteWhenChoseItem(void)
|
|
{
|
|
if (gMain.callback2 == BattleMainCB2 && !gPaletteFade.active)
|
|
{
|
|
BtlController_EmitOneReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, gSpecialVar_ItemId);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void CompleteOnSpecialAnimDone(void)
|
|
{
|
|
if (!gDoingBattleAnim || !gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void DoHitAnimBlinkSpriteEffect(void)
|
|
{
|
|
u8 spriteId = gBattlerSpriteIds[gActiveBattler];
|
|
|
|
if (gSprites[spriteId].data[1] == 32)
|
|
{
|
|
gSprites[spriteId].data[1] = 0;
|
|
gSprites[spriteId].invisible = FALSE;
|
|
gDoingBattleAnim = FALSE;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
if ((gSprites[spriteId].data[1] % 4) == 0)
|
|
gSprites[spriteId].invisible ^= 1;
|
|
gSprites[spriteId].data[1]++;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleYesNoInput(void)
|
|
{
|
|
if (JOY_NEW(DPAD_UP) && gMultiUsePlayerCursor != 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gMultiUsePlayerCursor);
|
|
gMultiUsePlayerCursor = 0;
|
|
BattleCreateYesNoCursorAt(0);
|
|
}
|
|
if (JOY_NEW(DPAD_DOWN) && gMultiUsePlayerCursor == 0)
|
|
{
|
|
PlaySE(SE_SELECT);
|
|
BattleDestroyYesNoCursorAt(gMultiUsePlayerCursor);
|
|
gMultiUsePlayerCursor = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
}
|
|
if (JOY_NEW(A_BUTTON))
|
|
{
|
|
HandleBattleWindow(YESNOBOX_X_Y, WINDOW_CLEAR);
|
|
PlaySE(SE_SELECT);
|
|
|
|
if (gMultiUsePlayerCursor != 0)
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0xE, 0);
|
|
else
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0xD, 0);
|
|
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
if (JOY_NEW(B_BUTTON))
|
|
{
|
|
HandleBattleWindow(YESNOBOX_X_Y, WINDOW_CLEAR);
|
|
PlaySE(SE_SELECT);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void MoveSelectionDisplayMoveNames(void)
|
|
{
|
|
s32 i;
|
|
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleBufferA[gActiveBattler][4]);
|
|
gNumberOfMovesToChoose = 0;
|
|
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
MoveSelectionDestroyCursorAt(i);
|
|
StringCopy(gDisplayedStringBattle, gMoveNames[moveInfo->moves[i]]);
|
|
// Prints on windows B_WIN_MOVE_NAME_1, B_WIN_MOVE_NAME_2, B_WIN_MOVE_NAME_3, B_WIN_MOVE_NAME_4
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, i + B_WIN_MOVE_NAME_1);
|
|
if (moveInfo->moves[i] != MOVE_NONE)
|
|
gNumberOfMovesToChoose++;
|
|
}
|
|
}
|
|
|
|
static void MoveSelectionDisplayPpString(void)
|
|
{
|
|
StringCopy(gDisplayedStringBattle, gText_MoveInterfacePP);
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_PP);
|
|
}
|
|
|
|
static void MoveSelectionDisplayPpNumber(void)
|
|
{
|
|
u8 *txtPtr;
|
|
struct ChooseMoveStruct *moveInfo;
|
|
|
|
if (gBattleBufferA[gActiveBattler][2] == TRUE) // check if we didn't want to display pp number
|
|
return;
|
|
|
|
SetPpNumbersPaletteInMoveSelection();
|
|
moveInfo = (struct ChooseMoveStruct *)(&gBattleBufferA[gActiveBattler][4]);
|
|
txtPtr = ConvertIntToDecimalStringN(gDisplayedStringBattle, moveInfo->currentPp[gMoveSelectionCursor[gActiveBattler]], STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
*(txtPtr)++ = CHAR_SLASH;
|
|
ConvertIntToDecimalStringN(txtPtr, moveInfo->maxPp[gMoveSelectionCursor[gActiveBattler]], STR_CONV_MODE_RIGHT_ALIGN, 2);
|
|
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_PP_REMAINING);
|
|
}
|
|
|
|
static void MoveSelectionDisplayMoveType(void)
|
|
{
|
|
u8 *txtPtr;
|
|
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleBufferA[gActiveBattler][4]);
|
|
|
|
txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType);
|
|
*(txtPtr)++ = EXT_CTRL_CODE_BEGIN;
|
|
*(txtPtr)++ = EXT_CTRL_CODE_FONT;
|
|
*(txtPtr)++ = FONT_NORMAL;
|
|
|
|
StringCopy(txtPtr, gTypeNames[gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].type]);
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_TYPE);
|
|
}
|
|
|
|
static void MoveSelectionCreateCursorAt(u8 cursorPosition, u8 baseTileNum)
|
|
{
|
|
u16 src[2];
|
|
src[0] = baseTileNum + 1;
|
|
src[1] = baseTileNum + 2;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 9 * (cursorPosition & 1) + 1, 55 + (cursorPosition & 2), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
static void MoveSelectionDestroyCursorAt(u8 cursorPosition)
|
|
{
|
|
u16 src[2];
|
|
src[0] = 0x1016;
|
|
src[1] = 0x1016;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 9 * (cursorPosition & 1) + 1, 55 + (cursorPosition & 2), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
void ActionSelectionCreateCursorAt(u8 cursorPosition, u8 baseTileNum)
|
|
{
|
|
u16 src[2];
|
|
src[0] = 1;
|
|
src[1] = 2;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 7 * (cursorPosition & 1) + 16, 35 + (cursorPosition & 2), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
void ActionSelectionDestroyCursorAt(u8 cursorPosition)
|
|
{
|
|
u16 src[2];
|
|
src[0] = 0x1016;
|
|
src[1] = 0x1016;
|
|
|
|
CopyToBgTilemapBufferRect_ChangePalette(0, src, 7 * (cursorPosition & 1) + 16, 35 + (cursorPosition & 2), 1, 2, 0x11);
|
|
CopyBgTilemapBufferToVram(0);
|
|
}
|
|
|
|
void CB2_SetUpReshowBattleScreenAfterMenu(void)
|
|
{
|
|
SetMainCallback2(ReshowBattleScreenAfterMenu);
|
|
}
|
|
|
|
void CB2_SetUpReshowBattleScreenAfterMenu2(void)
|
|
{
|
|
SetMainCallback2(ReshowBattleScreenAfterMenu);
|
|
}
|
|
|
|
static void CompleteOnFinishedStatusAnimation(void)
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].statusAnimActive)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void CompleteOnFinishedBattleAnimation(void)
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animFromTableActive)
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PrintLinkStandbyMsg(void)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
{
|
|
gBattle_BG0_X = 0;
|
|
gBattle_BG0_Y = 0;
|
|
BattlePutTextOnWindow(gText_LinkStandby, B_WIN_MSG);
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleGetMonData(void)
|
|
{
|
|
u8 monData[sizeof(struct Pokemon) * 2 + 56]; // this allows to get full data of two Pokémon, trying to get more will result in overwriting data
|
|
u32 size = 0;
|
|
u8 monToCheck;
|
|
s32 i;
|
|
|
|
if (gBattleBufferA[gActiveBattler][2] == 0)
|
|
{
|
|
size += CopyPlayerMonData(gBattlerPartyIndexes[gActiveBattler], monData);
|
|
}
|
|
else
|
|
{
|
|
monToCheck = gBattleBufferA[gActiveBattler][2];
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
if (monToCheck & 1)
|
|
size += CopyPlayerMonData(i, monData + size);
|
|
monToCheck >>= 1;
|
|
}
|
|
}
|
|
BtlController_EmitDataTransfer(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, size, monData);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static u32 CopyPlayerMonData(u8 monId, u8 *dst)
|
|
{
|
|
struct BattlePokemon battleMon;
|
|
struct MovePpInfo moveData;
|
|
u8 nickname[POKEMON_NAME_BUFFER_SIZE];
|
|
u8 *src;
|
|
s16 data16;
|
|
u32 data32;
|
|
s32 size = 0;
|
|
|
|
switch (gBattleBufferA[gActiveBattler][1])
|
|
{
|
|
case REQUEST_ALL_BATTLE:
|
|
battleMon.species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES);
|
|
battleMon.item = GetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM);
|
|
for (size = 0; size < MAX_MON_MOVES; size++)
|
|
{
|
|
battleMon.moves[size] = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + size);
|
|
battleMon.pp[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size);
|
|
}
|
|
battleMon.ppBonuses = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES);
|
|
battleMon.friendship = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
|
|
battleMon.experience = GetMonData(&gPlayerParty[monId], MON_DATA_EXP);
|
|
battleMon.hpIV = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
|
|
battleMon.attackIV = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
|
|
battleMon.defenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
|
|
battleMon.speedIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
|
|
battleMon.spAttackIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
|
|
battleMon.spDefenseIV = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
|
|
battleMon.personality = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
|
|
battleMon.status1 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
|
|
battleMon.level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
|
|
battleMon.hp = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
|
|
battleMon.maxHP = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
|
|
battleMon.attack = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
|
|
battleMon.defense = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
|
|
battleMon.speed = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
|
|
battleMon.spAttack = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
|
|
battleMon.spDefense = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
|
|
battleMon.isEgg = GetMonData(&gPlayerParty[monId], MON_DATA_IS_EGG);
|
|
battleMon.abilityNum = GetMonData(&gPlayerParty[monId], MON_DATA_ABILITY_NUM);
|
|
battleMon.otId = GetMonData(&gPlayerParty[monId], MON_DATA_OT_ID);
|
|
GetMonData(&gPlayerParty[monId], MON_DATA_NICKNAME, nickname);
|
|
StringCopy_Nickname(battleMon.nickname, nickname);
|
|
GetMonData(&gPlayerParty[monId], MON_DATA_OT_NAME, battleMon.otName);
|
|
src = (u8 *)&battleMon;
|
|
for (size = 0; size < sizeof(battleMon); size++)
|
|
dst[size] = src[size];
|
|
break;
|
|
case REQUEST_SPECIES_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_HELDITEM_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_MOVES_PP_BATTLE:
|
|
for (size = 0; size < MAX_MON_MOVES; size++)
|
|
{
|
|
moveData.moves[size] = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + size);
|
|
moveData.pp[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size);
|
|
}
|
|
moveData.ppBonuses = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES);
|
|
src = (u8 *)(&moveData);
|
|
for (size = 0; size < sizeof(moveData); size++)
|
|
dst[size] = src[size];
|
|
break;
|
|
case REQUEST_MOVE1_BATTLE:
|
|
case REQUEST_MOVE2_BATTLE:
|
|
case REQUEST_MOVE3_BATTLE:
|
|
case REQUEST_MOVE4_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBattler][1] - REQUEST_MOVE1_BATTLE);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_PP_DATA_BATTLE:
|
|
for (size = 0; size < MAX_MON_MOVES; size++)
|
|
dst[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + size);
|
|
dst[size] = GetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES);
|
|
size++;
|
|
break;
|
|
case REQUEST_PPMOVE1_BATTLE:
|
|
case REQUEST_PPMOVE2_BATTLE:
|
|
case REQUEST_PPMOVE3_BATTLE:
|
|
case REQUEST_PPMOVE4_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBattler][1] - REQUEST_PPMOVE1_BATTLE);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_OTID_BATTLE:
|
|
data32 = GetMonData(&gPlayerParty[monId], MON_DATA_OT_ID);
|
|
dst[0] = (data32 & 0x000000FF);
|
|
dst[1] = (data32 & 0x0000FF00) >> 8;
|
|
dst[2] = (data32 & 0x00FF0000) >> 16;
|
|
size = 3;
|
|
break;
|
|
case REQUEST_EXP_BATTLE:
|
|
data32 = GetMonData(&gPlayerParty[monId], MON_DATA_EXP);
|
|
dst[0] = (data32 & 0x000000FF);
|
|
dst[1] = (data32 & 0x0000FF00) >> 8;
|
|
dst[2] = (data32 & 0x00FF0000) >> 16;
|
|
size = 3;
|
|
break;
|
|
case REQUEST_HP_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_ATK_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_DEF_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPEED_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPATK_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPDEF_EV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_FRIENDSHIP_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_POKERUS_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKERUS);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_MET_LOCATION_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_MET_LEVEL_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_MET_GAME_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_POKEBALL_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_ALL_IVS_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
|
|
dst[1] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
|
|
dst[2] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
|
|
dst[3] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
|
|
dst[4] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
|
|
dst[5] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
|
|
size = 6;
|
|
break;
|
|
case REQUEST_HP_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_HP_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_ATK_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_DEF_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPEED_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPATK_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SPDEF_IV_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_PERSONALITY_BATTLE:
|
|
data32 = GetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY);
|
|
dst[0] = (data32 & 0x000000FF);
|
|
dst[1] = (data32 & 0x0000FF00) >> 8;
|
|
dst[2] = (data32 & 0x00FF0000) >> 16;
|
|
dst[3] = (data32 & 0xFF000000) >> 24;
|
|
size = 4;
|
|
break;
|
|
case REQUEST_CHECKSUM_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_STATUS_BATTLE:
|
|
data32 = GetMonData(&gPlayerParty[monId], MON_DATA_STATUS);
|
|
dst[0] = (data32 & 0x000000FF);
|
|
dst[1] = (data32 & 0x0000FF00) >> 8;
|
|
dst[2] = (data32 & 0x00FF0000) >> 16;
|
|
dst[3] = (data32 & 0xFF000000) >> 24;
|
|
size = 4;
|
|
break;
|
|
case REQUEST_LEVEL_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_HP_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_HP);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_MAX_HP_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_ATK_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_ATK);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_DEF_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_DEF);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_SPEED_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPEED);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_SPATK_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPATK);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_SPDEF_BATTLE:
|
|
data16 = GetMonData(&gPlayerParty[monId], MON_DATA_SPDEF);
|
|
dst[0] = data16;
|
|
dst[1] = data16 >> 8;
|
|
size = 2;
|
|
break;
|
|
case REQUEST_COOL_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_BEAUTY_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_CUTE_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SMART_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_TOUGH_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SHEEN_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SHEEN);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_COOL_RIBBON_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_BEAUTY_RIBBON_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_CUTE_RIBBON_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_SMART_RIBBON_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON);
|
|
size = 1;
|
|
break;
|
|
case REQUEST_TOUGH_RIBBON_BATTLE:
|
|
dst[0] = GetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON);
|
|
size = 1;
|
|
break;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
void PlayerHandleGetRawMonData(void)
|
|
{
|
|
struct BattlePokemon battleMon;
|
|
u8 *src = (u8 *)&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]] + gBattleBufferA[gActiveBattler][1];
|
|
u8 *dst = (u8 *)&battleMon + gBattleBufferA[gActiveBattler][1];
|
|
u8 i;
|
|
|
|
for (i = 0; i < gBattleBufferA[gActiveBattler][2]; i++)
|
|
dst[i] = src[i];
|
|
|
|
BtlController_EmitDataTransfer(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, gBattleBufferA[gActiveBattler][2], dst);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleSetMonData(void)
|
|
{
|
|
u8 monToCheck;
|
|
u8 i;
|
|
|
|
if (gBattleBufferA[gActiveBattler][2] == 0)
|
|
{
|
|
SetPlayerMonData(gBattlerPartyIndexes[gActiveBattler]);
|
|
}
|
|
else
|
|
{
|
|
monToCheck = gBattleBufferA[gActiveBattler][2];
|
|
for (i = 0; i < PARTY_SIZE; i++)
|
|
{
|
|
if (monToCheck & 1)
|
|
SetPlayerMonData(i);
|
|
monToCheck >>= 1;
|
|
}
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void SetPlayerMonData(u8 monId)
|
|
{
|
|
struct BattlePokemon *battlePokemon = (struct BattlePokemon *)&gBattleBufferA[gActiveBattler][3];
|
|
struct MovePpInfo *moveData = (struct MovePpInfo *)&gBattleBufferA[gActiveBattler][3];
|
|
s32 i;
|
|
|
|
switch (gBattleBufferA[gActiveBattler][1])
|
|
{
|
|
case REQUEST_ALL_BATTLE:
|
|
{
|
|
u8 iv;
|
|
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &battlePokemon->species);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &battlePokemon->item);
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + i, &battlePokemon->moves[i]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + i, &battlePokemon->pp[i]);
|
|
}
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &battlePokemon->ppBonuses);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &battlePokemon->friendship);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &battlePokemon->experience);
|
|
iv = battlePokemon->hpIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &iv);
|
|
iv = battlePokemon->attackIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &iv);
|
|
iv = battlePokemon->defenseIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &iv);
|
|
iv = battlePokemon->speedIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &iv);
|
|
iv = battlePokemon->spAttackIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &iv);
|
|
iv = battlePokemon->spDefenseIV;
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &iv);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &battlePokemon->personality);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &battlePokemon->status1);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &battlePokemon->level);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP, &battlePokemon->hp);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &battlePokemon->maxHP);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &battlePokemon->attack);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &battlePokemon->defense);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &battlePokemon->speed);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &battlePokemon->spAttack);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &battlePokemon->spDefense);
|
|
}
|
|
break;
|
|
case REQUEST_SPECIES_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_HELDITEM_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HELD_ITEM, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_MOVES_PP_BATTLE:
|
|
for (i = 0; i < MAX_MON_MOVES; i++)
|
|
{
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + i, &moveData->moves[i]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + i, &moveData->pp[i]);
|
|
}
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &moveData->ppBonuses);
|
|
break;
|
|
case REQUEST_MOVE1_BATTLE:
|
|
case REQUEST_MOVE2_BATTLE:
|
|
case REQUEST_MOVE3_BATTLE:
|
|
case REQUEST_MOVE4_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MOVE1 + gBattleBufferA[gActiveBattler][1] - REQUEST_MOVE1_BATTLE, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_PP_DATA_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP1, &gBattleBufferA[gActiveBattler][3]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP2, &gBattleBufferA[gActiveBattler][4]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP3, &gBattleBufferA[gActiveBattler][5]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP4, &gBattleBufferA[gActiveBattler][6]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP_BONUSES, &gBattleBufferA[gActiveBattler][7]);
|
|
break;
|
|
case REQUEST_PPMOVE1_BATTLE:
|
|
case REQUEST_PPMOVE2_BATTLE:
|
|
case REQUEST_PPMOVE3_BATTLE:
|
|
case REQUEST_PPMOVE4_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PP1 + gBattleBufferA[gActiveBattler][1] - REQUEST_PPMOVE1_BATTLE, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_OTID_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_OT_ID, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_EXP_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_HP_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_ATK_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_DEF_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPEED_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPATK_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPDEF_EV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_EV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_FRIENDSHIP_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_FRIENDSHIP, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_POKERUS_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_POKERUS, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_MET_LOCATION_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MET_LOCATION, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_MET_LEVEL_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MET_LEVEL, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_MET_GAME_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MET_GAME, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_POKEBALL_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_POKEBALL, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_ALL_IVS_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBattler][4]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBattler][5]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBattler][6]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBattler][7]);
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBattler][8]);
|
|
break;
|
|
case REQUEST_HP_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_ATK_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_DEF_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPEED_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPATK_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPDEF_IV_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF_IV, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_PERSONALITY_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_PERSONALITY, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_CHECKSUM_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_CHECKSUM, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_STATUS_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_STATUS, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_LEVEL_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_LEVEL, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_HP_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_MAX_HP_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_MAX_HP, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_ATK_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_ATK, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_DEF_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_DEF, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPEED_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPEED, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPATK_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPATK, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SPDEF_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SPDEF, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_COOL_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_COOL, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_BEAUTY_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_CUTE_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_CUTE, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SMART_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SMART, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_TOUGH_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SHEEN_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SHEEN, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_COOL_RIBBON_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_COOL_RIBBON, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_BEAUTY_RIBBON_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_BEAUTY_RIBBON, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_CUTE_RIBBON_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_CUTE_RIBBON, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_SMART_RIBBON_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_SMART_RIBBON, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
case REQUEST_TOUGH_RIBBON_BATTLE:
|
|
SetMonData(&gPlayerParty[monId], MON_DATA_TOUGH_RIBBON, &gBattleBufferA[gActiveBattler][3]);
|
|
break;
|
|
}
|
|
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
}
|
|
|
|
static void PlayerHandleSetRawMonData(void)
|
|
{
|
|
u8 *dst = (u8 *)&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]] + gBattleBufferA[gActiveBattler][1];
|
|
u8 i;
|
|
|
|
for (i = 0; i < gBattleBufferA[gActiveBattler][2]; i++)
|
|
dst[i] = gBattleBufferA[gActiveBattler][3 + i];
|
|
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleLoadMonSprite(void)
|
|
{
|
|
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnBankSpritePosX_0;
|
|
}
|
|
|
|
static void PlayerHandleSwitchInAnim(void)
|
|
{
|
|
ClearTemporarySpeciesSpriteData(gActiveBattler, gBattleBufferA[gActiveBattler][2]);
|
|
gBattlerPartyIndexes[gActiveBattler] = gBattleBufferA[gActiveBattler][1];
|
|
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
gActionSelectionCursor[gActiveBattler] = 0;
|
|
gMoveSelectionCursor[gActiveBattler] = 0;
|
|
StartSendOutAnim(gActiveBattler, gBattleBufferA[gActiveBattler][2]);
|
|
gBattlerControllerFuncs[gActiveBattler] = SwitchIn_TryShinyAnimShowHealthbox;
|
|
}
|
|
|
|
static void StartSendOutAnim(u8 battlerId, bool8 dontClearSubstituteBit)
|
|
{
|
|
u16 species;
|
|
|
|
ClearTemporarySpeciesSpriteData(battlerId, dontClearSubstituteBit);
|
|
gBattlerPartyIndexes[battlerId] = gBattleBufferA[battlerId][1];
|
|
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
|
|
gBattleControllerData[battlerId] = CreateInvisibleSpriteWithCallback(SpriteCB_WaitForBattlerBallReleaseAnim);
|
|
SetMultiuseSpriteTemplateToPokemon(species, GetBattlerPosition(battlerId));
|
|
|
|
gBattlerSpriteIds[battlerId] = CreateSprite(
|
|
&gMultiuseSpriteTemplate,
|
|
GetBattlerSpriteCoord(battlerId, BATTLER_COORD_X_2),
|
|
GetBattlerSpriteDefault_Y(battlerId),
|
|
GetBattlerSpriteSubpriority(battlerId));
|
|
|
|
gSprites[gBattleControllerData[battlerId]].data[1] = gBattlerSpriteIds[battlerId];
|
|
gSprites[gBattleControllerData[battlerId]].data[2] = battlerId;
|
|
|
|
gSprites[gBattlerSpriteIds[battlerId]].data[0] = battlerId;
|
|
gSprites[gBattlerSpriteIds[battlerId]].data[2] = species;
|
|
gSprites[gBattlerSpriteIds[battlerId]].oam.paletteNum = battlerId;
|
|
|
|
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerId]], gBattleMonForms[battlerId]);
|
|
|
|
gSprites[gBattlerSpriteIds[battlerId]].invisible = TRUE;
|
|
gSprites[gBattlerSpriteIds[battlerId]].callback = SpriteCallbackDummy;
|
|
|
|
gSprites[gBattleControllerData[battlerId]].data[0] = DoPokeballSendOutAnimation(0, POKEBALL_PLAYER_SENDOUT);
|
|
}
|
|
|
|
static void PlayerHandleReturnMonToBall(void)
|
|
{
|
|
if (!gBattleBufferA[gActiveBattler][1])
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
|
|
gBattlerControllerFuncs[gActiveBattler] = DoSwitchOutAnimation;
|
|
}
|
|
else
|
|
{
|
|
// Skip animation, just remove battler
|
|
FreeSpriteOamMatrix(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
DestroySprite(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gActiveBattler]);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void DoSwitchOutAnimation(void)
|
|
{
|
|
switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState)
|
|
{
|
|
case 0:
|
|
if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute)
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SUBSTITUTE_TO_MON);
|
|
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 1;
|
|
break;
|
|
case 1:
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SWITCH_OUT_PLAYER_MON);
|
|
gBattlerControllerFuncs[gActiveBattler] = FreeMonSpriteAfterSwitchOutAnim;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define sSpeedX data[0]
|
|
|
|
// In emerald it's possible to have a tag battle in the battle frontier facilities with AI
|
|
// which use the front sprite for both the player and the partner as opposed to any other battles (including the one with Steven)
|
|
// that use an animated back pic.
|
|
static void PlayerHandleDrawTrainerPic(void)
|
|
{
|
|
s16 xPos, yPos;
|
|
u32 trainerPicId;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
{
|
|
if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_FIRE_RED
|
|
|| (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_LEAF_GREEN)
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RED;
|
|
}
|
|
else if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_RUBY
|
|
|| (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_SAPPHIRE)
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN;
|
|
}
|
|
else
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_BRENDAN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trainerPicId = gSaveBlock2Ptr->playerGender;
|
|
}
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
|
{
|
|
if ((GetBattlerPosition(gActiveBattler) & BIT_FLANK) != B_FLANK_LEFT) // Second mon, on the right.
|
|
xPos = 90;
|
|
else // First mon, on the left.
|
|
xPos = 32;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER)
|
|
{
|
|
xPos = 90;
|
|
yPos = (8 - gTrainerFrontPicCoords[trainerPicId].size) * 4 + 80;
|
|
}
|
|
else
|
|
{
|
|
yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
xPos = 80;
|
|
yPos = (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80;
|
|
}
|
|
|
|
// Use front pic table for any tag battles unless your partner is Steven.
|
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId != TRAINER_STEVEN_PARTNER)
|
|
{
|
|
trainerPicId = PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender);
|
|
DecompressTrainerFrontPic(trainerPicId, gActiveBattler);
|
|
SetMultiuseSpriteTemplateToTrainerFront(trainerPicId, GetBattlerPosition(gActiveBattler));
|
|
gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));
|
|
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerFrontPicPaletteTable[trainerPicId].tag);
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].y2 = 48;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.affineMode = ST_OAM_AFFINE_OFF;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].hFlip = 1;
|
|
}
|
|
// Use the back pic in any other scenario.
|
|
else
|
|
{
|
|
DecompressTrainerBackPic(trainerPicId, gActiveBattler);
|
|
SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
|
|
gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, xPos, yPos, GetBattlerSpriteSubpriority(gActiveBattler));
|
|
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = DISPLAY_WIDTH;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = -2;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
|
|
}
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnBattlerSpriteCallbackDummy;
|
|
}
|
|
|
|
static void PlayerHandleTrainerSlide(void)
|
|
{
|
|
u32 trainerPicId;
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
|
{
|
|
if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_FIRE_RED
|
|
|| (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_LEAF_GREEN)
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RED;
|
|
}
|
|
else if ((gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_RUBY
|
|
|| (gLinkPlayers[GetMultiplayerId()].version & 0xFF) == VERSION_SAPPHIRE)
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN;
|
|
}
|
|
else
|
|
{
|
|
trainerPicId = gLinkPlayers[GetMultiplayerId()].gender + TRAINER_BACK_PIC_BRENDAN;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trainerPicId = gSaveBlock2Ptr->playerGender + TRAINER_BACK_PIC_BRENDAN;
|
|
}
|
|
|
|
DecompressTrainerBackPic(trainerPicId, gActiveBattler);
|
|
SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(gActiveBattler));
|
|
gBattlerSpriteIds[gActiveBattler] = CreateSprite(&gMultiuseSpriteTemplate, 80, (8 - gTrainerBackPicCoords[trainerPicId].size) * 4 + 80, 30);
|
|
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = gActiveBattler;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].x2 = -96;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = 2;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_TrainerSlideIn;
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnBankSpriteCallbackDummy2;
|
|
}
|
|
|
|
#undef sSpeedX
|
|
|
|
static void PlayerHandleTrainerSlideBack(void)
|
|
{
|
|
SetSpritePrimaryCoordsFromSecondaryCoords(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[0] = 50;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[2] = -40;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[4] = gSprites[gBattlerSpriteIds[gActiveBattler]].y;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = StartAnimLinearTranslation;
|
|
StoreSpriteCallbackInData6(&gSprites[gBattlerSpriteIds[gActiveBattler]], SpriteCallbackDummy);
|
|
StartSpriteAnim(&gSprites[gBattlerSpriteIds[gActiveBattler]], 1);
|
|
gBattlerControllerFuncs[gActiveBattler] = FreeTrainerSpriteAfterSlide;
|
|
}
|
|
|
|
#define sSpeedX data[1]
|
|
#define sSpeedY data[2]
|
|
|
|
static void PlayerHandleFaintAnimation(void)
|
|
{
|
|
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState == 0)
|
|
{
|
|
if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute)
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SUBSTITUTE_TO_MON);
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState++;
|
|
}
|
|
else
|
|
{
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
|
|
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
PlaySE12WithPanning(SE_FAINT, SOUND_PAN_ATTACKER);
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedX = 0;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sSpeedY = 5;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = SpriteCB_FaintSlideAnim;
|
|
gBattlerControllerFuncs[gActiveBattler] = FreeMonSpriteAfterFaintAnim;
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef sSpeedX
|
|
#undef sSpeedY
|
|
|
|
static void PlayerHandlePaletteFade(void)
|
|
{
|
|
BeginNormalPaletteFade(PALETTES_ALL, 2, 0, 16, RGB_BLACK);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleSuccessBallThrowAnim(void)
|
|
{
|
|
gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
|
|
gDoingBattleAnim = TRUE;
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW);
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
|
|
}
|
|
|
|
static void PlayerHandleBallThrowAnim(void)
|
|
{
|
|
u8 ballThrowCaseId = gBattleBufferA[gActiveBattler][1];
|
|
|
|
gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
|
|
gDoingBattleAnim = TRUE;
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW);
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
|
|
}
|
|
|
|
static void PlayerHandlePause(void)
|
|
{
|
|
u8 timer = gBattleBufferA[gActiveBattler][1];
|
|
|
|
while (timer != 0)
|
|
timer--;
|
|
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleMoveAnimation(void)
|
|
{
|
|
if (!IsBattleSEPlaying(gActiveBattler))
|
|
{
|
|
u16 move = gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8);
|
|
|
|
gAnimMoveTurn = gBattleBufferA[gActiveBattler][3];
|
|
gAnimMovePower = gBattleBufferA[gActiveBattler][4] | (gBattleBufferA[gActiveBattler][5] << 8);
|
|
gAnimMoveDmg = gBattleBufferA[gActiveBattler][6] | (gBattleBufferA[gActiveBattler][7] << 8) | (gBattleBufferA[gActiveBattler][8] << 16) | (gBattleBufferA[gActiveBattler][9] << 24);
|
|
gAnimFriendship = gBattleBufferA[gActiveBattler][10];
|
|
gWeatherMoveAnim = gBattleBufferA[gActiveBattler][12] | (gBattleBufferA[gActiveBattler][13] << 8);
|
|
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleBufferA[gActiveBattler][16];
|
|
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
|
|
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // Always returns FALSE.
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
|
|
gBattlerControllerFuncs[gActiveBattler] = PlayerDoMoveAnimation;
|
|
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void PlayerDoMoveAnimation(void)
|
|
{
|
|
u16 move = gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8);
|
|
u8 multihit = gBattleBufferA[gActiveBattler][11];
|
|
|
|
switch (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState)
|
|
{
|
|
case 0:
|
|
if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute
|
|
&& !gBattleSpritesDataPtr->battlerData[gActiveBattler].flag_x8)
|
|
{
|
|
gBattleSpritesDataPtr->battlerData[gActiveBattler].flag_x8 = 1;
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_SUBSTITUTE_TO_MON);
|
|
}
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 1;
|
|
break;
|
|
case 1:
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
{
|
|
SetBattlerSpriteAffineMode(ST_OAM_AFFINE_OFF);
|
|
DoMoveAnim(move);
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 2;
|
|
}
|
|
break;
|
|
case 2:
|
|
gAnimScriptCallback();
|
|
if (!gAnimScriptActive)
|
|
{
|
|
SetBattlerSpriteAffineMode(ST_OAM_AFFINE_NORMAL);
|
|
if (gBattleSpritesDataPtr->battlerData[gActiveBattler].behindSubstitute && multihit < 2)
|
|
{
|
|
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gActiveBattler, B_ANIM_MON_TO_SUBSTITUTE);
|
|
gBattleSpritesDataPtr->battlerData[gActiveBattler].flag_x8 = 0;
|
|
}
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 3;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (!gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].specialAnimActive)
|
|
{
|
|
CopyAllBattleSpritesInvisibilities();
|
|
TrySetBehindSubstituteSpriteBit(gActiveBattler, gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8));
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandlePrintString(void)
|
|
{
|
|
u16 *stringId;
|
|
|
|
gBattle_BG0_X = 0;
|
|
gBattle_BG0_Y = 0;
|
|
stringId = (u16 *)(&gBattleBufferA[gActiveBattler][2]);
|
|
BufferStringBattle(*stringId);
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter2;
|
|
BattleTv_SetDataBasedOnString(*stringId);
|
|
BattleArena_DeductSkillPoints(gActiveBattler, *stringId);
|
|
}
|
|
|
|
static void PlayerHandlePrintSelectionString(void)
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
PlayerHandlePrintString();
|
|
else
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void HandleChooseActionAfterDma3(void)
|
|
{
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
gBattle_BG0_X = 0;
|
|
gBattle_BG0_Y = DISPLAY_HEIGHT;
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseAction;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleChooseAction(void)
|
|
{
|
|
s32 i;
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleChooseActionAfterDma3;
|
|
BattleTv_ClearExplosionFaintCause();
|
|
BattlePutTextOnWindow(gText_BattleMenu, B_WIN_ACTION_MENU);
|
|
|
|
for (i = 0; i < 4; i++)
|
|
ActionSelectionDestroyCursorAt(i);
|
|
|
|
ActionSelectionCreateCursorAt(gActionSelectionCursor[gActiveBattler], 0);
|
|
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo);
|
|
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT);
|
|
}
|
|
|
|
static void PlayerHandleYesNoBox(void)
|
|
{
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
{
|
|
HandleBattleWindow(YESNOBOX_X_Y, 0);
|
|
BattlePutTextOnWindow(gText_BattleYesNoChoice, B_WIN_YESNO);
|
|
gMultiUsePlayerCursor = 1;
|
|
BattleCreateYesNoCursorAt(1);
|
|
gBattlerControllerFuncs[gActiveBattler] = PlayerHandleYesNoInput;
|
|
}
|
|
else
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void HandleChooseMoveAfterDma3(void)
|
|
{
|
|
if (!IsDma3ManagerBusyWithBgCopy())
|
|
{
|
|
gBattle_BG0_X = 0;
|
|
gBattle_BG0_Y = DISPLAY_HEIGHT * 2;
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleInputChooseMove;
|
|
}
|
|
}
|
|
|
|
// arenaMindPoints is used here as a placeholder for a timer.
|
|
|
|
static void PlayerChooseMoveInBattlePalace(void)
|
|
{
|
|
if (--*(gBattleStruct->arenaMindPoints + gActiveBattler) == 0)
|
|
{
|
|
gBattlePalaceMoveSelectionRngValue = gRngValue;
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 10, ChooseMoveAndTargetInBattlePalace());
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleChooseMove(void)
|
|
{
|
|
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
|
{
|
|
*(gBattleStruct->arenaMindPoints + gActiveBattler) = 8;
|
|
gBattlerControllerFuncs[gActiveBattler] = PlayerChooseMoveInBattlePalace;
|
|
}
|
|
else
|
|
{
|
|
InitMoveSelectionsVarsAndStrings();
|
|
gBattlerControllerFuncs[gActiveBattler] = HandleChooseMoveAfterDma3;
|
|
}
|
|
}
|
|
|
|
void InitMoveSelectionsVarsAndStrings(void)
|
|
{
|
|
MoveSelectionDisplayMoveNames();
|
|
gMultiUsePlayerCursor = 0xFF;
|
|
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
|
MoveSelectionDisplayPpString();
|
|
MoveSelectionDisplayPpNumber();
|
|
MoveSelectionDisplayMoveType();
|
|
}
|
|
|
|
static void PlayerHandleChooseItem(void)
|
|
{
|
|
s32 i;
|
|
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
|
|
gBattlerControllerFuncs[gActiveBattler] = OpenBagAndChooseItem;
|
|
gBattlerInMenuId = gActiveBattler;
|
|
|
|
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
|
gBattlePartyCurrentOrder[i] = gBattleBufferA[gActiveBattler][1 + i];
|
|
}
|
|
|
|
static void PlayerHandleChoosePokemon(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
|
gBattlePartyCurrentOrder[i] = gBattleBufferA[gActiveBattler][4 + i];
|
|
|
|
if (gBattleTypeFlags & BATTLE_TYPE_ARENA && (gBattleBufferA[gActiveBattler][1] & 0xF) != PARTY_ACTION_CANT_SWITCH)
|
|
{
|
|
BtlController_EmitChosenMonReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, gBattlerPartyIndexes[gActiveBattler] + 1, gBattlePartyCurrentOrder);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
gBattleControllerData[gActiveBattler] = CreateTask(TaskDummy, 0xFF);
|
|
gTasks[gBattleControllerData[gActiveBattler]].data[0] = gBattleBufferA[gActiveBattler][1] & 0xF;
|
|
*(&gBattleStruct->battlerPreventingSwitchout) = gBattleBufferA[gActiveBattler][1] >> 4;
|
|
*(&gBattleStruct->prevSelectedPartySlot) = gBattleBufferA[gActiveBattler][2];
|
|
*(&gBattleStruct->abilityPreventingSwitchout) = gBattleBufferA[gActiveBattler][3];
|
|
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
|
|
gBattlerControllerFuncs[gActiveBattler] = OpenPartyMenuToChooseMon;
|
|
gBattlerInMenuId = gActiveBattler;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleCmd23(void)
|
|
{
|
|
BattleStopLowHpSound();
|
|
BeginNormalPaletteFade(PALETTES_ALL, 2, 0, 16, RGB_BLACK);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleHealthBarUpdate(void)
|
|
{
|
|
s16 hpVal;
|
|
|
|
LoadBattleBarGfx(0);
|
|
hpVal = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8);
|
|
|
|
// gPlayerPartyLostHP used by Battle Dome, but never read
|
|
if (hpVal > 0)
|
|
gPlayerPartyLostHP += hpVal;
|
|
|
|
if (hpVal != INSTANT_HP_BAR_DROP)
|
|
{
|
|
u32 maxHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MAX_HP);
|
|
u32 curHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_HP);
|
|
|
|
SetBattleBarStruct(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], maxHP, curHP, hpVal);
|
|
}
|
|
else
|
|
{
|
|
u32 maxHP = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MAX_HP);
|
|
|
|
SetBattleBarStruct(gActiveBattler, gHealthboxSpriteIds[gActiveBattler], maxHP, 0, hpVal);
|
|
UpdateHpTextInHealthbox(gHealthboxSpriteIds[gActiveBattler], 0, HP_CURRENT);
|
|
}
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnHealthbarDone;
|
|
}
|
|
|
|
static void PlayerHandleExpUpdate(void)
|
|
{
|
|
u8 monId = gBattleBufferA[gActiveBattler][1];
|
|
|
|
if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
s16 expPointsToGive;
|
|
u8 taskId;
|
|
|
|
LoadBattleBarGfx(1);
|
|
GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); // Unused return value.
|
|
expPointsToGive = T1_READ_16(&gBattleBufferA[gActiveBattler][2]);
|
|
taskId = CreateTask(Task_GiveExpToMon, 10);
|
|
gTasks[taskId].tExpTask_monId = monId;
|
|
gTasks[taskId].tExpTask_gainedExp = expPointsToGive;
|
|
gTasks[taskId].tExpTask_battler = gActiveBattler;
|
|
gBattlerControllerFuncs[gActiveBattler] = BattleControllerDummy;
|
|
}
|
|
}
|
|
|
|
#undef tExpTask_monId
|
|
#undef tExpTask_gainedExp
|
|
#undef tExpTask_battler
|
|
#undef tExpTask_frames
|
|
|
|
static void PlayerHandleStatusIconUpdate(void)
|
|
{
|
|
if (!IsBattleSEPlaying(gActiveBattler))
|
|
{
|
|
u8 battlerId;
|
|
|
|
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], HEALTHBOX_STATUS_ICON);
|
|
battlerId = gActiveBattler;
|
|
gBattleSpritesDataPtr->healthBoxesData[battlerId].statusAnimActive = 0;
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnFinishedStatusAnimation;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleStatusAnimation(void)
|
|
{
|
|
if (!IsBattleSEPlaying(gActiveBattler))
|
|
{
|
|
InitAndLaunchChosenStatusAnimation(gBattleBufferA[gActiveBattler][1],
|
|
gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8) | (gBattleBufferA[gActiveBattler][4] << 16) | (gBattleBufferA[gActiveBattler][5] << 24));
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnFinishedStatusAnimation;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleStatusXor(void)
|
|
{
|
|
u8 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_STATUS) ^ gBattleBufferA[gActiveBattler][1];
|
|
|
|
SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_STATUS, &val);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleDataTransfer(void)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleDMA3Transfer(void)
|
|
{
|
|
u32 dstArg = gBattleBufferA[gActiveBattler][1]
|
|
| (gBattleBufferA[gActiveBattler][2] << 8)
|
|
| (gBattleBufferA[gActiveBattler][3] << 16)
|
|
| (gBattleBufferA[gActiveBattler][4] << 24);
|
|
u16 sizeArg = gBattleBufferA[gActiveBattler][5] | (gBattleBufferA[gActiveBattler][6] << 8);
|
|
|
|
const u8 *src = &gBattleBufferA[gActiveBattler][7];
|
|
u8 *dst = (u8 *)(dstArg);
|
|
u32 size = sizeArg;
|
|
|
|
while (1)
|
|
{
|
|
if (size <= 0x1000)
|
|
{
|
|
DmaCopy16(3, src, dst, size);
|
|
break;
|
|
}
|
|
DmaCopy16(3, src, dst, 0x1000);
|
|
src += 0x1000;
|
|
dst += 0x1000;
|
|
size -= 0x1000;
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandlePlayBGM(void)
|
|
{
|
|
PlayBGM(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8));
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleCmd32(void)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleTwoReturnValues(void)
|
|
{
|
|
BtlController_EmitTwoReturnValues(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0, 0);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleChosenMonReturnValue(void)
|
|
{
|
|
BtlController_EmitChosenMonReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0, NULL);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleOneReturnValue(void)
|
|
{
|
|
BtlController_EmitOneReturnValue(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleOneReturnValue_Duplicate(void)
|
|
{
|
|
BtlController_EmitOneReturnValue_Duplicate(BATTLELINKCOMMTYPE_CONTROLLER_TO_ENGINE, 0);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleClearUnkVar(void)
|
|
{
|
|
gUnusedControllerStruct.unk = 0;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleSetUnkVar(void)
|
|
{
|
|
gUnusedControllerStruct.unk = gBattleBufferA[gActiveBattler][1];
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleClearUnkFlag(void)
|
|
{
|
|
gUnusedControllerStruct.flag = 0;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleToggleUnkFlag(void)
|
|
{
|
|
gUnusedControllerStruct.flag ^= 1;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleHitAnimation(void)
|
|
{
|
|
if (gSprites[gBattlerSpriteIds[gActiveBattler]].invisible == TRUE)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
gDoingBattleAnim = TRUE;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[1] = 0;
|
|
DoHitAnimHealthboxEffect(gActiveBattler);
|
|
gBattlerControllerFuncs[gActiveBattler] = DoHitAnimBlinkSpriteEffect;
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleCantSwitch(void)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandlePlaySE(void)
|
|
{
|
|
s8 pan;
|
|
|
|
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
pan = SOUND_PAN_ATTACKER;
|
|
else
|
|
pan = SOUND_PAN_TARGET;
|
|
|
|
PlaySE12WithPanning(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8), pan);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandlePlayFanfareOrBGM(void)
|
|
{
|
|
if (gBattleBufferA[gActiveBattler][3])
|
|
{
|
|
BattleStopLowHpSound();
|
|
PlayBGM(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8));
|
|
}
|
|
else
|
|
{
|
|
PlayFanfare(gBattleBufferA[gActiveBattler][1] | (gBattleBufferA[gActiveBattler][2] << 8));
|
|
}
|
|
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleFaintingCry(void)
|
|
{
|
|
u16 species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES);
|
|
|
|
PlayCry_ByMode(species, -25, CRY_MODE_FAINT);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleIntroSlide(void)
|
|
{
|
|
HandleIntroSlide(gBattleBufferA[gActiveBattler][1]);
|
|
gIntroSlideFlags |= 1;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
// Task data for Task_StartSendOutAnim
|
|
#define tBattlerId data[0]
|
|
#define tStartTimer data[1]
|
|
|
|
#define sBattlerId data[5]
|
|
|
|
static void PlayerHandleIntroTrainerBallThrow(void)
|
|
{
|
|
u8 paletteNum;
|
|
u8 taskId;
|
|
|
|
SetSpritePrimaryCoordsFromSecondaryCoords(&gSprites[gBattlerSpriteIds[gActiveBattler]]);
|
|
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[0] = 50;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[2] = -40;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].data[4] = gSprites[gBattlerSpriteIds[gActiveBattler]].y;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].callback = StartAnimLinearTranslation;
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].sBattlerId = gActiveBattler;
|
|
|
|
StoreSpriteCallbackInData6(&gSprites[gBattlerSpriteIds[gActiveBattler]], SpriteCB_FreePlayerSpriteLoadMonSprite);
|
|
StartSpriteAnim(&gSprites[gBattlerSpriteIds[gActiveBattler]], 1);
|
|
|
|
paletteNum = AllocSpritePalette(0xD6F8);
|
|
LoadCompressedPalette(gTrainerBackPicPaletteTable[gSaveBlock2Ptr->playerGender].data, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].oam.paletteNum = paletteNum;
|
|
|
|
taskId = CreateTask(Task_StartSendOutAnim, 5);
|
|
gTasks[taskId].tBattlerId = gActiveBattler;
|
|
|
|
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown)
|
|
gTasks[gBattlerStatusSummaryTaskId[gActiveBattler]].func = Task_HidePartyStatusSummary;
|
|
|
|
gBattleSpritesDataPtr->animationData->introAnimActive = TRUE;
|
|
gBattlerControllerFuncs[gActiveBattler] = BattleControllerDummy;
|
|
}
|
|
|
|
void SpriteCB_FreePlayerSpriteLoadMonSprite(struct Sprite *sprite)
|
|
{
|
|
u8 battlerId = sprite->sBattlerId;
|
|
|
|
// Free player trainer sprite
|
|
FreeSpriteOamMatrix(sprite);
|
|
FreeSpritePaletteByTag(GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum));
|
|
DestroySprite(sprite);
|
|
|
|
// Load mon sprite
|
|
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerId]], battlerId);
|
|
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerId]], 0);
|
|
}
|
|
|
|
#undef sBattlerId
|
|
|
|
// Send out at start of battle
|
|
static void Task_StartSendOutAnim(u8 taskId)
|
|
{
|
|
if (gTasks[taskId].tStartTimer < 31)
|
|
{
|
|
gTasks[taskId].tStartTimer++;
|
|
}
|
|
else
|
|
{
|
|
u8 savedActiveBattler = gActiveBattler;
|
|
|
|
gActiveBattler = gTasks[taskId].tBattlerId;
|
|
if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
|
{
|
|
gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
|
|
StartSendOutAnim(gActiveBattler, FALSE);
|
|
}
|
|
else
|
|
{
|
|
gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
|
|
StartSendOutAnim(gActiveBattler, FALSE);
|
|
gActiveBattler ^= BIT_FLANK;
|
|
gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
|
|
BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
|
|
StartSendOutAnim(gActiveBattler, FALSE);
|
|
gActiveBattler ^= BIT_FLANK;
|
|
}
|
|
gBattlerControllerFuncs[gActiveBattler] = Intro_TryShinyAnimShowHealthbox;
|
|
gActiveBattler = savedActiveBattler;
|
|
DestroyTask(taskId);
|
|
}
|
|
}
|
|
|
|
#undef tBattlerId
|
|
#undef tStartTimer
|
|
|
|
static void PlayerHandleDrawPartyStatusSummary(void)
|
|
{
|
|
if (gBattleBufferA[gActiveBattler][1] != 0 && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
|
|
{
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
else
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown = 1;
|
|
gBattlerStatusSummaryTaskId[gActiveBattler] = CreatePartyStatusSummarySprites(gActiveBattler, (struct HpAndStatus *)&gBattleBufferA[gActiveBattler][4], gBattleBufferA[gActiveBattler][1], gBattleBufferA[gActiveBattler][2]);
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusDelayTimer = 0;
|
|
|
|
// If intro, skip the delay after drawing
|
|
if (gBattleBufferA[gActiveBattler][2] != 0)
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusDelayTimer = 93;
|
|
|
|
gBattlerControllerFuncs[gActiveBattler] = EndDrawPartyStatusSummary;
|
|
}
|
|
}
|
|
|
|
static void EndDrawPartyStatusSummary(void)
|
|
{
|
|
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusDelayTimer++ > 92)
|
|
{
|
|
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusDelayTimer = 0;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleHidePartyStatusSummary(void)
|
|
{
|
|
if (gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].partyStatusSummaryShown)
|
|
gTasks[gBattlerStatusSummaryTaskId[gActiveBattler]].func = Task_HidePartyStatusSummary;
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleEndBounceEffect(void)
|
|
{
|
|
EndBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX);
|
|
EndBounceEffect(gActiveBattler, BOUNCE_MON);
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleSpriteInvisibility(void)
|
|
{
|
|
if (IsBattlerSpritePresent(gActiveBattler))
|
|
{
|
|
gSprites[gBattlerSpriteIds[gActiveBattler]].invisible = gBattleBufferA[gActiveBattler][1];
|
|
CopyBattleSpriteInvisibility(gActiveBattler);
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleBattleAnimation(void)
|
|
{
|
|
if (!IsBattleSEPlaying(gActiveBattler))
|
|
{
|
|
u8 animationId = gBattleBufferA[gActiveBattler][1];
|
|
u16 argument = gBattleBufferA[gActiveBattler][2] | (gBattleBufferA[gActiveBattler][3] << 8);
|
|
|
|
if (TryHandleLaunchBattleTableAnimation(gActiveBattler, gActiveBattler, gActiveBattler, animationId, argument))
|
|
PlayerBufferExecCompleted();
|
|
else
|
|
gBattlerControllerFuncs[gActiveBattler] = CompleteOnFinishedBattleAnimation;
|
|
|
|
BattleTv_SetDataBasedOnAnimation(animationId);
|
|
}
|
|
}
|
|
|
|
static void PlayerHandleLinkStandbyMsg(void)
|
|
{
|
|
RecordedBattle_RecordAllBattlerData(&gBattleBufferA[gActiveBattler][2]);
|
|
switch (gBattleBufferA[gActiveBattler][1])
|
|
{
|
|
case LINK_STANDBY_MSG_STOP_BOUNCE:
|
|
PrintLinkStandbyMsg();
|
|
// fall through
|
|
case LINK_STANDBY_STOP_BOUNCE_ONLY:
|
|
EndBounceEffect(gActiveBattler, BOUNCE_HEALTHBOX);
|
|
EndBounceEffect(gActiveBattler, BOUNCE_MON);
|
|
break;
|
|
case LINK_STANDBY_MSG_ONLY:
|
|
PrintLinkStandbyMsg();
|
|
break;
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleResetActionMoveSelection(void)
|
|
{
|
|
switch (gBattleBufferA[gActiveBattler][1])
|
|
{
|
|
case RESET_ACTION_MOVE_SELECTION:
|
|
gActionSelectionCursor[gActiveBattler] = 0;
|
|
gMoveSelectionCursor[gActiveBattler] = 0;
|
|
break;
|
|
case RESET_ACTION_SELECTION:
|
|
gActionSelectionCursor[gActiveBattler] = 0;
|
|
break;
|
|
case RESET_MOVE_SELECTION:
|
|
gMoveSelectionCursor[gActiveBattler] = 0;
|
|
break;
|
|
}
|
|
PlayerBufferExecCompleted();
|
|
}
|
|
|
|
static void PlayerHandleEndLinkBattle(void)
|
|
{
|
|
RecordedBattle_RecordAllBattlerData(&gBattleBufferA[gActiveBattler][4]);
|
|
gBattleOutcome = gBattleBufferA[gActiveBattler][1];
|
|
gSaveBlock2Ptr->frontier.disableRecordBattle = gBattleBufferA[gActiveBattler][2];
|
|
FadeOutMapMusic(5);
|
|
BeginFastPaletteFade(3);
|
|
PlayerBufferExecCompleted();
|
|
gBattlerControllerFuncs[gActiveBattler] = SetBattleEndCallbacks;
|
|
}
|
|
|
|
static void PlayerCmdEnd(void)
|
|
{
|
|
}
|