Fix AI trying to switch when it can't, also ghosts can escape
This commit is contained in:
parent
97eaf8b559
commit
14bc2f65f3
7 changed files with 66 additions and 83 deletions
|
@ -81,6 +81,7 @@ u32 IsAbilityOnSide(u32 battlerId, u32 ability);
|
|||
u32 IsAbilityOnOpposingSide(u32 battlerId, u32 ability);
|
||||
u32 IsAbilityOnField(u32 ability);
|
||||
u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability);
|
||||
u32 IsAbilityPreventingEscape(u32 battlerId);
|
||||
void BattleScriptExecute(const u8* BS_ptr);
|
||||
void BattleScriptPushCursorAndCallback(const u8* BS_ptr);
|
||||
u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn);
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#define B_ABILITY_WEATHER GEN_6 // Up to gen5 - weather induced by abilities such as Drought or Drizzle lasted till the battle's end or weather change by a move. From Gen6 onwards, weather caused by abilities lasts the same amount of turns as induced from a move.
|
||||
#define B_GALE_WINGS GEN_6 // Gen7 requires full hp.
|
||||
#define B_STANCE_CHANGE_FAIL GEN_7 // In Gen7, Aegislash's form change does not happen, if the pokemon cannot use a move, because of confusion, paralysis, etc. In gen6, the form change occurs despite not being able to move.
|
||||
#define B_GHOSTS_ESCAPE GEN_6 // From Gen6 onwards, ghosts can escape even when blocked by abilities such as Shadow Tag.
|
||||
|
||||
// Other
|
||||
#define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a pokemon, as opposing to waiting for the animation to end.
|
||||
|
|
|
@ -494,41 +494,44 @@ static u8 ChooseMoveOrAction_Singles(void)
|
|||
return AI_CHOICE_WATCH;
|
||||
|
||||
gActiveBattler = sBattler_AI;
|
||||
// Consider switching if all moves are worthless to use.
|
||||
if (AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_PREFER_BATON_PASS)
|
||||
&& CountUsablePartyMons(sBattler_AI) >= 1
|
||||
&& GetTotalBaseStat(gBattleMons[sBattler_AI].species) >= 310 // Mon is not weak.
|
||||
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_PALACE))
|
||||
// If can switch.
|
||||
if (CountUsablePartyMons(sBattler_AI) >= 1
|
||||
&& !IsAbilityPreventingEscape(sBattler_AI)
|
||||
&& !(gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
&& !(gStatuses3[gActiveBattler] & STATUS3_ROOTED)
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_ARENA | BATTLE_TYPE_PALACE))
|
||||
&& AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY | AI_SCRIPT_CHECK_BAD_MOVE | AI_SCRIPT_TRY_TO_FAINT | AI_SCRIPT_PREFER_BATON_PASS))
|
||||
{
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY) ? 95 : 93;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
// Consider switching if all moves are worthless to use.
|
||||
if (GetTotalBaseStat(gBattleMons[sBattler_AI].species) >= 310 // Mon is not weak.
|
||||
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->score[i] > cap)
|
||||
break;
|
||||
s32 cap = AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY) ? 95 : 93;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (AI_THINKING_STRUCT->score[i] > cap)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == MAX_MON_MOVES && GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
|
||||
{
|
||||
AI_THINKING_STRUCT->switchMon = TRUE;
|
||||
return AI_CHOICE_SWITCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MAX_MON_MOVES && GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
|
||||
// Consider switching if your mon with truant is bodied by Protect spam.
|
||||
// Or is using a double turn semi invulnerable move(such as Fly) and is faster.
|
||||
if (GetBattlerAbility(sBattler_AI) == ABILITY_TRUANT
|
||||
&& IsTruantMonVulnerable(sBattler_AI, gBattlerTarget)
|
||||
&& gDisableStructs[sBattler_AI].truantCounter
|
||||
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2)
|
||||
{
|
||||
AI_THINKING_STRUCT->switchMon = TRUE;
|
||||
return AI_CHOICE_SWITCH;
|
||||
}
|
||||
}
|
||||
|
||||
// Consider switching if your mon with truant is bodied by Protect spam.
|
||||
// Or is using a double turn semi invulnerable move(such as Fly) and is faster.
|
||||
if (GetBattlerAbility(sBattler_AI) == ABILITY_TRUANT
|
||||
&& IsTruantMonVulnerable(sBattler_AI, gBattlerTarget)
|
||||
&& gDisableStructs[sBattler_AI].truantCounter
|
||||
&& AI_THINKING_STRUCT->aiFlags & (AI_SCRIPT_CHECK_VIABILITY)
|
||||
&& gBattleMons[sBattler_AI].hp >= gBattleMons[sBattler_AI].maxHP / 2
|
||||
&& CountUsablePartyMons(sBattler_AI) >= 1)
|
||||
{
|
||||
if (GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
|
||||
{
|
||||
AI_THINKING_STRUCT->switchMon = TRUE;
|
||||
return AI_CHOICE_SWITCH;
|
||||
if (GetMostSuitableMonToSwitchInto() != PARTY_SIZE)
|
||||
{
|
||||
AI_THINKING_STRUCT->switchMon = TRUE;
|
||||
return AI_CHOICE_SWITCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -420,44 +420,34 @@ static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent)
|
|||
static bool8 ShouldSwitch(void)
|
||||
{
|
||||
u8 battlerIn1, battlerIn2;
|
||||
u8 *activeBattlerPtr; // Needed to match.
|
||||
s32 firstId;
|
||||
s32 lastId; // + 1
|
||||
struct Pokemon *party;
|
||||
s32 i;
|
||||
s32 availableToSwitch;
|
||||
|
||||
if (gBattleMons[*(activeBattlerPtr = &gActiveBattler)].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
if (gBattleMons[gActiveBattler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
return FALSE;
|
||||
if (gStatuses3[gActiveBattler] & STATUS3_ROOTED)
|
||||
return FALSE;
|
||||
if (IsAbilityOnOpposingSide(gActiveBattler, ABILITY_SHADOW_TAG))
|
||||
if (IsAbilityPreventingEscape(gActiveBattler))
|
||||
return FALSE;
|
||||
if (IsAbilityOnOpposingSide(gActiveBattler, ABILITY_ARENA_TRAP)) // Misses the flying type and Levitate check.
|
||||
return FALSE;
|
||||
if (IsAbilityOnField(ABILITY_MAGNET_PULL))
|
||||
{
|
||||
if (gBattleMons[gActiveBattler].type1 == TYPE_STEEL)
|
||||
return FALSE;
|
||||
if (gBattleMons[gActiveBattler].type2 == TYPE_STEEL)
|
||||
return FALSE;
|
||||
}
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||
return FALSE;
|
||||
|
||||
availableToSwitch = 0;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
{
|
||||
battlerIn1 = *activeBattlerPtr;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(*activeBattlerPtr) ^ BIT_FLANK)])
|
||||
battlerIn2 = *activeBattlerPtr;
|
||||
battlerIn1 = gActiveBattler;
|
||||
if (gAbsentBattlerFlags & gBitTable[GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK)])
|
||||
battlerIn2 = gActiveBattler;
|
||||
else
|
||||
battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(*activeBattlerPtr) ^ BIT_FLANK);
|
||||
battlerIn2 = GetBattlerAtPosition(GetBattlerPosition(gActiveBattler) ^ BIT_FLANK);
|
||||
}
|
||||
else
|
||||
{
|
||||
battlerIn1 = *activeBattlerPtr;
|
||||
battlerIn2 = *activeBattlerPtr;
|
||||
battlerIn1 = gActiveBattler;
|
||||
battlerIn2 = gActiveBattler;
|
||||
}
|
||||
|
||||
GetAIPartyIndexes(gActiveBattler, &firstId, &lastId);
|
||||
|
|
|
@ -3652,9 +3652,7 @@ void BattleTurnPassed(void)
|
|||
|
||||
u8 IsRunningFromBattleImpossible(void)
|
||||
{
|
||||
u8 holdEffect;
|
||||
u8 side;
|
||||
s32 i;
|
||||
u32 holdEffect, i;
|
||||
|
||||
if (gBattleMons[gActiveBattler].item == ITEM_ENIGMA_BERRY)
|
||||
holdEffect = gEnigmaBerries[gActiveBattler].holdEffect;
|
||||
|
@ -3681,37 +3679,14 @@ u8 IsRunningFromBattleImpossible(void)
|
|||
if (gBattleMons[gActiveBattler].ability == ABILITY_RUN_AWAY)
|
||||
return 0;
|
||||
|
||||
side = GetBattlerSide(gActiveBattler);
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (side != GetBattlerSide(i)
|
||||
&& gBattleMons[i].ability == ABILITY_SHADOW_TAG)
|
||||
{
|
||||
gBattleScripting.battler = i;
|
||||
gLastUsedAbility = gBattleMons[i].ability;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
||||
return 2;
|
||||
}
|
||||
if (side != GetBattlerSide(i)
|
||||
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE
|
||||
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING)
|
||||
&& gBattleMons[i].ability == ABILITY_ARENA_TRAP)
|
||||
{
|
||||
gBattleScripting.battler = i;
|
||||
gLastUsedAbility = gBattleMons[i].ability;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
i = IsAbilityOnFieldExcept(gActiveBattler, ABILITY_MAGNET_PULL);
|
||||
if (i != 0 && IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL))
|
||||
if ((i = IsAbilityPreventingEscape(gActiveBattler)))
|
||||
{
|
||||
gBattleScripting.battler = i - 1;
|
||||
gLastUsedAbility = gBattleMons[i - 1].ability;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((gBattleMons[gActiveBattler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))
|
||||
|| (gStatuses3[gActiveBattler] & STATUS3_ROOTED))
|
||||
{
|
||||
|
@ -3895,12 +3870,7 @@ static void HandleTurnActionSelectionState(void)
|
|||
{
|
||||
BtlController_EmitChoosePokemon(0, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->field_60[gActiveBattler]);
|
||||
}
|
||||
else if ((i = IsAbilityOnOpposingSide(gActiveBattler, ABILITY_SHADOW_TAG))
|
||||
|| ((i = IsAbilityOnOpposingSide(gActiveBattler, ABILITY_ARENA_TRAP))
|
||||
&& !IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_FLYING)
|
||||
&& gBattleMons[gActiveBattler].ability != ABILITY_LEVITATE)
|
||||
|| ((i = IsAbilityOnFieldExcept(gActiveBattler, ABILITY_MAGNET_PULL))
|
||||
&& IS_BATTLER_OF_TYPE(gActiveBattler, TYPE_STEEL)))
|
||||
else if ((i = IsAbilityPreventingEscape(gActiveBattler)))
|
||||
{
|
||||
BtlController_EmitChoosePokemon(0, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gLastUsedAbility, gBattleStruct->field_60[gActiveBattler]);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "field_weather.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/battle_anim.h"
|
||||
#include "constants/battle_config.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/battle_script_commands.h"
|
||||
#include "constants/battle_string_ids.h"
|
||||
|
@ -3801,6 +3802,23 @@ u32 IsAbilityOnFieldExcept(u32 battlerId, u32 ability)
|
|||
return 0;
|
||||
}
|
||||
|
||||
u32 IsAbilityPreventingEscape(u32 battlerId)
|
||||
{
|
||||
u32 id;
|
||||
|
||||
if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battlerId, TYPE_GHOST))
|
||||
return 0;
|
||||
|
||||
if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_SHADOW_TAG)) && gBattleMons[battlerId].ability != ABILITY_SHADOW_TAG)
|
||||
return id;
|
||||
if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_ARENA_TRAP)) && IsBattlerGrounded(battlerId))
|
||||
return id;
|
||||
if ((id = IsAbilityOnOpposingSide(battlerId, ABILITY_MAGNET_PULL)) && IS_BATTLER_OF_TYPE(battlerId, TYPE_STEEL))
|
||||
return id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BattleScriptExecute(const u8 *BS_ptr)
|
||||
{
|
||||
gBattlescriptCurrInstr = BS_ptr;
|
||||
|
|
|
@ -5510,7 +5510,7 @@ void AdjustFriendship(struct Pokemon *mon, u8 event)
|
|||
if (friendship > 199)
|
||||
friendshipLevel++;
|
||||
|
||||
if ((event != FRIENDSHIP_EVENT_WALKING || !(Random() & 1))
|
||||
if ((event != FRIENDSHIP_EVENT_WALKING || !(Random() & 1))
|
||||
&& (event != FRIENDSHIP_EVENT_LEAGUE_BATTLE || IS_LEAGUE_BATTLE))
|
||||
{
|
||||
s8 mod = sFriendshipEventModifiers[event][friendshipLevel];
|
||||
|
|
Loading…
Reference in a new issue