2017-10-22 19:49:21 +01:00
# include "global.h"
# include "battle.h"
2020-12-20 21:47:20 +00:00
# include "battle_ai_main.h"
2022-03-22 18:10:24 +00:00
# include "battle_ai_util.h"
2018-11-14 00:01:50 +00:00
# include "battle_anim.h"
2017-10-22 19:49:21 +01:00
# include "battle_controllers.h"
# include "battle_message.h"
# include "battle_interface.h"
2018-11-14 00:01:50 +00:00
# include "battle_setup.h"
2018-12-03 15:20:39 +00:00
# include "battle_tower.h"
2020-12-01 18:43:15 +00:00
# include "battle_z_move.h"
2018-11-14 00:01:50 +00:00
# include "bg.h"
2019-04-04 22:53:06 +01:00
# include "data.h"
2018-11-14 00:01:50 +00:00
# include "item_use.h"
2017-10-22 19:49:21 +01:00
# include "link.h"
# include "main.h"
# include "m4a.h"
# include "palette.h"
2023-04-12 01:14:25 +01:00
# include "party_menu.h"
2018-11-14 00:01:50 +00:00
# include "pokeball.h"
# include "pokemon.h"
# include "reshow_battle_screen.h"
# include "sound.h"
# include "string_util.h"
2017-10-22 19:49:21 +01:00
# include "task.h"
# include "text.h"
2018-11-14 00:01:50 +00:00
# include "util.h"
# include "window.h"
# include "constants/battle_anim.h"
2023-12-20 11:38:28 +00:00
# include "constants/battle_partner.h"
2018-11-14 00:01:50 +00:00
# include "constants/songs.h"
2023-04-12 01:14:25 +01:00
# include "constants/party_menu.h"
2018-11-14 00:01:50 +00:00
# include "constants/trainers.h"
2017-10-22 19:49:21 +01:00
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleLoadMonSprite ( u32 battler ) ;
static void PlayerPartnerHandleSwitchInAnim ( u32 battler ) ;
static void PlayerPartnerHandleDrawTrainerPic ( u32 battler ) ;
static void PlayerPartnerHandleTrainerSlideBack ( u32 battler ) ;
static void PlayerPartnerHandleMoveAnimation ( u32 battler ) ;
static void PlayerPartnerHandlePrintString ( u32 battler ) ;
static void PlayerPartnerHandleChooseAction ( u32 battler ) ;
static void PlayerPartnerHandleChooseMove ( u32 battler ) ;
static void PlayerPartnerHandleChoosePokemon ( u32 battler ) ;
static void PlayerPartnerHandleHealthBarUpdate ( u32 battler ) ;
static void PlayerPartnerHandleIntroTrainerBallThrow ( u32 battler ) ;
static void PlayerPartnerHandleDrawPartyStatusSummary ( u32 battler ) ;
static void PlayerPartnerHandleBattleAnimation ( u32 battler ) ;
static void PlayerPartnerHandleEndLinkBattle ( u32 battler ) ;
static void PlayerPartnerBufferRunCommand ( u32 battler ) ;
static void PlayerPartnerBufferExecCompleted ( u32 battler ) ;
static void SwitchIn_WaitAndEnd ( u32 battler ) ;
static void ( * const sPlayerPartnerBufferCommands [ CONTROLLER_CMDS_COUNT ] ) ( u32 battler ) =
2017-10-22 19:49:21 +01:00
{
2023-08-05 11:53:14 +01:00
[ CONTROLLER_GETMONDATA ] = BtlController_HandleGetMonData ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_GETRAWMONDATA ] = BtlController_Empty ,
2023-08-05 11:53:14 +01:00
[ CONTROLLER_SETMONDATA ] = BtlController_HandleSetMonData ,
[ CONTROLLER_SETRAWMONDATA ] = BtlController_HandleSetRawMonData ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_LOADMONSPRITE ] = PlayerPartnerHandleLoadMonSprite ,
[ CONTROLLER_SWITCHINANIM ] = PlayerPartnerHandleSwitchInAnim ,
2023-08-05 13:11:25 +01:00
[ CONTROLLER_RETURNMONTOBALL ] = BtlController_HandleReturnMonToBall ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_DRAWTRAINERPIC ] = PlayerPartnerHandleDrawTrainerPic ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_TRAINERSLIDE ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_TRAINERSLIDEBACK ] = PlayerPartnerHandleTrainerSlideBack ,
2023-08-05 13:11:25 +01:00
[ CONTROLLER_FAINTANIMATION ] = BtlController_HandleFaintAnimation ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_PALETTEFADE ] = BtlController_Empty ,
[ CONTROLLER_SUCCESSBALLTHROWANIM ] = BtlController_Empty ,
[ CONTROLLER_BALLTHROWANIM ] = BtlController_Empty ,
[ CONTROLLER_PAUSE ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_MOVEANIMATION ] = PlayerPartnerHandleMoveAnimation ,
[ CONTROLLER_PRINTSTRING ] = PlayerPartnerHandlePrintString ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_PRINTSTRINGPLAYERONLY ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_CHOOSEACTION ] = PlayerPartnerHandleChooseAction ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_YESNOBOX ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_CHOOSEMOVE ] = PlayerPartnerHandleChooseMove ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_OPENBAG ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_CHOOSEPOKEMON ] = PlayerPartnerHandleChoosePokemon ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_23 ] = BtlController_Empty ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_HEALTHBARUPDATE ] = PlayerPartnerHandleHealthBarUpdate ,
2023-08-05 21:41:13 +01:00
[ CONTROLLER_EXPUPDATE ] = PlayerHandleExpUpdate , // Partner's player gets experience the same way as the player.
2023-08-05 19:42:19 +01:00
[ CONTROLLER_STATUSICONUPDATE ] = BtlController_HandleStatusIconUpdate ,
[ CONTROLLER_STATUSANIMATION ] = BtlController_HandleStatusAnimation ,
2023-08-05 10:05:37 +01:00
[ 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 ,
2023-08-05 13:11:25 +01:00
[ CONTROLLER_CLEARUNKVAR ] = BtlController_HandleClearUnkVar ,
[ CONTROLLER_SETUNKVAR ] = BtlController_HandleSetUnkVar ,
[ CONTROLLER_CLEARUNKFLAG ] = BtlController_HandleClearUnkFlag ,
[ CONTROLLER_TOGGLEUNKFLAG ] = BtlController_HandleToggleUnkFlag ,
[ CONTROLLER_HITANIMATION ] = BtlController_HandleHitAnimation ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_CANTSWITCH ] = BtlController_Empty ,
2023-08-05 11:13:50 +01:00
[ CONTROLLER_PLAYSE ] = BtlController_HandlePlaySE ,
[ CONTROLLER_PLAYFANFAREORBGM ] = BtlController_HandlePlayFanfareOrBGM ,
[ CONTROLLER_FAINTINGCRY ] = BtlController_HandleFaintingCry ,
2023-08-05 13:11:25 +01:00
[ CONTROLLER_INTROSLIDE ] = BtlController_HandleIntroSlide ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_INTROTRAINERBALLTHROW ] = PlayerPartnerHandleIntroTrainerBallThrow ,
[ CONTROLLER_DRAWPARTYSTATUSSUMMARY ] = PlayerPartnerHandleDrawPartyStatusSummary ,
2023-08-05 22:27:56 +01:00
[ CONTROLLER_HIDEPARTYSTATUSSUMMARY ] = BtlController_HandleHidePartyStatusSummary ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_ENDBOUNCE ] = BtlController_Empty ,
2023-08-05 13:11:25 +01:00
[ CONTROLLER_SPRITEINVISIBILITY ] = BtlController_HandleSpriteInvisibility ,
2020-12-29 21:51:44 +00:00
[ CONTROLLER_BATTLEANIMATION ] = PlayerPartnerHandleBattleAnimation ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_LINKSTANDBYMSG ] = BtlController_Empty ,
[ CONTROLLER_RESETACTIONMOVESELECTION ] = BtlController_Empty ,
2021-01-22 07:48:22 +00:00
[ CONTROLLER_ENDLINKBATTLE ] = PlayerPartnerHandleEndLinkBattle ,
2023-08-05 10:05:37 +01:00
[ CONTROLLER_DEBUGMENU ] = BtlController_Empty ,
[ CONTROLLER_TERMINATOR_NOP ] = BtlController_TerminatorNop
2017-10-22 19:49:21 +01:00
} ;
2023-08-07 11:51:58 +01:00
void SetControllerToPlayerPartner ( u32 battler )
2017-10-22 19:49:21 +01:00
{
2023-08-07 11:51:58 +01:00
gBattlerControllerEndFuncs [ battler ] = PlayerPartnerBufferExecCompleted ;
gBattlerControllerFuncs [ battler ] = PlayerPartnerBufferRunCommand ;
2017-10-22 19:49:21 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerBufferRunCommand ( u32 battler )
2017-10-22 19:49:21 +01:00
{
2023-08-07 11:51:58 +01:00
if ( gBattleControllerExecFlags & gBitTable [ battler ] )
2017-10-22 19:49:21 +01:00
{
2023-08-07 11:51:58 +01:00
if ( gBattleResources - > bufferA [ battler ] [ 0 ] < ARRAY_COUNT ( sPlayerPartnerBufferCommands ) )
sPlayerPartnerBufferCommands [ gBattleResources - > bufferA [ battler ] [ 0 ] ] ( battler ) ;
2017-10-22 19:49:21 +01:00
else
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-22 19:49:21 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void Intro_DelayAndEnd ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( - - gBattleSpritesDataPtr - > healthBoxesData [ battler ] . introEndDelay = = ( u8 ) - 1 )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattleSpritesDataPtr - > healthBoxesData [ battler ] . introEndDelay = 0 ;
BattleControllerComplete ( battler ) ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void Intro_WaitForHealthbox ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2021-01-23 01:48:25 +00:00
bool32 finished = FALSE ;
2017-10-23 10:07:36 +01:00
if ( ! IsDoubleBattle ( ) | | ( IsDoubleBattle ( ) & & ( gBattleTypeFlags & BATTLE_TYPE_MULTI ) ) )
{
2023-08-07 11:51:58 +01:00
if ( gSprites [ gHealthboxSpriteIds [ battler ] ] . callback = = SpriteCallbackDummy )
2021-01-23 01:48:25 +00:00
finished = TRUE ;
2017-10-23 10:07:36 +01:00
}
else
{
2023-08-07 11:51:58 +01:00
if ( gSprites [ gHealthboxSpriteIds [ battler ] ] . callback = = SpriteCallbackDummy
& & gSprites [ gHealthboxSpriteIds [ BATTLE_PARTNER ( battler ) ] ] . callback = = SpriteCallbackDummy )
2017-10-23 10:07:36 +01:00
{
2021-01-23 01:48:25 +00:00
finished = TRUE ;
2017-10-23 10:07:36 +01:00
}
}
if ( IsCryPlayingOrClearCrySongs ( ) )
2021-01-23 01:48:25 +00:00
finished = FALSE ;
2017-10-23 10:07:36 +01:00
2021-01-23 01:48:25 +00:00
if ( finished )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattleSpritesDataPtr - > healthBoxesData [ battler ] . introEndDelay = 3 ;
gBattlerControllerFuncs [ battler ] = Intro_DelayAndEnd ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-06 11:41:36 +01:00
// Also used by the link partner.
2023-08-07 11:51:58 +01:00
void Controller_PlayerPartnerShowIntroHealthbox ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( ! gBattleSpritesDataPtr - > healthBoxesData [ battler ] . ballAnimActive
& & ! gBattleSpritesDataPtr - > healthBoxesData [ BATTLE_PARTNER ( battler ) ] . ballAnimActive
& & gSprites [ gBattleControllerData [ battler ] ] . callback = = SpriteCallbackDummy
& & gSprites [ gBattlerSpriteIds [ battler ] ] . callback = = SpriteCallbackDummy
& & + + gBattleSpritesDataPtr - > healthBoxesData [ battler ] . introEndDelay ! = 1 )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattleSpritesDataPtr - > healthBoxesData [ battler ] . introEndDelay = 0 ;
2023-12-17 20:10:03 +00:00
TryShinyAnimation ( battler , & gPlayerParty [ gBattlerPartyIndexes [ battler ] ] ) ;
2017-10-23 10:07:36 +01:00
if ( IsDoubleBattle ( ) & & ! ( gBattleTypeFlags & BATTLE_TYPE_MULTI ) )
{
2023-08-07 11:51:58 +01:00
DestroySprite ( & gSprites [ gBattleControllerData [ BATTLE_PARTNER ( battler ) ] ] ) ;
UpdateHealthboxAttribute ( gHealthboxSpriteIds [ BATTLE_PARTNER ( battler ) ] , & gPlayerParty [ gBattlerPartyIndexes [ BATTLE_PARTNER ( battler ) ] ] , HEALTHBOX_ALL ) ;
StartHealthboxSlideIn ( BATTLE_PARTNER ( battler ) ) ;
SetHealthboxSpriteVisible ( gHealthboxSpriteIds [ BATTLE_PARTNER ( battler ) ] ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
DestroySprite ( & gSprites [ gBattleControllerData [ battler ] ] ) ;
UpdateHealthboxAttribute ( gHealthboxSpriteIds [ battler ] , & gPlayerParty [ gBattlerPartyIndexes [ battler ] ] , HEALTHBOX_ALL ) ;
StartHealthboxSlideIn ( battler ) ;
SetHealthboxSpriteVisible ( gHealthboxSpriteIds [ battler ] ) ;
2017-10-23 10:07:36 +01:00
2021-01-23 01:03:21 +00:00
gBattleSpritesDataPtr - > animationData - > introAnimActive = FALSE ;
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
gBattlerControllerFuncs [ battler ] = Intro_WaitForHealthbox ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void WaitForMonAnimAfterLoad ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( gSprites [ gBattlerSpriteIds [ battler ] ] . animEnded & & gSprites [ gBattlerSpriteIds [ battler ] ] . x2 = = 0 )
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void SwitchIn_ShowSubstitute ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( gSprites [ gHealthboxSpriteIds [ battler ] ] . callback = = SpriteCallbackDummy )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
CopyBattleSpriteInvisibility ( battler ) ;
if ( gBattleSpritesDataPtr - > battlerData [ battler ] . behindSubstitute )
InitAndLaunchSpecialAnimation ( battler , battler , battler , B_ANIM_MON_TO_SUBSTITUTE ) ;
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
gBattlerControllerFuncs [ battler ] = SwitchIn_WaitAndEnd ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void SwitchIn_WaitAndEnd ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( ! gBattleSpritesDataPtr - > healthBoxesData [ battler ] . specialAnimActive
& & gSprites [ gBattlerSpriteIds [ battler ] ] . callback = = SpriteCallbackDummy )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void SwitchIn_ShowHealthbox ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( gBattleSpritesDataPtr - > healthBoxesData [ battler ] . finishedShinyMonAnim )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattleSpritesDataPtr - > healthBoxesData [ battler ] . triedShinyMonAnim = FALSE ;
gBattleSpritesDataPtr - > healthBoxesData [ battler ] . finishedShinyMonAnim = FALSE ;
2017-10-23 10:07:36 +01:00
2021-01-23 01:03:21 +00:00
FreeSpriteTilesByTag ( ANIM_TAG_GOLD_STARS ) ;
FreeSpritePaletteByTag ( ANIM_TAG_GOLD_STARS ) ;
2017-10-23 10:07:36 +01:00
2021-01-23 01:03:21 +00:00
CreateTask ( Task_PlayerController_RestoreBgmAfterCry , 10 ) ;
2023-08-07 11:51:58 +01:00
HandleLowHpMusicChange ( & gPlayerParty [ gBattlerPartyIndexes [ battler ] ] , battler ) ;
StartSpriteAnim ( & gSprites [ gBattlerSpriteIds [ battler ] ] , 0 ) ;
UpdateHealthboxAttribute ( gHealthboxSpriteIds [ battler ] , & gPlayerParty [ gBattlerPartyIndexes [ battler ] ] , HEALTHBOX_ALL ) ;
StartHealthboxSlideIn ( battler ) ;
SetHealthboxSpriteVisible ( gHealthboxSpriteIds [ battler ] ) ;
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
gBattlerControllerFuncs [ battler ] = SwitchIn_ShowSubstitute ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void SwitchIn_TryShinyAnim ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
if ( ! gBattleSpritesDataPtr - > healthBoxesData [ battler ] . triedShinyMonAnim
& & ! gBattleSpritesDataPtr - > healthBoxesData [ battler ] . ballAnimActive )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
TryShinyAnimation ( battler , & gPlayerParty [ gBattlerPartyIndexes [ battler ] ] ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
if ( gSprites [ gBattleControllerData [ battler ] ] . callback = = SpriteCallbackDummy
& & ! gBattleSpritesDataPtr - > healthBoxesData [ battler ] . ballAnimActive )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
DestroySprite ( & gSprites [ gBattleControllerData [ battler ] ] ) ;
gBattlerControllerFuncs [ battler ] = SwitchIn_ShowHealthbox ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerBufferExecCompleted ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattlerControllerFuncs [ battler ] = PlayerPartnerBufferRunCommand ;
2017-10-23 10:07:36 +01:00
if ( gBattleTypeFlags & BATTLE_TYPE_LINK )
{
u8 playerId = GetMultiplayerId ( ) ;
2023-08-29 14:21:31 +01:00
PrepareBufferDataTransferLink ( battler , 2 , 4 , & playerId ) ;
2023-08-07 11:51:58 +01:00
gBattleResources - > bufferA [ battler ] [ 0 ] = CONTROLLER_TERMINATOR_NOP ;
2017-10-23 10:07:36 +01:00
}
else
{
2023-08-07 11:51:58 +01:00
gBattleControllerExecFlags & = ~ gBitTable [ battler ] ;
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleLoadMonSprite ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-21 08:43:01 +01:00
BtlController_HandleLoadMonSprite ( battler , WaitForMonAnimAfterLoad ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleSwitchInAnim ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleSwitchInAnim ( battler , TRUE , SwitchIn_TryShinyAnim ) ;
2017-10-23 10:07:36 +01:00
}
// some explanation here
// 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 the back pic as well as animate it
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleDrawTrainerPic ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-06 20:50:59 +01:00
bool32 isFrontPic ;
2017-10-23 10:07:36 +01:00
s16 xPos , yPos ;
u32 trainerPicId ;
2023-12-20 11:38:28 +00:00
if ( gPartnerTrainerId > TRAINER_PARTNER ( PARTNER_NONE ) )
2017-10-23 10:07:36 +01:00
{
2023-12-20 11:38:28 +00:00
trainerPicId = gBattlePartners [ gPartnerTrainerId - TRAINER_PARTNER ( PARTNER_NONE ) ] . trainerPic ;
2018-11-24 00:02:02 +00:00
xPos = 90 ;
2023-12-20 22:14:33 +00:00
yPos = ( 8 - gTrainerBacksprites [ trainerPicId ] . coordinates . size ) * 4 + 80 ;
2018-11-24 00:02:02 +00:00
}
2023-08-09 14:57:22 +01:00
else if ( IsAiVsAiBattle ( ) )
2023-08-09 08:57:42 +01:00
{
2024-02-22 13:22:57 +00:00
trainerPicId = GetTrainerPicFromId ( gPartnerTrainerId ) ;
2023-08-09 08:57:42 +01:00
xPos = 60 ;
2024-02-06 21:24:36 +00:00
yPos = 80 ;
2023-08-09 08:57:42 +01:00
}
2017-10-23 10:07:36 +01:00
else
{
trainerPicId = GetFrontierTrainerFrontSpriteId ( gPartnerTrainerId ) ;
xPos = 32 ;
2024-02-06 21:24:36 +00:00
yPos = 80 ;
2017-10-23 10:07:36 +01:00
}
2023-12-20 11:38:28 +00:00
// Use back pic only if the partner Steven or is custom.
if ( gPartnerTrainerId > TRAINER_PARTNER ( PARTNER_NONE ) )
2023-08-06 20:50:59 +01:00
isFrontPic = FALSE ;
else
isFrontPic = TRUE ;
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
BtlController_HandleDrawTrainerPic ( battler , trainerPicId , isFrontPic , xPos , yPos , - 1 ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleTrainerSlideBack ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleTrainerSlideBack ( battler , 35 , FALSE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleMoveAnimation ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleMoveAnimation ( battler , FALSE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandlePrintString ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandlePrintString ( battler , FALSE , FALSE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleChooseAction ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-29 14:21:31 +01:00
AI_TrySwitchOrUseItem ( battler ) ;
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleChooseMove ( u32 battler )
2017-10-23 10:07:36 +01:00
{
u8 chosenMoveId ;
2023-08-07 11:51:58 +01:00
struct ChooseMoveStruct * moveInfo = ( struct ChooseMoveStruct * ) ( & gBattleResources - > bufferA [ battler ] [ 4 ] ) ;
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
chosenMoveId = gBattleStruct - > aiMoveOrAction [ battler ] ;
gBattlerTarget = gBattleStruct - > aiChosenTarget [ battler ] ;
2021-12-17 03:57:30 +00:00
2023-08-08 11:55:47 +01:00
if ( chosenMoveId = = AI_CHOICE_SWITCH )
2017-10-23 10:07:36 +01:00
{
2023-08-30 12:23:55 +01:00
BtlController_EmitTwoReturnValues ( battler , BUFFER_B , 10 , 0xFFFF ) ;
2017-10-23 10:07:36 +01:00
}
2020-12-11 14:31:00 +00:00
else
2023-08-08 11:55:47 +01:00
{
2024-01-29 11:51:32 +00:00
if ( gMovesInfo [ moveInfo - > moves [ chosenMoveId ] ] . target & ( MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED ) )
2023-08-29 09:41:05 +01:00
gBattlerTarget = battler ;
2024-01-29 11:51:32 +00:00
if ( gMovesInfo [ moveInfo - > moves [ chosenMoveId ] ] . target & MOVE_TARGET_BOTH )
2023-08-08 11:55:47 +01:00
{
gBattlerTarget = GetBattlerAtPosition ( B_POSITION_OPPONENT_LEFT ) ;
if ( gAbsentBattlerFlags & gBitTable [ gBattlerTarget ] )
gBattlerTarget = GetBattlerAtPosition ( B_POSITION_OPPONENT_RIGHT ) ;
}
2024-06-22 21:25:40 +01:00
// If partner can and should use a gimmick (considering trainer data), do it
if ( gBattleStruct - > gimmick . usableGimmick [ battler ] ! = GIMMICK_NONE
& & ! ( gBattleStruct - > gimmick . usableGimmick [ battler ] = = GIMMICK_Z_MOVE
& & ! ShouldUseZMove ( battler , gBattlerTarget , moveInfo - > moves [ chosenMoveId ] ) ) )
{
BtlController_EmitTwoReturnValues ( battler , BUFFER_B , 10 , ( chosenMoveId ) | ( RET_GIMMICK ) | ( gBattlerTarget < < 8 ) ) ;
}
2023-08-08 11:55:47 +01:00
else
2024-06-22 21:25:40 +01:00
{
2023-08-30 12:23:55 +01:00
BtlController_EmitTwoReturnValues ( battler , BUFFER_B , 10 , ( chosenMoveId ) | ( gBattlerTarget < < 8 ) ) ;
2024-06-22 21:25:40 +01:00
}
2023-08-08 11:55:47 +01:00
}
2021-12-04 01:30:45 +00:00
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleChoosePokemon ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-04-12 01:14:25 +01:00
s32 chosenMonId ;
// Choosing Revival Blessing target
2023-08-07 11:51:58 +01:00
if ( ( gBattleResources - > bufferA [ battler ] [ 1 ] & 0xF ) = = PARTY_ACTION_CHOOSE_FAINTED_MON )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
chosenMonId = gSelectedMonPartyId = GetFirstFaintedPartyIndex ( battler ) ;
2023-04-12 01:14:25 +01:00
}
// Switching out
2023-09-10 23:01:12 +01:00
else if ( gBattleStruct - > monToSwitchIntoId [ battler ] > = PARTY_SIZE | | ! IsValidForBattle ( & gPlayerParty [ gBattleStruct - > monToSwitchIntoId [ battler ] ] ) )
2023-04-12 01:14:25 +01:00
{
Smarter SwitchAI Mon Choices | HasBadOdds Switch Check (#3253)
* SwitchAI makes much smarter mon choices
* Add HasHadOdds check to ShouldSwitch decision
* Remove early return
* Rework Baton Pass check as per discussion with Alex
* Forgot to adjust a comment
* Don't program before breakfast lol (if / else if fix)
* Switch AI_CalcDamage for AI_DATA->simulatedDmg in HasBadOdds
Thanks Alex! :D
* Typo in a hitToKO comparison
* Remove and replace AI_CalcPartyMonBestMoveDamage and IsAiPartyMonOHKOBy from https://github.com/rh-hideout/pokeemerald-expansion/pull/3146
See https://discord.com/channels/419213663107416084/1144447521960251472 for details
* Major refactor, new struct, switchin considers damage / healing from hazards / status / held item / weather
* Forgot Snow exists and heals Ice Body, haven't played Switch games lol
* (https://github.com/rh-hideout/pokeemerald-expansion/commit/766a1a27a7298e50dd89c5fecc1989b3dd8b8ce3) Compatibility, use new struct field instead of function call
* Fixing oversight from previous upstream merge
* Improve TSpikes handling to make GetSwitchinHazardDamage more applicable
Small fixes:
- EFFECT_EXPLOSION typo (!= to ==)
- Order of if statements near bestResistEffective
- Spacing of terms in big HasBadOdds if statements
* Forgot to uncomment blocks disabled for debugging what turned out to be vanilla behaviour lol
* Remove another holdover from debugging, sorry :/
* Lastly, undoing my debug trainer
* Type matchup based on species type rather than current type
Suggested by BLourenco on Discord, the idea is that a mon that's had its type affected by a move like Soak will still have moves as though it was its regular typing, and so prioritizing the temporary typing wouldn't be ideal.
https://discord.com/channels/419213663107416084/1144447521960251472/1146644578141736970
* gActiveBattler upcoming merge fixes
* Egg changes part 1
* Egg changes part 2, just need to address EWRAM still
* Move SwitchinCandidate struct to AiLogicData
* Consider Steel type when checking TSpikes
* Comment about CanBePoisoned compatibility
* Changes for Egg's 2nd review
* Put period back in comment, whoops lol
* Latest upcoming merge fixes
* Missed a few u32 updates
* Combine GetBestMonIntegrate functions / flags, some modularization
* Fix merge error
* Make modern fixes
* Two tests done, two to go
* Accidentally pushed reference test, removing it
* Type matchup switching tests
* Tests for defensive vs offense switches
---------
Co-authored-by: DizzyEggg <jajkodizzy@wp.pl>
2023-11-11 13:37:35 +00:00
chosenMonId = GetMostSuitableMonToSwitchInto ( battler , TRUE ) ;
2023-09-10 23:01:12 +01:00
if ( chosenMonId = = PARTY_SIZE | | ! IsValidForBattle ( & gPlayerParty [ chosenMonId ] ) ) // just switch to the next mon
2017-10-23 10:07:36 +01:00
{
2023-09-10 23:01:12 +01:00
s32 firstId = ( IsAiVsAiBattle ( ) ) ? 0 : ( PARTY_SIZE / 2 ) ;
u32 battler1 = GetBattlerAtPosition ( B_POSITION_PLAYER_LEFT ) ;
u32 battler2 = IsDoubleBattle ( ) ? GetBattlerAtPosition ( B_POSITION_PLAYER_RIGHT ) : battler1 ;
2023-04-12 01:14:25 +01:00
2023-09-10 23:01:12 +01:00
for ( chosenMonId = firstId ; chosenMonId < PARTY_SIZE ; chosenMonId + + )
2017-10-23 10:07:36 +01:00
{
2023-04-12 01:14:25 +01:00
if ( GetMonData ( & gPlayerParty [ chosenMonId ] , MON_DATA_HP ) ! = 0
2023-09-10 23:01:12 +01:00
& & chosenMonId ! = gBattlerPartyIndexes [ battler1 ]
& & chosenMonId ! = gBattlerPartyIndexes [ battler2 ] )
2023-04-12 01:14:25 +01:00
{
break ;
}
2017-10-23 10:07:36 +01:00
}
}
2023-08-07 11:51:58 +01:00
* ( gBattleStruct - > monToSwitchIntoId + battler ) = chosenMonId ;
2017-10-23 10:07:36 +01:00
}
2023-08-08 11:55:47 +01:00
else // Mon to switch out has been already chosen.
2017-10-23 10:07:36 +01:00
{
2023-08-29 09:41:05 +01:00
chosenMonId = gBattleStruct - > monToSwitchIntoId [ battler ] ;
2023-08-30 12:23:55 +01:00
gBattleStruct - > AI_monToSwitchIntoId [ battler ] = PARTY_SIZE ;
gBattleStruct - > monToSwitchIntoId [ battler ] = chosenMonId ;
2017-10-23 10:07:36 +01:00
}
2023-08-29 14:21:31 +01:00
BtlController_EmitChosenMonReturnValue ( battler , BUFFER_B , chosenMonId , NULL ) ;
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleHealthBarUpdate ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleHealthBarUpdate ( battler , FALSE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleIntroTrainerBallThrow ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-06 11:41:36 +01:00
const u32 * trainerPal ;
2017-10-23 10:07:36 +01:00
2023-12-20 11:38:28 +00:00
if ( gPartnerTrainerId > TRAINER_PARTNER ( PARTNER_NONE ) )
2024-06-07 20:05:16 +01:00
trainerPal = gTrainerBacksprites [ gBattlePartners [ gPartnerTrainerId - TRAINER_PARTNER ( PARTNER_NONE ) ] . trainerPic ] . palette . data ;
2023-08-09 14:57:22 +01:00
else if ( IsAiVsAiBattle ( ) )
2024-02-22 13:22:57 +00:00
trainerPal = gTrainerSprites [ GetTrainerPicFromId ( gPartnerTrainerId ) ] . palette . data ;
2017-10-23 10:07:36 +01:00
else
2023-12-20 22:14:33 +00:00
trainerPal = gTrainerSprites [ GetFrontierTrainerFrontSpriteId ( gPartnerTrainerId ) ] . palette . data ; // 2 vs 2 multi battle in Battle Frontier, load front sprite and pal.
2017-10-23 10:07:36 +01:00
2023-08-07 11:51:58 +01:00
BtlController_HandleIntroTrainerBallThrow ( battler , 0xD6F9 , trainerPal , 24 , Controller_PlayerPartnerShowIntroHealthbox ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleDrawPartyStatusSummary ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleDrawPartyStatusSummary ( battler , B_SIDE_PLAYER , TRUE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleBattleAnimation ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
BtlController_HandleBattleAnimation ( battler , FALSE , FALSE ) ;
2017-10-23 10:07:36 +01:00
}
2023-08-07 11:51:58 +01:00
static void PlayerPartnerHandleEndLinkBattle ( u32 battler )
2017-10-23 10:07:36 +01:00
{
2023-08-07 11:51:58 +01:00
gBattleOutcome = gBattleResources - > bufferA [ battler ] [ 1 ] ;
2017-10-23 10:07:36 +01:00
FadeOutMapMusic ( 5 ) ;
BeginFastPaletteFade ( 3 ) ;
2023-08-07 11:51:58 +01:00
PlayerPartnerBufferExecCompleted ( battler ) ;
gBattlerControllerFuncs [ battler ] = SetBattleEndCallbacks ;
2017-10-23 10:07:36 +01:00
}