AI smarter status handling (#6550)
This commit is contained in:
parent
69f2f9f151
commit
54928726cb
@ -177,11 +177,13 @@ bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
|
||||
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability);
|
||||
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability);
|
||||
bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 ShouldBurnSelf(u32 battler, u32 ability);
|
||||
bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
|
||||
@ -1456,6 +1456,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_TOXIC:
|
||||
if (!AI_CanPoison(battlerAtk, battlerDef, abilityDef, move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
if (!ShouldPoison(battlerAtk, battlerDef))
|
||||
ADJUST_SCORE(-5);
|
||||
break;
|
||||
case EFFECT_LIGHT_SCREEN:
|
||||
if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_LIGHTSCREEN
|
||||
@ -1499,6 +1501,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_PARALYZE:
|
||||
if (!AI_CanParalyze(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
if (!ShouldParalyze(battlerAtk, battlerDef))
|
||||
ADJUST_SCORE(-5);
|
||||
break;
|
||||
case EFFECT_SUBSTITUTE:
|
||||
if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR)
|
||||
@ -1791,6 +1795,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_WILL_O_WISP:
|
||||
if (!AI_CanBurn(battlerAtk, battlerDef, aiData->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
if (!ShouldBurn(battlerAtk, battlerDef))
|
||||
ADJUST_SCORE(-5);
|
||||
break;
|
||||
case EFFECT_MEMENTO:
|
||||
if (CountUsablePartyMons(battlerAtk) == 0 || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
|
||||
@ -4057,11 +4063,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_TOXIC_ORB:
|
||||
if (!ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (!ShouldPoison(battlerAtk, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (!ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]) && CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
if (!ShouldBurn(battlerAtk, battlerAtk) && CanBeBurned(battlerAtk, aiData->abilities[battlerDef]))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
@ -4107,11 +4113,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case HOLD_EFFECT_CHOICE_BAND:
|
||||
break;
|
||||
case HOLD_EFFECT_TOXIC_ORB:
|
||||
if (ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (ShouldPoison(battlerAtk, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (ShouldBurn(battlerAtk, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
@ -4761,11 +4767,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_TOXIC_ORB:
|
||||
if (ShouldPoisonSelf(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (ShouldPoison(battlerAtk, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_FLAME_ORB:
|
||||
if (ShouldBurnSelf(battlerAtk, aiData->abilities[battlerAtk]))
|
||||
if (ShouldBurn(battlerAtk, battlerAtk))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case HOLD_EFFECT_BLACK_SLUDGE:
|
||||
|
||||
@ -3118,21 +3118,110 @@ bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability)
|
||||
static inline bool32 DoesBattlerBenefitFromAllVolatileStatus(u32 battler, u32 ability)
|
||||
{
|
||||
if (CanBePoisoned(battler, battler, GetBattlerAbility(battler)) && (
|
||||
ability == ABILITY_MARVEL_SCALE
|
||||
|| ability == ABILITY_POISON_HEAL
|
||||
|| ability == ABILITY_QUICK_FEET
|
||||
|| ability == ABILITY_MAGIC_GUARD
|
||||
|| (ability == ABILITY_TOXIC_BOOST && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL))
|
||||
|| (ability == ABILITY_GUTS && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL))
|
||||
|| HasMoveEffect(battler, EFFECT_FACADE)
|
||||
|| HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT)))
|
||||
return TRUE; // battler can be poisoned and has move/ability that synergizes with being poisoned
|
||||
if (ability == ABILITY_MARVEL_SCALE
|
||||
|| ability == ABILITY_QUICK_FEET
|
||||
|| ability == ABILITY_MAGIC_GUARD
|
||||
|| (ability == ABILITY_GUTS && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL))
|
||||
|| HasMoveEffect(battler, EFFECT_FACADE)
|
||||
|| HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 ShouldPoison(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
u32 defAbility = GetBattlerAbility(battlerDef);
|
||||
// Battler can be poisoned and has move/ability that synergizes with being poisoned
|
||||
if (CanBePoisoned(battlerAtk, battlerDef, GetBattlerAbility(battlerDef)) && (
|
||||
DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility)
|
||||
|| defAbility == ABILITY_POISON_HEAL
|
||||
|| (defAbility == ABILITY_TOXIC_BOOST && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_PHYSICAL))))
|
||||
{
|
||||
if (battlerAtk == battlerDef) // Targeting self
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
if (battlerAtk == battlerDef)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldBurn(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
u32 defAbility = GetBattlerAbility(battlerDef);
|
||||
// Battler can be burned and has move/ability that synergizes with being burned
|
||||
if (CanBeBurned(battlerDef, defAbility) && (
|
||||
DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility)
|
||||
|| defAbility == ABILITY_HEATPROOF
|
||||
|| (defAbility == ABILITY_FLARE_BOOST && HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_SPECIAL))))
|
||||
{
|
||||
if (battlerAtk == battlerDef) // Targeting self
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (battlerAtk == battlerDef)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldFreezeOrFrostbite(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
if (!B_USE_FROSTBITE)
|
||||
{
|
||||
if (CanBeFrozen(battlerDef))
|
||||
{
|
||||
if (battlerAtk == battlerDef) // Targeting self
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 defAbility = GetBattlerAbility(battlerDef);
|
||||
// Battler can be frostbitten and has move/ability that synergizes with being frostbitten
|
||||
if (CanBeFrozen(battlerDef) &&
|
||||
DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility))
|
||||
{
|
||||
if (battlerAtk == battlerDef) // Targeting self
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (battlerAtk == battlerDef)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 ShouldParalyze(u32 battlerAtk, u32 battlerDef)
|
||||
{
|
||||
u32 defAbility = GetBattlerAbility(battlerDef);
|
||||
// Battler can be paralyzed and has move/ability that synergizes with being paralyzed
|
||||
if (CanBeParalyzed(battlerDef, defAbility) && (
|
||||
DoesBattlerBenefitFromAllVolatileStatus(battlerDef, defAbility)))
|
||||
{
|
||||
if (battlerAtk == battlerDef) // Targeting self
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
if (battlerAtk == battlerDef)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!CanBePoisoned(battlerAtk, battlerDef, GetBattlerAbility(battlerDef))
|
||||
@ -3196,20 +3285,6 @@ bool32 AI_CanGetFrostbite(u32 battler, u32 ability)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool32 ShouldBurnSelf(u32 battler, u32 ability)
|
||||
{
|
||||
if (CanBeBurned(battler, ability) && (
|
||||
ability == ABILITY_QUICK_FEET
|
||||
|| ability == ABILITY_HEATPROOF
|
||||
|| ability == ABILITY_MAGIC_GUARD
|
||||
|| (ability == ABILITY_FLARE_BOOST && HasMoveWithCategory(battler, DAMAGE_CATEGORY_SPECIAL))
|
||||
|| (ability == ABILITY_GUTS && HasMoveWithCategory(battler, DAMAGE_CATEGORY_PHYSICAL))
|
||||
|| HasMoveEffect(battler, EFFECT_FACADE)
|
||||
|| HasMoveEffect(battler, EFFECT_PSYCHO_SHIFT)))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (!CanBeBurned(battlerDef, defAbility)
|
||||
|
||||
@ -911,3 +911,21 @@ AI_SINGLE_BATTLE_TEST("AI won't boost stats against opponent with Unaware")
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_BODY_SLAM); }
|
||||
}
|
||||
}
|
||||
|
||||
AI_SINGLE_BATTLE_TEST("AI won't use status moves against opponents that would benefit")
|
||||
{
|
||||
u32 aiMove;
|
||||
PARAMETRIZE { aiMove = MOVE_WILL_O_WISP; }
|
||||
PARAMETRIZE { aiMove = MOVE_TOXIC; }
|
||||
PARAMETRIZE { aiMove = MOVE_THUNDER_WAVE; }
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP);
|
||||
ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC);
|
||||
ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_PARALYZE);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(SPECIES_SWELLOW) { Ability(ABILITY_GUTS); Moves(MOVE_TACKLE); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, aiMove); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user