diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 93c747810..4b6cc0961 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 @@ -2028,11 +2034,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_scripts_1.s b/data/battle_scripts_1.s index 6017e5349..e7fb0149c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -836,12 +836,10 @@ BattleScript_SkyDropFlyingAlreadyConfused: goto BattleScript_ThrashConfuses BattleScript_EffectFling: - jumpifcantfling BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce - jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce - jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce + attackcanceler + jumpifcantfling BS_ATTACKER, BattleScript_FailedFromAtkString setlastuseditem BS_ATTACKER removeitem BS_ATTACKER - attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring pause B_WAIT_TIME_SHORT @@ -883,6 +881,10 @@ BattleScript_FlingEnd: tryfaintmon BS_TARGET trysymbiosis goto BattleScript_MoveEnd + +BattleScript_FlingFailConsumeItem:: + removeitem BS_ATTACKER + goto BattleScript_FailedFromAtkString BattleScript_FlingFlameOrb: setmoveeffect MOVE_EFFECT_BURN @@ -971,7 +973,7 @@ BattleScript_EffectClangorousSoul: BattleScript_EffectOctolock: attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce @@ -1019,9 +1021,9 @@ BattleScript_EffectPoltergeist: BattleScript_EffectTarShot: attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - cantarshotwork BS_TARGET, BattleScript_ButItFailedAtkStringPpReduce + cantarshotwork BS_TARGET, BattleScript_FailedFromAtkString attackstring ppreduce setstatchanger STAT_SPEED, 1, TRUE @@ -1502,7 +1504,7 @@ BattleScript_PurifyWorks: BattleScript_EffectStrengthSap: setstatchanger STAT_ATK, 1, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce @@ -2070,7 +2072,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_ButItFailedAtkStringPpReduce + defogclear BS_ATTACKER, FALSE, BattleScript_FailedFromAtkString BattleScript_DefogWorks: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring @@ -2216,9 +2218,9 @@ BattleScript_EffectClearSmog: BattleScript_EffectToxicThread: setstatchanger STAT_SPEED, 2, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_SPEED, MIN_STAT_STAGE, BattleScript_ToxicThreadWorks - jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_ButItFailedAtkStringPpReduce + jumpifstatus BS_TARGET, STATUS1_PSN_ANY, BattleScript_FailedFromAtkString BattleScript_ToxicThreadWorks: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring @@ -2572,7 +2574,7 @@ BattleScript_EffectSpeedUpHit: BattleScript_EffectMeFirst: attackcanceler attackstring - trymefirst BattleScript_ButItFailedPpReduce + trymefirst BattleScript_FailedFromPpReduce attackanimation waitanimation setbyte sB_ANIM_TURN, 0 @@ -2738,7 +2740,7 @@ BattleScript_EffectSimpleBeam: BattleScript_EffectSuckerPunch: attackcanceler - suckerpunchcheck BattleScript_ButItFailedAtkStringPpReduce + suckerpunchcheck BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE goto BattleScript_HitFromAtkString @@ -2755,7 +2757,7 @@ BattleScript_EffectLuckyChant: BattleScript_EffectMetalBurst: attackcanceler - metalburstdamagecalculator BattleScript_ButItFailedAtkStringPpReduce + metalburstdamagecalculator BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce @@ -2766,7 +2768,7 @@ BattleScript_EffectMetalBurst: BattleScript_EffectHealingWish: attackcanceler - jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce + jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_FailedFromAtkString attackstring ppreduce attackanimation @@ -3126,9 +3128,9 @@ BattleScript_EffectRoost: BattleScript_EffectCaptivate: setstatchanger STAT_SPATK, 2, TRUE attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString jumpifoppositegenders BattleScript_CaptivateCheckAcc - goto BattleScript_ButItFailedAtkStringPpReduce + goto BattleScript_FailedFromAtkString BattleScript_CaptivateCheckAcc: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE goto BattleScript_StatDownFromAttackString @@ -3706,7 +3708,7 @@ BattleScript_EffectEvasionDown: setstatchanger STAT_EVASION, 1, TRUE BattleScript_EffectStatDown: attackcanceler - jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce + jumpifsubstituteblocks BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE BattleScript_StatDownFromAttackString: attackstring @@ -4601,7 +4603,7 @@ BattleScript_EffectPsywave:: BattleScript_EffectCounter:: attackcanceler - counterdamagecalculator BattleScript_ButItFailedAtkStringPpReduce + counterdamagecalculator BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce @@ -4908,7 +4910,7 @@ BattleScript_DoGhostCurse:: BattleScript_EffectMatBlock:: attackcanceler - jumpifnotfirstturn BattleScript_ButItFailedAtkStringPpReduce + jumpifnotfirstturn BattleScript_FailedFromAtkString goto BattleScript_ProtectLikeAtkString BattleScript_EffectProtect:: @@ -4926,7 +4928,7 @@ BattleScript_ProtectLikeAtkString: BattleScript_EffectSpikes:: attackcanceler - trysetspikes BattleScript_ButItFailedAtkStringPpReduce + trysetspikes BattleScript_FailedFromAtkString attackstring ppreduce attackanimation @@ -5324,7 +5326,7 @@ BattleScript_EffectPsychUp:: BattleScript_EffectMirrorCoat:: attackcanceler - mirrorcoatdamagecalculator BattleScript_ButItFailedAtkStringPpReduce + mirrorcoatdamagecalculator BattleScript_FailedFromAtkString accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce @@ -5542,15 +5544,13 @@ BattleScript_AlreadyAtFullHp:: BattleScript_EffectFakeOut:: attackcanceler - jumpifnotfirstturn BattleScript_ButItFailedAtkStringPpReduce + jumpifnotfirstturn BattleScript_FailedFromAtkString setmoveeffect MOVE_EFFECT_FLINCH goto BattleScript_EffectHit -BattleScript_ButItFailedAtkCanceler:: - attackcanceler -BattleScript_ButItFailedAtkStringPpReduce:: +BattleScript_FailedFromAtkString:: attackstring -BattleScript_ButItFailedPpReduce:: +BattleScript_FailedFromPpReduce:: ppreduce BattleScript_ButItFailed:: pause B_WAIT_TIME_SHORT @@ -5940,7 +5940,7 @@ BattleScript_EffectWish:: BattleScript_EffectAssist: attackcanceler attackstring - assistattackselect BattleScript_ButItFailedPpReduce + assistattackselect BattleScript_FailedFromPpReduce attackanimation waitanimation setbyte sB_ANIM_TURN, 0 @@ -5968,7 +5968,7 @@ BattleScript_EffectCloseCombat: BattleScript_EffectMagicCoat: attackcanceler - trysetmagiccoat BattleScript_ButItFailedAtkStringPpReduce + trysetmagiccoat BattleScript_FailedFromAtkString attackstring ppreduce attackanimation @@ -6126,7 +6126,7 @@ BattleScript_EffectGrudge: BattleScript_EffectSnatch: attackcanceler - trysetsnatch BattleScript_ButItFailedAtkStringPpReduce + trysetsnatch BattleScript_FailedFromAtkString attackstring ppreduce attackanimation diff --git a/include/battle_scripts.h b/include/battle_scripts.h index a6b897077..ecfbb9bec 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -10,7 +10,8 @@ extern const u8 BattleScript_MakeMoveMissed[]; extern const u8 BattleScript_PrintMoveMissed[]; extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissed[]; -extern const u8 BattleScript_ButItFailedAtkStringPpReduce[]; +extern const u8 BattleScript_FlingFailConsumeItem[]; +extern const u8 BattleScript_FailedFromAtkString[]; extern const u8 BattleScript_ButItFailed[]; extern const u8 BattleScript_StatUp[]; extern const u8 BattleScript_StatDown[]; diff --git a/include/battle_util.h b/include/battle_util.h index 51375000c..925a21a8a 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -190,7 +190,7 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId); u8 GetBattleMoveSplit(u32 moveId); bool32 TestMoveFlags(u16 move, u32 flag); -bool32 CanFling(u8 battlerId); +bool32 CanFling(u32 battlerId); bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsHealBlockPreventingMove(u32 battler, u32 move); bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId); diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 387800da4..e71e445fe 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 c6f6f1bf5..caca41a26 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1600,9 +1600,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_ButItFailedAtkStringPpReduce; + 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; @@ -10905,15 +10911,6 @@ static void Cmd_various(void) gBattlescriptCurrInstr = cmd->failInstr; return; } - case VARIOUS_JUMP_IF_CANT_FLING: - { - VARIOUS_ARGS(const u8 *jumpInstr); - if (!CanFling(gActiveBattler)) - gBattlescriptCurrInstr = cmd->jumpInstr; - else - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } case VARIOUS_CURE_CERTAIN_STATUSES: { VARIOUS_ARGS(); @@ -16158,11 +16155,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 91df461f0..1ff0a762e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6594,8 +6594,9 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split) if (IsBattlerAlive(battlerId) && TARGET_TURN_DAMAGED && CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) - && !DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) - && GetBattleMoveSplit(gCurrentMove) == split) + && (gBattleScripting.overrideBerryRequirements + || (!DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && GetBattleMoveSplit(gCurrentMove) == split)) + ) { BufferStatChange(battlerId, statId, STRINGID_STATROSE); @@ -6801,6 +6802,12 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) case HOLD_EFFECT_SP_DEFENSE_UP: effect = StatRaiseBerry(battlerId, gLastUsedItem, STAT_SPDEF, FALSE); break; + case HOLD_EFFECT_KEE_BERRY: // consume and boost defense if used physical move + effect = DamagedStatBoostBerryEffect(battlerId, STAT_DEF, SPLIT_PHYSICAL); + break; + case HOLD_EFFECT_MARANGA_BERRY: // consume and boost sp. defense if used special move + effect = DamagedStatBoostBerryEffect(battlerId, STAT_SPDEF, SPLIT_SPECIAL); + break; case HOLD_EFFECT_RANDOM_STAT_UP: effect = RandomStatRaiseBerry(battlerId, gLastUsedItem, FALSE); break; @@ -10493,11 +10500,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 battlerId) +bool32 CanFling(u32 battlerId) { u16 item = gBattleMons[battlerId].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); + } + } +} +