Skip to content

Commit

Permalink
Increase score of secondary effects only at 100% chance (#3583)
Browse files Browse the repository at this point in the history
Co-authored-by: Bassoonian <[email protected]>
  • Loading branch information
AlexOn1ine and Bassoonian committed Nov 21, 2023
1 parent 4c783e2 commit be42d4e
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 16 deletions.
2 changes: 1 addition & 1 deletion data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/battle_ai_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
23 changes: 8 additions & 15 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
24 changes: 24 additions & 0 deletions test/battle/ai_check_viability.c
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
}
}
20 changes: 20 additions & 0 deletions test/battle/move_effect/relic_song.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit be42d4e

Please sign in to comment.