#include "global.h" #include "battle.h" #include "battle_ai_main.h" #include "battle_anim.h" #include "battle_controllers.h" #include "battle_interface.h" #include "battle_message.h" #include "battle_setup.h" #include "battle_tower.h" #include "battle_tv.h" #include "bg.h" #include "data.h" #include "link.h" #include "main.h" #include "m4a.h" #include "palette.h" #include "pokeball.h" #include "pokemon.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/songs.h" #include "constants/trainers.h" #include "recorded_battle.h" #include "random.h" static void LinkPartnerHandleLoadMonSprite(u32 battler); static void LinkPartnerHandleSwitchInAnim(u32 battler); static void LinkPartnerHandleDrawTrainerPic(u32 battler); static void LinkPartnerHandleTrainerSlideBack(u32 battler); static void LinkPartnerHandleMoveAnimation(u32 battler); static void LinkPartnerHandlePrintString(u32 battler); static void LinkPartnerHandleHealthBarUpdate(u32 battler); static void LinkPartnerHandleIntroTrainerBallThrow(u32 battler); static void LinkPartnerHandleDrawPartyStatusSummary(u32 battler); static void LinkPartnerHandleBattleAnimation(u32 battler); static void LinkPartnerHandleLinkStandbyMsg(u32 battler); static void LinkPartnerHandleEndLinkBattle(u32 battler); static void LinkPartnerBufferRunCommand(u32 battler); static void LinkPartnerBufferExecCompleted(u32 battler); static void SwitchIn_WaitAndEnd(u32 battler); static void (*const sLinkPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = { [CONTROLLER_GETMONDATA] = BtlController_HandleGetMonData, [CONTROLLER_GETRAWMONDATA] = BtlController_Empty, [CONTROLLER_SETMONDATA] = BtlController_HandleSetMonData, [CONTROLLER_SETRAWMONDATA] = BtlController_HandleSetRawMonData, [CONTROLLER_LOADMONSPRITE] = LinkPartnerHandleLoadMonSprite, [CONTROLLER_SWITCHINANIM] = LinkPartnerHandleSwitchInAnim, [CONTROLLER_RETURNMONTOBALL] = BtlController_HandleReturnMonToBall, [CONTROLLER_DRAWTRAINERPIC] = LinkPartnerHandleDrawTrainerPic, [CONTROLLER_TRAINERSLIDE] = BtlController_Empty, [CONTROLLER_TRAINERSLIDEBACK] = LinkPartnerHandleTrainerSlideBack, [CONTROLLER_FAINTANIMATION] = BtlController_HandleFaintAnimation, [CONTROLLER_PALETTEFADE] = BtlController_Empty, [CONTROLLER_SUCCESSBALLTHROWANIM] = BtlController_Empty, [CONTROLLER_BALLTHROWANIM] = BtlController_Empty, [CONTROLLER_PAUSE] = BtlController_Empty, [CONTROLLER_MOVEANIMATION] = LinkPartnerHandleMoveAnimation, [CONTROLLER_PRINTSTRING] = LinkPartnerHandlePrintString, [CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, [CONTROLLER_CHOOSEACTION] = BtlController_Empty, [CONTROLLER_YESNOBOX] = BtlController_Empty, [CONTROLLER_CHOOSEMOVE] = BtlController_Empty, [CONTROLLER_OPENBAG] = BtlController_Empty, [CONTROLLER_CHOOSEPOKEMON] = BtlController_Empty, [CONTROLLER_23] = BtlController_Empty, [CONTROLLER_HEALTHBARUPDATE] = LinkPartnerHandleHealthBarUpdate, [CONTROLLER_EXPUPDATE] = BtlController_Empty, [CONTROLLER_STATUSICONUPDATE] = BtlController_HandleStatusIconUpdate, [CONTROLLER_STATUSANIMATION] = BtlController_HandleStatusAnimation, [CONTROLLER_STATUSXOR] = BtlController_Empty, [CONTROLLER_DATATRANSFER] = BtlController_Empty, [CONTROLLER_DMA3TRANSFER] = BtlController_Empty, [CONTROLLER_PLAYBGM] = BtlController_Empty, [CONTROLLER_32] = BtlController_Empty, [CONTROLLER_TWORETURNVALUES] = BtlController_Empty, [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, [CONTROLLER_PLAYFANFAREORBGM] = BtlController_HandlePlayFanfareOrBGM, [CONTROLLER_FAINTINGCRY] = BtlController_HandleFaintingCry, [CONTROLLER_INTROSLIDE] = BtlController_HandleIntroSlide, [CONTROLLER_INTROTRAINERBALLTHROW] = LinkPartnerHandleIntroTrainerBallThrow, [CONTROLLER_DRAWPARTYSTATUSSUMMARY] = LinkPartnerHandleDrawPartyStatusSummary, [CONTROLLER_HIDEPARTYSTATUSSUMMARY] = BtlController_HandleHidePartyStatusSummary, [CONTROLLER_ENDBOUNCE] = BtlController_Empty, [CONTROLLER_SPRITEINVISIBILITY] = BtlController_HandleSpriteInvisibility, [CONTROLLER_BATTLEANIMATION] = LinkPartnerHandleBattleAnimation, [CONTROLLER_LINKSTANDBYMSG] = LinkPartnerHandleLinkStandbyMsg, [CONTROLLER_RESETACTIONMOVESELECTION] = BtlController_Empty, [CONTROLLER_ENDLINKBATTLE] = LinkPartnerHandleEndLinkBattle, [CONTROLLER_DEBUGMENU] = BtlController_Empty, [CONTROLLER_TERMINATOR_NOP] = BtlController_TerminatorNop }; void SetControllerToLinkPartner(u32 battler) { gBattlerControllerEndFuncs[battler] = LinkPartnerBufferExecCompleted; gBattlerControllerFuncs[battler] = LinkPartnerBufferRunCommand; } static void LinkPartnerBufferRunCommand(u32 battler) { if (gBattleControllerExecFlags & gBitTable[battler]) { if (gBattleResources->bufferA[battler][0] < ARRAY_COUNT(sLinkPartnerBufferCommands)) sLinkPartnerBufferCommands[gBattleResources->bufferA[battler][0]](battler); else LinkPartnerBufferExecCompleted(battler); } } static void WaitForMonAnimAfterLoad(u32 battler) { if (gSprites[gBattlerSpriteIds[battler]].animEnded && gSprites[gBattlerSpriteIds[battler]].x2 == 0) LinkPartnerBufferExecCompleted(battler); } static void SwitchIn_ShowSubstitute(u32 battler) { if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy) { CopyBattleSpriteInvisibility(battler); if (gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) InitAndLaunchSpecialAnimation(battler, battler, battler, B_ANIM_MON_TO_SUBSTITUTE); gBattlerControllerFuncs[battler] = SwitchIn_WaitAndEnd; } } static void SwitchIn_WaitAndEnd(u32 battler) { if (!gBattleSpritesDataPtr->healthBoxesData[battler].specialAnimActive && gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy) { LinkPartnerBufferExecCompleted(battler); } } static void SwitchIn_ShowHealthbox(u32 battler) { if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim) { gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS); FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); CreateTask(Task_PlayerController_RestoreBgmAfterCry, 10); HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[battler]], battler); StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL); StartHealthboxSlideIn(battler); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); gBattlerControllerFuncs[battler] = SwitchIn_ShowSubstitute; } } static void SwitchIn_TryShinyAnim(u32 battler) { if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim && !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive) { TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]); } if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy && !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive) { DestroySprite(&gSprites[gBattleControllerData[battler]]); gBattlerControllerFuncs[battler] = SwitchIn_ShowHealthbox; } } static void LinkPartnerBufferExecCompleted(u32 battler) { gBattlerControllerFuncs[battler] = LinkPartnerBufferRunCommand; if (gBattleTypeFlags & BATTLE_TYPE_LINK) { u8 playerId = GetMultiplayerId(); PrepareBufferDataTransferLink(battler, 2, 4, &playerId); gBattleResources->bufferA[battler][0] = CONTROLLER_TERMINATOR_NOP; } else { gBattleControllerExecFlags &= ~gBitTable[battler]; } } static void LinkPartnerHandleLoadMonSprite(u32 battler) { BtlController_HandleLoadMonSprite(battler, WaitForMonAnimAfterLoad); } static void LinkPartnerHandleSwitchInAnim(u32 battler) { BtlController_HandleSwitchInAnim(battler, TRUE, SwitchIn_TryShinyAnim); } static void LinkPartnerHandleDrawTrainerPic(u32 battler) { s16 xPos; u32 trainerPicId; if (gBattleTypeFlags & BATTLE_TYPE_MULTI) { if ((GetBattlerPosition(battler) & BIT_FLANK) != 0) // second mon xPos = 90; else // first mon xPos = 32; } else { xPos = 80; } trainerPicId = LinkPlayerGetTrainerPicId(GetBattlerMultiplayerId(battler)); BtlController_HandleDrawTrainerPic(battler, trainerPicId, FALSE, xPos, 80 + 4 * (8 - gTrainerBacksprites[trainerPicId].coordinates.size), -1); } static void LinkPartnerHandleTrainerSlideBack(u32 battler) { BtlController_HandleTrainerSlideBack(battler, 35, FALSE); } static void LinkPartnerHandleMoveAnimation(u32 battler) { BtlController_HandleMoveAnimation(battler, TRUE); } static void LinkPartnerHandlePrintString(u32 battler) { BtlController_HandlePrintString(battler, TRUE, FALSE); } static void LinkPartnerHandleHealthBarUpdate(u32 battler) { BtlController_HandleHealthBarUpdate(battler, FALSE); } static void LinkPartnerHandleIntroTrainerBallThrow(u32 battler) { u32 trainerPicId = LinkPlayerGetTrainerPicId(GetBattlerMultiplayerId(battler)); const u32 *trainerPal = gTrainerBacksprites[trainerPicId].palette.data; // Link partner uses the same intro sequence as the player partner. BtlController_HandleIntroTrainerBallThrow(battler, 0xD6F9, trainerPal, 24, Controller_PlayerPartnerShowIntroHealthbox); } static void LinkPartnerHandleDrawPartyStatusSummary(u32 battler) { BtlController_HandleDrawPartyStatusSummary(battler, B_SIDE_PLAYER, TRUE); } static void LinkPartnerHandleBattleAnimation(u32 battler) { BtlController_HandleBattleAnimation(battler, FALSE, TRUE); } static void LinkPartnerHandleLinkStandbyMsg(u32 battler) { RecordedBattle_RecordAllBattlerData(&gBattleResources->bufferA[battler][2]); LinkPartnerBufferExecCompleted(battler); } static void LinkPartnerHandleEndLinkBattle(u32 battler) { RecordedBattle_RecordAllBattlerData(&gBattleResources->bufferA[battler][4]); gBattleOutcome = gBattleResources->bufferA[battler][1]; gSaveBlock2Ptr->frontier.disableRecordBattle = gBattleResources->bufferA[battler][2]; FadeOutMapMusic(5); BeginFastPaletteFade(3); LinkPartnerBufferExecCompleted(battler); gBattlerControllerFuncs[battler] = SetBattleEndCallbacks; }