Increase score of secondary effects only at 100% chance (#3583)

Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
Alex 2023-11-21 11:30:20 +01:00 committed by GitHub
parent 4c783e2ae1
commit be42d4eafb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 16 deletions

View file

@ -441,7 +441,7 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectHit @ EFFECT_IVY_CUDGEL
.4byte BattleScript_EffectMaxMove @ EFFECT_MAX_MOVE
.4byte BattleScript_EffectGlaiveRush @ EFFECT_GLAIVE_RUSH
.4byte BattleScript_EffectBrickBreak @ EFFECT_RAGING_BULL
.4byte BattleScript_EffectBrickBreak @ EFFECT_RAGING_BULL
BattleScript_EffectGlaiveRush::
call BattleScript_EffectHit_Ret

View file

@ -64,6 +64,7 @@ bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move);
u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move);
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove);
u32 AI_CalcSecondaryEffectChance(u32 battler, u32 secondaryEffectChance);
// stat stage checks
bool32 AnyStatIsRaised(u32 battlerId);

View file

@ -3211,13 +3211,12 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
struct AiLogicData *aiData = AI_DATA;
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
u32 secondaryEffectChance = AI_CalcSecondaryEffectChance(battlerAtk, gBattleMoves[move].secondaryEffectChance);
s8 atkPriority = GetMovePriority(battlerAtk, move);
u32 predictedMove = aiData->predictedMoves[battlerDef];
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
u32 i;
// We only check for moves that have a 20% chance or more for their secondary effect to happen because moves with a smaller chance are rather worthless. We don't want the AI to use those.
bool32 sereneGraceBoost = (aiData->abilities[battlerAtk] == ABILITY_SERENE_GRACE && (gBattleMoves[move].secondaryEffectChance >= 20 && gBattleMoves[move].secondaryEffectChance < 100));
// The AI should understand that while Dynamaxed, status moves function like Protect.
if (IsDynamaxed(battlerAtk) && gBattleMoves[move].split == SPLIT_STATUS)
@ -3646,24 +3645,18 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
case EFFECT_PARALYZE:
IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score);
break;
case EFFECT_SPEED_DOWN_HIT:
if (!ShouldLowerSpeed(battlerAtk, battlerDef, aiData->abilities[battlerDef]))
break;
case EFFECT_ATTACK_DOWN_HIT:
case EFFECT_DEFENSE_DOWN_HIT:
case EFFECT_SPECIAL_ATTACK_DOWN_HIT:
case EFFECT_SPECIAL_DEFENSE_DOWN_HIT:
case EFFECT_ACCURACY_DOWN_HIT:
case EFFECT_EVASION_DOWN_HIT:
if (sereneGraceBoost && aiData->abilities[battlerDef] != ABILITY_CONTRARY)
if (secondaryEffectChance >= 100 && aiData->abilities[battlerDef] != ABILITY_CONTRARY)
ADJUST_SCORE(2);
break;
case EFFECT_SPEED_DOWN_HIT:
if (ShouldLowerSpeed(battlerAtk, battlerDef, aiData->abilities[battlerDef]))
{
if (sereneGraceBoost && aiData->abilities[battlerDef] != ABILITY_CONTRARY)
ADJUST_SCORE(5);
else
ADJUST_SCORE(2);
}
break;
case EFFECT_SUBSTITUTE:
if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG)
ADJUST_SCORE(3);
@ -3789,7 +3782,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
ADJUST_SCORE(1);
break;
case EFFECT_SPEED_UP_HIT:
if (sereneGraceBoost && aiData->abilities[battlerDef] != ABILITY_CONTRARY && !AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
if (secondaryEffectChance >= 100 && aiData->abilities[battlerDef] != ABILITY_CONTRARY && !AI_STRIKES_FIRST(battlerAtk, battlerDef, move))
ADJUST_SCORE(3);
break;
case EFFECT_DESTINY_BOND:
@ -4048,11 +4041,11 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
}
break;
case EFFECT_ATTACK_UP_HIT:
if (sereneGraceBoost)
if (secondaryEffectChance >= 100)
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_ATK, &score);
break;
case EFFECT_SPECIAL_ATTACK_UP_HIT:
if (sereneGraceBoost)
if (secondaryEffectChance >= 100)
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPATK, &score);
break;
case EFFECT_FELL_STINGER:

View file

@ -3806,3 +3806,11 @@ bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId)
{
return (gBattleMons[battlerId].status1 & STATUS1_SLEEP) || AI_DATA->abilities[battlerId] == ABILITY_COMATOSE;
}
u32 AI_CalcSecondaryEffectChance(u32 battler, u32 secondaryEffectChance)
{
if (AI_DATA->abilities[battler] == ABILITY_SERENE_GRACE)
secondaryEffectChance *= 2;
return secondaryEffectChance;
}

View file

@ -165,3 +165,27 @@ AI_SINGLE_BATTLE_TEST("AI can choose Counter or Mirror Coat if the predicted mov
MESSAGE("Foe Wobbuffet fainted!");
}
}
AI_SINGLE_BATTLE_TEST("AI chooses moves with secondary effect that have a 100% chance to trigger")
{
u16 ability;
PARAMETRIZE { ability = ABILITY_NONE; }
PARAMETRIZE { ability = ABILITY_SERENE_GRACE; }
GIVEN {
AI_LOG;
ASSUME(gBattleMoves[MOVE_SHADOW_BALL].effect == EFFECT_SPECIAL_DEFENSE_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_SHADOW_BALL].secondaryEffectChance == 20);
ASSUME(gBattleMoves[MOVE_LUSTER_PURGE].effect == EFFECT_SPECIAL_DEFENSE_DOWN_HIT);
ASSUME(gBattleMoves[MOVE_LUSTER_PURGE].secondaryEffectChance == 50);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_REGICE);
OPPONENT(SPECIES_REGIROCK) { Ability(ability); Moves(MOVE_SHADOW_BALL, MOVE_LUSTER_PURGE); }
} WHEN {
if (ability == ABILITY_NONE)
TURN { EXPECT_MOVE(opponent, MOVE_SHADOW_BALL); }
else
TURN { EXPECT_MOVES(opponent, MOVE_LUSTER_PURGE); }
}
}

View file

@ -160,3 +160,23 @@ SINGLE_BATTLE_TEST("Relic Song loses the form-changing effect with Sheer Force")
EXPECT_EQ(player->species, SPECIES_MELOETTA_ARIA);
}
}
SINGLE_BATTLE_TEST("Relic Song transforms Meloetta after Magician was activated")
{
GIVEN {
ASSUME(P_GEN_6_POKEMON == TRUE);
PLAYER(SPECIES_MELOETTA_ARIA);
OPPONENT(SPECIES_DELPHOX) { Ability(ABILITY_MAGICIAN); Item(ITEM_POTION); }
} WHEN {
TURN { MOVE(opponent, MOVE_SKILL_SWAP); MOVE(player, MOVE_RELIC_SONG); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player);
HP_BAR(opponent);
ABILITY_POPUP(player, ABILITY_MAGICIAN);
MESSAGE("Meloetta stole Foe Delphox's Potion!");
MESSAGE("Meloetta transformed!");
} THEN {
EXPECT_EQ(player->species, SPECIES_MELOETTA_PIROUETTE);
}
}