Increase score of secondary effects only at 100% chance (#3583)
Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
parent
4c783e2ae1
commit
be42d4eafb
6 changed files with 62 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue