Split ai function IsBattlerTrapped (#6438)

This commit is contained in:
Alex 2025-03-18 17:00:11 +01:00 committed by GitHub
parent 29fa249762
commit 6031bb2a78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 60 additions and 22 deletions

View File

@ -52,7 +52,8 @@ u32 GetTotalBaseStat(u32 species);
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
bool32 AI_BattlerAtMaxHp(u32 battler);
u32 GetHealthPercentage(u32 battler);
bool32 IsBattlerTrapped(u32 battler, bool32 switching);
bool32 AI_CanBattlerEscape(u32 battler);
bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef);
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);

View File

@ -1600,7 +1600,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10); // if mon will wake up, is not asleep, or is not comatose
break;
case EFFECT_MEAN_LOOK:
if (IsBattlerTrapped(battlerDef, TRUE) || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
if (AI_CanBattlerEscape(battlerDef)
|| IsBattlerTrapped(battlerAtk, battlerDef)
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;
case EFFECT_NIGHTMARE:
@ -2713,7 +2715,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
else if (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_STATUS
&& (CountUsablePartyMons(battlerAtk) < 1
|| AI_DATA->mostSuitableMonId[battlerAtk] == PARTY_SIZE
|| IsBattlerTrapped(battlerAtk, TRUE)))
|| (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk))))
ADJUST_SCORE(-30);
}
@ -3666,7 +3668,8 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|| aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD)
break;
ADJUST_SCORE(GOOD_EFFECT);
if (!HasDamagingMove(battlerDef) || IsBattlerTrapped(battlerDef, FALSE)
if (!HasDamagingMove(battlerDef)
|| (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef))
|| aiData->holdEffects[battlerAtk] == HOLD_EFFECT_BIG_ROOT)
ADJUST_SCORE(DECENT_EFFECT);
break;
@ -3761,7 +3764,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_CURSE:
if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST))
{
if (IsBattlerTrapped(battlerDef, TRUE))
if (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
else
ADJUST_SCORE(WEAK_EFFECT);
@ -3854,7 +3857,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(DECENT_EFFECT);
break;
case EFFECT_PERISH_SONG:
if (IsBattlerTrapped(battlerDef, TRUE))
if (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef))
ADJUST_SCORE(GOOD_EFFECT);
break;
case EFFECT_SANDSTORM:
@ -3995,7 +3998,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
break; // Don't use if the attract won't have a change to activate
if (gBattleMons[battlerDef].status1 & STATUS1_ANY
|| (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|| IsBattlerTrapped(battlerDef, TRUE))
|| (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef)))
ADJUST_SCORE(GOOD_EFFECT);
else
ADJUST_SCORE(DECENT_EFFECT);
@ -5091,7 +5094,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|| CountUsablePartyMons(battlerAtk) == 0
|| !IsBattleMoveStatus(move)
|| !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS)
|| IsBattlerTrapped(battlerAtk, TRUE))
|| (!AI_CanBattlerEscape(battlerAtk) && IsBattlerTrapped(battlerDef, battlerAtk)))
return score;
u32 effect = GetMoveEffect(move);
@ -5582,7 +5585,16 @@ static void AI_Watch(void)
// Roaming pokemon logic
static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
if (IsBattlerTrapped(battlerAtk, FALSE))
bool32 roamerCanFlee = FALSE;
if (AI_CanBattlerEscape(battlerAtk))
roamerCanFlee = TRUE;
else if (AI_DATA->abilities[battlerAtk] == ABILITY_RUN_AWAY)
roamerCanFlee = TRUE;
else if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CAN_ALWAYS_RUN)
roamerCanFlee = TRUE;
if (!roamerCanFlee && IsBattlerTrapped(battlerDef, battlerAtk))
return score;
AI_Flee();

View File

@ -339,25 +339,35 @@ bool32 AI_BattlerAtMaxHp(u32 battlerId)
return FALSE;
}
bool32 IsBattlerTrapped(u32 battler, bool32 checkSwitch)
bool32 AI_CanBattlerEscape(u32 battler)
{
u32 holdEffect = AI_DATA->holdEffects[battler];
if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST))
return FALSE;
if (checkSwitch && holdEffect == HOLD_EFFECT_SHED_SHELL)
return FALSE;
else if (!checkSwitch && AI_DATA->abilities[battler] == ABILITY_RUN_AWAY)
return FALSE;
else if (!checkSwitch && holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
return FALSE;
else if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))
return TRUE;
else if (gStatuses3[battler] & (STATUS3_ROOTED | STATUS3_SKY_DROPPED))
if (holdEffect == HOLD_EFFECT_SHED_SHELL)
return TRUE;
else if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)
return FALSE;
}
bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef)
{
if (gBattleMons[battlerDef].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))
return TRUE;
else if (IsAbilityPreventingEscape(battler))
if (gStatuses3[battlerDef] & (STATUS3_ROOTED | STATUS3_SKY_DROPPED))
return TRUE;
if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)
return TRUE;
if (AI_IsAbilityOnSide(battlerAtk, ABILITY_SHADOW_TAG)
&& (B_SHADOW_TAG_ESCAPE >= GEN_4 && AI_DATA->abilities[battlerDef] != ABILITY_SHADOW_TAG))
return TRUE;
if (AI_IsAbilityOnSide(battlerAtk, ABILITY_ARENA_TRAP)
&& IsBattlerGrounded(battlerAtk))
return TRUE;
if (AI_IsAbilityOnSide(battlerAtk, ABILITY_MAGNET_PULL)
&& IS_BATTLER_OF_TYPE(battlerAtk, TYPE_STEEL))
return TRUE;
return FALSE;
@ -3256,7 +3266,10 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi
bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move)
{
if (IsBattlerTrapped(battlerDef, TRUE))
if (AI_CanBattlerEscape(battlerDef))
return FALSE;
if (IsBattlerTrapped(battlerAtk, battlerDef))
return FALSE;
if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef]))

View File

@ -845,3 +845,15 @@ AI_SINGLE_BATTLE_TEST("AI won't use Sucker Punch if it expects a move of the sam
TURN { MOVE(player, MOVE_QUICK_ATTACK); EXPECT_MOVE(opponent, MOVE_TACKLE); }
}
}
AI_SINGLE_BATTLE_TEST("AI score for Mean Look will be decreased if target can escape")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(SPECIES_BULBASAUR) { Item(ITEM_SHED_SHELL); }
OPPONENT(SPECIES_BULBASAUR) { Moves(MOVE_TACKLE, MOVE_MEAN_LOOK); }
} WHEN {
TURN { SCORE_EQ_VAL(opponent, MOVE_MEAN_LOOK, 90); }
}
}