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

Rename EFFECT_FAKE_OUT to EFFECT_FIRST_TURN_ONLY #4081

Merged
merged 9 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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 data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -4834,7 +4834,7 @@ BattleScript_AlreadyAtFullHp::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd

BattleScript_EffectFakeOut::
BattleScript_EffectFirstTurnOnly::
attackcanceler
jumpifnotfirstturn BattleScript_FailedFromAtkString
goto BattleScript_EffectHit
Expand Down
2 changes: 1 addition & 1 deletion include/battle_ai_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ bool32 IsBattlerTrapped(u32 battler, bool32 switching);
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);
u32 GetBestDmgMoveFromTarget(u32 battlerAtk, u32 battlerDef);
u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef);
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
s32 AI_DecideKnownAbilityForTurn(u32 battlerId);
Expand Down
2 changes: 1 addition & 1 deletion include/battle_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ extern const u8 BattleScript_EffectBeatUp[];
extern const u8 BattleScript_EffectSemiInvulnerable[];
extern const u8 BattleScript_EffectDefenseCurl[];
extern const u8 BattleScript_EffectSoftboiled[];
extern const u8 BattleScript_EffectFakeOut[];
extern const u8 BattleScript_EffectFirstTurnOnly[];
extern const u8 BattleScript_EffectUproar[];
extern const u8 BattleScript_EffectStockpile[];
extern const u8 BattleScript_EffectSpitUp[];
Expand Down
2 changes: 1 addition & 1 deletion include/constants/battle_move_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ enum {
EFFECT_SEMI_INVULNERABLE,
EFFECT_DEFENSE_CURL,
EFFECT_SOFTBOILED, // differences vs Recover - can be used outside of battle to restore HP
EFFECT_FAKE_OUT,
EFFECT_FIRST_TURN_ONLY,
EFFECT_UPROAR,
EFFECT_STOCKPILE,
EFFECT_SPIT_UP,
Expand Down
19 changes: 9 additions & 10 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
Expand Down Expand Up @@ -979,6 +980,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case ABILITY_DAZZLING:
case ABILITY_QUEENLY_MAJESTY:
case ABILITY_ARMOR_TAIL:
if (atkPriority > 0)
RETURN_SCORE_MINUS(10);
break;
Expand Down Expand Up @@ -1706,7 +1708,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_TELEPORT:
ADJUST_SCORE(-10);
break;
case EFFECT_FAKE_OUT:
case EFFECT_FIRST_TURN_ONLY:
if (!gDisableStructs[battlerAtk].isFirstTurn)
ADJUST_SCORE(-10);
break;
Expand Down Expand Up @@ -3818,14 +3820,11 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(DECENT_EFFECT);
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF, &score);
break;
case EFFECT_FAKE_OUT:
if (move == MOVE_FAKE_OUT) // filter out first impression
{
if (ShouldFakeOut(battlerAtk, battlerDef, move))
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(-10);
}
case EFFECT_FIRST_TURN_ONLY:
if (ShouldFakeOut(battlerAtk, battlerDef, move))
ADJUST_SCORE(GOOD_EFFECT);
else if (gMovesInfo[move].priority >= 1 && gDisableStructs[battlerAtk].isFirstTurn && GetBestDmgMoveFromBattler(battlerAtk, battlerDef) == move)
ADJUST_SCORE(BEST_EFFECT);
break;
case EFFECT_STOCKPILE:
if (aiData->abilities[battlerAtk] == ABILITY_CONTRARY)
Expand Down Expand Up @@ -4623,7 +4622,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move)
ADJUST_SCORE(GOOD_EFFECT);
break;
case MOVE_EFFECT_THROAT_CHOP:
if (gMovesInfo[GetBestDmgMoveFromTarget(battlerDef, battlerAtk)].soundMove)
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove)
{
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
ADJUST_SCORE(GOOD_EFFECT);
Expand Down
2 changes: 1 addition & 1 deletion src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static bool32 HasBadOdds(u32 battler, bool32 emitResult)
|| aiMoveEffect == EFFECT_SPIKES || aiMoveEffect == EFFECT_TOXIC_SPIKES || aiMoveEffect == EFFECT_STEALTH_ROCK || aiMoveEffect == EFFECT_STICKY_WEB || aiMoveEffect == EFFECT_LEECH_SEED
|| aiMoveEffect == EFFECT_EXPLOSION
|| aiMoveEffect == EFFECT_SLEEP || aiMoveEffect == EFFECT_YAWN || aiMoveEffect == EFFECT_TOXIC || aiMoveEffect == EFFECT_WILL_O_WISP || aiMoveEffect == EFFECT_PARALYZE
|| aiMoveEffect == EFFECT_TRICK || aiMoveEffect == EFFECT_TRICK_ROOM || aiMoveEffect== EFFECT_WONDER_ROOM || aiMoveEffect == EFFECT_PSYCHO_SHIFT || aiMoveEffect == EFFECT_FAKE_OUT
|| aiMoveEffect == EFFECT_TRICK || aiMoveEffect == EFFECT_TRICK_ROOM || aiMoveEffect== EFFECT_WONDER_ROOM || aiMoveEffect == EFFECT_PSYCHO_SHIFT || aiMoveEffect == EFFECT_FIRST_TURN_ONLY
)
{
hasStatusMove = TRUE;
Expand Down
16 changes: 8 additions & 8 deletions src/battle_ai_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,20 +867,20 @@ u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk)
return leastNumberOfHits;
}

u32 GetBestDmgMoveFromTarget(u32 battlerDef, u32 battlerAtk)
u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef)
{
u32 i;
u32 move = 0;
u32 bestDmg = 0;
u32 unusable = AI_DATA->moveLimitations[battlerDef];
u16 *moves = GetMovesArray(battlerDef);
u32 unusable = AI_DATA->moveLimitations[battlerAtk];
u16 *moves = GetMovesArray(battlerAtk);

for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !(unusable & gBitTable[i])
&& bestDmg < AI_DATA->simulatedDmg[battlerDef][battlerAtk][i])
&& bestDmg < AI_DATA->simulatedDmg[battlerAtk][battlerDef][i])
{
bestDmg = AI_DATA->simulatedDmg[battlerDef][battlerAtk][i];
bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i];
move = moves[i];
}
}
Expand Down Expand Up @@ -2724,7 +2724,7 @@ bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move)

bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move)
{
if (!gDisableStructs[battlerAtk].isFirstTurn
if ((!gDisableStructs[battlerAtk].isFirstTurn && MoveHasMoveEffectWithChance(move, MOVE_EFFECT_FLINCH, 100))
|| AI_DATA->abilities[battlerAtk] == ABILITY_GORILLA_TACTICS
|| AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND
|| AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_COVERT_CLOAK
Expand Down Expand Up @@ -3418,7 +3418,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)

if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe
|| HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS)
|| (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FAKE_OUT)) // filter out Fake Out
|| (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)) // filter out Fake Out
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|| gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
ADJUST_SCORE_PTR(GOOD_EFFECT);
Expand Down Expand Up @@ -3459,7 +3459,7 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score
{
if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|| (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FAKE_OUT)))
|| (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)))
ADJUST_SCORE_PTR(GOOD_EFFECT);
else
ADJUST_SCORE_PTR(DECENT_EFFECT);
Expand Down
2 changes: 1 addition & 1 deletion src/battle_arena.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ void BattleArena_AddMindPoints(u8 battler)
// All moves with power == 0 give 0 points, with the following exceptions:
// - Protect, Detect, and Endure subtract 1 point

if (gMovesInfo[gCurrentMove].effect == EFFECT_FAKE_OUT
if (gMovesInfo[gCurrentMove].effect == EFFECT_FIRST_TURN_ONLY
|| gMovesInfo[gCurrentMove].effect == EFFECT_PROTECT
|| gMovesInfo[gCurrentMove].effect == EFFECT_ENDURE)
{
Expand Down
4 changes: 2 additions & 2 deletions src/data/battle_move_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.encourageEncore = TRUE,
},

[EFFECT_FAKE_OUT] =
[EFFECT_FIRST_TURN_ONLY] =
{
.battleScript = BattleScript_EffectFakeOut,
.battleScript = BattleScript_EffectFirstTurnOnly,
.battleTvScore = 4,
.encourageEncore = TRUE,
},
Expand Down
4 changes: 2 additions & 2 deletions src/data/moves_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6188,7 +6188,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
"that causes flinching."),
.priority = B_UPDATED_MOVE_DATA >= GEN_5 ? 3 : 1,
.makesContact = B_UPDATED_MOVE_DATA >= GEN_4,
.effect = EFFECT_FAKE_OUT,
.effect = EFFECT_FIRST_TURN_ONLY,
.power = 40,
.type = TYPE_NORMAL,
.accuracy = 100,
Expand Down Expand Up @@ -14987,7 +14987,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.description = COMPOUND_STRING(
"Hits hard and first.\n"
"Only works first turn."),
.effect = EFFECT_FAKE_OUT,
.effect = EFFECT_FIRST_TURN_ONLY,
.power = 90,
.type = TYPE_BUG,
.accuracy = 100,
Expand Down
59 changes: 48 additions & 11 deletions test/battle/ai.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI considers hazard damage whe
OPPONENT(SPECIES_TYPHLOSION) { Speed(200); Moves(MOVE_FLAMETHROWER); SpAttack(317); SpDefense(207); MaxHP(297); } // Outspeends and 2HKOs Meganium
} WHEN {
TURN { MOVE(player, MOVE_STEALTH_ROCK) ;}
TURN { MOVE(player, MOVE_SURF) ; EXPECT_SEND_OUT(opponent, aiIsSmart ? 2 : 1); } // AI sends out Typhlosion to get the KO with the flag rather than Charizard
TURN { MOVE(player, MOVE_SURF); EXPECT_SEND_OUT(opponent, aiIsSmart ? 2 : 1); } // AI sends out Typhlosion to get the KO with the flag rather than Charizard
}
}

Expand All @@ -593,7 +593,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize
OPPONENT(SPECIES_LOMBRE) { Level(30); Moves(move2); Speed(4); }
OPPONENT(SPECIES_HARIYAMA) { Level(30); Moves(MOVE_VITAL_THROW); Speed(4); }
} WHEN {
TURN { MOVE(player, MOVE_GROWL) ; EXPECT_SWITCH(opponent, expectedIndex); }
TURN { MOVE(player, MOVE_GROWL); EXPECT_SWITCH(opponent, expectedIndex); }
}
}

Expand All @@ -606,7 +606,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); } // Mid battle, AI sends out Aron
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
} WHEN {
TURN { MOVE(player, MOVE_WING_ATTACK) ; EXPECT_SWITCH(opponent, 1); }
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SWITCH(opponent, 1); }
}
}

Expand All @@ -619,7 +619,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Post-KO switches prioritize of
OPPONENT(SPECIES_ARON) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); } // Mid battle, AI sends out Aron
OPPONENT(SPECIES_ELECTRODE) { Level(30); Moves(MOVE_CHARGE_BEAM); Speed(6); }
} WHEN {
TURN { MOVE(player, MOVE_WING_ATTACK) ; EXPECT_SEND_OUT(opponent, 2); }
TURN { MOVE(player, MOVE_WING_ATTACK); EXPECT_SEND_OUT(opponent, 2); }
}
}

Expand All @@ -631,17 +631,17 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI switches out after sufficient
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Speed(4); }
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT); Speed(4); }
} WHEN {
TURN { MOVE(player, MOVE_CHARM) ;}
TURN { MOVE(player, MOVE_TACKLE) ; EXPECT_SWITCH(opponent, 1); }
TURN { MOVE(player, MOVE_CHARM); }
TURN { MOVE(player, MOVE_TACKLE); EXPECT_SWITCH(opponent, 1); }
}
}

AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemon would faint to hazards unless party member can clear them")
{
u32 move1;

PARAMETRIZE{move1 = MOVE_TACKLE; }
PARAMETRIZE{move1 = MOVE_RAPID_SPIN; }
PARAMETRIZE{ move1 = MOVE_TACKLE; }
PARAMETRIZE{ move1 = MOVE_RAPID_SPIN; }

GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
Expand All @@ -653,9 +653,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemo
OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Item(ITEM_FOCUS_SASH); Speed(4); }
OPPONENT(SPECIES_PONYTA) { Level(30); Moves(MOVE_HEADBUTT, move1); Speed(4); }
} WHEN {
TURN { MOVE(player, MOVE_STEALTH_ROCK) ;}
TURN { MOVE(player, MOVE_EARTHQUAKE) ;}
TURN { MOVE(player, MOVE_CHARM) ;}
TURN { MOVE(player, MOVE_STEALTH_ROCK); }
TURN { MOVE(player, MOVE_EARTHQUAKE); }
TURN { MOVE(player, MOVE_CHARM); }
TURN { // If the AI has a mon that can remove hazards, don't prevent them switching out
MOVE(player, MOVE_CHARM);
if (move1 == MOVE_RAPID_SPIN)
Expand All @@ -665,3 +665,40 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemo
}
}
}

AI_SINGLE_BATTLE_TEST("First Impression is preferred on the first turn of the species if it's the best dmg move")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].effect == EFFECT_FIRST_TURN_ONLY);
ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].power == 90);
ASSUME(gMovesInfo[MOVE_LUNGE].power == 80);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_KANGASKHAN);
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_FIRST_IMPRESSION, MOVE_LUNGE); }
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_FIRST_IMPRESSION); }
TURN { EXPECT_MOVE(opponent, MOVE_LUNGE); }
}
}

AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain abilities")
{
u16 species;
u16 ability;

PARAMETRIZE { species = SPECIES_BRUXISH; ability = ABILITY_DAZZLING; }
PARAMETRIZE { species = SPECIES_FARIGIRAF; ability = ABILITY_ARMOR_TAIL; }
PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; }

KNOWN_FAILING; // Fails because the Omniscient flag is currently broken. It should pass after it is fixed
GIVEN {
ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].effect == EFFECT_FIRST_TURN_ONLY);
ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].power == 90);
ASSUME(gMovesInfo[MOVE_LUNGE].power == 80);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
PLAYER(species) { Ability(ability); }
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_FIRST_IMPRESSION, MOVE_LUNGE); }
} WHEN {
TURN { EXPECT_MOVE(opponent, MOVE_LUNGE); }
}
}
2 changes: 1 addition & 1 deletion test/dynamax.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp)
SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FAKE_OUT].effect == EFFECT_FAKE_OUT);
ASSUME(gMovesInfo[MOVE_FAKE_OUT].effect == EFFECT_FIRST_TURN_ONLY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
Expand Down
Loading