2017-10-10 18:01:45 +02:00
# include "global.h"
# include "battle.h"
2018-07-15 12:39:07 +02:00
# include "battle_ai_script_commands.h"
2019-03-31 19:15:39 +02:00
# include "battle_anim.h"
2017-10-10 18:01:45 +02:00
# include "battle_controllers.h"
2019-01-27 20:54:34 +01:00
# include "battle_setup.h"
2017-10-10 18:01:45 +02:00
# include "pokemon.h"
2017-12-05 19:27:33 +01:00
# include "random.h"
2017-10-10 18:01:45 +02:00
# include "util.h"
2018-11-14 01:01:50 +01:00
# include "constants/abilities.h"
2019-04-14 17:20:26 +02:00
# include "constants/item_effects.h"
2017-12-05 18:55:48 +01:00
# include "constants/items.h"
2018-11-14 01:01:50 +01:00
# include "constants/moves.h"
2017-10-10 18:01:45 +02:00
// this file's functions
2017-10-11 12:49:42 +02:00
static bool8 HasSuperEffectiveMoveAgainstOpponents ( bool8 noRng ) ;
2018-07-15 12:39:07 +02:00
static bool8 FindMonWithFlagsAndSuperEffective ( u16 flags , u8 moduloPercent ) ;
2017-10-11 12:49:42 +02:00
static bool8 ShouldUseItem ( void ) ;
2017-10-10 18:01:45 +02:00
2019-01-27 20:54:34 +01:00
void GetAIPartyIndexes ( u32 battlerId , s32 * firstId , s32 * lastId )
{
if ( BATTLE_TWO_VS_ONE_OPPONENT & & ( battlerId & BIT_SIDE ) = = B_SIDE_OPPONENT )
{
* firstId = 0 , * lastId = 6 ;
}
else if ( gBattleTypeFlags & ( BATTLE_TYPE_TWO_OPPONENTS | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_x800000 ) )
{
if ( ( battlerId & BIT_FLANK ) = = B_FLANK_LEFT )
* firstId = 0 , * lastId = 3 ;
else
* firstId = 3 , * lastId = 6 ;
}
else
{
* firstId = 0 , * lastId = 6 ;
}
}
2019-06-11 10:45:12 +02:00
static bool8 ShouldSwitchIfAllBadMoves ( void )
{
if ( gBattleResources - > ai - > switchMon )
{
gBattleResources - > ai - > switchMon = 0 ;
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = PARTY_SIZE ;
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
return TRUE ;
}
else
{
return FALSE ;
}
}
2017-10-11 12:49:42 +02:00
static bool8 ShouldSwitchIfPerishSong ( void )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
if ( gStatuses3 [ gActiveBattler ] & STATUS3_PERISH_SONG
2018-10-14 18:37:52 +02:00
& & gDisableStructs [ gActiveBattler ] . perishSongTimer = = 0 )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = PARTY_SIZE ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
2018-06-17 16:48:58 +02:00
else
{
return FALSE ;
}
2017-10-10 18:01:45 +02:00
}
2017-10-11 12:49:42 +02:00
static bool8 ShouldSwitchIfWonderGuard ( void )
2017-10-10 18:01:45 +02:00
{
2018-01-16 22:12:38 +01:00
u8 opposingPosition ;
2018-06-17 16:48:58 +02:00
u8 opposingBattler ;
2017-10-10 18:01:45 +02:00
s32 i , j ;
s32 firstId ;
s32 lastId ; // + 1
struct Pokemon * party = NULL ;
u16 move ;
if ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE )
return FALSE ;
2018-02-06 23:09:39 +01:00
opposingPosition = BATTLE_OPPOSITE ( GetBattlerPosition ( gActiveBattler ) ) ;
2017-10-10 18:01:45 +02:00
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ GetBattlerAtPosition ( opposingPosition ) ] . ability ! = ABILITY_WONDER_GUARD )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-06-17 16:48:58 +02:00
// Check if Pokemon has a super effective move.
2018-12-25 18:50:15 +01:00
for ( opposingBattler = GetBattlerAtPosition ( opposingPosition ) , i = 0 ; i < MAX_MON_MOVES ; i + + )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
move = gBattleMons [ gActiveBattler ] . moves [ i ] ;
2018-07-15 12:39:07 +02:00
if ( move ! = MOVE_NONE )
{
if ( AI_GetTypeEffectiveness ( move , gActiveBattler , opposingBattler ) > = UQ_4_12 ( 2.0 ) )
return FALSE ;
}
2017-10-10 18:01:45 +02:00
}
2018-06-17 16:48:58 +02:00
// Get party information.
2019-01-27 20:54:34 +01:00
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
2017-10-10 18:01:45 +02:00
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-10 18:01:45 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
2018-06-17 16:48:58 +02:00
// Find a Pokemon in the party that has a super effective move.
2017-10-10 18:01:45 +02:00
for ( i = firstId ; i < lastId ; i + + )
{
if ( GetMonData ( & party [ i ] , MON_DATA_HP ) = = 0 )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_NONE )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_EGG )
continue ;
2018-02-06 20:48:02 +01:00
if ( i = = gBattlerPartyIndexes [ gActiveBattler ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-12-25 18:50:15 +01:00
for ( opposingBattler = GetBattlerAtPosition ( opposingPosition ) , j = 0 ; j < MAX_MON_MOVES ; j + + )
2017-10-10 18:01:45 +02:00
{
move = GetMonData ( & party [ i ] , MON_DATA_MOVE1 + j ) ;
2018-07-15 12:39:07 +02:00
if ( move ! = MOVE_NONE )
2017-10-10 18:01:45 +02:00
{
2018-07-15 12:39:07 +02:00
if ( AI_GetTypeEffectiveness ( move , gActiveBattler , opposingBattler ) > = UQ_4_12 ( 2.0 ) & & Random ( ) % 3 < 2 )
{
// We found a mon.
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = i ;
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
return TRUE ;
}
2017-10-10 18:01:45 +02:00
}
}
}
2018-06-17 16:48:58 +02:00
return FALSE ; // There is not a single Pokemon in the party that has a super effective move against a mon with Wonder Guard.
2017-10-10 18:01:45 +02:00
}
2017-10-11 12:49:42 +02:00
static bool8 FindMonThatAbsorbsOpponentsMove ( void )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
u8 battlerIn1 , battlerIn2 ;
2020-05-18 23:54:12 +02:00
u16 absorbingTypeAbility ;
2017-10-10 18:01:45 +02:00
s32 firstId ;
s32 lastId ; // + 1
struct Pokemon * party ;
s32 i ;
if ( HasSuperEffectiveMoveAgainstOpponents ( TRUE ) & & Random ( ) % 3 ! = 0 )
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gLastLandedMoves [ gActiveBattler ] = = 0 )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gLastLandedMoves [ gActiveBattler ] = = 0xFFFF )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . power = = 0 )
2017-10-10 18:01:45 +02:00
return FALSE ;
if ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE )
{
2018-06-17 16:48:58 +02:00
battlerIn1 = gActiveBattler ;
2018-02-06 23:09:39 +01:00
if ( gAbsentBattlerFlags & gBitTable [ GetBattlerAtPosition ( BATTLE_PARTNER ( GetBattlerPosition ( gActiveBattler ) ) ) ] )
2018-06-17 16:48:58 +02:00
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
else
2018-06-17 16:48:58 +02:00
battlerIn2 = GetBattlerAtPosition ( BATTLE_PARTNER ( GetBattlerPosition ( gActiveBattler ) ) ) ;
2017-10-10 18:01:45 +02:00
}
else
{
2018-06-17 16:48:58 +02:00
battlerIn1 = gActiveBattler ;
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
}
2018-02-06 02:46:59 +01:00
if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . type = = TYPE_FIRE )
2017-10-10 18:01:45 +02:00
absorbingTypeAbility = ABILITY_FLASH_FIRE ;
2018-02-06 02:46:59 +01:00
else if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . type = = TYPE_WATER )
2017-10-10 18:01:45 +02:00
absorbingTypeAbility = ABILITY_WATER_ABSORB ;
2018-02-06 02:46:59 +01:00
else if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . type = = TYPE_ELECTRIC )
2017-10-10 18:01:45 +02:00
absorbingTypeAbility = ABILITY_VOLT_ABSORB ;
else
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . ability = = absorbingTypeAbility )
2017-10-10 18:01:45 +02:00
return FALSE ;
2019-01-27 20:54:34 +01:00
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
2017-10-10 18:01:45 +02:00
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-10 18:01:45 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
for ( i = firstId ; i < lastId ; i + + )
{
u16 species ;
2020-05-18 23:54:12 +02:00
u16 monAbility ;
2017-10-10 18:01:45 +02:00
if ( GetMonData ( & party [ i ] , MON_DATA_HP ) = = 0 )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_NONE )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_EGG )
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn1 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn2 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn1 ) )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn2 ) )
2017-10-10 18:01:45 +02:00
continue ;
species = GetMonData ( & party [ i ] , MON_DATA_SPECIES ) ;
2019-05-14 15:22:16 +02:00
if ( GetMonData ( & party [ i ] , MON_DATA_ABILITY_NUM ) ! = 0 )
2019-05-14 15:42:55 +02:00
monAbility = gBaseStats [ species ] . abilities [ 1 ] ;
2017-10-10 18:01:45 +02:00
else
2019-05-14 15:42:55 +02:00
monAbility = gBaseStats [ species ] . abilities [ 0 ] ;
2017-10-10 18:01:45 +02:00
if ( absorbingTypeAbility = = monAbility & & Random ( ) & 1 )
{
2018-06-17 16:48:58 +02:00
// we found a mon.
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = i ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
}
return FALSE ;
}
2017-10-11 12:49:42 +02:00
static bool8 ShouldSwitchIfNaturalCure ( void )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
if ( ! ( gBattleMons [ gActiveBattler ] . status1 & STATUS1_SLEEP ) )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . ability ! = ABILITY_NATURAL_CURE )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . hp < gBattleMons [ gActiveBattler ] . maxHP / 2 )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( ( gLastLandedMoves [ gActiveBattler ] = = 0 | | gLastLandedMoves [ gActiveBattler ] = = 0xFFFF ) & & Random ( ) & 1 )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = PARTY_SIZE ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
2018-02-06 02:46:59 +01:00
else if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . power = = 0 & & Random ( ) & 1 )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = PARTY_SIZE ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
2018-01-16 22:12:38 +01:00
if ( FindMonWithFlagsAndSuperEffective ( MOVE_RESULT_DOESNT_AFFECT_FOE , 1 ) )
2017-10-10 18:01:45 +02:00
return TRUE ;
2018-01-16 22:12:38 +01:00
if ( FindMonWithFlagsAndSuperEffective ( MOVE_RESULT_NOT_VERY_EFFECTIVE , 1 ) )
2017-10-10 18:01:45 +02:00
return TRUE ;
2018-06-17 16:48:58 +02:00
2017-10-10 18:01:45 +02:00
if ( Random ( ) & 1 )
{
2018-06-17 16:48:58 +02:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = PARTY_SIZE ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
return FALSE ;
}
2017-10-11 12:49:42 +02:00
static bool8 HasSuperEffectiveMoveAgainstOpponents ( bool8 noRng )
2017-10-10 18:01:45 +02:00
{
2018-01-16 22:12:38 +01:00
u8 opposingPosition ;
2018-06-17 16:48:58 +02:00
u8 opposingBattler ;
2017-10-10 18:01:45 +02:00
s32 i ;
u16 move ;
2018-02-06 23:09:39 +01:00
opposingPosition = BATTLE_OPPOSITE ( GetBattlerPosition ( gActiveBattler ) ) ;
2018-06-17 16:48:58 +02:00
opposingBattler = GetBattlerAtPosition ( opposingPosition ) ;
2017-10-10 18:01:45 +02:00
2018-06-17 16:48:58 +02:00
if ( ! ( gAbsentBattlerFlags & gBitTable [ opposingBattler ] ) )
2017-10-10 18:01:45 +02:00
{
2018-12-25 18:50:15 +01:00
for ( i = 0 ; i < MAX_MON_MOVES ; i + + )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
move = gBattleMons [ gActiveBattler ] . moves [ i ] ;
2017-10-10 18:01:45 +02:00
if ( move = = MOVE_NONE )
continue ;
2018-07-15 12:39:07 +02:00
if ( AI_GetTypeEffectiveness ( move , gActiveBattler , opposingBattler ) > = UQ_4_12 ( 2.0 ) )
2017-10-10 18:01:45 +02:00
{
if ( noRng )
return TRUE ;
if ( Random ( ) % 10 ! = 0 )
return TRUE ;
}
}
}
if ( ! ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE ) )
return FALSE ;
2018-06-17 16:48:58 +02:00
opposingBattler = GetBattlerAtPosition ( BATTLE_PARTNER ( opposingPosition ) ) ;
2017-10-10 18:01:45 +02:00
2018-06-17 16:48:58 +02:00
if ( ! ( gAbsentBattlerFlags & gBitTable [ opposingBattler ] ) )
2017-10-10 18:01:45 +02:00
{
2018-12-25 18:50:15 +01:00
for ( i = 0 ; i < MAX_MON_MOVES ; i + + )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
move = gBattleMons [ gActiveBattler ] . moves [ i ] ;
2017-10-10 18:01:45 +02:00
if ( move = = MOVE_NONE )
continue ;
2018-07-15 12:39:07 +02:00
if ( AI_GetTypeEffectiveness ( move , gActiveBattler , opposingBattler ) > = UQ_4_12 ( 2.0 ) )
2017-10-10 18:01:45 +02:00
{
if ( noRng )
return TRUE ;
if ( Random ( ) % 10 ! = 0 )
return TRUE ;
}
}
}
return FALSE ;
}
2017-10-11 12:49:42 +02:00
static bool8 AreStatsRaised ( void )
2017-10-10 18:01:45 +02:00
{
u8 buffedStatsValue = 0 ;
s32 i ;
2018-11-18 20:00:36 +01:00
for ( i = 0 ; i < NUM_BATTLE_STATS ; i + + )
2017-10-10 18:01:45 +02:00
{
2020-08-05 02:33:05 +02:00
if ( gBattleMons [ gActiveBattler ] . statStages [ i ] > DEFAULT_STAT_STAGE )
buffedStatsValue + = gBattleMons [ gActiveBattler ] . statStages [ i ] - DEFAULT_STAT_STAGE ;
2017-10-10 18:01:45 +02:00
}
return ( buffedStatsValue > 3 ) ;
}
2018-07-15 12:39:07 +02:00
static bool8 FindMonWithFlagsAndSuperEffective ( u16 flags , u8 moduloPercent )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
u8 battlerIn1 , battlerIn2 ;
2017-10-10 18:01:45 +02:00
s32 firstId ;
s32 lastId ; // + 1
struct Pokemon * party ;
s32 i , j ;
u16 move ;
2018-02-06 02:46:59 +01:00
if ( gLastLandedMoves [ gActiveBattler ] = = 0 )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gLastLandedMoves [ gActiveBattler ] = = 0xFFFF )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gLastHitBy [ gActiveBattler ] = = 0xFF )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleMoves [ gLastLandedMoves [ gActiveBattler ] ] . power = = 0 )
2017-10-10 18:01:45 +02:00
return FALSE ;
if ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE )
{
2018-06-17 16:48:58 +02:00
battlerIn1 = gActiveBattler ;
2018-02-06 23:09:39 +01:00
if ( gAbsentBattlerFlags & gBitTable [ GetBattlerAtPosition ( BATTLE_PARTNER ( GetBattlerPosition ( gActiveBattler ) ) ) ] )
2018-06-17 16:48:58 +02:00
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
else
2018-06-17 16:48:58 +02:00
battlerIn2 = GetBattlerAtPosition ( BATTLE_PARTNER ( GetBattlerPosition ( gActiveBattler ) ) ) ;
2017-10-10 18:01:45 +02:00
}
else
{
2018-06-17 16:48:58 +02:00
battlerIn1 = gActiveBattler ;
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
}
2019-01-27 20:54:34 +01:00
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
2017-10-10 18:01:45 +02:00
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-10 18:01:45 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
for ( i = firstId ; i < lastId ; i + + )
{
u16 species ;
2020-05-18 23:54:12 +02:00
u16 monAbility ;
2017-10-10 18:01:45 +02:00
if ( GetMonData ( & party [ i ] , MON_DATA_HP ) = = 0 )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_NONE )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_EGG )
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn1 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn2 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn1 ) )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn2 ) )
2017-10-10 18:01:45 +02:00
continue ;
species = GetMonData ( & party [ i ] , MON_DATA_SPECIES ) ;
2019-05-14 15:22:16 +02:00
if ( GetMonData ( & party [ i ] , MON_DATA_ABILITY_NUM ) ! = 0 )
2019-05-14 15:42:55 +02:00
monAbility = gBaseStats [ species ] . abilities [ 1 ] ;
2017-10-10 18:01:45 +02:00
else
2019-05-14 15:42:55 +02:00
monAbility = gBaseStats [ species ] . abilities [ 0 ] ;
2017-10-10 18:01:45 +02:00
2018-07-15 12:39:07 +02:00
CalcPartyMonTypeEffectivenessMultiplier ( gLastLandedMoves [ gActiveBattler ] , species , monAbility ) ;
if ( gMoveResultFlags & flags )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
battlerIn1 = gLastHitBy [ gActiveBattler ] ;
2017-10-10 18:01:45 +02:00
2018-12-25 18:50:15 +01:00
for ( j = 0 ; j < MAX_MON_MOVES ; j + + )
2017-10-10 18:01:45 +02:00
{
move = GetMonData ( & party [ i ] , MON_DATA_MOVE1 + j ) ;
if ( move = = 0 )
continue ;
2018-07-15 12:39:07 +02:00
if ( AI_GetTypeEffectiveness ( move , gActiveBattler , battlerIn1 ) > = UQ_4_12 ( 2.0 ) & & Random ( ) % moduloPercent = = 0 )
2017-10-10 18:01:45 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = i ;
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_SWITCH , 0 ) ;
2017-10-10 18:01:45 +02:00
return TRUE ;
}
}
}
}
return FALSE ;
}
2017-10-11 12:49:42 +02:00
static bool8 ShouldSwitch ( void )
2017-10-10 18:01:45 +02:00
{
2018-06-17 16:48:58 +02:00
u8 battlerIn1 , battlerIn2 ;
2017-10-10 18:01:45 +02:00
s32 firstId ;
s32 lastId ; // + 1
struct Pokemon * party ;
s32 i ;
s32 availableToSwitch ;
2020-02-08 14:20:02 +01:00
if ( gBattleMons [ gActiveBattler ] . status2 & ( STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION ) )
2017-10-10 18:01:45 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( gStatuses3 [ gActiveBattler ] & STATUS3_ROOTED )
2017-10-10 18:01:45 +02:00
return FALSE ;
2020-02-08 14:20:02 +01:00
if ( IsAbilityPreventingEscape ( gActiveBattler ) )
2017-10-10 18:01:45 +02:00
return FALSE ;
if ( gBattleTypeFlags & BATTLE_TYPE_ARENA )
return FALSE ;
availableToSwitch = 0 ;
if ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE )
{
2020-02-08 14:20:02 +01:00
battlerIn1 = gActiveBattler ;
if ( gAbsentBattlerFlags & gBitTable [ GetBattlerAtPosition ( GetBattlerPosition ( gActiveBattler ) ^ BIT_FLANK ) ] )
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
else
2020-02-08 14:20:02 +01:00
battlerIn2 = GetBattlerAtPosition ( GetBattlerPosition ( gActiveBattler ) ^ BIT_FLANK ) ;
2017-10-10 18:01:45 +02:00
}
else
{
2020-02-08 14:20:02 +01:00
battlerIn1 = gActiveBattler ;
battlerIn2 = gActiveBattler ;
2017-10-10 18:01:45 +02:00
}
2019-01-27 20:54:34 +01:00
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
2017-10-10 18:01:45 +02:00
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-10 18:01:45 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
for ( i = firstId ; i < lastId ; i + + )
{
if ( GetMonData ( & party [ i ] , MON_DATA_HP ) = = 0 )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_NONE )
continue ;
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) = = SPECIES_EGG )
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn1 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = gBattlerPartyIndexes [ battlerIn2 ] )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn1 ) )
2017-10-10 18:01:45 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn2 ) )
2017-10-10 18:01:45 +02:00
continue ;
availableToSwitch + + ;
}
if ( availableToSwitch = = 0 )
return FALSE ;
2019-06-11 10:45:12 +02:00
if ( ShouldSwitchIfAllBadMoves ( ) )
return TRUE ;
2017-10-10 18:01:45 +02:00
if ( ShouldSwitchIfPerishSong ( ) )
return TRUE ;
if ( ShouldSwitchIfWonderGuard ( ) )
return TRUE ;
2017-10-10 21:45:07 +02:00
if ( FindMonThatAbsorbsOpponentsMove ( ) )
2017-10-10 18:01:45 +02:00
return TRUE ;
if ( ShouldSwitchIfNaturalCure ( ) )
return TRUE ;
if ( HasSuperEffectiveMoveAgainstOpponents ( FALSE ) )
return FALSE ;
if ( AreStatsRaised ( ) )
return FALSE ;
2018-01-16 22:12:38 +01:00
if ( FindMonWithFlagsAndSuperEffective ( MOVE_RESULT_DOESNT_AFFECT_FOE , 2 )
| | FindMonWithFlagsAndSuperEffective ( MOVE_RESULT_NOT_VERY_EFFECTIVE , 3 ) )
2017-10-10 18:01:45 +02:00
return TRUE ;
return FALSE ;
}
2017-10-10 21:45:07 +02:00
void AI_TrySwitchOrUseItem ( void )
{
struct Pokemon * party ;
2018-06-17 16:48:58 +02:00
u8 battlerIn1 , battlerIn2 ;
2017-10-10 21:45:07 +02:00
s32 firstId ;
s32 lastId ; // + 1
2018-06-17 16:48:58 +02:00
u8 battlerIdentity = GetBattlerPosition ( gActiveBattler ) ;
2017-10-10 21:45:07 +02:00
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-10 21:45:07 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
if ( gBattleTypeFlags & BATTLE_TYPE_TRAINER )
{
if ( ShouldSwitch ( ) )
{
2018-06-17 16:48:58 +02:00
if ( * ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = = PARTY_SIZE )
2017-10-10 21:45:07 +02:00
{
s32 monToSwitchId = GetMostSuitableMonToSwitchInto ( ) ;
2018-06-17 16:48:58 +02:00
if ( monToSwitchId = = PARTY_SIZE )
2017-10-10 21:45:07 +02:00
{
if ( ! ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE ) )
{
2018-06-17 16:48:58 +02:00
battlerIn1 = GetBattlerAtPosition ( battlerIdentity ) ;
battlerIn2 = battlerIn1 ;
2017-10-10 21:45:07 +02:00
}
else
{
2018-06-17 16:48:58 +02:00
battlerIn1 = GetBattlerAtPosition ( battlerIdentity ) ;
battlerIn2 = GetBattlerAtPosition ( battlerIdentity ^ BIT_FLANK ) ;
2017-10-10 21:45:07 +02:00
}
2019-01-27 20:54:34 +01:00
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
2017-10-10 21:45:07 +02:00
for ( monToSwitchId = firstId ; monToSwitchId < lastId ; monToSwitchId + + )
{
if ( GetMonData ( & party [ monToSwitchId ] , MON_DATA_HP ) = = 0 )
continue ;
2018-06-17 16:48:58 +02:00
if ( monToSwitchId = = gBattlerPartyIndexes [ battlerIn1 ] )
2017-10-10 21:45:07 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( monToSwitchId = = gBattlerPartyIndexes [ battlerIn2 ] )
2017-10-10 21:45:07 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( monToSwitchId = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn1 ) )
2017-10-10 21:45:07 +02:00
continue ;
2018-06-17 16:48:58 +02:00
if ( monToSwitchId = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn2 ) )
2017-10-10 21:45:07 +02:00
continue ;
break ;
}
}
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) = monToSwitchId ;
2017-10-10 21:45:07 +02:00
}
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > monToSwitchIntoId + gActiveBattler ) = * ( gBattleStruct - > AI_monToSwitchIntoId + gActiveBattler ) ;
2017-10-10 21:45:07 +02:00
return ;
}
else if ( ShouldUseItem ( ) )
{
return ;
}
}
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_USE_MOVE , ( gActiveBattler ^ BIT_SIDE ) < < 8 ) ;
2017-10-10 21:45:07 +02:00
}
2019-09-01 14:23:11 +02:00
// If there are two(or more) mons to choose from, always choose one that has baton pass
// as most often it can't do much on its own.
static u32 GetBestMonBatonPass ( struct Pokemon * party , int firstId , int lastId , u8 invalidMons , int aliveCount )
2017-10-10 21:45:07 +02:00
{
2019-09-01 14:23:11 +02:00
int i , j , bits = 0 ;
2017-10-10 21:45:07 +02:00
2019-08-30 17:57:19 +02:00
for ( i = firstId ; i < lastId ; i + + )
{
if ( invalidMons & gBitTable [ i ] )
continue ;
for ( j = 0 ; j < MAX_MON_MOVES ; j + + )
{
if ( GetMonData ( & party [ i ] , MON_DATA_MOVE1 + j , NULL ) = = MOVE_BATON_PASS )
{
bits | = gBitTable [ i ] ;
break ;
}
}
}
2019-09-01 14:23:11 +02:00
2019-08-30 17:57:19 +02:00
if ( ( aliveCount = = 2 | | ( aliveCount > 2 & & Random ( ) % 3 = = 0 ) ) & & bits )
{
do
{
2019-09-01 14:23:11 +02:00
i = ( Random ( ) % ( lastId - firstId ) ) + firstId ;
} while ( ! ( bits & gBitTable [ i ] ) ) ;
return i ;
2019-08-30 17:57:19 +02:00
}
2017-10-10 21:45:07 +02:00
2019-09-01 14:23:11 +02:00
return PARTY_SIZE ;
}
static u32 GestBestMonOffensive ( struct Pokemon * party , int firstId , int lastId , u8 invalidMons , u32 opposingBattler )
{
int i , bits = 0 ;
while ( bits ! = 0x3F ) // All mons were checked.
2017-10-10 21:45:07 +02:00
{
2019-09-01 14:23:11 +02:00
int bestDmg = 0 ;
int bestMonId = PARTY_SIZE ;
2018-06-17 16:48:58 +02:00
// Find the mon whose type is the most suitable offensively.
2017-10-10 21:45:07 +02:00
for ( i = firstId ; i < lastId ; i + + )
{
2019-08-30 17:57:19 +02:00
if ( ! ( gBitTable [ i ] & invalidMons ) & & ! ( gBitTable [ i ] & bits ) )
2017-10-10 21:45:07 +02:00
{
2019-08-30 17:57:19 +02:00
u16 species = GetMonData ( & party [ i ] , MON_DATA_SPECIES ) ;
2018-07-15 12:39:07 +02:00
u32 typeDmg = UQ_4_12 ( 1.0 ) ;
u8 atkType1 = gBaseStats [ species ] . type1 ;
u8 atkType2 = gBaseStats [ species ] . type2 ;
u8 defType1 = gBattleMons [ opposingBattler ] . type1 ;
u8 defType2 = gBattleMons [ opposingBattler ] . type2 ;
typeDmg * = GetTypeModifier ( atkType1 , defType1 ) ;
if ( atkType2 ! = atkType1 )
typeDmg * = GetTypeModifier ( atkType2 , defType1 ) ;
if ( defType2 ! = defType1 )
{
typeDmg * = GetTypeModifier ( atkType1 , defType2 ) ;
if ( atkType2 ! = atkType1 )
typeDmg * = GetTypeModifier ( atkType2 , defType2 ) ;
}
2017-10-10 21:45:07 +02:00
if ( bestDmg < typeDmg )
{
bestDmg = typeDmg ;
bestMonId = i ;
}
}
}
2018-06-17 16:48:58 +02:00
// Ok, we know the mon has the right typing but does it have at least one super effective move?
if ( bestMonId ! = PARTY_SIZE )
2017-10-10 21:45:07 +02:00
{
2018-12-25 18:50:15 +01:00
for ( i = 0 ; i < MAX_MON_MOVES ; i + + )
2017-10-10 21:45:07 +02:00
{
2019-09-01 14:23:11 +02:00
u32 move = GetMonData ( & party [ bestMonId ] , MON_DATA_MOVE1 + i ) ;
2018-07-15 12:39:07 +02:00
if ( move ! = MOVE_NONE & & AI_GetTypeEffectiveness ( move , gActiveBattler , opposingBattler ) > = UQ_4_12 ( 2.0 ) )
2017-10-10 21:45:07 +02:00
break ;
}
2018-12-25 18:50:15 +01:00
if ( i ! = MAX_MON_MOVES )
2018-06-17 16:48:58 +02:00
return bestMonId ; // Has both the typing and at least one super effective move.
2017-10-10 21:45:07 +02:00
2019-08-30 17:57:19 +02:00
bits | = gBitTable [ bestMonId ] ; // Sorry buddy, we want something better.
2017-10-10 21:45:07 +02:00
}
else
{
2019-08-30 17:57:19 +02:00
bits = 0x3F ; // No viable mon to switch.
2017-10-10 21:45:07 +02:00
}
}
2019-09-01 14:23:11 +02:00
return PARTY_SIZE ;
}
2017-10-10 21:45:07 +02:00
2019-09-01 14:23:11 +02:00
static u32 GetBestMonDmg ( struct Pokemon * party , int firstId , int lastId , u8 invalidMons , u32 opposingBattler )
{
int i , j ;
int bestDmg = 0 ;
int bestMonId = PARTY_SIZE ;
gMoveResultFlags = 0 ;
2018-06-17 16:48:58 +02:00
// If we couldn't find the best mon in terms of typing, find the one that deals most damage.
2017-10-10 21:45:07 +02:00
for ( i = firstId ; i < lastId ; i + + )
{
2019-08-30 17:57:19 +02:00
if ( gBitTable [ i ] & invalidMons )
2017-10-10 21:45:07 +02:00
continue ;
2018-12-25 18:50:15 +01:00
for ( j = 0 ; j < MAX_MON_MOVES ; j + + )
2017-10-10 21:45:07 +02:00
{
2019-09-01 14:23:11 +02:00
u32 move = GetMonData ( & party [ i ] , MON_DATA_MOVE1 + j ) ;
2019-08-30 17:57:19 +02:00
if ( move ! = MOVE_NONE & & gBattleMoves [ move ] . power ! = 0 )
2017-10-10 21:45:07 +02:00
{
2019-08-30 17:57:19 +02:00
s32 dmg = AI_CalcPartyMonDamage ( move , gActiveBattler , opposingBattler , & party [ i ] ) ;
if ( bestDmg < dmg )
{
bestDmg = dmg ;
bestMonId = i ;
}
2017-10-10 21:45:07 +02:00
}
}
}
return bestMonId ;
}
2017-10-11 12:49:42 +02:00
2019-09-01 14:23:11 +02:00
u8 GetMostSuitableMonToSwitchInto ( void )
{
u32 opposingBattler = 0 ;
u32 bestDmg = 0 ;
u32 bestMonId = 0 ;
u8 battlerIn1 = 0 , battlerIn2 = 0 ;
s32 firstId = 0 ;
s32 lastId = 0 ; // + 1
struct Pokemon * party ;
s32 i , j , aliveCount = 0 ;
u8 invalidMons = 0 ;
if ( * ( gBattleStruct - > monToSwitchIntoId + gActiveBattler ) ! = PARTY_SIZE )
return * ( gBattleStruct - > monToSwitchIntoId + gActiveBattler ) ;
if ( gBattleTypeFlags & BATTLE_TYPE_ARENA )
return gBattlerPartyIndexes [ gActiveBattler ] + 1 ;
if ( gBattleTypeFlags & BATTLE_TYPE_DOUBLE )
{
battlerIn1 = gActiveBattler ;
if ( gAbsentBattlerFlags & gBitTable [ GetBattlerAtPosition ( GetBattlerPosition ( gActiveBattler ) ^ BIT_FLANK ) ] )
battlerIn2 = gActiveBattler ;
else
battlerIn2 = GetBattlerAtPosition ( GetBattlerPosition ( gActiveBattler ) ^ BIT_FLANK ) ;
opposingBattler = BATTLE_OPPOSITE ( battlerIn1 ) ;
if ( gAbsentBattlerFlags & gBitTable [ opposingBattler ] )
opposingBattler ^ = BIT_FLANK ;
}
else
{
opposingBattler = GetBattlerAtPosition ( GetBattlerPosition ( gActiveBattler ) ^ BIT_SIDE ) ;
battlerIn1 = gActiveBattler ;
battlerIn2 = gActiveBattler ;
}
GetAIPartyIndexes ( gActiveBattler , & firstId , & lastId ) ;
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
party = gPlayerParty ;
else
party = gEnemyParty ;
// Get invalid slots ids.
for ( i = firstId ; i < lastId ; i + + )
{
if ( GetMonData ( & party [ i ] , MON_DATA_SPECIES ) = = SPECIES_NONE
| | GetMonData ( & party [ i ] , MON_DATA_HP ) = = 0
| | gBattlerPartyIndexes [ battlerIn1 ] = = i
| | gBattlerPartyIndexes [ battlerIn2 ] = = i
| | i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn1 )
| | i = = * ( gBattleStruct - > monToSwitchIntoId + battlerIn2 )
| | ( GetMonAbility ( & party [ i ] ) = = ABILITY_TRUANT & & IsTruantMonVulnerable ( gActiveBattler , opposingBattler ) ) ) // While not really invalid per say, not really wise to switch into this mon.
invalidMons | = gBitTable [ i ] ;
else
aliveCount + + ;
}
bestMonId = GetBestMonBatonPass ( party , firstId , lastId , invalidMons , aliveCount ) ;
if ( bestMonId ! = PARTY_SIZE )
return bestMonId ;
bestMonId = GestBestMonOffensive ( party , firstId , lastId , invalidMons , opposingBattler ) ;
if ( bestMonId ! = PARTY_SIZE )
return bestMonId ;
bestMonId = GetBestMonDmg ( party , firstId , lastId , invalidMons , opposingBattler ) ;
if ( bestMonId ! = PARTY_SIZE )
return bestMonId ;
return PARTY_SIZE ;
}
2018-07-15 12:39:07 +02:00
static u8 GetAI_ItemType ( u16 itemId , const u8 * itemEffect )
2017-10-11 12:49:42 +02:00
{
if ( itemId = = ITEM_FULL_RESTORE )
return AI_ITEM_FULL_RESTORE ;
2019-04-14 17:20:26 +02:00
else if ( itemEffect [ 4 ] & ITEM4_HEAL_HP )
2017-10-11 12:49:42 +02:00
return AI_ITEM_HEAL_HP ;
2019-04-14 17:20:26 +02:00
else if ( itemEffect [ 3 ] & ITEM3_STATUS_ALL )
2017-10-11 12:49:42 +02:00
return AI_ITEM_CURE_CONDITION ;
2019-12-22 01:01:38 +01:00
else if ( itemEffect [ 0 ] & ( ITEM0_DIRE_HIT | ITEM0_X_ATTACK ) | | itemEffect [ 1 ] ! = 0 | | itemEffect [ 2 ] ! = 0 )
2017-10-11 12:49:42 +02:00
return AI_ITEM_X_STAT ;
2019-12-22 01:01:38 +01:00
else if ( itemEffect [ 3 ] & ITEM3_GUARD_SPEC )
2017-10-11 12:49:42 +02:00
return AI_ITEM_GUARD_SPECS ;
2018-06-17 16:48:58 +02:00
else
return AI_ITEM_NOT_RECOGNIZABLE ;
2017-10-11 12:49:42 +02:00
}
static bool8 ShouldUseItem ( void )
{
struct Pokemon * party ;
s32 i ;
u8 validMons = 0 ;
bool8 shouldUse = FALSE ;
2018-02-06 02:46:59 +01:00
if ( gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER & & GetBattlerPosition ( gActiveBattler ) = = B_POSITION_PLAYER_RIGHT )
2017-10-11 12:49:42 +02:00
return FALSE ;
2018-02-06 02:46:59 +01:00
if ( GetBattlerSide ( gActiveBattler ) = = B_SIDE_PLAYER )
2017-10-11 12:49:42 +02:00
party = gPlayerParty ;
else
party = gEnemyParty ;
2018-06-17 16:48:58 +02:00
for ( i = 0 ; i < PARTY_SIZE ; i + + )
2017-10-11 12:49:42 +02:00
{
if ( GetMonData ( & party [ i ] , MON_DATA_HP ) ! = 0
& & GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) ! = SPECIES_NONE
& & GetMonData ( & party [ i ] , MON_DATA_SPECIES2 ) ! = SPECIES_EGG )
{
validMons + + ;
}
}
2019-09-08 18:21:24 +02:00
for ( i = 0 ; i < MAX_TRAINER_ITEMS ; i + + )
2017-10-11 12:49:42 +02:00
{
u16 item ;
const u8 * itemEffects ;
u8 paramOffset ;
2018-06-17 16:48:58 +02:00
u8 battlerSide ;
2017-10-11 12:49:42 +02:00
if ( i ! = 0 & & validMons > ( gBattleResources - > battleHistory - > itemsNo - i ) + 1 )
continue ;
item = gBattleResources - > battleHistory - > trainerItems [ i ] ;
if ( item = = ITEM_NONE )
continue ;
2019-04-14 17:20:26 +02:00
if ( gItemEffectTable [ item - ITEM_POTION ] = = NULL )
2017-10-11 12:49:42 +02:00
continue ;
if ( item = = ITEM_ENIGMA_BERRY )
itemEffects = gSaveBlock1Ptr - > enigmaBerry . itemEffect ;
else
2019-04-14 17:20:26 +02:00
itemEffects = gItemEffectTable [ item - ITEM_POTION ] ;
2017-10-11 12:49:42 +02:00
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemType + gActiveBattler / 2 ) = GetAI_ItemType ( item , itemEffects ) ;
2017-10-11 12:49:42 +02:00
2018-02-06 02:46:59 +01:00
switch ( * ( gBattleStruct - > AI_itemType + gActiveBattler / 2 ) )
2017-10-11 12:49:42 +02:00
{
case AI_ITEM_FULL_RESTORE :
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . hp > = gBattleMons [ gActiveBattler ] . maxHP / 4 )
2017-10-11 12:49:42 +02:00
break ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . hp = = 0 )
2017-10-11 12:49:42 +02:00
break ;
shouldUse = TRUE ;
break ;
case AI_ITEM_HEAL_HP :
paramOffset = GetItemEffectParamOffset ( item , 4 , 4 ) ;
if ( paramOffset = = 0 )
break ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . hp = = 0 )
2017-10-11 12:49:42 +02:00
break ;
2018-02-06 02:46:59 +01:00
if ( gBattleMons [ gActiveBattler ] . hp < gBattleMons [ gActiveBattler ] . maxHP / 4 | | gBattleMons [ gActiveBattler ] . maxHP - gBattleMons [ gActiveBattler ] . hp > itemEffects [ paramOffset ] )
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
break ;
case AI_ITEM_CURE_CONDITION :
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) = 0 ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_SLEEP & & gBattleMons [ gActiveBattler ] . status1 & STATUS1_SLEEP )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x20 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_POISON & & ( gBattleMons [ gActiveBattler ] . status1 & STATUS1_POISON | | gBattleMons [ gActiveBattler ] . status1 & STATUS1_TOXIC_POISON ) )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x10 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_BURN & & gBattleMons [ gActiveBattler ] . status1 & STATUS1_BURN )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x8 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_FREEZE & & gBattleMons [ gActiveBattler ] . status1 & STATUS1_FREEZE )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x4 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_PARALYSIS & & gBattleMons [ gActiveBattler ] . status1 & STATUS1_PARALYSIS )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x2 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 3 ] & ITEM3_CONFUSION & & gBattleMons [ gActiveBattler ] . status2 & STATUS2_CONFUSION )
2017-10-11 12:49:42 +02:00
{
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x1 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
}
break ;
case AI_ITEM_X_STAT :
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) = 0 ;
if ( gDisableStructs [ gActiveBattler ] . isFirstTurn = = 0 )
2017-10-11 12:49:42 +02:00
break ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 0 ] & ITEM0_X_ATTACK )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x1 ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 1 ] & ITEM1_X_DEFEND )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x2 ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 1 ] & ITEM1_X_SPEED )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x4 ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 2 ] & ITEM2_X_SPATK )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x8 ;
2019-04-14 17:20:26 +02:00
if ( itemEffects [ 2 ] & ITEM2_X_ACCURACY )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x20 ;
2019-12-22 01:01:38 +01:00
if ( itemEffects [ 0 ] & ITEM0_DIRE_HIT )
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > AI_itemFlags + gActiveBattler / 2 ) | = 0x80 ;
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
break ;
case AI_ITEM_GUARD_SPECS :
2018-06-17 16:48:58 +02:00
battlerSide = GetBattlerSide ( gActiveBattler ) ;
if ( gDisableStructs [ gActiveBattler ] . isFirstTurn ! = 0 & & gSideTimers [ battlerSide ] . mistTimer = = 0 )
2017-10-11 12:49:42 +02:00
shouldUse = TRUE ;
break ;
case AI_ITEM_NOT_RECOGNIZABLE :
return FALSE ;
}
if ( shouldUse )
{
2018-02-06 23:09:39 +01:00
BtlController_EmitTwoReturnValues ( 1 , B_ACTION_USE_ITEM , 0 ) ;
2018-02-06 02:46:59 +01:00
* ( gBattleStruct - > chosenItem + ( gActiveBattler / 2 ) * 2 ) = item ;
2017-10-11 12:49:42 +02:00
gBattleResources - > battleHistory - > trainerItems [ i ] = 0 ;
return shouldUse ;
}
}
return FALSE ;
}