Smarter Focus Punch and Substitute (#4952)
* Smarter Focus Punch * Smarter Substitute, review feedback * Use HasAnyKnownMove instead of isFirstTurn * When are we removing agbcc again * Use HasMoveEffect
This commit is contained in:
parent
f6d2b2861a
commit
c721f1b04a
5 changed files with 83 additions and 12 deletions
|
@ -42,6 +42,7 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
|
|||
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
|
||||
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);
|
||||
u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef);
|
||||
u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget);
|
||||
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
|
||||
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
|
||||
s32 AI_DecideKnownAbilityForTurn(u32 battlerId);
|
||||
|
@ -115,6 +116,7 @@ bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect);
|
|||
bool32 HasMoveWithCriticalHitChance(u32 battlerId);
|
||||
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception);
|
||||
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
bool32 HasAnyKnownMove(u32 battlerId);
|
||||
bool32 IsAromaVeilProtectedMove(u32 move);
|
||||
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
|
||||
bool32 IsStatLoweringMoveEffect(u32 moveEffect);
|
||||
|
|
|
@ -3564,11 +3564,17 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score);
|
||||
break;
|
||||
case EFFECT_SUBSTITUTE:
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
if (HasAnyKnownMove(battlerDef) && GetBestDmgFromBattler(battlerDef, battlerAtk) < gBattleMons[battlerAtk].maxHP / 4)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE))
|
||||
if (gBattleMons[battlerDef].status1 & STATUS1_SLEEP)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
// TODO:
|
||||
// if (IsPredictedToSwitch(battlerDef, battlerAtk)
|
||||
// ADJUST_SCORE(DECENT_EFFECT);
|
||||
if (HasMoveEffect(battlerDef, EFFECT_SLEEP)
|
||||
|| HasMoveEffect(battlerDef, EFFECT_TOXIC)
|
||||
|| HasMoveEffect(battlerDef, EFFECT_POISON)
|
||||
|
@ -4462,15 +4468,6 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
|||
else if (ShouldRecover(battlerAtk, battlerDef, move, 50))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_FOCUS_PUNCH:
|
||||
if (!isDoubleBattle && effectiveness > AI_EFFECTIVENESS_x0_5)
|
||||
{
|
||||
if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
if (gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
}
|
||||
break;
|
||||
case EFFECT_ENDEAVOR:
|
||||
if (AI_IsSlower(battlerAtk, battlerDef, move) && !CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
|
|
|
@ -493,6 +493,16 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef)
|
|||
if (!gDisableStructs[battlerAtk].isFirstTurn)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_FOCUS_PUNCH:
|
||||
if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE)
|
||||
|| IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef])
|
||||
|| gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)))
|
||||
// TODO: || IsPredictedToSwitch(battlerDef, battlerAtk)
|
||||
return TRUE;
|
||||
// If AI could Sub and doesn't have a Sub, don't Punch yet
|
||||
if (HasMoveEffect(battlerAtk, EFFECT_SUBSTITUTE) && !(gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE))
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
@ -1106,6 +1116,27 @@ u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef)
|
|||
return move;
|
||||
}
|
||||
|
||||
u32 GetBestDmgFromBattler(u32 battler, u32 battlerTarget)
|
||||
{
|
||||
u32 i;
|
||||
u32 bestDmg = 0;
|
||||
u32 unusable = AI_DATA->moveLimitations[battler];
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE
|
||||
&& moves[i] != MOVE_UNAVAILABLE
|
||||
&& !(unusable & gBitTable[i])
|
||||
&& bestDmg < AI_DATA->simulatedDmg[battler][battlerTarget][i].expected)
|
||||
{
|
||||
bestDmg = AI_DATA->simulatedDmg[battler][battlerTarget][i].expected;
|
||||
}
|
||||
}
|
||||
|
||||
return bestDmg;
|
||||
}
|
||||
|
||||
// Check if AI mon has the means to faint the target with any of its moves.
|
||||
// If numHits > 1, check if the target will be KO'ed by that number of hits (ignoring healing effects)
|
||||
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits)
|
||||
|
@ -1998,6 +2029,20 @@ bool32 HasMove(u32 battlerId, u32 move)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasAnyKnownMove(u32 battlerId)
|
||||
{
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battlerId);
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect)
|
||||
{
|
||||
s32 i;
|
||||
|
|
|
@ -74,3 +74,28 @@ DOUBLE_BATTLE_TEST("Focus Punch activation is based on Speed")
|
|||
MESSAGE("Foe Wobbuffet lost its focus and couldn't move!");
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use Focus Punch if it predicts a damaging move")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MAGNEZONE) { Moves(MOVE_THUNDER_WAVE, MOVE_FLASH_CANNON, MOVE_DISCHARGE, MOVE_TRI_ATTACK); }
|
||||
OPPONENT(SPECIES_BRELOOM) { Moves(MOVE_FOCUS_PUNCH, MOVE_SEED_BOMB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_FOCUS_PUNCH); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SEED_BOMB); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI will Incapacitate -> Substitute -> Focus Punch if able")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_MAGNEZONE) { Moves(MOVE_THUNDER_WAVE, MOVE_FLASH_CANNON, MOVE_DISCHARGE, MOVE_TRI_ATTACK); }
|
||||
OPPONENT(SPECIES_BRELOOM) { Moves(MOVE_SPORE, MOVE_FOCUS_PUNCH, MOVE_SUBSTITUTE, MOVE_SEED_BOMB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SPORE); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { MOVE(player, MOVE_DISCHARGE); EXPECT_MOVE(opponent, MOVE_FOCUS_PUNCH); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,13 +74,14 @@ SINGLE_BATTLE_TEST("Tidy Up removes Substitute")
|
|||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI prefers to keep it's substitute over removing hazards if target is slower")
|
||||
AI_SINGLE_BATTLE_TEST("AI prefers to keep its substitute over removing hazards if target is slower")
|
||||
{
|
||||
GIVEN {
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(50); Status1(STATUS1_PARALYSIS); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_BITE); }
|
||||
}
|
||||
|
@ -93,6 +94,7 @@ AI_SINGLE_BATTLE_TEST("AI will try to remove hazards if slower then target even
|
|||
PLAYER(SPECIES_WOBBUFFET) { Speed(100); Status1(STATUS1_BURN); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||
TURN { EXPECT_MOVE(opponent, MOVE_TIDY_UP); }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue