Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AI for Palafin to activate Zero to Hero #5806

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/battle_ai_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ u32 GetBattlerSideSpeedAverage(u32 battler);
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage);
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent);
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect);
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move, u32 moveIndex);
bool32 IsRecycleEncouragedItem(u32 item);
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
bool32 IsStatBoostingBerry(u32 item);
Expand Down
2 changes: 1 addition & 1 deletion src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3524,7 +3524,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
case EFFECT_CHILLY_RECEPTION:
if (!IsDoubleBattle())
{
switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, movesetIndex))
switch (ShouldPivot(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move, movesetIndex))
{
case DONT_PIVOT:
ADJUST_SCORE(-10); // technically should go in CheckBadMove, but this is easier/less computationally demanding
Expand Down
7 changes: 7 additions & 0 deletions src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,13 @@ static bool32 ShouldSwitchIfAbilityBenefit(u32 battler)

return FALSE;

case ABILITY_ZERO_TO_HERO:
//Zero to Hero only works on Palafin-Zero
if (gBattleMons[battler].species == SPECIES_PALAFIN_ZERO
&& AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question, this implementation means Zero to Hero will only prompt switches if the AI sees it has a good switchin candidate. Is Zero to Hero worth switching for even if the AI doesn't have a good switchin candidate? If so we don't need need the mostSuitableMonId check, if it isn't worth it then everything's fine as is :)

(I know nothing about Palafin other than hearing that it needs to switch from you)

Copy link
Collaborator

@Bassoonian Bassoonian Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say a bad switch-in is also preferable - even if the mon you send out dies because it's at low health or whatever, it still powers up Palafin. If anything, I would actually encourage some sort of viability curve where medium health is discouraged, but high HP and low HP are both discouraged (either because they're a good switch-in according to the AI, or because they likely served their use and can be sacrificed to power up Palafin who is likely to be more useful in battle than them at that point)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wrote this thinking that Palafin wants to switch at all costs so I'll tweak it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm if I remove this, then it will always switch and won't use a pivoting move when it should probably prioritize pivoting moves.

break;

return FALSE;
default:
return FALSE;
}
Expand Down
12 changes: 9 additions & 3 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
switch (gMovesInfo[move].effect)
{
case EFFECT_HIT_ESCAPE:
if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityDef, move, AI_THINKING_STRUCT->movesetIndex))
if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityAtk, abilityDef, move, AI_THINKING_STRUCT->movesetIndex))
return TRUE;
break;
case EFFECT_FELL_STINGER:
Expand Down Expand Up @@ -2692,13 +2692,19 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler)
return FALSE;
}

enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex)
enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move, u32 moveIndex)
{
bool32 hasStatBoost = AnyUsefulStatIsRaised(battlerAtk) || gBattleMons[battlerDef].statStages[STAT_EVASION] >= 9; //Significant boost in evasion for any class
u32 battlerToSwitch;

battlerToSwitch = gBattleStruct->AI_monToSwitchIntoId[battlerAtk];

// Palafin has a unique playstyle where it should pivot as soon as possible no matter what in order to transform. It can ignore any other checks to achieve this.
if (gBattleMons[battlerAtk].species == SPECIES_PALAFIN_ZERO
&& atkAbility == ABILITY_ZERO_TO_HERO
&& CountUsablePartyMons(battlerAtk) != 0)
return SHOULD_PIVOT;

if (PartyBattlerShouldAvoidHazards(battlerAtk, battlerToSwitch))
return DONT_PIVOT;

Expand Down Expand Up @@ -4086,7 +4092,7 @@ void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *
}
else if (gMovesInfo[move].effect == EFFECT_SHED_TAIL) // Shed Tail specific
{
if ((ShouldPivot(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_THINKING_STRUCT->movesetIndex))
if ((ShouldPivot(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move, AI_THINKING_STRUCT->movesetIndex))
&& (HasAnyKnownMove(battlerDef) && (GetBestDmgFromBattler(battlerDef, battlerAtk) < gBattleMons[battlerAtk].maxHP / 2)))
ADJUST_SCORE_PTR(BEST_EFFECT);
}
Expand Down
12 changes: 12 additions & 0 deletions test/battle/ai/ai_switching.c
Original file line number Diff line number Diff line change
Expand Up @@ -909,3 +909,15 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI correctly handles abilities
TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_MOVE(opponent, MOVE_ABSORB); }
}
}

AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if Palafin-Zero isn't transformed yet")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_FINIZEN);
OPPONENT(SPECIES_PALAFIN_ZERO);
OPPONENT(SPECIES_FINIZEN);
} WHEN {
TURN { MOVE(player, MOVE_CELEBRATE); EXPECT_SWITCH(opponent, 1); }
}
}
Loading