diff --git a/include/config/battle.h b/include/config/battle.h index 242e4bea68..16b4ac9b64 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -124,6 +124,7 @@ #define B_WIDE_GUARD GEN_LATEST // In Gen5 only, Wide Guard has a chance to fail if used consecutively. #define B_QUICK_GUARD GEN_LATEST // In Gen5 only, Quick Guard has a chance to fail if used consecutively. #define B_IMPRISON GEN_LATEST // In Gen5+, Imprison doesn't fail if opposing pokemon don't have any moves the user knows. +#define B_TAUNT_ME_FIRST GEN_LATEST // In Gen5+, Taunt does not block Me First. #define B_ALLY_SWITCH_FAIL_CHANCE GEN_LATEST // In Gen9+, using Ally Switch consecutively decreases the chance of success for each consecutive use. #define B_SKETCH_BANS GEN_LATEST // In Gen9+, Sketch is unable to copy more moves than in previous generations. #define B_KNOCK_OFF_REMOVAL GEN_LATEST // In Gen5+, Knock Off removes the foe's item instead of rendering it unusable. diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h index 84b9da76b1..8a8a31e830 100644 --- a/include/constants/generational_changes.h +++ b/include/constants/generational_changes.h @@ -115,6 +115,7 @@ F(B_WIDE_GUARD, wideGuard, (u32, GEN_COUNT - 1)) \ F(B_QUICK_GUARD, quickGuard, (u32, GEN_COUNT - 1)) \ F(B_IMPRISON, imprison, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ + F(B_TAUNT_ME_FIRST, tauntMeFirst, (u32, GEN_COUNT - 1)) \ F(B_ALLY_SWITCH_FAIL_CHANCE, allySwitchFailChance, (u32, GEN_COUNT - 1)) \ F(B_SKETCH_BANS, sketchBans, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ F(B_KNOCK_OFF_REMOVAL, knockOffRemoval, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \ diff --git a/src/battle_util.c b/src/battle_util.c index f0b4925229..8535da5493 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1474,7 +1474,10 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].tauntTimer != 0 && IsBattleMoveStatus(move)) + if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE + && gDisableStructs[battler].tauntTimer != 0 + && IsBattleMoveStatus(move) + && (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST)) { if ((GetActiveGimmick(battler) == GIMMICK_DYNAMAX)) gCurrentMove = MOVE_MAX_GUARD; @@ -1709,7 +1712,10 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].volatiles.torment == TRUE) unusableMoves |= 1u << i; // Taunt - else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IsBattleMoveStatus(move)) + else if (check & MOVE_LIMITATION_TAUNT + && gDisableStructs[battler].tauntTimer + && IsBattleMoveStatus(move) + && (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST)) unusableMoves |= 1u << i; // Imprison else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, move)) @@ -2249,7 +2255,12 @@ static enum MoveCanceler CancelerVolatileBlocked(struct BattleContext *ctx) static enum MoveCanceler CancelerTaunted(struct BattleContext *ctx) { - if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].tauntTimer && IsBattleMoveStatus(ctx->currentMove)) + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->currentMove); + + if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE + && gDisableStructs[ctx->battlerAtk].tauntTimer + && IsBattleMoveStatus(ctx->currentMove) + && (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || moveEffect != EFFECT_ME_FIRST)) { gProtectStructs[ctx->battlerAtk].unableToUseMove = TRUE; CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); diff --git a/test/battle/move_effect/me_first.c b/test/battle/move_effect/me_first.c index 8ccaa324ef..48f8d179be 100644 --- a/test/battle/move_effect/me_first.c +++ b/test/battle/move_effect/me_first.c @@ -82,6 +82,37 @@ SINGLE_BATTLE_TEST("Me First can be selected if users holds Assault Vest") } } +SINGLE_BATTLE_TEST("Me First can be selected under Taunt in Gen5+") +{ + u32 gen = 0; + + PARAMETRIZE { gen = GEN_4; } + PARAMETRIZE { gen = GEN_5; } + + GIVEN { + WITH_CONFIG(B_TAUNT_ME_FIRST, gen); + PLAYER(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_ME_FIRST, MOVE_TACKLE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_TAUNT, MOVE_TACKLE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TAUNT); } + if (gen >= GEN_5) { + TURN { MOVE(player, MOVE_ME_FIRST); MOVE(opponent, MOVE_TACKLE); } + } else { + TURN { + MOVE(player, MOVE_ME_FIRST, allowed: FALSE); + MOVE(player, MOVE_TACKLE); + MOVE(opponent, MOVE_TACKLE); + } + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); + if (gen >= GEN_5) + ANIMATION(ANIM_TYPE_MOVE, MOVE_ME_FIRST, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + } +} + SINGLE_BATTLE_TEST("Me First deducts power points from itself, not the copied move") { ASSUME(GetMovePP(MOVE_ME_FIRST) == 20);