diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 930d20a018..f5bedcbf7f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,6 +11,9 @@ +## Issue(s) that this PR introduces + + ## **Discord contact info** \ No newline at end of file diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 7592fce313..b60b7faf74 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1551,6 +1551,12 @@ .4byte \failInstr .endm + .macro trydefog clear:req, failInstr:req + callnative BS_TryDefog + .byte \clear + .4byte \failInstr + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES @@ -1818,12 +1824,6 @@ various \battler, VARIOUS_UPDATE_ABILITY_POPUP .endm - .macro defogclear battler:req, clear:req, failInstr:req - various \battler, VARIOUS_DEFOG - .byte \clear - .4byte \failInstr - .endm - .macro jumpiftargetally jumpInstr:req various BS_ATTACKER, VARIOUS_JUMP_IF_TARGET_ALLY .4byte \jumpInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3a8f7f1582..1598ecd53c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1086,8 +1086,7 @@ BattleScript_EffectFling: attackcanceler jumpifcantfling BS_ATTACKER, BattleScript_FailedFromAtkString setlastuseditem BS_ATTACKER - removeitem BS_ATTACKER - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + accuracycheck BattleScript_FlingMissed, ACC_CURR_MOVE attackstring pause B_WAIT_TIME_SHORT printstring STRINGID_PKMNFLUNG @@ -1096,6 +1095,7 @@ BattleScript_EffectFling: critcalc damagecalc adjustdamage + removeitem BS_ATTACKER attackanimation waitanimation effectivenesssound @@ -1171,6 +1171,12 @@ BattleScript_FlingWhiteHerb: swapattackerwithtarget goto BattleScript_FlingEnd +BattleScript_FlingMissed: + removeitem BS_ATTACKER + attackstring + ppreduce + goto BattleScript_MoveMissedPause + BattleScript_EffectShellSideArm: shellsidearmcheck setmoveeffect MOVE_EFFECT_POISON @@ -2150,7 +2156,7 @@ BattleScript_EffectDefog: jumpifsubstituteblocks BattleScript_DefogIfCanClearHazards jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_EVASION, MIN_STAT_STAGE, BattleScript_DefogWorks BattleScript_DefogIfCanClearHazards: - defogclear BS_ATTACKER, FALSE, BattleScript_FailedFromAtkString + trydefog FALSE, BattleScript_FailedFromAtkString BattleScript_DefogWorks: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring @@ -2170,7 +2176,7 @@ BattleScript_DefogPrintString:: waitmessage B_WAIT_TIME_LONG BattleScript_DefogTryHazards:: copybyte gEffectBattler, gBattlerAttacker - defogclear BS_ATTACKER, TRUE, NULL + trydefog TRUE, NULL copybyte gBattlerAttacker, gEffectBattler goto BattleScript_MoveEnd BattleScript_DefogTryHazardsWithAnim: @@ -4834,8 +4840,11 @@ BattleScript_EffectThief:: goto BattleScript_EffectHit BattleScript_EffectHitPreventEscape: + attackcanceler + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE setmoveeffect MOVE_EFFECT_PREVENT_ESCAPE - goto BattleScript_EffectHit + seteffectprimary + goto BattleScript_HitFromAtkString BattleScript_EffectMeanLook:: attackcanceler @@ -8028,10 +8037,11 @@ BattleScript_IllusionOff:: return BattleScript_CottonDownActivates:: - setbyte sFIXED_ABILITY_POPUP, TRUE - call BattleScript_AbilityPopUp + showabilitypopup BS_TARGET + pause B_WAIT_TIME_LONG + destroyabilitypopup copybyte gEffectBattler, gBattlerTarget - savetarget + swapattackerwithtarget setbyte gBattlerTarget, 0 BattleScript_CottonDownLoop: jumpiffainted BS_TARGET, TRUE, BattleScript_CottonDownLoopIncrement @@ -8050,8 +8060,7 @@ BattleScript_CottonDownLoopIncrement: addbyte gBattlerTarget, 1 jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_CottonDownLoop BattleScript_CottonDownReturn: - restoretarget - destroyabilitypopup + swapattackerwithtarget return BattleScript_AnticipationActivates:: diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index eabc965e57..7e95ea785b 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -144,104 +144,103 @@ #define VARIOUS_TRY_HIT_SWITCH_TARGET 52 #define VARIOUS_TRY_AUTOTOMIZE 53 #define VARIOUS_ABILITY_POPUP 54 -#define VARIOUS_DEFOG 55 -#define VARIOUS_JUMP_IF_TARGET_ALLY 56 -#define VARIOUS_TRY_SYNCHRONOISE 57 -#define VARIOUS_PSYCHO_SHIFT 58 -#define VARIOUS_CURE_STATUS 59 -#define VARIOUS_POWER_TRICK 60 -#define VARIOUS_AFTER_YOU 61 -#define VARIOUS_BESTOW 62 -#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 63 -#define VARIOUS_JUMP_IF_NOT_GROUNDED 64 -#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 65 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 66 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 67 -#define VARIOUS_SET_AURORA_VEIL 68 -#define VARIOUS_TRY_THIRD_TYPE 69 -#define VARIOUS_ACUPRESSURE 70 -#define VARIOUS_SET_POWDER 71 -#define VARIOUS_SPECTRAL_THIEF 72 -#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 73 -#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 74 -#define VARIOUS_JUMP_IF_ROAR_FAILS 75 -#define VARIOUS_TRY_INSTRUCT 76 -#define VARIOUS_JUMP_IF_NOT_BERRY 77 -#define VARIOUS_TRACE_ABILITY 78 -#define VARIOUS_UPDATE_NICK 79 -#define VARIOUS_TRY_ILLUSION_OFF 80 -#define VARIOUS_SET_SPRITEIGNORE0HP 81 -#define VARIOUS_HANDLE_FORM_CHANGE 82 -#define VARIOUS_GET_STAT_VALUE 83 -#define VARIOUS_JUMP_IF_FULL_HP 84 -#define VARIOUS_LOSE_TYPE 85 -#define VARIOUS_TRY_ACTIVATE_SOULHEART 86 -#define VARIOUS_TRY_ACTIVATE_RECEIVER 87 -#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 88 -#define VARIOUS_TRY_FRISK 89 -#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 90 -#define VARIOUS_TRY_FAIRY_LOCK 91 -#define VARIOUS_JUMP_IF_NO_ALLY 92 -#define VARIOUS_POISON_TYPE_IMMUNITY 93 -#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 94 -#define VARIOUS_INFATUATE_WITH_BATTLER 95 -#define VARIOUS_SET_LAST_USED_ITEM 96 -#define VARIOUS_PARALYZE_TYPE_IMMUNITY 97 -#define VARIOUS_JUMP_IF_ABSENT 98 -#define VARIOUS_DESTROY_ABILITY_POPUP 99 -#define VARIOUS_TOTEM_BOOST 100 -#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 101 -#define VARIOUS_MOVEEND_ITEM_EFFECTS 102 -#define VARIOUS_TERRAIN_SEED 103 -#define VARIOUS_MAKE_INVISIBLE 104 -#define VARIOUS_ROOM_SERVICE 105 -#define VARIOUS_EERIE_SPELL_PP_REDUCE 106 -#define VARIOUS_JUMP_IF_TEAM_HEALTHY 107 -#define VARIOUS_TRY_HEAL_QUARTER_HP 108 -#define VARIOUS_REMOVE_TERRAIN 109 -#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 110 -#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 111 -#define VARIOUS_GET_ROTOTILLER_TARGETS 112 -#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 113 -#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 114 -#define VARIOUS_CONSUME_BERRY 115 -#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 116 -#define VARIOUS_JUMP_IF_SPECIES 117 -#define VARIOUS_UPDATE_ABILITY_POPUP 118 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 119 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 120 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 121 -#define VARIOUS_PHOTON_GEYSER_CHECK 122 -#define VARIOUS_SHELL_SIDE_ARM_CHECK 123 -#define VARIOUS_TRY_NO_RETREAT 124 -#define VARIOUS_TRY_TAR_SHOT 125 -#define VARIOUS_CAN_TAR_SHOT_WORK 126 -#define VARIOUS_CHECK_POLTERGEIST 127 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 128 -#define VARIOUS_TRY_END_NEUTRALIZING_GAS 129 -#define VARIOUS_JUMP_IF_UNDER_200 130 -#define VARIOUS_SET_SKY_DROP 131 -#define VARIOUS_CLEAR_SKY_DROP 132 -#define VARIOUS_SKY_DROP_YAWN 133 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 134 -#define VARIOUS_CURE_CERTAIN_STATUSES 135 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 136 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 137 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 138 -#define VARIOUS_SAVE_BATTLER_ITEM 139 -#define VARIOUS_RESTORE_BATTLER_ITEM 140 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 141 -#define VARIOUS_SET_BEAK_BLAST 142 -#define VARIOUS_SWAP_SIDE_STATUSES 143 -#define VARIOUS_SWAP_STATS 144 -#define VARIOUS_TEATIME_INVUL 145 -#define VARIOUS_TEATIME_TARGETS 146 -#define VARIOUS_TRY_WIND_RIDER_POWER 147 -#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 148 -#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 149 -#define VARIOUS_STORE_HEALING_WISH 150 -#define VARIOUS_HIT_SWITCH_TARGET_FAILED 151 -#define VARIOUS_TRY_REVIVAL_BLESSING 152 +#define VARIOUS_JUMP_IF_TARGET_ALLY 55 +#define VARIOUS_TRY_SYNCHRONOISE 56 +#define VARIOUS_PSYCHO_SHIFT 57 +#define VARIOUS_CURE_STATUS 58 +#define VARIOUS_POWER_TRICK 59 +#define VARIOUS_AFTER_YOU 60 +#define VARIOUS_BESTOW 61 +#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 62 +#define VARIOUS_JUMP_IF_NOT_GROUNDED 63 +#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 64 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 65 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 66 +#define VARIOUS_SET_AURORA_VEIL 67 +#define VARIOUS_TRY_THIRD_TYPE 68 +#define VARIOUS_ACUPRESSURE 69 +#define VARIOUS_SET_POWDER 70 +#define VARIOUS_SPECTRAL_THIEF 71 +#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 72 +#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 73 +#define VARIOUS_JUMP_IF_ROAR_FAILS 74 +#define VARIOUS_TRY_INSTRUCT 75 +#define VARIOUS_JUMP_IF_NOT_BERRY 76 +#define VARIOUS_TRACE_ABILITY 77 +#define VARIOUS_UPDATE_NICK 78 +#define VARIOUS_TRY_ILLUSION_OFF 79 +#define VARIOUS_SET_SPRITEIGNORE0HP 80 +#define VARIOUS_HANDLE_FORM_CHANGE 81 +#define VARIOUS_GET_STAT_VALUE 82 +#define VARIOUS_JUMP_IF_FULL_HP 83 +#define VARIOUS_LOSE_TYPE 84 +#define VARIOUS_TRY_ACTIVATE_SOULHEART 85 +#define VARIOUS_TRY_ACTIVATE_RECEIVER 86 +#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 87 +#define VARIOUS_TRY_FRISK 88 +#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 89 +#define VARIOUS_TRY_FAIRY_LOCK 90 +#define VARIOUS_JUMP_IF_NO_ALLY 91 +#define VARIOUS_POISON_TYPE_IMMUNITY 92 +#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 93 +#define VARIOUS_INFATUATE_WITH_BATTLER 94 +#define VARIOUS_SET_LAST_USED_ITEM 95 +#define VARIOUS_PARALYZE_TYPE_IMMUNITY 96 +#define VARIOUS_JUMP_IF_ABSENT 97 +#define VARIOUS_DESTROY_ABILITY_POPUP 98 +#define VARIOUS_TOTEM_BOOST 99 +#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 100 +#define VARIOUS_MOVEEND_ITEM_EFFECTS 101 +#define VARIOUS_TERRAIN_SEED 102 +#define VARIOUS_MAKE_INVISIBLE 103 +#define VARIOUS_ROOM_SERVICE 104 +#define VARIOUS_EERIE_SPELL_PP_REDUCE 105 +#define VARIOUS_JUMP_IF_TEAM_HEALTHY 106 +#define VARIOUS_TRY_HEAL_QUARTER_HP 107 +#define VARIOUS_REMOVE_TERRAIN 108 +#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 109 +#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 110 +#define VARIOUS_GET_ROTOTILLER_TARGETS 111 +#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 112 +#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 113 +#define VARIOUS_CONSUME_BERRY 114 +#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 115 +#define VARIOUS_JUMP_IF_SPECIES 116 +#define VARIOUS_UPDATE_ABILITY_POPUP 117 +#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 118 +#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 119 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 120 +#define VARIOUS_PHOTON_GEYSER_CHECK 121 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 122 +#define VARIOUS_TRY_NO_RETREAT 123 +#define VARIOUS_TRY_TAR_SHOT 124 +#define VARIOUS_CAN_TAR_SHOT_WORK 125 +#define VARIOUS_CHECK_POLTERGEIST 126 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 127 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 128 +#define VARIOUS_JUMP_IF_UNDER_200 129 +#define VARIOUS_SET_SKY_DROP 130 +#define VARIOUS_CLEAR_SKY_DROP 131 +#define VARIOUS_SKY_DROP_YAWN 132 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 133 +#define VARIOUS_CURE_CERTAIN_STATUSES 134 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 135 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 136 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 137 +#define VARIOUS_SAVE_BATTLER_ITEM 138 +#define VARIOUS_RESTORE_BATTLER_ITEM 139 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 140 +#define VARIOUS_SET_BEAK_BLAST 141 +#define VARIOUS_SWAP_SIDE_STATUSES 142 +#define VARIOUS_SWAP_STATS 143 +#define VARIOUS_TEATIME_INVUL 144 +#define VARIOUS_TEATIME_TARGETS 145 +#define VARIOUS_TRY_WIND_RIDER_POWER 146 +#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 147 +#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 148 +#define VARIOUS_STORE_HEALING_WISH 149 +#define VARIOUS_HIT_SWITCH_TARGET_FAILED 150 +#define VARIOUS_TRY_REVIVAL_BLESSING 151 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ce885ec3ef..67f1c1355b 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2345,7 +2345,7 @@ static void Cmd_datahpupdate(void) // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are // used in combination as general damage trackers for other purposes. specialDmg is additionally used // to help determine if a fire move should defrost the target. - if (IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && gCurrentMove != MOVE_PAIN_SPLIT) + if (IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && gBattleMoves[gCurrentMove].effect != EFFECT_PAIN_SPLIT) { gProtectStructs[battler].physicalDmg = gHpDealt; gSpecialStatuses[battler].physicalDmg = gHpDealt; @@ -2360,7 +2360,7 @@ static void Cmd_datahpupdate(void) gSpecialStatuses[battler].physicalBattlerId = gBattlerTarget; } } - else if (!IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE)) + else if (!IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && gBattleMoves[gCurrentMove].effect != EFFECT_PAIN_SPLIT) { // Record special damage/attacker for Mirror Coat gProtectStructs[battler].specialDmg = gHpDealt; @@ -5848,9 +5848,9 @@ static void Cmd_moveend(void) u8 battler = battlers[i]; // Attacker is the damage-dealer, battler is mon to be switched out if (IsBattlerAlive(battler) + && gBattlerAttacker != battler && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_BUTTON - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0) + && TARGET_TURN_DAMAGED && CountUsablePartyMons(battler) > 0) // Has mon to switch into { gBattleScripting.battler = battler; @@ -8178,6 +8178,8 @@ static void RemoveAllTerrains(void) static bool32 TryDefogClear(u32 battlerAtk, bool32 clear) { s32 i; + u8 saveBattler = gBattlerAttacker; + for (i = 0; i < 2; i++) { struct SideTimer *sideTimer = &gSideTimers[i]; @@ -8206,6 +8208,8 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear) } } + gBattlerAttacker = saveBattler; + return FALSE; } @@ -9571,25 +9575,6 @@ static void Cmd_various(void) UpdateAbilityPopup(battler); break; } - case VARIOUS_DEFOG: - { - VARIOUS_ARGS(bool8 clear, const u8 *failInstr); - if (cmd->clear) // Clear - { - if (TryDefogClear(gEffectBattler, TRUE)) - return; - else - gBattlescriptCurrInstr = cmd->nextInstr; - } - else - { - if (TryDefogClear(battler, FALSE)) - gBattlescriptCurrInstr = cmd->nextInstr; - else - gBattlescriptCurrInstr = cmd->failInstr; - } - return; - } case VARIOUS_JUMP_IF_TARGET_ALLY: { VARIOUS_ARGS(const u8 *jumpInstr); @@ -16468,3 +16453,23 @@ void BS_TryCopycat(void) gBattlescriptCurrInstr = cmd->nextInstr; } } + +void BS_TryDefog(void) +{ + NATIVE_ARGS(u8 clear, const u8 *failInstr); + + if (cmd->clear) + { + if (TryDefogClear(gEffectBattler, TRUE)) + return; + else + gBattlescriptCurrInstr = cmd->nextInstr; + } + else + { + if (TryDefogClear(gBattlerAttacker, FALSE)) + gBattlescriptCurrInstr = cmd->nextInstr; + else + gBattlescriptCurrInstr = cmd->failInstr; + } +} diff --git a/src/battle_util.c b/src/battle_util.c index 2d89aa100d..182e1fc302 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -5233,6 +5233,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case ABILITY_STAMINA: if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattlerAttacker != gBattlerTarget && TARGET_TURN_DAMAGED && IsBattlerAlive(battler) && CompareStat(battler, STAT_DEF, MAX_STAT_STAGE, CMP_LESS_THAN)) diff --git a/test/battle/ability/cotton_down.c b/test/battle/ability/cotton_down.c new file mode 100644 index 0000000000..8e15283926 --- /dev/null +++ b/test/battle/ability/cotton_down.c @@ -0,0 +1,64 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Cotton Down drops speed by one of opposing battler if hit by a damaging move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ELDEGOSS) { Ability(ABILITY_COTTON_DOWN); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + ABILITY_POPUP(opponent, ABILITY_COTTON_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed fell!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + } +} + +SINGLE_BATTLE_TEST("Cotton Down drops speed by one for each multi hit") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ELDEGOSS) { Ability(ABILITY_COTTON_DOWN); } + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_KICK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_KICK, player); + ABILITY_POPUP(opponent, ABILITY_COTTON_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed fell!"); + ABILITY_POPUP(opponent, ABILITY_COTTON_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed fell!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 2); + } +} + +DOUBLE_BATTLE_TEST("Cotton Down drops speed by one of all other battlers on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_ELDEGOSS) { Ability(ABILITY_COTTON_DOWN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_COTTON_DOWN); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Wobbuffet's Speed fell!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Wynaut's Speed fell!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("Foe Wobbuffet's Speed fell!"); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + } +} diff --git a/test/battle/ability/defiant.c b/test/battle/ability/defiant.c index e8443ecc5f..3463cad18d 100644 --- a/test/battle/ability/defiant.c +++ b/test/battle/ability/defiant.c @@ -138,3 +138,40 @@ SINGLE_BATTLE_TEST("Defiant activates after Sticky Web lowers Speed") MESSAGE("Mankey's Attack sharply rose!"); } } + + +DOUBLE_BATTLE_TEST("Defiant is activated by Cotton Down for non-ally pokemon") +{ + GIVEN { + PLAYER(SPECIES_MANKEY) { Ability(ABILITY_DEFIANT); } + PLAYER(SPECIES_MANKEY) { Ability(ABILITY_DEFIANT); } + OPPONENT(SPECIES_ELDEGOSS) { Ability(ABILITY_COTTON_DOWN); } + OPPONENT(SPECIES_MANKEY) { Ability(ABILITY_DEFIANT); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_COTTON_DOWN); + + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Mankey's Speed fell!"); + ABILITY_POPUP(playerLeft, ABILITY_DEFIANT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Mankey's Attack sharply rose!"); + + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Mankey's Speed fell!"); + ABILITY_POPUP(playerRight, ABILITY_DEFIANT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Mankey's Attack sharply rose!"); + + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("Foe Mankey's Speed fell!"); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + EXPECT_EQ(playerLeft->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + EXPECT_EQ(playerRight->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2); + } +} diff --git a/test/battle/ability/stamina.c b/test/battle/ability/stamina.c index 3470cce518..e4a1a255a3 100644 --- a/test/battle/ability/stamina.c +++ b/test/battle/ability/stamina.c @@ -87,3 +87,39 @@ DOUBLE_BATTLE_TEST("Stamina activates correctly for every battler with the abili EXPECT_EQ(opponentLeft->hp, opponentLeft->maxHP); } } + +SINGLE_BATTLE_TEST("Stamina activates for every hit of a multi hit move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_MUDBRAY) { Ability(ABILITY_STAMINA); } + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_KICK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_KICK, player); + HP_BAR(opponent); + STAMINA_STAT_RAISE(opponent, "Foe Mudbray's Defense rose!"); + STAMINA_STAT_RAISE(opponent, "Foe Mudbray's Defense rose!"); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2); + } +} + +SINGLE_BATTLE_TEST("Stamina is not activated by users own Substitute") +{ + GIVEN { + PLAYER(SPECIES_MUDBRAY) { Ability(ABILITY_STAMINA); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SUBSTITUTE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, player); + MESSAGE("Mudbray made a SUBSTITUTE!"); + NONE_OF { + ABILITY_POPUP(player, ABILITY_STAMINA); + MESSAGE("Mudbray's Defense rose!"); + } + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/hold_effect/eject_button.c b/test/battle/hold_effect/eject_button.c index 45dfc539b8..a94978b3ee 100644 --- a/test/battle/hold_effect/eject_button.c +++ b/test/battle/hold_effect/eject_button.c @@ -187,3 +187,24 @@ SINGLE_BATTLE_TEST("Eject Button is activated before Emergency Exit") MESSAGE("Foe Golisopod is switched out with the Eject Button!"); } } + +SINGLE_BATTLE_TEST("Eject Button is not triggered after High Jump Kick crash damage") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_BUTTON); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(player, MOVE_PROTECT); + MOVE(opponent, MOVE_HIGH_JUMP_KICK); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, player); + MESSAGE("Foe Wobbuffet kept going and crashed!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("Foe Wobbuffet is switched out with the Eject Button!"); + } + } +} diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index 71775e51e7..b8d35bd46d 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -272,7 +272,7 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even PARAMETRIZE { item = ITEM_SALAC_BERRY; effect = HOLD_EFFECT_SPEED_UP; statId = STAT_SPEED; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Item(item); } + PLAYER(SPECIES_WOBBUFFET) { Item(item); Attack(1); } OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); HP(399); MaxHP(400); MovesWithPP({MOVE_CELEBRATE, 35}); } } WHEN { TURN { MOVE(player, MOVE_FLING); } @@ -345,3 +345,24 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even } } +SINGLE_BATTLE_TEST("Fling deals damage based on items fling power") +{ + s16 damage[2]; + + GIVEN { + ASSUME(gBattleMoves[MOVE_CRUNCH].power == 80); + ASSUME(gItems[ITEM_VENUSAURITE].flingPower == 80); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_VENUSAURITE); } + OPPONENT(SPECIES_REGIROCK); + } WHEN { + TURN { MOVE(player, MOVE_CRUNCH); } + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CRUNCH, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + } +}