diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 34aea69998..eb25849356 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2379,10 +2379,6 @@ manipulatedamage DMG_CURR_ATTACKER_HP .endm - .macro dmg_1_2_attackerhp - manipulatedamage DMG_1_2_ATTACKER_HP - .endm - .macro jumpifflowerveil jumpInstr:req jumpifnottype BS_TARGET, TYPE_GRASS, 1f jumpifability BS_TARGET_SIDE, ABILITY_FLOWER_VEIL, \jumpInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 8a5891f068..5fa5bf342d 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -547,36 +547,6 @@ BattleScript_EffectShellTrap:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectMaxHp50Recoil:: - attackcanceler - attackstring - ppreduce - accuracycheck BattleScript_SteelBeamMiss, ACC_CURR_MOVE - call BattleScript_EffectHit_RetFromCritCalc - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_SteelBeamAfterSelfDamage - call BattleScript_SteelBeamSelfDamage -BattleScript_SteelBeamAfterSelfDamage:: - waitstate - tryfaintmon BS_ATTACKER - tryfaintmon BS_TARGET - goto BattleScript_MoveEnd -BattleScript_SteelBeamMiss:: - pause B_WAIT_TIME_SHORT - effectivenesssound - resultmessage - waitmessage B_WAIT_TIME_LONG - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_MoveEnd - bichalfword gMoveResultFlags, MOVE_RESULT_MISSED - call BattleScript_SteelBeamSelfDamage - orhalfword gMoveResultFlags, MOVE_RESULT_MISSED - goto BattleScript_SteelBeamAfterSelfDamage - -BattleScript_SteelBeamSelfDamage:: - dmg_1_2_attackerhp - healthbarupdate BS_ATTACKER - datahpupdate BS_ATTACKER - return - BattleScript_EffectCourtChange:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE @@ -2968,84 +2938,26 @@ BattleScript_AbsorbHealBlock:: tryfaintmon BS_TARGET goto BattleScript_MoveEnd -BattleScript_EffectExplosion_AnimDmgRet: - jumpifbyte CMP_NO_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_MISSED, BattleScript_ExplosionAnimRet - call BattleScript_PreserveMissedBitDoMoveAnim - goto BattleScript_ExplosionDmgRet -BattleScript_ExplosionAnimRet: - attackanimation - waitanimation -BattleScript_ExplosionDmgRet: - movevaluescleanup - critcalc - damagecalc - adjustdamage - accuracycheck BattleScript_ExplosionMissedRet, ACC_CURR_MOVE - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG - tryfaintmon BS_TARGET -BattleScript_ExplosionAnimEndRet_Return: - return -BattleScript_ExplosionMissedRet: - effectivenesssound - resultmessage - waitmessage B_WAIT_TIME_LONG - goto BattleScript_ExplosionAnimEndRet_Return - BattleScript_EffectExplosion:: attackcanceler attackstring ppreduce -@ Below jumps to BattleScript_DampStopsExplosion if it fails (only way it can) tryexplosion - waitstate -BattleScript_EffectExplosion_AnimDmgFaintAttacker: - call BattleScript_EffectExplosion_AnimDmgRet - moveendall setatkhptozero - tryfaintmon BS_ATTACKER - end - -BattleScript_EffectMindBlown:: - attackcanceler - attackstring - ppreduce - jumpifbyte CMP_GREATER_THAN, sB_ANIM_TARGETS_HIT, 0, BattleScript_EffectMindBlown_NoHpLoss - jumpifabilitypresent ABILITY_DAMP, BattleScript_MindBlownDamp - jumpifmorethanhalfHP BS_ATTACKER, BattleScript_EffectMindBlown_HpDown - setbyte sMULTIHIT_EFFECT, 0 @ Note to faint the attacker - instanthpdrop BS_ATTACKER waitstate - goto BattleScript_EffectExplosion_AnimDmgFaintAttacker -BattleScript_EffectMindBlown_NoHpLoss: - jumpifbyte CMP_EQUAL, sMULTIHIT_EFFECT, 0, BattleScript_EffectExplosion_AnimDmgFaintAttacker - goto BattleScript_EffectMindBlown_AnimDmgNoFaint -BattleScript_MindBlownDamp: - copybyte gBattlerTarget, gBattlerAbility - goto BattleScript_DampStopsExplosion -BattleScript_EffectMindBlown_HpDown: - setbyte sMULTIHIT_EFFECT, 1 @ Note to not faint the attacker - jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_EffectMindBlown_AnimDmgNoFaint - dmg_1_2_attackerhp + jumpiffainted BS_TARGET, TRUE, BattleScript_MoveEnd + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE + goto BattleScript_HitFromCritCalc + +BattleScript_FaintAttackerForExplosion:: + tryfaintmon BS_ATTACKER + return + +BattleScript_MaxHp50Recoil:: + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE healthbarupdate BS_ATTACKER datahpupdate BS_ATTACKER - waitstate -BattleScript_EffectMindBlown_AnimDmgNoFaint: - call BattleScript_EffectExplosion_AnimDmgRet - goto BattleScript_MoveEnd - -BattleScript_PreserveMissedBitDoMoveAnim: - bichalfword gMoveResultFlags, MOVE_RESULT_MISSED - attackanimation - waitanimation - orhalfword gMoveResultFlags, MOVE_RESULT_MISSED + tryfaintmon BS_ATTACKER return BattleScript_EffectDreamEater:: @@ -7597,6 +7509,15 @@ BattleScript_AbilityPopUp: sethword sABILITY_OVERWRITE, 0 return +BattleScript_AbilityPopUpScripting: + .if B_ABILITY_POP_UP == TRUE + showabilitypopup BS_SCRIPTING + pause 40 + .endif + recordability BS_SCRIPTING + sethword sABILITY_OVERWRITE, 0 + return + BattleScript_SpeedBoostActivates:: statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_SpeedBoostActivatesEnd call BattleScript_AbilityPopUp @@ -8130,7 +8051,7 @@ BattleScript_SturdyPreventsOHKO:: BattleScript_DampStopsExplosion:: pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUpTarget + call BattleScript_AbilityPopUpScripting printstring STRINGID_PKMNPREVENTSUSAGE pause B_WAIT_TIME_LONG moveendto MOVEEND_NEXT_TARGET diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 878389da98..30f7f76425 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -152,6 +152,8 @@ extern const u8 BattleScript_MoveEffectPayDay[]; extern const u8 BattleScript_MoveEffectWrap[]; extern const u8 BattleScript_MoveEffectConfusion[]; extern const u8 BattleScript_MoveEffectRecoil[]; +extern const u8 BattleScript_FaintAttackerForExplosion[]; +extern const u8 BattleScript_MaxHp50Recoil[]; extern const u8 BattleScript_DoRecoil33[]; extern const u8 BattleScript_Recoil33End[]; extern const u8 BattleScript_ItemSteal[]; @@ -772,7 +774,6 @@ extern const u8 BattleScript_EffectLaserFocus[]; extern const u8 BattleScript_EffectMagneticFlux[]; extern const u8 BattleScript_EffectGearUp[]; extern const u8 BattleScript_EffectStrengthSap[]; -extern const u8 BattleScript_EffectMindBlown[]; extern const u8 BattleScript_EffectPurify[]; extern const u8 BattleScript_FailIfNotArgType[]; extern const u8 BattleScript_EffectShoreUp[]; @@ -804,7 +805,6 @@ extern const u8 BattleScript_EffectClangorousSoul[]; extern const u8 BattleScript_EffectSkyDrop[]; extern const u8 BattleScript_EffectMeteorBeam[]; extern const u8 BattleScript_EffectCourtChange[]; -extern const u8 BattleScript_EffectMaxHp50Recoil[]; extern const u8 BattleScript_EffectExtremeEvoboost[]; extern const u8 BattleScript_EffectHitSetRemoveTerrain[]; extern const u8 BattleScript_EffectDarkVoid[]; diff --git a/include/battle_util.h b/include/battle_util.h index 1fb6d6a8f7..d6ed8b3427 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -91,6 +91,7 @@ enum CANCELLER_POWDER_MOVE, CANCELLER_POWDER_STATUS, CANCELLER_THROAT_CHOP, + CANCELLER_EXPLODING_DAMP, CANCELLER_MULTIHIT_MOVES, CANCELLER_Z_MOVES, CANCELLER_END, diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index bd55b6954a..d2ad1afdbc 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -275,7 +275,6 @@ enum { EFFECT_MAGNETIC_FLUX, EFFECT_GEAR_UP, EFFECT_STRENGTH_SAP, - EFFECT_MIND_BLOWN, EFFECT_PURIFY, EFFECT_FAIL_IF_NOT_ARG_TYPE, EFFECT_SHORE_UP, @@ -318,6 +317,7 @@ enum { EFFECT_BEAK_BLAST, EFFECT_COURT_CHANGE, EFFECT_MAX_HP_50_RECOIL, + EFFECT_MIND_BLOWN, // Same as EFFECT_MAX_HP_50_RECOIL but is cancelled by Damp EFFECT_EXTREME_EVOBOOST, EFFECT_HIT_SET_REMOVE_TERRAIN, EFFECT_DARK_VOID, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index ef8803ce42..7228954f21 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -246,8 +246,7 @@ #define DMG_FULL_ATTACKER_HP 4 #define DMG_CURR_ATTACKER_HP 5 #define DMG_BIG_ROOT 6 -#define DMG_1_2_ATTACKER_HP 7 -#define DMG_RECOIL_FROM_IMMUNE 8 // Used to calculate recoil for the Gen 4 version of Jump Kick +#define DMG_RECOIL_FROM_IMMUNE 7 // Used to calculate recoil for the Gen 4 version of Jump Kick // Cmd_jumpifcantswitch #define SWITCH_IGNORE_ESCAPE_PREVENTION (1 << 7) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0fcb8b1fc2..02e6c6151b 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -733,8 +733,8 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s switch (gMovesInfo[move].effect) { - case EFFECT_MIND_BLOWN: case EFFECT_MAX_HP_50_RECOIL: + case EFFECT_MIND_BLOWN: return TRUE; case EFFECT_RECOIL_IF_MISS: if (AI_IsDamagedByRecoil(battlerAtk)) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f723ce6566..bc3e2f7198 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1289,7 +1289,7 @@ static void Cmd_attackcanceler(void) gCurrentActionFuncId = B_ACTION_FINISHED; return; } - if (gBattleMons[gBattlerAttacker].hp == 0 && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + if (gBattleMons[gBattlerAttacker].hp == 0 && gMovesInfo[gCurrentMove].effect != EFFECT_EXPLOSION && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; @@ -5549,18 +5549,38 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_RECOIL: - if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && IsBattlerAlive(gBattlerAttacker) - && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one + if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) { - if (gMovesInfo[gCurrentMove].recoil > 0) - { - gBattleMoveDamage = max(1, gBattleScripting.savedDmg * max(1, gMovesInfo[gCurrentMove].recoil) / 100); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; - effect = TRUE; - } + gBattleScripting.moveendState++; + break; + } + else if (gMovesInfo[gCurrentMove].recoil > 0 + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && IsBattlerAlive(gBattlerAttacker) + && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one + { + gBattleMoveDamage = max(1, gBattleScripting.savedDmg * max(1, gMovesInfo[gCurrentMove].recoil) / 100); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; + effect = TRUE; + } + else if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION && !IsAbilityOnField(ABILITY_DAMP)) + { + gBattleMoveDamage = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_FaintAttackerForExplosion; + effect = TRUE; + } + else if ((gMovesInfo[gCurrentMove].effect == EFFECT_MAX_HP_50_RECOIL + || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN) + && IsBattlerAlive(gBattlerAttacker) + && !(gMoveResultFlags & MOVE_RESULT_FAILED) + && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) + { + gBattleMoveDamage = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MaxHp50Recoil; + effect = TRUE; } gBattleScripting.moveendState++; break; @@ -5905,7 +5925,11 @@ static void Cmd_moveend(void) gBattleScripting.moveendState = 0; MoveValuesCleanUp(); gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + + if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION) + BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); // Edge case for Explosion not changing targets + else + BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -7200,22 +7224,10 @@ static void Cmd_switchineffects(void) gDisableStructs[battler].truantSwitchInHack = 0; - // Don't activate switch-in abilities if the opposing field is empty. - // This could happen when a mon uses explosion and causes everyone to faint. - if ((battlerAbility == ABILITY_INTIMIDATE || battlerAbility == ABILITY_SUPERSWEET_SYRUP || battlerAbility == ABILITY_DOWNLOAD) - && !IsBattlerAlive(BATTLE_OPPOSITE(battler)) - && !IsBattlerAlive(BATTLE_PARTNER(BATTLE_OPPOSITE(battler)))) - { - if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) - return; - } - else - { - if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) - return; - else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0)) - return; - } + if (DoSwitchInAbilities(battler) || ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, battler, FALSE)) + return; + else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0)) + return; gDisableStructs[battler].stickyWebDone = FALSE; gDisableStructs[battler].spikesDone = FALSE; @@ -10946,19 +10958,9 @@ static void Cmd_tryexplosion(void) { CMD_ARGS(); - u32 dampBattler; if (gBattleControllerExecFlags) return; - if ((dampBattler = IsAbilityOnField(ABILITY_DAMP))) - { - // Failed, a battler has Damp - gLastUsedAbility = ABILITY_DAMP; - gBattlerTarget = --dampBattler; - gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; - return; - } - gBattleMoveDamage = gBattleMons[gBattlerAttacker].hp; BtlController_EmitHealthBarUpdate(gBattlerAttacker, BUFFER_A, INSTANT_HP_BAR_DROP); MarkBattlerForControllerExec(gBattlerAttacker); @@ -11183,9 +11185,6 @@ static void Cmd_manipulatedamage(void) case DMG_BIG_ROOT: gBattleMoveDamage = GetDrainedBigRootHp(gBattlerAttacker, gBattleMoveDamage); break; - case DMG_1_2_ATTACKER_HP: - gBattleMoveDamage = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP - break; case DMG_RECOIL_FROM_IMMUNE: gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerTarget) / 2; break; diff --git a/src/battle_util.c b/src/battle_util.c index 57eb560cd5..1bdc1d9050 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3554,6 +3554,20 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) } gBattleStruct->atkCancellerTracker++; break; + case CANCELLER_EXPLODING_DAMP: + { + u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); + if (dampBattler && (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION + || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN)) + { + gBattleScripting.battler = dampBattler - 1; + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + effect = 1; + } + gBattleStruct->atkCancellerTracker++; + break; + } case CANCELLER_MULTIHIT_MOVES: if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) { diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 4cf54b0370..d0dc94afff 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1766,12 +1766,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_MIND_BLOWN] = - { - .battleScript = BattleScript_EffectMindBlown, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_PURIFY] = { .battleScript = BattleScript_EffectPurify, @@ -2029,7 +2023,13 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MAX_HP_50_RECOIL] = { - .battleScript = BattleScript_EffectMaxHp50Recoil, + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, + + [EFFECT_MIND_BLOWN] = + { + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, diff --git a/test/battle/ability/supreme_overlord.c b/test/battle/ability/supreme_overlord.c index 5d24850245..061324c739 100644 --- a/test/battle/ability/supreme_overlord.c +++ b/test/battle/ability/supreme_overlord.c @@ -94,17 +94,14 @@ SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Player") { - // For some reason the Ability Pop Up fails to appear after Explosion. - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} - PLAYER(SPECIES_KINGAMBIT); + PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } - TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_KOWTOW_CLEAVE); } } SCENE { HP_BAR(opponent, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); @@ -118,18 +115,14 @@ SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all batt SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Opponent") { - // For some reason the Ability Pop Up fails to appear after Explosion. - KNOWN_FAILING; GIVEN { ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_KINGAMBIT); + OPPONENT(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); } } WHEN { TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } - TURN { SWITCH(opponent, 2); MOVE(player, MOVE_TACKLE); } } SCENE { HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); diff --git a/test/battle/move_effect/explosion.c b/test/battle/move_effect/explosion.c index 21d3f1b790..10e9feaa80 100644 --- a/test/battle/move_effect/explosion.c +++ b/test/battle/move_effect/explosion.c @@ -62,7 +62,6 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect" TURN { MOVE(player, MOVE_EXPLOSION); } } SCENE { HP_BAR(player, hp: 0); - ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); MESSAGE("It doesn't affect Foe Gastly…"); NOT HP_BAR(opponent); MESSAGE("Wobbuffet fainted!"); @@ -91,3 +90,36 @@ DOUBLE_BATTLE_TEST("Explosion causes everyone to faint in a double battle") MESSAGE("Wobbuffet fainted!"); } } + +SINGLE_BATTLE_TEST("Explosion is blocked by Ability Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + HP_BAR(player, hp: 0); + } + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Explosion!"); + } +} + +SINGLE_BATTLE_TEST("Explosion does not trigger Destiny Bond") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_EXPLOSION);} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + HP_BAR(player); + NOT HP_BAR(opponent); + } +} diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index f4bfc42cc8..235e0773fe 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -137,6 +137,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") { + KNOWN_FAILING; GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); } diff --git a/test/battle/move_effect/max_hp_50_recoil.c b/test/battle/move_effect/max_hp_50_recoil.c index d310de84c2..8d5cbdaed2 100644 --- a/test/battle/move_effect/max_hp_50_recoil.c +++ b/test/battle/move_effect/max_hp_50_recoil.c @@ -6,21 +6,80 @@ ASSUMPTIONS ASSUME(gMovesInfo[MOVE_STEEL_BEAM].effect == EFFECT_MAX_HP_50_RECOIL); } -SINGLE_BATTLE_TEST("Steel Beam causes the user to take damage equal to half of its maximum HP") +SINGLE_BATTLE_TEST("Steel Beam makes the user lose 1/2 of its Max HP") { - s16 recoilDamage; - GIVEN { - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_STEEL_BEAM); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); - HP_BAR(opponent); - HP_BAR(player, captureDamage: &recoilDamage); - } THEN { - EXPECT_EQ(player->maxHP / 2, recoilDamage); + HP_BAR(player, damage: 200); + NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. + } +} + +DOUBLE_BATTLE_TEST("Steel Beam makes the user lose 1/2 of its Max HP in a double battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_STEEL_BEAM, target:opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, playerLeft); + HP_BAR(playerLeft, damage: 200); + NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. + } +} + +SINGLE_BATTLE_TEST("Steel Beam causes the user to faint when below 1/2 of its Max HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player, hp: 0); + MESSAGE("Wobbuffet fainted!"); + } +} + +DOUBLE_BATTLE_TEST("Steel Beam causes the user to faint when below 1/2 of its Max HP in a double battle") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_STEEL_BEAM, target:opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, playerLeft); + HP_BAR(playerLeft, hp: 0); + MESSAGE("Wobbuffet fainted!"); + } +} + +SINGLE_BATTLE_TEST("Steel Beam causes the user & the target to faint when below 1/2 of its Max HP") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200) ; MaxHP(400); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(opponent, hp: 0); + MESSAGE("Foe Wobbuffet fainted!"); + HP_BAR(player, hp: 0); + MESSAGE("Wobbuffet fainted!"); } } @@ -32,8 +91,58 @@ SINGLE_BATTLE_TEST("Steel Beam hp loss is prevented by Magic Guard") } WHEN { TURN { MOVE(player, MOVE_STEEL_BEAM); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); - HP_BAR(opponent); NOT HP_BAR(player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + } +} + +SINGLE_BATTLE_TEST("Steel Beam makes the user lose HP even if the opposing mon protected") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Steel Beam does not cause the user to lose HP if there is no target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_MEMENTO); MOVE(player, MOVE_STEEL_BEAM); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player); + } + MESSAGE("Wobbuffet used Steel Beam!"); + MESSAGE("But it failed!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Steel Beam is not blocked by Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_STEEL_BEAM); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEEL_BEAM, player); + HP_BAR(player, damage: 200); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Steel Beam!"); + } } } diff --git a/test/battle/move_effect/mind_blown.c b/test/battle/move_effect/mind_blown.c index 4f4d31cb18..f1b7d8b98a 100644 --- a/test/battle/move_effect/mind_blown.c +++ b/test/battle/move_effect/mind_blown.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(gMovesInfo[MOVE_MIND_BLOWN].effect == EFFECT_MIND_BLOWN); } -SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } @@ -14,13 +14,13 @@ SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP") } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); HP_BAR(player, damage: 200); - ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. } } -DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP in a double battle") +DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its Max HP in a double battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } @@ -30,13 +30,13 @@ DOUBLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its HP in a double bat } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, damage: 200); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); + HP_BAR(playerLeft, damage: 200); NOT MESSAGE("Wobbuffet fainted!"); // Wobb had more than 1/2 of its HP, so it can't faint. } } -SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } @@ -44,13 +44,13 @@ SINGLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player, hp: 0); MESSAGE("Wobbuffet fainted!"); } } -DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP in a double battle") +DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its Max HP in a double battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200); MaxHP(400); } @@ -60,13 +60,13 @@ DOUBLE_BATTLE_TEST("Mind Blown causes the user to faint when below 1/2 of its HP } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); + HP_BAR(playerLeft, hp: 0); MESSAGE("Wobbuffet fainted!"); } } -SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below 1/2 of its HP") +SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below 1/2 of its Max HP") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { HP(200) ; MaxHP(400); } @@ -75,10 +75,10 @@ SINGLE_BATTLE_TEST("Mind Blown causes the user & the target to faint when below } WHEN { TURN { MOVE(player, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(player, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); HP_BAR(opponent, hp: 0); MESSAGE("Foe Wobbuffet fainted!"); + HP_BAR(player, hp: 0); MESSAGE("Wobbuffet fainted!"); } } @@ -94,7 +94,6 @@ DOUBLE_BATTLE_TEST("Mind Blown causes everyone to faint in a double battle") } WHEN { TURN { MOVE(playerLeft, MOVE_MIND_BLOWN); } } SCENE { - HP_BAR(playerLeft, hp: 0); ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, playerLeft); HP_BAR(opponentLeft, hp: 0); MESSAGE("Foe Abra fainted!"); @@ -102,6 +101,7 @@ DOUBLE_BATTLE_TEST("Mind Blown causes everyone to faint in a double battle") MESSAGE("Wynaut fainted!"); HP_BAR(opponentRight, hp: 0); MESSAGE("Foe Kadabra fainted!"); + HP_BAR(playerLeft, hp: 0); MESSAGE("Wobbuffet fainted!"); } } @@ -118,3 +118,69 @@ SINGLE_BATTLE_TEST("Mind Blown hp loss is prevented by Magic Guard") ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); } } + +SINGLE_BATTLE_TEST("Mind Blown is blocked by Damp") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(400); MaxHP(400); } + OPPONENT(SPECIES_GOLDUCK) { Ability(ABILITY_DAMP); } + } WHEN { + TURN { MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player, damage: 200); + } + ABILITY_POPUP(opponent, ABILITY_DAMP); + MESSAGE("Foe Golduck's Damp prevents Wobbuffet from using Mind Blown!"); + } +} + +SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if the opposing mon protected") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if it is absorbed by Flash Fire") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_MIND_BLOWN].type == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CYNDAQUIL) { Ability(ABILITY_FLASH_FIRE); } + } WHEN { + TURN { MOVE(player, MOVE_MIND_BLOWN); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_FLASH_FIRE); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Mind Blown does not cause the user to lose HP if there is no target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_MEMENTO); MOVE(player, MOVE_MIND_BLOWN); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIND_BLOWN, player); + HP_BAR(player); + } + MESSAGE("Wobbuffet used Mind Blown!"); + MESSAGE("But it failed!"); + MESSAGE("2 sent out Wobbuffet!"); + } +}