From cd596fdd802fc5c26cf5ead808ed274d2e73f538 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:00:36 +0100 Subject: [PATCH] Adds Tidy Up + minor Dragon Cheer follow up (#4136) * Adds Tidy Up + minor Dragon Cheer follow up * improve tidy up script * Add IncreaseTidyUpScore function * remove useless calls * 2 small tests and a correction for IncreasyTidyUpScore --- asm/macros/battle_script.inc | 12 ++- data/battle_scripts_1.s | 18 +++++ include/battle_ai_util.h | 4 +- include/battle_scripts.h | 1 + include/constants/battle_move_effects.h | 1 + include/constants/battle_string_ids.h | 3 +- src/battle_ai_main.c | 14 ++-- src/battle_ai_util.c | 37 ++++++++- src/battle_message.c | 2 + src/battle_script_commands.c | 58 +++++++++++++++ src/data/battle_move_effects.h | 9 +++ src/data/battle_partners.h | 1 - src/data/moves_info.h | 2 +- test/battle/move_effect/tidy_up.c | 99 +++++++++++++++++++++++++ test/test_runner_battle.c | 2 +- 15 files changed, 248 insertions(+), 15 deletions(-) create mode 100644 test/battle/move_effect/tidy_up.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 6e26a267ac..d2a8115089 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1360,11 +1360,11 @@ .byte \battler .4byte \jumpInstr .endm - + .macro allyswitchswapbattlers callnative BS_AllySwitchSwapBattler .endm - + .macro allyswitchfailchance jumpInstr:req callnative BS_AllySwitchFailChance .4byte \jumpInstr @@ -1616,11 +1616,17 @@ callnative BS_TryUpperHand .4byte \failInstr .endm - + .macro tryupdaterecoiltracker callnative BS_TryUpdateRecoilTracker .endm + .macro trytidyup clear:req, jumpInstr:req + callnative BS_TryTidyUp + .byte \clear + .4byte \jumpInstr + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 572aedbac7..e2d696a081 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -20,6 +20,23 @@ .section script_data, "aw", %progbits +BattleScript_EffectTidyUp:: + attackcanceler + attackstring + pause B_WAIT_TIME_MED + ppreduce + waitstate + trytidyup FALSE, BattleScript_EffectTidyUpDoMoveAnimation + goto BattleScript_EffectDragonDanceFromStatUp + +BattleScript_EffectTidyUpDoMoveAnimation:: + attackanimation + waitanimation + trytidyup TRUE, NULL + printstring STRINGID_TIDYINGUPCOMPLETE + waitmessage B_WAIT_TIME_LONG + goto BattleScript_EffectDragonDanceFromStatUp + BattleScript_EffectUpperHand:: attackcanceler tryupperhand BattleScript_FailedFromAtkString @@ -5460,6 +5477,7 @@ BattleScript_EffectDragonDance:: attackcanceler attackstring ppreduce +BattleScript_EffectDragonDanceFromStatUp:: jumpifstat BS_ATTACKER, CMP_LESS_THAN, STAT_ATK, MAX_STAT_STAGE, BattleScript_DragonDanceDoMoveAnim jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_CantRaiseMultipleStats BattleScript_DragonDanceDoMoveAnim:: diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 2d541ea73e..1a2157bc37 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -99,7 +99,8 @@ bool32 HasMoveWithCategory(u32 battler, u32 category); bool32 HasMoveWithType(u32 battler, u32 type); bool32 HasMoveEffect(u32 battlerId, u32 moveEffect); bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument); -bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect); +bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect); +bool32 HasMoveWithCriticalHitChance(u32 battlerId); bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception); bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); bool32 IsAromaVeilProtectedMove(u32 move); @@ -190,5 +191,6 @@ s32 AI_CheckMoveEffects(u32 battlerAtk, u32 battlerDef, u32 move, s32 score, str s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle); bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef); bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData); +void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); #endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 2eeba2cc33..7ce97b6ec3 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -824,5 +824,6 @@ extern const u8 BattleScript_EffectDoodle[]; extern const u8 BattleScript_EffectFilletAway[]; extern const u8 BattleScript_EffectShedTail[]; extern const u8 BattleScript_EffectUpperHand[]; +extern const u8 BattleScript_EffectTidyUp[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 41c1e82f1f..81ab42f51d 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -350,6 +350,7 @@ enum { EFFECT_UPPER_HAND, EFFECT_DRAGON_CHEER, EFFECT_LAST_RESPECTS, + EFFECT_TIDY_UP, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index e79e3f55a0..7a64f6d6fd 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -706,8 +706,9 @@ #define STRINGID_DIMENSIONSWERETWISTED 704 #define STRINGID_BIZARREARENACREATED 705 #define STRINGID_BIZARREAREACREATED 706 +#define STRINGID_TIDYINGUPCOMPLETE 707 -#define BATTLESTRINGS_COUNT 707 +#define BATTLESTRINGS_COUNT 708 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 19d43d7f51..0e1e9aec11 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1763,7 +1763,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_FOLLOW_ME: case EFFECT_HELPING_HAND: - case EFFECT_DRAGON_CHEER: if (!isDoubleBattle || !IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) @@ -2791,7 +2790,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-5); else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON) - || gMovesInfo[aiData->partnerMove].criticalHitStage > 0) + || gMovesInfo[aiData->partnerMove].criticalHitStage > 0 + || HasMoveWithCriticalHitChance(battlerAtkPartner)) ADJUST_SCORE(GOOD_EFFECT); } // our effect relative to partner @@ -3535,6 +3535,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) IncreaseParalyzeScore(battlerAtk, battlerDef, move, &score); break; case EFFECT_SUBSTITUTE: + ADJUST_SCORE(GOOD_EFFECT); if (gStatuses3[battlerDef] & STATUS3_PERISH_SONG) ADJUST_SCORE(GOOD_EFFECT); if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE)) @@ -3560,7 +3561,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_LEECH_SEED: if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || gStatuses3[battlerDef] & STATUS3_LEECHSEED - || HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) || aiData->abilities[battlerDef] == ABILITY_LIQUID_OOZE || aiData->abilities[battlerDef] == ABILITY_MAGIC_GUARD) break; @@ -3865,7 +3866,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) case EFFECT_FLATTER: if (HasMoveEffect(battlerAtk, EFFECT_FOUL_PLAY) || HasMoveEffect(battlerAtk, EFFECT_PSYCH_UP) - || HasMoveWithMoveEffect(battlerAtk, MOVE_EFFECT_SPECTRAL_THIEF)) + || HasMoveWithAdditionalEffect(battlerAtk, MOVE_EFFECT_SPECTRAL_THIEF)) ADJUST_SCORE(DECENT_EFFECT); if (aiData->abilities[battlerDef] == ABILITY_CONTRARY) ADJUST_SCORE(GOOD_EFFECT); @@ -4177,6 +4178,8 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPATK, &score); IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_ATK, &score); break; + case EFFECT_TIDY_UP: + IncreaseTidyUpScore(battlerAtk, battlerDef, move, &score); case EFFECT_DRAGON_DANCE: case EFFECT_SHIFT_GEAR: IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPEED, &score); @@ -4667,7 +4670,7 @@ static u32 AI_CalcMoveScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case MOVE_EFFECT_WRAP: - if (!HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) + if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) ADJUST_SCORE(BEST_EFFECT); break; } @@ -4794,6 +4797,7 @@ static s32 AI_SetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score case EFFECT_MAGIC_ROOM: case EFFECT_TAILWIND: case EFFECT_DRAGON_DANCE: + case EFFECT_TIDY_UP: case EFFECT_STICKY_WEB: case EFFECT_RAIN_DANCE: case EFFECT_SUNNY_DAY: diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 2c878097db..b77750f652 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -1709,7 +1709,7 @@ bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument) return FALSE; } -bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect) +bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect) { s32 i; u16 *moves = GetMovesArray(battlerId); @@ -1724,6 +1724,21 @@ bool32 HasMoveWithMoveEffect(u32 battlerId, u32 moveEffect) return FALSE; } +bool32 HasMoveWithCriticalHitChance(u32 battlerId) +{ + s32 i; + u16 *moves = GetMovesArray(battlerId); + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE + && gMovesInfo[moves[i]].criticalHitStage > 0) + return TRUE; + } + + return FALSE; +} + bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception) { s32 i; @@ -3595,9 +3610,27 @@ bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData { if (aiData->abilities[battlerDef] == ABILITY_MAGIC_BOUNCE || CountUsablePartyMons(battlerDef) == 0 - || HasMoveWithMoveEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) + || HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) || HasMoveEffect(battlerDef, EFFECT_DEFOG)) return FALSE; return TRUE; } + +void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) +{ + if (gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) + ADJUST_SCORE_PTR(GOOD_EFFECT); + if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerDef) != 0) + ADJUST_SCORE_PTR(-2); + + if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_STRIKES_FIRST(battlerAtk, battlerDef, move)) + ADJUST_SCORE_PTR(-10); + if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE) + ADJUST_SCORE_PTR(GOOD_EFFECT); + + if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED) + ADJUST_SCORE_PTR(DECENT_EFFECT); + if (gStatuses3[battlerDef] & STATUS3_LEECHSEED) + ADJUST_SCORE_PTR(-2); +} diff --git a/src/battle_message.c b/src/battle_message.c index b186f059a6..c17997dab0 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -843,9 +843,11 @@ static const u8 sText_ItemWasUsedUp[] = _("The {B_LAST_ITEM}\nwas used up..."); static const u8 sText_AttackerLostItsType[] = _("{B_ATK_NAME_WITH_PREFIX} lost\nits {B_BUFF1} type!"); static const u8 sText_ShedItsTail[] = _("{B_ATK_NAME_WITH_PREFIX} shed its tail\nto create a decoy!"); static const u8 sText_SupersweetAromaWafts[] = _("A supersweet aroma is wafting from\nthe syrup covering {B_ATK_NAME_WITH_PREFIX}!"); +static const u8 sText_TidyingUpComplete[] = _("Tidying up complete!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_TIDYINGUPCOMPLETE - BATTLESTRINGS_TABLE_START] = sText_TidyingUpComplete, [STRINGID_SUPERSWEETAROMAWAFTS - BATTLESTRINGS_TABLE_START] = sText_SupersweetAromaWafts, [STRINGID_SHEDITSTAIL - BATTLESTRINGS_TABLE_START] = sText_ShedItsTail, [STRINGID_ELECTROSHOTCHARGING - BATTLESTRINGS_TABLE_START] = sText_ElectroShotCharging, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 6e3ae76b4e..7a3dc7ff76 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8397,6 +8397,44 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear) return FALSE; } +static bool32 TryTidyUpClear(u32 battlerAtk, bool32 clear) +{ + s32 i; + u8 saveBattler = gBattlerAttacker; + + for (i = 0; i < NUM_BATTLE_SIDES; i++) + { + struct SideTimer *sideTimer = &gSideTimers[i]; + u32 *sideStatuses = &gSideStatuses[i]; + + gBattlerAttacker = i; // For correct battle string. Ally's / Foe's + DEFOG_CLEAR(SIDE_STATUS_SPIKES, spikesAmount, BattleScript_SpikesDefog, 0); + DEFOG_CLEAR(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, BattleScript_StealthRockDefog, 0); + DEFOG_CLEAR(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, BattleScript_ToxicSpikesDefog, 0); + DEFOG_CLEAR(SIDE_STATUS_STICKY_WEB, stickyWebAmount, BattleScript_StickyWebDefog, 0); + } + + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (gBattleMons[i].status2 & STATUS2_SUBSTITUTE) + { + if (clear) + { + gBattlerTarget = i; + gDisableStructs[i].substituteHP = 0; + gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SubstituteFade; + } + gBattlerAttacker = saveBattler; + return TRUE; + } + } + + gBattlerAttacker = saveBattler; + return FALSE; +} + u32 IsFlowerVeilProtected(u32 battler) { if (IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) @@ -16671,3 +16709,23 @@ void BS_TryUpdateRecoilTracker(void) TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_FEMALE, gBattleMoveDamage); gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_TryTidyUp(void) +{ + NATIVE_ARGS(u8 clear, const u8 *jumpInstr); + + if (cmd->clear) + { + if (TryTidyUpClear(gEffectBattler, TRUE)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + if (TryTidyUpClear(gBattlerAttacker, FALSE)) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; + } +} diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 0aa18ceeea..32438fa812 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2200,12 +2200,14 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = { .battleScript = BattleScript_EffectShedTail, .battleTvScore = 0, // TODO: Assign points + .encourageEncore = TRUE, }, [EFFECT_UPPER_HAND] = { .battleScript = BattleScript_EffectUpperHand, .battleTvScore = 0, // TODO: Assign points + .encourageEncore = TRUE, }, [EFFECT_DRAGON_CHEER] = @@ -2220,4 +2222,11 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_TIDY_UP] = + { + .battleScript = BattleScript_EffectTidyUp, + .battleTvScore = 0, // TODO: Assign points + .encourageEncore = TRUE, + }, }; diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index 806a50bdf6..39bb91132f 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -17,5 +17,4 @@ const struct Trainer gBattlePartners[] = { .trainerPic = TRAINER_BACK_PIC_STEVEN, .trainerName = _("STEVEN"), }, - }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 9de5dbaf1d..958142a49e 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -19207,7 +19207,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "User tidies up hazards and\n" "raises its Attack and Speed."), - .effect = EFFECT_PLACEHOLDER, // EFFECT_TIDY_UP + .effect = EFFECT_TIDY_UP, .power = 0, .type = TYPE_NORMAL, .accuracy = 0, diff --git a/test/battle/move_effect/tidy_up.c b/test/battle/move_effect/tidy_up.c new file mode 100644 index 0000000000..463fb65af8 --- /dev/null +++ b/test/battle/move_effect/tidy_up.c @@ -0,0 +1,99 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_TIDY_UP].effect == EFFECT_TIDY_UP); +} + +SINGLE_BATTLE_TEST("Tidy Up raises Attack and Speed by one") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TIDY_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TIDY_UP, player); + NOT MESSAGE("Tidying up complete!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Wobbuffet's Speed rose!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + } +} + +SINGLE_BATTLE_TEST("Tidy Up removes hazards and raises Stats") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SPIKES); } + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } + TURN { MOVE(opponent, MOVE_TOXIC_SPIKES); } + TURN { MOVE(opponent, MOVE_STICKY_WEB); MOVE(player, MOVE_TIDY_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent); + MESSAGE("Wobbuffet used Tidy Up!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TIDY_UP, player); + MESSAGE("The spikes disappeared from the ground around your team!"); + MESSAGE("The pointed stones disappeared from around your team!"); + MESSAGE("The poison spikes disappeared from the ground around your team!"); + MESSAGE("The sticky web has disappeared from the ground around your team!"); + MESSAGE("Tidying up complete!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Wobbuffet's Speed rose!"); + } +} + +SINGLE_BATTLE_TEST("Tidy Up removes Substitute") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TIDY_UP); } + } SCENE { + MESSAGE("Foe Wobbuffet used Substitute!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent); + MESSAGE("Foe Wobbuffet made a SUBSTITUTE!"); + MESSAGE("Wobbuffet used Tidy Up!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TIDY_UP, player); + MESSAGE("Foe Wobbuffet's SUBSTITUTE faded!"); + MESSAGE("Tidying up complete!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Wobbuffet's Speed rose!"); + } +} + +AI_SINGLE_BATTLE_TEST("AI prefers to keep it's substitute over removing hazards if target is slower") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET) { Speed(50); Status1(STATUS1_PARALYSIS); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); } + } WHEN { + TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); } + TURN { EXPECT_MOVE(opponent, MOVE_BITE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI will try to remove hazards if slower then target even with a Substitute because it expects the Sub to be broken") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET) { Speed(100); Status1(STATUS1_BURN); Moves(MOVE_SLEEP_POWDER, MOVE_STEALTH_ROCK, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Moves(MOVE_BITE, MOVE_TACKLE, MOVE_SUBSTITUTE, MOVE_TIDY_UP); } + } WHEN { + TURN { MOVE(player, MOVE_STEALTH_ROCK); EXPECT_MOVE(opponent, MOVE_SUBSTITUTE); } + TURN { EXPECT_MOVE(opponent, MOVE_TIDY_UP); } + } +} diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 3adebd78ab..68a83321fe 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -1533,7 +1533,7 @@ void SetFlagForTest(u32 sourceLine, u16 flagId) void ClearFlagAfterTest(void) { - if (DATA.flagId != 0) + if (DATA.flagId != 0) { FlagClear(DATA.flagId); DATA.flagId = 0;