diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 53af7fc3269a..5a45cccfedb6 100755 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1372,6 +1372,14 @@ .4byte \failInstr .endm + .macro setglaiverush + callnative BS_SetGlaiveRush + .endm + + .macro tryrelicsong + callnative BS_TryRelicSong + .endm + .macro setzeffect callnative BS_SetZEffect .endm @@ -1500,7 +1508,7 @@ callnative BS_TryRecycleBerry .4byte \ptr .endm - + .macro updatedynamax callnative BS_UpdateDynamax .endm @@ -2053,10 +2061,6 @@ .4byte \jumpInstr .endm - .macro applyplasmafists - various BS_ATTACKER, VARIOUS_APPLY_PLASMA_FISTS - .endm - .macro jumpifweatheraffected battler:req, flags:req, jumpInstr:req various \battler, VARIOUS_JUMP_IF_WEATHER_AFFECTED .4byte \flags diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 0ae1279f2e67..ab625c627a4f 100755 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -440,11 +440,17 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectSyrupBomb @ EFFECT_SYRUP_BOMB .4byte BattleScript_EffectHit @ EFFECT_IVY_CUDGEL .4byte BattleScript_EffectMaxMove @ EFFECT_MAX_MOVE + .4byte BattleScript_EffectGlaiveRush @ EFFECT_GLAIVE_RUSH + +BattleScript_EffectGlaiveRush:: + call BattleScript_EffectHit_Ret + jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_TryFaintMon + setglaiverush + goto BattleScript_TryFaintMon BattleScript_EffectSyrupBomb:: setmoveeffect MOVE_EFFECT_SYRUP_BOMB call BattleScript_EffectHit_Ret - seteffectwithchance tryfaintmon BS_TARGET goto BattleScript_MoveEnd @@ -529,7 +535,6 @@ BattleScript_EffectMakeItRain: BattleScript_MakeItRainContinuous: setmoveeffect MOVE_EFFECT_PAYDAY call BattleScript_EffectHit_Ret - seteffectwithchance tryfaintmon BS_TARGET setmoveeffect MOVE_EFFECT_SP_ATK_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN seteffectprimary @@ -1167,9 +1172,8 @@ BattleScript_HyperspaceFuryRemoveProtect:: BattleScript_EffectPlasmaFists: call BattleScript_EffectHit_Ret - seteffectwithchance tryfaintmon BS_TARGET - applyplasmafists + orword gFieldStatuses, STATUS_FIELD_ION_DELUGE printstring STRINGID_IONDELUGEON waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd @@ -1345,12 +1349,12 @@ BattleScript_NoMoveEffect: goto BattleScript_EffectHit BattleScript_EffectRelicSong: - setmoveeffect MOVE_EFFECT_RELIC_SONG | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN + setmoveeffect MOVE_EFFECT_SLEEP call BattleScript_EffectHit_Ret - seteffectwithchance - argumentstatuseffect tryfaintmon BS_TARGET - goto BattleScript_MoveEnd + moveendall + tryrelicsong + end BattleScript_EffectAllySwitch: attackcanceler @@ -3135,6 +3139,7 @@ BattleScript_HitFromAtkAnimation:: resultmessage waitmessage B_WAIT_TIME_LONG seteffectwithchance +BattleScript_TryFaintMon:: tryfaintmon BS_TARGET BattleScript_MoveEnd:: moveendall @@ -3159,6 +3164,7 @@ BattleScript_EffectHit_Ret:: waitmessage B_WAIT_TIME_LONG resultmessage waitmessage B_WAIT_TIME_LONG + seteffectwithchance return BattleScript_EffectNaturalGift: @@ -3353,7 +3359,6 @@ BattleScript_EffectPoisonHit: BattleScript_EffectAbsorb:: call BattleScript_EffectHit_Ret - seteffectwithchance jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock setdrainedhp manipulatedamage DMG_BIG_ROOT @@ -3788,7 +3793,6 @@ BattleScript_EffectFlinchHit:: BattleScript_EffectFlinchStatus: setmoveeffect MOVE_EFFECT_FLINCH call BattleScript_EffectHit_Ret - seteffectwithchance argumentstatuseffect tryfaintmon BS_TARGET goto BattleScript_MoveEnd @@ -7836,7 +7840,7 @@ BattleScript_AttackerFormChangeMoveEffect:: printstring STRINGID_PKMNTRANSFORMED waitmessage B_WAIT_TIME_LONG handleformchange BS_ATTACKER, 2 - end3 + return BattleScript_BallFetch:: call BattleScript_AbilityPopUp diff --git a/include/battle_util.h b/include/battle_util.h index 7c9b4b79ee9e..4f8312152db9 100755 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -157,7 +157,7 @@ bool32 CanBattlerEscape(u32 battler); // no ability check void BattleScriptExecute(const u8 *BS_ptr); void BattleScriptPushCursorAndCallback(const u8 *BS_ptr); u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn); -void ClearFuryCutterDestinyBondGrudge(u32 battler); +void ClearVariousBattlerFlags(u32 battler); void HandleAction_RunBattleScript(void); u32 SetRandomTarget(u32 battler); u32 GetMoveTarget(u16 move, u8 setTarget); diff --git a/include/constants/battle.h b/include/constants/battle.h index 482ad0385cda..b1900b7bb50f 100755 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -183,12 +183,12 @@ #define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) #define STATUS4_ELECTRIFIED (1 << 0) -#define STATUS4_PLASMA_FISTS (1 << 1) -#define STATUS4_MUD_SPORT (1 << 2) // Only used if B_SPORT_TURNS < GEN_6 -#define STATUS4_WATER_SPORT (1 << 3) // Only used if B_SPORT_TURNS < GEN_6 -#define STATUS4_INFINITE_CONFUSION (1 << 4) // Used for Berserk Gene -#define STATUS4_SALT_CURE (1 << 5) -#define STATUS4_SYRUP_BOMB (1 << 6) +#define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6 +#define STATUS4_WATER_SPORT (1 << 2) // Only used if B_SPORT_TURNS < GEN_6 +#define STATUS4_INFINITE_CONFUSION (1 << 3) // Used for Berserk Gene +#define STATUS4_SALT_CURE (1 << 4) +#define STATUS4_SYRUP_BOMB (1 << 5) +#define STATUS4_GLAIVE_RUSH (1 << 6) #define HITMARKER_WAKE_UP_CLEAR (1 << 4) // Cleared when waking up. Never set or checked. #define HITMARKER_SKIP_DMG_TRACK (1 << 5) @@ -380,18 +380,17 @@ #define MOVE_EFFECT_INCINERATE 67 #define MOVE_EFFECT_BUG_BITE 68 #define MOVE_EFFECT_RECOIL_HP_25 69 -#define MOVE_EFFECT_RELIC_SONG 70 -#define MOVE_EFFECT_TRAP_BOTH 71 -#define MOVE_EFFECT_DOUBLE_SHOCK 72 -#define MOVE_EFFECT_ROUND 73 -#define MOVE_EFFECT_STOCKPILE_WORE_OFF 74 -#define MOVE_EFFECT_DIRE_CLAW 75 -#define MOVE_EFFECT_STEALTH_ROCK 76 -#define MOVE_EFFECT_SPIKES 77 -#define MOVE_EFFECT_TRIPLE_ARROWS 78 -#define MOVE_EFFECT_SYRUP_BOMB 79 - -#define NUM_MOVE_EFFECTS 80 +#define MOVE_EFFECT_TRAP_BOTH 70 +#define MOVE_EFFECT_DOUBLE_SHOCK 71 +#define MOVE_EFFECT_ROUND 72 +#define MOVE_EFFECT_STOCKPILE_WORE_OFF 73 +#define MOVE_EFFECT_DIRE_CLAW 74 +#define MOVE_EFFECT_STEALTH_ROCK 75 +#define MOVE_EFFECT_SPIKES 76 +#define MOVE_EFFECT_TRIPLE_ARROWS 77 +#define MOVE_EFFECT_SYRUP_BOMB 78 + +#define NUM_MOVE_EFFECTS 79 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index aa378ac15da8..4e21557766fd 100755 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -417,7 +417,8 @@ #define EFFECT_SYRUP_BOMB 411 #define EFFECT_IVY_CUDGEL 412 #define EFFECT_MAX_MOVE 413 +#define EFFECT_GLAIVE_RUSH 414 -#define NUM_BATTLE_MOVE_EFFECTS 414 +#define NUM_BATTLE_MOVE_EFFECTS 415 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 678ffc623444..f3a0eecf26d1 100755 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -209,47 +209,45 @@ #define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 116 #define VARIOUS_CONSUME_BERRY 117 #define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 118 -#define VARIOUS_APPLY_PLASMA_FISTS 119 -#define VARIOUS_JUMP_IF_SPECIES 120 -#define VARIOUS_UPDATE_ABILITY_POPUP 121 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 122 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 123 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 124 -#define VARIOUS_PHOTON_GEYSER_CHECK 125 -#define VARIOUS_SHELL_SIDE_ARM_CHECK 126 -#define VARIOUS_TRY_NO_RETREAT 127 -#define VARIOUS_TRY_TAR_SHOT 128 -#define VARIOUS_CAN_TAR_SHOT_WORK 129 -#define VARIOUS_CHECK_POLTERGEIST 130 -#define VARIOUS_SET_OCTOLOCK 131 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 132 -#define VARIOUS_TRY_END_NEUTRALIZING_GAS 133 -#define VARIOUS_JUMP_IF_UNDER_200 134 -#define VARIOUS_SET_SKY_DROP 135 -#define VARIOUS_CLEAR_SKY_DROP 136 -#define VARIOUS_SKY_DROP_YAWN 137 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 138 -#define VARIOUS_CURE_CERTAIN_STATUSES 139 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 140 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 141 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 142 -#define VARIOUS_SAVE_BATTLER_ITEM 143 -#define VARIOUS_RESTORE_BATTLER_ITEM 144 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 145 -#define VARIOUS_SET_BEAK_BLAST 146 -#define VARIOUS_SWAP_SIDE_STATUSES 147 -#define VARIOUS_SWAP_STATS 148 -#define VARIOUS_TEATIME_INVUL 149 -#define VARIOUS_TEATIME_TARGETS 150 -#define VARIOUS_TRY_WIND_RIDER_POWER 151 -#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 152 -#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 153 -#define VARIOUS_STORE_HEALING_WISH 154 -#define VARIOUS_HIT_SWITCH_TARGET_FAILED 155 -#define VARIOUS_TRY_REVIVAL_BLESSING 156 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE 157 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION 158 -#define VARIOUS_GIVE_DROPPED_ITEMS 159 +#define VARIOUS_JUMP_IF_SPECIES 119 +#define VARIOUS_UPDATE_ABILITY_POPUP 120 +#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 121 +#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 122 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 123 +#define VARIOUS_PHOTON_GEYSER_CHECK 124 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 125 +#define VARIOUS_TRY_NO_RETREAT 126 +#define VARIOUS_TRY_TAR_SHOT 127 +#define VARIOUS_CAN_TAR_SHOT_WORK 128 +#define VARIOUS_CHECK_POLTERGEIST 129 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 130 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 131 +#define VARIOUS_JUMP_IF_UNDER_200 132 +#define VARIOUS_SET_SKY_DROP 133 +#define VARIOUS_CLEAR_SKY_DROP 134 +#define VARIOUS_SKY_DROP_YAWN 135 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 136 +#define VARIOUS_CURE_CERTAIN_STATUSES 137 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 138 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 139 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 140 +#define VARIOUS_SAVE_BATTLER_ITEM 141 +#define VARIOUS_RESTORE_BATTLER_ITEM 142 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 143 +#define VARIOUS_SET_BEAK_BLAST 144 +#define VARIOUS_SWAP_SIDE_STATUSES 145 +#define VARIOUS_SWAP_STATS 146 +#define VARIOUS_TEATIME_INVUL 147 +#define VARIOUS_TEATIME_TARGETS 148 +#define VARIOUS_TRY_WIND_RIDER_POWER 149 +#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 150 +#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 151 +#define VARIOUS_STORE_HEALING_WISH 152 +#define VARIOUS_HIT_SWITCH_TARGET_FAILED 153 +#define VARIOUS_TRY_REVIVAL_BLESSING 154 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE 155 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION 156 +#define VARIOUS_GIVE_DROPPED_ITEMS 157 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_main.c b/src/battle_main.c index 414687b0dec3..89573d502000 100755 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5769,13 +5769,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) } attackerAbility = GetBattlerAbility(battlerAtk); - GET_MOVE_TYPE(move, moveType); - if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL) - || gStatuses4[battlerAtk] & STATUS4_ELECTRIFIED) - { - gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_2; - } - else if (gBattleMoves[move].type == TYPE_NORMAL + + if (gBattleMoves[move].type == TYPE_NORMAL && gBattleMoves[move].effect != EFFECT_HIDDEN_POWER && gBattleMoves[move].effect != EFFECT_WEATHER_BALL && gBattleMoves[move].effect != EFFECT_CHANGE_TYPE_ON_ITEM @@ -5804,15 +5799,16 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) { gBattleStruct->dynamicMoveType = TYPE_WATER | F_DYNAMIC_TYPE_2; } - else if (gStatuses4[battlerAtk] & STATUS4_PLASMA_FISTS && moveType == TYPE_NORMAL) - { - gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_2; - } else if (move == MOVE_AURA_WHEEL && gBattleMons[battlerAtk].species == SPECIES_MORPEKO_HANGRY) { gBattleStruct->dynamicMoveType = TYPE_DARK | F_DYNAMIC_TYPE_2; } + GET_MOVE_TYPE(move, moveType); + if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL) + || gStatuses4[battlerAtk] & STATUS4_ELECTRIFIED) + gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_2; + // Check if a gem should activate. GET_MOVE_TYPE(move, moveType); if (holdEffect == HOLD_EFFECT_GEMS diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index bea44d0a6cf7..8b3428001363 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1531,12 +1531,9 @@ static bool8 JumpIfMoveAffectedByProtect(u16 move) static bool32 AccuracyCalcHelper(u16 move) { - if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) - { - JumpIfMoveFailed(7, move); - return TRUE; - } - else if (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON)) + if ((gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker) + || (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON)) + || gStatuses4[gBattlerTarget] & STATUS4_GLAIVE_RUSH) { JumpIfMoveFailed(7, move); return TRUE; @@ -3565,21 +3562,6 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite; } break; - case MOVE_EFFECT_RELIC_SONG: - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SHEER_FORCE && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED)) - { - if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_ARIA) - { - gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_PIROUETTE; - BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeMoveEffect); - } - else if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_PIROUETTE) - { - gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_ARIA; - BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeMoveEffect); - } - } - break; case MOVE_EFFECT_TRAP_BOTH: if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_ESCAPE_PREVENTION)) { @@ -10270,13 +10252,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr = cmd->nextInstr; return; } - case VARIOUS_APPLY_PLASMA_FISTS: - { - VARIOUS_ARGS(); - for (i = 0; i < gBattlersCount; i++) - gStatuses4[i] |= STATUS4_PLASMA_FISTS; - break; - } case VARIOUS_JUMP_IF_SPECIES: { VARIOUS_ARGS(u16 species, const u8 *jumpInstr); @@ -16363,3 +16338,30 @@ void BS_TrySetOctolock(void) gBattlescriptCurrInstr = cmd->nextInstr; } } + +void BS_SetGlaiveRush(void) +{ + NATIVE_ARGS(); + + gStatuses4[gBattlerAttacker] |= STATUS4_GLAIVE_RUSH; + + gBattlescriptCurrInstr = cmd->nextInstr; +} + +void BS_TryRelicSong(void) +{ + NATIVE_ARGS(); + + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_SHEER_FORCE && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED)) + { + if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_ARIA) + gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_PIROUETTE; + else if (gBattleMons[gBattlerAttacker].species == SPECIES_MELOETTA_PIROUETTE) + gBattleMons[gBattlerAttacker].species = SPECIES_MELOETTA_ARIA; + + BattleScriptPush(cmd->nextInstr); + gBattlescriptCurrInstr = BattleScript_AttackerFormChangeMoveEffect; + } + else + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_util.c b/src/battle_util.c index a4303508bd3e..c744e40dee1a 100755 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -322,7 +322,6 @@ void HandleAction_UseMove(void) gCurrentMove = gBattleStruct->zmove.toBeUsed[gBattlerAttacker]; } - if (gBattleMons[gBattlerAttacker].hp != 0) { if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) @@ -557,7 +556,7 @@ void HandleAction_UseItem(void) gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; gBattle_BG0_X = 0; gBattle_BG0_Y = 0; - ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + ClearVariousBattlerFlags(gBattlerAttacker); gLastUsedItem = gBattleResources->bufferB[gBattlerAttacker][1] | (gBattleResources->bufferB[gBattlerAttacker][2] << 8); gBattlescriptCurrInstr = gBattlescriptsForUsingItem[ItemId_GetBattleUsage(gLastUsedItem) - 1]; @@ -681,7 +680,7 @@ void HandleAction_Run(void) { if (!TryRunFromBattle(gBattlerAttacker)) // failed to run away { - ClearFuryCutterDestinyBondGrudge(gBattlerAttacker); + ClearVariousBattlerFlags(gBattlerAttacker); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_CANT_ESCAPE_2; gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; @@ -1334,6 +1333,7 @@ const u8* CancelMultiTurnMoves(u32 battler) gDisableStructs[battler].rolloutTimer = 0; gDisableStructs[battler].furyCutterCounter = 0; + return result; } @@ -2468,7 +2468,6 @@ enum ENDTURN_POWDER, ENDTURN_THROAT_CHOP, ENDTURN_SLOW_START, - ENDTURN_PLASMA_FISTS, ENDTURN_CUD_CHEW, ENDTURN_TORMENT, // supposedly this goes after Taunt, before Encore, but Encore is first right now? ENDTURN_SALT_CURE, @@ -3005,10 +3004,6 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; - case ENDTURN_PLASMA_FISTS: - gStatuses4[battler] &= ~STATUS4_PLASMA_FISTS; - gBattleStruct->turnEffectsTracker++; - break; case ENDTURN_CUD_CHEW: if (GetBattlerAbility(battler) == ABILITY_CUD_CHEW && !gDisableStructs[battler].cudChew && ItemId_GetPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES) gDisableStructs[battler].cudChew = TRUE; @@ -3314,6 +3309,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) case CANCELLER_FLAGS: // flags clear gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_DESTINY_BOND; gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE; + gStatuses4[gBattlerAttacker] &= ~ STATUS4_GLAIVE_RUSH; gBattleScripting.tripleKickPower = 0; gBattleStruct->atkCancellerTracker++; break; @@ -7901,11 +7897,12 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn) return effect; } -void ClearFuryCutterDestinyBondGrudge(u32 battler) +void ClearVariousBattlerFlags(u32 battler) { gDisableStructs[battler].furyCutterCounter = 0; gBattleMons[battler].status2 &= ~STATUS2_DESTINY_BOND; gStatuses3[battler] &= ~STATUS3_GRUDGE; + gStatuses4[battler] &= ~ STATUS4_GLAIVE_RUSH; } void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands @@ -9567,6 +9564,13 @@ static inline uq4_12_t GetCriticalModifier(bool32 isCrit) return UQ_4_12(1.0); } +static inline uq4_12_t GetGlaiveRushModifier(u32 battlerDef) +{ + if (gStatuses4[battlerDef] & STATUS4_GLAIVE_RUSH) + return UQ_4_12(2.0); + return UQ_4_12(1.0); +} + static inline uq4_12_t GetZMaxMoveAgainstProtectionModifier(u32 battlerDef, u32 move) { if ((gBattleStruct->zmove.active || IsMaxMove(move)) && IS_BATTLER_PROTECTED(battlerDef)) @@ -9802,7 +9806,8 @@ static inline s32 DoMoveDamageCalcVars(u32 move, u32 battlerAtk, u32 battlerDef, DAMAGE_APPLY_MODIFIER(GetParentalBondModifier(battlerAtk)); DAMAGE_APPLY_MODIFIER(GetWeatherDamageModifier(battlerAtk, move, moveType, holdEffectAtk, holdEffectDef, weather)); DAMAGE_APPLY_MODIFIER(GetCriticalModifier(isCrit)); - // TODO: Glaive Rush (Gen IX effect) + DAMAGE_APPLY_MODIFIER(GetGlaiveRushModifier(battlerDef)); + if (randomFactor) { dmg *= 100 - RandomUniform(RNG_DAMAGE_MODIFIER, 0, 15); diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index af733b7e1535..80f08c419440 100755 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -9585,7 +9585,6 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = .priority = 0, .split = SPLIT_SPECIAL, .zMoveEffect = Z_EFFECT_NONE, - .argument = STATUS1_SLEEP, .sheerForceBoost = TRUE, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, @@ -13685,7 +13684,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_DYNAMAX] = [MOVE_GLAIVE_RUSH] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_GLAIVE_RUSH + .effect = EFFECT_GLAIVE_RUSH, .power = 120, .type = TYPE_DRAGON, .accuracy = 100, diff --git a/test/battle/move_effect/flinch_status.c b/test/battle/move_effect/flinch_status.c new file mode 100644 index 000000000000..6d0012d42cda --- /dev/null +++ b/test/battle/move_effect/flinch_status.c @@ -0,0 +1,64 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_THUNDER_FANG].effect == EFFECT_FLINCH_STATUS); + ASSUME(gBattleMoves[MOVE_THUNDER_FANG].argument == STATUS1_PARALYSIS); + ASSUME(gBattleMoves[MOVE_ICE_FANG].effect == EFFECT_FLINCH_STATUS); + ASSUME(gBattleMoves[MOVE_ICE_FANG].argument == STATUS1_FREEZE); + ASSUME(gBattleMoves[MOVE_FIRE_FANG].effect == EFFECT_FLINCH_STATUS); + ASSUME(gBattleMoves[MOVE_FIRE_FANG].argument == STATUS1_BURN); +} + +SINGLE_BATTLE_TEST("Thunder, Ice and Fire Fang inflict status 10% of the time") +{ + u16 move; + + PARAMETRIZE { move = MOVE_THUNDER_FANG; } + PARAMETRIZE { move = MOVE_ICE_FANG; } + PARAMETRIZE { move = MOVE_FIRE_FANG; } + + PASSES_RANDOMLY(10, 100, RNG_SECONDARY_EFFECT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + if (move == MOVE_THUNDER_FANG) { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent); + STATUS_ICON(opponent, paralysis: TRUE); + } if (move == MOVE_ICE_FANG) { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_FRZ, opponent); + STATUS_ICON(opponent, freeze: TRUE); + } if (move == MOVE_FIRE_FANG) { + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponent); + STATUS_ICON(opponent, burn: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Thunder, Ice and Fire Fang cause the opponent to flinch 10% of the time") +{ + u16 move; + + PARAMETRIZE { move = MOVE_THUNDER_FANG; } + PARAMETRIZE { move = MOVE_ICE_FANG; } + PARAMETRIZE { move = MOVE_FIRE_FANG; } + + PASSES_RANDOMLY(10, 100, RNG_SECONDARY_EFFECT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(100); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + MESSAGE("Foe Wobbuffet flinched!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } +} diff --git a/test/battle/move_effect/glaive_rush.c b/test/battle/move_effect/glaive_rush.c new file mode 100644 index 000000000000..6cbc92fa9546 --- /dev/null +++ b/test/battle/move_effect/glaive_rush.c @@ -0,0 +1,143 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_GLAIVE_RUSH].effect == EFFECT_GLAIVE_RUSH); +} + +SINGLE_BATTLE_TEST("If Glaive Rush is successful moves targeted at the user do not check accuracy") +{ + PASSES_RANDOMLY(100, 100, RNG_ACCURACY); + GIVEN { + ASSUME(gBattleMoves[MOVE_MEGA_PUNCH].accuracy == 85); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GLAIVE_RUSH); MOVE(opponent, MOVE_MEGA_PUNCH); } + } SCENE { + MESSAGE("Wobbuffet used Glaive Rush!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_PUNCH, opponent); + } +} + +SINGLE_BATTLE_TEST("If Glaive Rush is successful, moves targeted at the user deal double damage") +{ + s16 glaiveRushEffectedDmg; + s16 normalDmg; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GLAIVE_RUSH); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &glaiveRushEffectedDmg); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &normalDmg); + } THEN { + EXPECT_MUL_EQ(normalDmg, Q_4_12(2.0), glaiveRushEffectedDmg); + } +} + +SINGLE_BATTLE_TEST("If Glaive Rush is successful, moves targeted at the user deal double damage until the user moves again") +{ + s16 glaiveRushEffectedDmg; + s16 normalDmg; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_GLAIVE_RUSH); } + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &normalDmg); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &glaiveRushEffectedDmg); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } THEN { + EXPECT_MUL_EQ(normalDmg, Q_4_12(2.0), glaiveRushEffectedDmg); + } +} + +SINGLE_BATTLE_TEST("If Glaive Rush isn't successful moves targeted at the user don't deal double damage", s16 damage) +{ + bool32 missesGlaiveRush; + + PARAMETRIZE { missesGlaiveRush = FALSE; } + PARAMETRIZE { missesGlaiveRush = TRUE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); } + } WHEN { + TURN { MOVE(player, MOVE_GLAIVE_RUSH, hit: missesGlaiveRush); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (!missesGlaiveRush) + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Glaive Rush doesn't affect the user if the effect is blocked", s16 damage) +{ + u32 species; + + PARAMETRIZE { species = SPECIES_CLEFAIRY; } + PARAMETRIZE { species = SPECIES_WOBBUFFET; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species) { Attack(50); } + } WHEN { + TURN { MOVE(player, MOVE_GLAIVE_RUSH); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (species == SPECIES_CLEFAIRY) + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Glaive Rush status last until the the user's next turn") +{ + s16 normalDmgFristHit; + s16 normalDmgSecondHit; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GLAIVE_RUSH); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLAIVE_RUSH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &normalDmgFristHit); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &normalDmgSecondHit); + } THEN { + EXPECT_EQ(normalDmgFristHit, normalDmgSecondHit); + } +} diff --git a/test/battle/move_effect/plasma_fists.c b/test/battle/move_effect/plasma_fists.c new file mode 100644 index 000000000000..daef90ec5053 --- /dev/null +++ b/test/battle/move_effect/plasma_fists.c @@ -0,0 +1,99 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_PLASMA_FISTS].effect == EFFECT_PLASMA_FISTS); +} + +SINGLE_BATTLE_TEST("Ion Duldge turns normal moves into electric for the remainder of the current turn") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_ION_DELUGE].effect == EFFECT_ION_DELUGE); + PLAYER(SPECIES_KRABBY); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ION_DELUGE); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Krabby used Ion Deluge!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ION_DELUGE, player); + MESSAGE("A deluge of ions showers the battlefield!"); + MESSAGE("Foe Wobbuffet used Tackle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + MESSAGE("It's super effective!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + NOT MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Plasma Fists turns normal moves into electric for the remainder of the current turn") +{ + GIVEN { + PLAYER(SPECIES_KRABBY); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Krabby used Plasma Fists!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + MESSAGE("Foe Wobbuffet used Tackle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + MESSAGE("It's super effective!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + NOT MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Plasma Fists type-changing effect is applied after Pixilate") +{ + GIVEN { + PLAYER(SPECIES_KRABBY) { Speed(300); }; + OPPONENT(SPECIES_ALTARIA) { Speed(1); Item(ITEM_ALTARIANITE); } + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_EMBER, megaEvolve: TRUE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent); + MESSAGE("Krabby used Plasma Fists!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + MESSAGE("Foe Altaria used Ember!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + NOT MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Plasma Fists type-changing effect is applied after Normalize") +{ + GIVEN { + PLAYER(SPECIES_KRABBY); + OPPONENT(SPECIES_SKITTY) { Ability(ABILITY_NORMALIZE); } + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_EMBER); } + } SCENE { + MESSAGE("Krabby used Plasma Fists!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + MESSAGE("Foe Skitty used Ember!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Plasma Fists turns normal type dynamax-moves into electric type moves") +{ + GIVEN { + PLAYER(SPECIES_KRABBY) { Speed(100); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE, dynamax: TRUE); } + } SCENE { + MESSAGE("Krabby used Plasma Fists!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + MESSAGE("Foe Wobbuffet used Max Lightning!"); + MESSAGE("It's super effective!"); + } +} diff --git a/test/battle/move_effect/relic_song.c b/test/battle/move_effect/relic_song.c new file mode 100644 index 000000000000..7b14a57e7210 --- /dev/null +++ b/test/battle/move_effect/relic_song.c @@ -0,0 +1,162 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_RELIC_SONG].effect == EFFECT_RELIC_SONG); + ASSUME(P_GEN_5_POKEMON == TRUE); +} + +SINGLE_BATTLE_TEST("Relic Song has a 10% chance to put the target to sleep") +{ + PASSES_RANDOMLY(10, 100, RNG_SECONDARY_EFFECT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + STATUS_ICON(opponent, sleep: TRUE); + } +} + +SINGLE_BATTLE_TEST("Relic Song is prevented by Soundproof") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VOLTORB) { Ability(ABILITY_SOUNDPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF); + MESSAGE("Foe Voltorb's Soundproof blocks Relic Song!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + } + } +} + +SINGLE_BATTLE_TEST("Relic Song will become a Water-type move when used by a Pokémon with the Ability Liquid Voice") +{ + GIVEN { + ASSUME(P_GEN_7_POKEMON == TRUE); + PLAYER(SPECIES_VULPIX); + OPPONENT(SPECIES_POPPLIO) { Ability(ABILITY_LIQUID_VOICE); } + } WHEN { + TURN { MOVE(opponent, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, opponent); + HP_BAR(player); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Relic Song is blocked by Throat Chop") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_THROAT_CHOP); MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_THROAT_CHOP, opponent); + HP_BAR(player); + MESSAGE("Wobbuffet can't use Relic Song due to Throat Chop!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + } +} + +SINGLE_BATTLE_TEST("Relic Song transforms Meloetta if used successfully") +{ + GIVEN { + PLAYER(SPECIES_MELOETTA_ARIA); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + MESSAGE("Meloetta transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_MELOETTA_PIROUETTE); + } +} + +SINGLE_BATTLE_TEST("Relic Song transforms Meloetta twice if used successfully") +{ + GIVEN { + PLAYER(SPECIES_MELOETTA_ARIA); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RELIC_SONG); } + TURN { MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + MESSAGE("Meloetta transformed!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + MESSAGE("Meloetta transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_MELOETTA_ARIA); + } +} + +SINGLE_BATTLE_TEST("Relic Song transformation is the last thing that happens after it hits") +{ + GIVEN { + PLAYER(SPECIES_MELOETTA_ARIA); + OPPONENT(SPECIES_GOSSIFLEUR) { HP(1); Ability(ABILITY_COTTON_DOWN); } + } WHEN { + TURN { MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + MESSAGE("Foe Gossifleur fainted!"); + ABILITY_POPUP(opponent, ABILITY_COTTON_DOWN); + MESSAGE("Meloetta's Speed fell!"); + MESSAGE("Meloetta transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_MELOETTA_PIROUETTE); + } +} + +DOUBLE_BATTLE_TEST("Relic Song transforms once Meloetta in a double battle") +{ + GIVEN { + PLAYER(SPECIES_MELOETTA_ARIA); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, playerLeft); + HP_BAR(opponentLeft); + HP_BAR(opponentRight); + MESSAGE("Meloetta transformed!"); + } THEN { + EXPECT_EQ(playerLeft->species, SPECIES_MELOETTA_PIROUETTE); + } +} + +SINGLE_BATTLE_TEST("Relic Song loses the form-changing effect with Sheer Force") +{ + GIVEN { + PLAYER(SPECIES_MELOETTA_ARIA); + OPPONENT(SPECIES_NIDOKING) { Ability(ABILITY_SHEER_FORCE); } + } WHEN { + TURN { MOVE(opponent, MOVE_SKILL_SWAP); MOVE(player, MOVE_RELIC_SONG); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RELIC_SONG, player); + HP_BAR(opponent); + NOT MESSAGE("Meloetta transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_MELOETTA_ARIA); + } +}