From 0d75ccd2d2faedf613c28217c5660825afc704f0 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Tue, 9 Jan 2024 05:15:23 -0300 Subject: [PATCH] Stuff Cheeks cleanup (#3950) Co-authored-by: Biffalo XIII <--global> --- src/battle_util.c | 41 +++++----- test/battle/move_effect/stuff_cheeks.c | 106 +++++++++++++++++++++++++ test/battle/move_effect/teatime.c | 4 +- 3 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 test/battle/move_effect/stuff_cheeks.c diff --git a/src/battle_util.c b/src/battle_util.c index 04ba26ed86..e61b5048e2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1409,7 +1409,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (DYNAMAX_BYPASS_CHECK && move == MOVE_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) + if (DYNAMAX_BYPASS_CHECK && gBattleMoves[move].effect == EFFECT_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1456,7 +1456,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) limitations++; } } - else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(move) && move != MOVE_ME_FIRST) + else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(move) && gBattleMoves[move].effect != EFFECT_ME_FIRST) { if (IsDynamaxed(gBattlerAttacker)) gCurrentMove = MOVE_MAX_GUARD; @@ -1523,7 +1523,8 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) { - u8 holdEffect = GetBattlerHoldEffect(battler, TRUE); + u32 move, moveEffect; + u32 holdEffect = GetBattlerHoldEffect(battler, TRUE); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; s32 i; @@ -1531,56 +1532,58 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) for (i = 0; i < MAX_MON_MOVES; i++) { + move = gBattleMons[battler].moves[i]; + moveEffect = gBattleMoves[move].effect; // No move - if (check & MOVE_LIMITATION_ZEROMOVE && gBattleMons[battler].moves[i] == MOVE_NONE) + if (check & MOVE_LIMITATION_ZEROMOVE && move == MOVE_NONE) unusableMoves |= gBitTable[i]; // No PP else if (check & MOVE_LIMITATION_PP && gBattleMons[battler].pp[i] == 0) unusableMoves |= gBitTable[i]; // Placeholder - else if (check & MOVE_LIMITATION_PLACEHOLDER && gBattleMoves[gBattleMons[battler].moves[i]].effect == EFFECT_PLACEHOLDER) + else if (check & MOVE_LIMITATION_PLACEHOLDER && moveEffect == EFFECT_PLACEHOLDER) unusableMoves |= gBitTable[i]; // Disable - else if (check & MOVE_LIMITATION_DISABLED && gBattleMons[battler].moves[i] == gDisableStructs[battler].disabledMove) + else if (check & MOVE_LIMITATION_DISABLED && move == gDisableStructs[battler].disabledMove) unusableMoves |= gBitTable[i]; // Torment - else if (check & MOVE_LIMITATION_TORMENTED && gBattleMons[battler].moves[i] == gLastMoves[battler] && gBattleMons[battler].status2 & STATUS2_TORMENT) + else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].status2 & STATUS2_TORMENT) unusableMoves |= gBitTable[i]; // Taunt - else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IS_MOVE_STATUS(gBattleMons[battler].moves[i])) + else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IS_MOVE_STATUS(move)) unusableMoves |= gBitTable[i]; // Imprison - else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, gBattleMons[battler].moves[i])) + else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, move)) unusableMoves |= gBitTable[i]; // Encore - else if (check & MOVE_LIMITATION_ENCORE && gDisableStructs[battler].encoreTimer && gDisableStructs[battler].encoredMove != gBattleMons[battler].moves[i]) + else if (check & MOVE_LIMITATION_ENCORE && gDisableStructs[battler].encoreTimer && gDisableStructs[battler].encoredMove != move) unusableMoves |= gBitTable[i]; // Choice Items - else if (check & MOVE_LIMITATION_CHOICE_ITEM && HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != gBattleMons[battler].moves[i]) + else if (check & MOVE_LIMITATION_CHOICE_ITEM && HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) unusableMoves |= gBitTable[i]; // Assault Vest - else if (check & MOVE_LIMITATION_ASSAULT_VEST && holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(gBattleMons[battler].moves[i]) && gBattleMons[battler].moves[i] != MOVE_ME_FIRST) + else if (check & MOVE_LIMITATION_ASSAULT_VEST && holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(move) && gBattleMoves[move].effect != EFFECT_ME_FIRST) unusableMoves |= gBitTable[i]; // Gravity - else if (check & MOVE_LIMITATION_GRAVITY && IsGravityPreventingMove(gBattleMons[battler].moves[i])) + else if (check & MOVE_LIMITATION_GRAVITY && IsGravityPreventingMove(move)) unusableMoves |= gBitTable[i]; // Heal Block - else if (check & MOVE_LIMITATION_HEAL_BLOCK && IsHealBlockPreventingMove(battler, gBattleMons[battler].moves[i])) + else if (check & MOVE_LIMITATION_HEAL_BLOCK && IsHealBlockPreventingMove(battler, move)) unusableMoves |= gBitTable[i]; // Belch - else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, gBattleMons[battler].moves[i])) + else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, move)) unusableMoves |= gBitTable[i]; // Throat Chop - else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer && gBattleMoves[gBattleMons[battler].moves[i]].soundMove) + else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer && gBattleMoves[move].soundMove) unusableMoves |= gBitTable[i]; // Stuff Cheeks - else if (check & MOVE_LIMITATION_STUFF_CHEEKS && gBattleMons[battler].moves[i] == MOVE_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) + else if (check & MOVE_LIMITATION_STUFF_CHEEKS && moveEffect == EFFECT_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) unusableMoves |= gBitTable[i]; // Gorilla Tactics - else if (check & MOVE_LIMITATION_CHOICE_ITEM && GetBattlerAbility(battler) == ABILITY_GORILLA_TACTICS && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != gBattleMons[battler].moves[i]) + else if (check & MOVE_LIMITATION_CHOICE_ITEM && GetBattlerAbility(battler) == ABILITY_GORILLA_TACTICS && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) unusableMoves |= gBitTable[i]; // Can't Use Twice flag - else if (check & MOVE_LIMITATION_CANT_USE_TWICE && gBattleMoves[gBattleMons[battler].moves[i]].cantUseTwice && gBattleMons[battler].moves[i] == gLastResultingMoves[battler]) + else if (check & MOVE_LIMITATION_CANT_USE_TWICE && gBattleMoves[move].cantUseTwice && move == gLastResultingMoves[battler]) unusableMoves |= gBitTable[i]; } return unusableMoves; diff --git a/test/battle/move_effect/stuff_cheeks.c b/test/battle/move_effect/stuff_cheeks.c new file mode 100644 index 0000000000..e0d1e5aadc --- /dev/null +++ b/test/battle/move_effect/stuff_cheeks.c @@ -0,0 +1,106 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(gItems[ITEM_LIECHI_BERRY].pocket == POCKET_BERRIES); + ASSUME(gItems[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); +} + +SINGLE_BATTLE_TEST("Stuff Cheeks cannot be used if the user doesn't hold a berry") +{ + u16 item = 0; + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_LIECHI_BERRY; } + GIVEN { + PLAYER(SPECIES_SKWOVET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (item == ITEM_NONE) + TURN { MOVE(player, MOVE_STUFF_CHEEKS, allowed: FALSE); MOVE(player, MOVE_CELEBRATE); } + else + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + } SCENE { + if (item == ITEM_NONE) + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + } +} + +SINGLE_BATTLE_TEST("Stuff Cheeks forces Struggle if it's the only move is blocked") +{ + GIVEN { + PLAYER(SPECIES_SKWOVET) { Moves(MOVE_STUFF_CHEEKS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS, allowed: FALSE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, player); + } +} + +SINGLE_BATTLE_TEST("Stuff Cheeks raises Defense by 2 stages after consuming the berry and gaining its effect") +{ + GIVEN { + PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + } SCENE { + MESSAGE("Skwovet used Stuff Cheeks!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + MESSAGE("Using Liechi Berry, the Attack of Skwovet rose!"); + MESSAGE("Skwovet's Defense sharply rose!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2); + EXPECT_EQ(player->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Stuff Cheeks can be used even if Unnerve is present") +{ + GIVEN { + PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } + OPPONENT(SPECIES_EKANS) { Ability(ABILITY_UNNERVE); } + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + } SCENE { + MESSAGE("Skwovet used Stuff Cheeks!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + } +} + +SINGLE_BATTLE_TEST("Stuff Cheeks can be used even if Magic Room is active") +{ + GIVEN { + PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(opponent, MOVE_MAGIC_ROOM); + MOVE(player, MOVE_STUFF_CHEEKS); + } + } SCENE { + MESSAGE("Skwovet used Stuff Cheeks!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + MESSAGE("Using Liechi Berry, the Attack of Skwovet rose!"); + } +} + +SINGLE_BATTLE_TEST("Stuff Cheeks fails if the user's berry is removed before they use the move") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); + PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_KNOCK_OFF); MOVE(player, MOVE_STUFF_CHEEKS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, opponent); + MESSAGE("Skwovet used Stuff Cheeks!"); + MESSAGE("But it failed!"); + } +} + diff --git a/test/battle/move_effect/teatime.c b/test/battle/move_effect/teatime.c index 2d7c7426e8..4d00205a2d 100644 --- a/test/battle/move_effect/teatime.c +++ b/test/battle/move_effect/teatime.c @@ -35,14 +35,14 @@ SINGLE_BATTLE_TEST("Teatime causes the user to consume its Berry, even in the pr } } -SINGLE_BATTLE_TEST("Teatime causes the user to consume its Berry, even under the effects of Wonder Room") +SINGLE_BATTLE_TEST("Teatime causes the user to consume its Berry, even under the effects of Magic Room") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIECHI_BERRY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { - MOVE(opponent, MOVE_WONDER_ROOM); + MOVE(opponent, MOVE_MAGIC_ROOM); MOVE(player, MOVE_TEATIME); } } SCENE {