diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 25898a7d8..88bb85c87 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1311,6 +1311,12 @@ callnative BS_CalcMetalBurstDmg .4byte \failInstr .endm + + .macro jumpifcantfling battler:req, jumpInstr:req + callnative BS_JumpIfCantFling + .byte \battler + .4byte \jumpInstr + .endm .macro jumpifholdeffect battler:req, holdEffect:req, jumpInstr:req callnative BS_JumpIfHoldEffect @@ -2039,11 +2045,6 @@ .4byte \jumpInstr .endm - .macro jumpifcantfling battler:req, jumpInstr:req - various \battler, VARIOUS_JUMP_IF_CANT_FLING - .4byte \jumpInstr - .endm - .macro curecertainstatuses battler:req various \battler, VARIOUS_CURE_CERTAIN_STATUSES .endm diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 50d4638bd..e9b7c538f 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -1882,28 +1882,28 @@ Move_MAGNET_RISE: delay 0 createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 5, 5, RGB(31, 31, 20) playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER - createvisualtask AnimTask_WindUpLunge, 5, ANIM_OPPONENT_RIGHT, 0, -12, 4, 10, 10, 12, 6 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 32, 24, 190, 12, 0, 1, 0 + createvisualtask AnimTask_WindUpLunge, 5, ANIM_ATTACKER, -12, 4, 10, 10, 12, 6 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, ANIM_ATTACKER, 1, 0 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 80, 24, 22, 12, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 156, 24, 121, 13, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 80, 24, 22, 12, ANIM_ATTACKER, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 156, 24, 121, 13, ANIM_ATTACKER, 1, 1 delay 0 playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER delay 4 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 100, 24, 60, 10, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 170, 24, 42, 11, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 100, 24, 60, 10, ANIM_ATTACKER, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 170, 24, 42, 11, ANIM_ATTACKER, 1, 1 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 238, 24, 165, 10, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 238, 24, 165, 10, ANIM_ATTACKER, 1, 1 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 32, 24, 190, 12, 0, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, ANIM_ATTACKER, 1, 0 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 80, 24, 22, 12, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 156, 24, 121, 13, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 80, 24, 22, 12, ANIM_ATTACKER, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 156, 24, 121, 13, ANIM_ATTACKER, 1, 1 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 100, 24, 60, 10, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 170, 24, 42, 11, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 100, 24, 60, 10, ANIM_ATTACKER, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 170, 24, 42, 11, ANIM_ATTACKER, 1, 1 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 238, 24, 165, 10, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 238, 24, 165, 10, ANIM_ATTACKER, 1, 1 delay 0 createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 0, 0, RGB(31, 31, 20) delay 20 @@ -8927,7 +8927,7 @@ Boomburst_Doubles: Move_FAIRY_LOCK:: loadspritegfx ANIM_TAG_CHAIN_LINK @Chain Colour - loadspritegfx ANIM_TAG_FAIRY_LOCK_CHAINS @Fairy Lock Chain + loadspritegfx ANIM_TAG_FAIRY_LOCK_CHAINS @AnimTask is missing for Fairy Lock Chain setalpha 8, 8 monbg ANIM_ATK_PARTNER createvisualtask AnimTask_BlendBattleAnimPal, 0xa, F_PAL_BG, 0x1, 0x0, 0x8, 0x6B1F diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 0f394f8d2..981cf5ae3 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -918,12 +918,10 @@ BattleScript_SkyDropFlyingAlreadyConfused: goto BattleScript_ThrashConfuses BattleScript_EffectFling: + attackcanceler jumpifcantfling BS_ATTACKER, BattleScript_FailedFromAtkString - jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_FailedFromAtkString - jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_FailedFromAtkString setlastuseditem BS_ATTACKER removeitem BS_ATTACKER - attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring pause B_WAIT_TIME_SHORT @@ -965,6 +963,10 @@ BattleScript_FlingEnd: tryfaintmon BS_TARGET trysymbiosis goto BattleScript_MoveEnd + +BattleScript_FlingFailConsumeItem:: + removeitem BS_ATTACKER + goto BattleScript_FailedFromAtkString BattleScript_FlingFlameOrb: setmoveeffect MOVE_EFFECT_BURN diff --git a/include/battle_scripts.h b/include/battle_scripts.h index de9ab36bd..498845983 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -10,6 +10,7 @@ extern const u8 BattleScript_MakeMoveMissed[]; extern const u8 BattleScript_PrintMoveMissed[]; extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissed[]; +extern const u8 BattleScript_FlingFailConsumeItem[]; extern const u8 BattleScript_FailedFromAtkString[]; extern const u8 BattleScript_ButItFailed[]; extern const u8 BattleScript_StatUp[]; diff --git a/include/battle_util.h b/include/battle_util.h index 723a5362b..81b0f8760 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -192,7 +192,7 @@ void ClearIllusionMon(u32 battler); bool32 SetIllusionMon(struct Pokemon *mon, u32 battler); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battler); u8 GetBattleMoveSplit(u32 moveId); -bool32 CanFling(u8 battler); +bool32 CanFling(u32 battler); bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); bool32 HasEnoughHpToEatBerry(u32 battler, u32 hpFraction, u32 itemId); diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 20e6d7e45..581566297 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -230,7 +230,6 @@ #define VARIOUS_SET_SKY_DROP 138 #define VARIOUS_CLEAR_SKY_DROP 139 #define VARIOUS_SKY_DROP_YAWN 140 -#define VARIOUS_JUMP_IF_CANT_FLING 141 #define VARIOUS_JUMP_IF_HOLD_EFFECT 142 #define VARIOUS_CURE_CERTAIN_STATUSES 143 #define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 144 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index dfadd828f..2aed36fb9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1370,9 +1370,15 @@ static void Cmd_attackcanceler(void) } gHitMarker |= HITMARKER_OBEYS; - if (NoTargetPresent(gBattlerAttacker, gCurrentMove) && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) + // Check if no available target present on the field. + if (NoTargetPresent(gBattlerAttacker, gCurrentMove) + && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) { - gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; + if (gBattleMoves[gCurrentMove].effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. + gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem; + else + gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; + if (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) CancelMultiTurnMoves(gBattlerAttacker); return; @@ -10554,15 +10560,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr = cmd->failInstr; return; } - case VARIOUS_JUMP_IF_CANT_FLING: - { - VARIOUS_ARGS(const u8 *jumpInstr); - if (!CanFling(battler)) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } case VARIOUS_CURE_CERTAIN_STATUSES: { VARIOUS_ARGS(); @@ -15787,11 +15784,22 @@ void BS_CalcMetalBurstDmg(void) } } +void BS_JumpIfCantFling(void) +{ + NATIVE_ARGS(u8 battler, const u8 *jumpInstr); + + u32 battler = GetBattlerForBattleScript(cmd->battler); + if (!CanFling(battler)) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; +} + void BS_JumpIfMoreThanHalfHP(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); - u8 battler = GetBattlerForBattleScript(cmd->battler); + u32 battler = GetBattlerForBattleScript(cmd->battler); if (gBattleMons[battler].hp > (gBattleMons[battler].maxHP + 1) / 2) gBattlescriptCurrInstr = cmd->jumpInstr; else diff --git a/src/battle_util.c b/src/battle_util.c index 1481bcb51..9b7f09290 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6535,8 +6535,9 @@ static u8 DamagedStatBoostBerryEffect(u8 battler, u8 statId, u8 split) if (IsBattlerAlive(battler) && TARGET_TURN_DAMAGED && CompareStat(battler, statId, MAX_STAT_STAGE, CMP_LESS_THAN) - && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && GetBattleMoveSplit(gCurrentMove) == split) + && (gBattleScripting.overrideBerryRequirements + || (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && GetBattleMoveSplit(gCurrentMove) == split)) + ) { BufferStatChange(battler, statId, STRINGID_STATROSE); @@ -6742,6 +6743,12 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect) case HOLD_EFFECT_SP_DEFENSE_UP: effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, FALSE); break; + case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move + effect = DamagedStatBoostBerryEffect(battler, STAT_DEF, SPLIT_PHYSICAL); + break; + case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move + effect = DamagedStatBoostBerryEffect(battler, STAT_SPDEF, SPLIT_SPECIAL); + break; case HOLD_EFFECT_RANDOM_STAT_UP: effect = RandomStatRaiseBerry(battler, gLastUsedItem, FALSE); break; @@ -10601,11 +10608,9 @@ static u8 GetFlingPowerFromItemId(u16 itemId) return ItemId_GetFlingPower(itemId); } -// Make sure the input bank is any bank on the specific mon's side -bool32 CanFling(u8 battler) +bool32 CanFling(u32 battler) { u16 item = gBattleMons[battler].item; - u16 itemEffect = ItemId_GetHoldEffect(item); if (item == ITEM_NONE #if B_KLUTZ_FLING_INTERACTION >= GEN_5 diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c new file mode 100644 index 000000000..8016b2f22 --- /dev/null +++ b/test/battle/move_effect/fling.c @@ -0,0 +1,336 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_FLING].effect == EFFECT_FLING); +} + +SINGLE_BATTLE_TEST("Fling fails if pokemon holds no item") +{ + u16 item; + + PARAMETRIZE {item = ITEM_NONE; } + PARAMETRIZE {item = ITEM_RAZOR_CLAW; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLING);} + } SCENE { + MESSAGE("Wobbuffet used Fling!"); + if (item != ITEM_NONE) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + } else { + MESSAGE("But it failed!"); + } + } +} + +SINGLE_BATTLE_TEST("Fling fails if pokemon is under the effects of Embargo or Magic Room") +{ + u16 move; + + PARAMETRIZE {move = MOVE_CELEBRATE; } + PARAMETRIZE {move = MOVE_EMBARGO; } + PARAMETRIZE {move = MOVE_MAGIC_ROOM; } + + GIVEN { + ASSUME(gBattleMoves[MOVE_EMBARGO].effect == EFFECT_EMBARGO); + ASSUME(gBattleMoves[MOVE_MAGIC_ROOM].effect == EFFECT_MAGIC_ROOM); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RAZOR_CLAW); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Wobbuffet used Fling!"); + if (move == MOVE_CELEBRATE) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + } else { + MESSAGE("But it failed!"); + } + } +} + +SINGLE_BATTLE_TEST("Fling fails for pokemon with Klutz ability") +{ + u16 ability; + + PARAMETRIZE {ability = ABILITY_KLUTZ; } + PARAMETRIZE {ability = ABILITY_RUN_AWAY; } + + GIVEN { + ASSUME(P_GEN_4_POKEMON == TRUE); + ASSUME(B_KLUTZ_FLING_INTERACTION >= GEN_5); + PLAYER(SPECIES_BUNEARY) { Item(ITEM_RAZOR_CLAW); Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Buneary used Fling!"); + if (ability != ABILITY_KLUTZ) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + } else { + MESSAGE("But it failed!"); + } + } +} + +SINGLE_BATTLE_TEST("Fling's thrown item can be regained with Recycle") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLING);} + TURN { MOVE(player, MOVE_RECYCLE);} + TURN { MOVE(player, MOVE_FLING);} + } SCENE { + MESSAGE("Wobbuffet used Fling!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + MESSAGE("Wobbuffet used Recycle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RECYCLE, player); + MESSAGE("Wobbuffet found one Razor Claw!"); + MESSAGE("Wobbuffet used Fling!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Fling - Item is lost even when there is no target") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_SELF_DESTRUCT].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); Speed(2); } + OPPONENT(SPECIES_WOBBUFFET) {Speed(5); } + OPPONENT(SPECIES_WOBBUFFET) {Speed(5); } + } WHEN { + TURN { MOVE(opponent, MOVE_SELF_DESTRUCT); MOVE(player, MOVE_FLING); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Foe Wobbuffet used SelfDestruct!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SELF_DESTRUCT, opponent); + HP_BAR(player); + MESSAGE("Foe Wobbuffet fainted!"); + MESSAGE("Wobbuffet used Fling!"); + MESSAGE("But it failed!"); + + MESSAGE("Wobbuffet used Fling!"); + MESSAGE("But it failed!"); + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Fling - Item is lost when target protects itself") +{ + GIVEN { + ASSUME(gBattleMoves[MOVE_PROTECT].effect == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_FLING);} + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Foe Wobbuffet used Protect!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + MESSAGE("Wobbuffet used Fling!"); + MESSAGE("Foe Wobbuffet protected itself!"); + + MESSAGE("Wobbuffet used Fling!"); + MESSAGE("But it failed!"); + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Fling doesn't consume the item if pokemon is asleep/frozen/paralyzed") +{ + u32 status; + u16 item; + + PARAMETRIZE {status = STATUS1_SLEEP_TURN(2); item = ITEM_RAZOR_CLAW; } + PARAMETRIZE {status = STATUS1_PARALYSIS; item = ITEM_RAZOR_CLAW; } + PARAMETRIZE {status = STATUS1_FREEZE; item = ITEM_RAZOR_CLAW; } + PARAMETRIZE {status = STATUS1_SLEEP_TURN(2); item = ITEM_NONE; } + PARAMETRIZE {status = STATUS1_PARALYSIS; item = ITEM_NONE; } + PARAMETRIZE {status = STATUS1_FREEZE; item = ITEM_NONE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) {Item(item); Status1(status); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (status == STATUS1_FREEZE) { + TURN { MOVE(player, MOVE_FLING, WITH_RNG(RNG_FROZEN, FALSE)); } + TURN { MOVE(player, MOVE_FLING, WITH_RNG(RNG_FROZEN, TRUE)); } + } else if (status == STATUS1_PARALYSIS) { + TURN { MOVE(player, MOVE_FLING, WITH_RNG(RNG_PARALYSIS, FALSE)); } + TURN { MOVE(player, MOVE_FLING, WITH_RNG(RNG_PARALYSIS, TRUE)); } + } else { + TURN { MOVE(player, MOVE_FLING); } + TURN { MOVE(player, MOVE_FLING); } + } + } SCENE { + if (status == STATUS1_FREEZE) { + MESSAGE("Wobbuffet is frozen solid!"); + MESSAGE("Wobbuffet was defrosted!"); + } + else if (status == STATUS1_PARALYSIS) { + MESSAGE("Wobbuffet is paralyzed! It can't move!"); + } + else { + MESSAGE("Wobbuffet is fast asleep."); + MESSAGE("Wobbuffet woke up!"); + } + MESSAGE("Wobbuffet used Fling!"); + if (item != ITEM_NONE) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + } else { + MESSAGE("But it failed!"); + } + + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Fling applies special effects when throwing specific Items") +{ + u16 item, effect; + + PARAMETRIZE {item = ITEM_FLAME_ORB; effect = EFFECT_WILL_O_WISP; } + PARAMETRIZE {item = ITEM_TOXIC_ORB; effect = EFFECT_TOXIC; } + PARAMETRIZE {item = ITEM_POISON_BARB; effect = EFFECT_POISON; } + PARAMETRIZE {item = ITEM_LIGHT_BALL; effect = EFFECT_PARALYZE; } + PARAMETRIZE {item = ITEM_RAZOR_FANG; effect = EFFECT_FLINCH_HIT; } + PARAMETRIZE {item = ITEM_KINGS_ROCK; effect = EFFECT_FLINCH_HIT; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Wobbuffet used Fling!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + switch (effect) + { + case EFFECT_WILL_O_WISP: + MESSAGE("Foe Wobbuffet was burned!"); + STATUS_ICON(opponent, STATUS1_BURN); + break; + case EFFECT_PARALYZE: + MESSAGE("Foe Wobbuffet is paralyzed! It may be unable to move!"); + STATUS_ICON(opponent, STATUS1_PARALYSIS); + break; + case EFFECT_POISON: + MESSAGE("Foe Wobbuffet was poisoned!"); + STATUS_ICON(opponent, STATUS1_POISON); + break; + case EFFECT_TOXIC: + MESSAGE("Foe Wobbuffet is badly poisoned!"); + STATUS_ICON(opponent, STATUS1_TOXIC_POISON); + break; + case EFFECT_FLINCH_HIT: + MESSAGE("Foe Wobbuffet flinched!"); + break; + } + } +} + +SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even if the trigger conditions are not met") +{ + u16 item, effect; + u8 statId = 0; + u32 status1 = STATUS1_NONE; + + PARAMETRIZE { item = ITEM_ORAN_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } + PARAMETRIZE { item = ITEM_SITRUS_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } + PARAMETRIZE { item = ITEM_CHESTO_BERRY; effect = HOLD_EFFECT_CURE_SLP; status1 = STATUS1_SLEEP; } + PARAMETRIZE { item = ITEM_CHERI_BERRY; effect = HOLD_EFFECT_CURE_PAR; status1 = STATUS1_PARALYSIS; } + PARAMETRIZE { item = ITEM_PECHA_BERRY; effect = HOLD_EFFECT_CURE_PSN; status1 = STATUS1_POISON; } + PARAMETRIZE { item = ITEM_PECHA_BERRY; effect = HOLD_EFFECT_CURE_PSN; status1 = STATUS1_TOXIC_POISON; } + PARAMETRIZE { item = ITEM_RAWST_BERRY; effect = HOLD_EFFECT_CURE_BRN; status1 = STATUS1_BURN; } + PARAMETRIZE { item = ITEM_ASPEAR_BERRY; effect = HOLD_EFFECT_CURE_FRZ; status1 = STATUS1_FREEZE; } + PARAMETRIZE { item = ITEM_APICOT_BERRY; effect = HOLD_EFFECT_SP_DEFENSE_UP; statId = STAT_SPDEF; } + PARAMETRIZE { item = ITEM_MARANGA_BERRY; effect = HOLD_EFFECT_MARANGA_BERRY; statId = STAT_SPDEF; } + PARAMETRIZE { item = ITEM_GANLON_BERRY; effect = HOLD_EFFECT_DEFENSE_UP; statId = STAT_DEF; } + PARAMETRIZE { item = ITEM_KEE_BERRY; effect = HOLD_EFFECT_KEE_BERRY; statId = STAT_DEF; } + PARAMETRIZE { item = ITEM_LIECHI_BERRY; effect = HOLD_EFFECT_ATTACK_UP; statId = STAT_ATK; } + PARAMETRIZE { item = ITEM_PETAYA_BERRY; effect = HOLD_EFFECT_SP_ATTACK_UP; statId = STAT_SPATK; } + PARAMETRIZE { item = ITEM_SALAC_BERRY; effect = HOLD_EFFECT_SPEED_UP; statId = STAT_SPEED; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); HP(399); MaxHP(400); } + } WHEN { + TURN { MOVE(player, MOVE_FLING); } + } SCENE { + MESSAGE("Wobbuffet used Fling!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, player); + HP_BAR(opponent); + if (effect == HOLD_EFFECT_RESTORE_HP) { + if (item == ITEM_ORAN_BERRY) { + MESSAGE("Foe Wobbuffet's Oran Berry restored health!"); + } else { + MESSAGE("Foe Wobbuffet's Sitrus Berry restored health!"); + } + HP_BAR(opponent); + } + else if (status1 != STATUS1_NONE) { + if (status1 == STATUS1_BURN) { + MESSAGE("Foe Wobbuffet's Rawst Berry healed its burn!"); + } else if (status1 == STATUS1_SLEEP) { + MESSAGE("Foe Wobbuffet's Chesto Berry woke it from its sleep!"); + } else if (status1 == STATUS1_FREEZE) { + MESSAGE("Foe Wobbuffet's Aspear Berry defrosted it!"); + } else if (status1 == STATUS1_PARALYSIS) { + MESSAGE("Foe Wobbuffet's Cheri Berry cured paralysis!"); + } else if (status1 == STATUS1_TOXIC_POISON || status1 == STATUS1_POISON) { + MESSAGE("Foe Wobbuffet's Pecha Berry cured poison!"); + } + NOT STATUS_ICON(opponent, status1); + } + else if (statId != 0) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + if (statId == STAT_ATK) { + MESSAGE("Using Liechi Berry, the Attack of Foe Wobbuffet rose!"); + } else if (statId == STAT_DEF) { + if (item == ITEM_GANLON_BERRY) { + MESSAGE("Using Ganlon Berry, the Defense of Foe Wobbuffet rose!"); + } else { + MESSAGE("Using Kee Berry, the Defense of Foe Wobbuffet rose!"); + } + } else if (statId == STAT_SPDEF) { + if (item == ITEM_APICOT_BERRY) { + MESSAGE("Using Apicot Berry, the Sp. Def of Foe Wobbuffet rose!"); + } else { + MESSAGE("Using Maranga Berry, the Sp. Def of Foe Wobbuffet rose!"); + } + } else if (statId == STAT_SPEED) { + MESSAGE("Using Salac Berry, the Speed of Foe Wobbuffet rose!"); + } else if (statId == STAT_SPATK) { + MESSAGE("Using Petaya Berry, the Sp. Atk of Foe Wobbuffet rose!"); + } + } + } THEN { + if (effect == HOLD_EFFECT_RESTORE_HP) { + EXPECT_EQ(opponent->hp, opponent->maxHP); + } else if (status1 != STATUS1_NONE) { + EXPECT_EQ(opponent->status1, STATUS1_NONE); + } + else if (statId != 0) { + EXPECT_EQ(opponent->statStages[statId], DEFAULT_STAT_STAGE + 1); + } + } +} +