Fling fixes and tests (#3191)

* begin fling tests

* fling fixes and tests

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Update test/move_effect_fling.c

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* scripts names change

* fix fling's test file

---------

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>
This commit is contained in:
DizzyEggg 2023-09-05 11:56:36 +02:00 committed by GitHub
parent d78d63e537
commit cfd802423b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 405 additions and 55 deletions

View File

@ -1311,6 +1311,12 @@
callnative BS_CalcMetalBurstDmg callnative BS_CalcMetalBurstDmg
.4byte \failInstr .4byte \failInstr
.endm .endm
.macro jumpifcantfling battler:req, jumpInstr:req
callnative BS_JumpIfCantFling
.byte \battler
.4byte \jumpInstr
.endm
.macro jumpifholdeffect battler:req, holdEffect:req, jumpInstr:req .macro jumpifholdeffect battler:req, holdEffect:req, jumpInstr:req
callnative BS_JumpIfHoldEffect callnative BS_JumpIfHoldEffect
@ -2028,11 +2034,6 @@
.4byte \jumpInstr .4byte \jumpInstr
.endm .endm
.macro jumpifcantfling battler:req, jumpInstr:req
various \battler, VARIOUS_JUMP_IF_CANT_FLING
.4byte \jumpInstr
.endm
.macro curecertainstatuses battler:req .macro curecertainstatuses battler:req
various \battler, VARIOUS_CURE_CERTAIN_STATUSES various \battler, VARIOUS_CURE_CERTAIN_STATUSES
.endm .endm

View File

@ -836,12 +836,10 @@ BattleScript_SkyDropFlyingAlreadyConfused:
goto BattleScript_ThrashConfuses goto BattleScript_ThrashConfuses
BattleScript_EffectFling: BattleScript_EffectFling:
jumpifcantfling BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce attackcanceler
jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce jumpifcantfling BS_ATTACKER, BattleScript_FailedFromAtkString
jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce
setlastuseditem BS_ATTACKER setlastuseditem BS_ATTACKER
removeitem BS_ATTACKER removeitem BS_ATTACKER
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
@ -883,6 +881,10 @@ BattleScript_FlingEnd:
tryfaintmon BS_TARGET tryfaintmon BS_TARGET
trysymbiosis trysymbiosis
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_FlingFailConsumeItem::
removeitem BS_ATTACKER
goto BattleScript_FailedFromAtkString
BattleScript_FlingFlameOrb: BattleScript_FlingFlameOrb:
setmoveeffect MOVE_EFFECT_BURN setmoveeffect MOVE_EFFECT_BURN
@ -971,7 +973,7 @@ BattleScript_EffectClangorousSoul:
BattleScript_EffectOctolock: BattleScript_EffectOctolock:
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
ppreduce ppreduce
@ -1019,9 +1021,9 @@ BattleScript_EffectPoltergeist:
BattleScript_EffectTarShot: BattleScript_EffectTarShot:
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
cantarshotwork BS_TARGET, BattleScript_ButItFailedAtkStringPpReduce cantarshotwork BS_TARGET, BattleScript_FailedFromAtkString
attackstring attackstring
ppreduce ppreduce
setstatchanger STAT_SPEED, 1, TRUE setstatchanger STAT_SPEED, 1, TRUE
@ -1502,7 +1504,7 @@ BattleScript_PurifyWorks:
BattleScript_EffectStrengthSap: BattleScript_EffectStrengthSap:
setstatchanger STAT_ATK, 1, TRUE setstatchanger STAT_ATK, 1, TRUE
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
ppreduce ppreduce
@ -2070,7 +2072,7 @@ BattleScript_EffectDefog:
jumpifsubstituteblocks BattleScript_DefogIfCanClearHazards jumpifsubstituteblocks BattleScript_DefogIfCanClearHazards
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_EVASION, MIN_STAT_STAGE, BattleScript_DefogWorks jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_EVASION, MIN_STAT_STAGE, BattleScript_DefogWorks
BattleScript_DefogIfCanClearHazards: BattleScript_DefogIfCanClearHazards:
defogclear BS_ATTACKER, FALSE, BattleScript_ButItFailedAtkStringPpReduce defogclear BS_ATTACKER, FALSE, BattleScript_FailedFromAtkString
BattleScript_DefogWorks: BattleScript_DefogWorks:
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
@ -2216,9 +2218,9 @@ BattleScript_EffectClearSmog:
BattleScript_EffectToxicThread: BattleScript_EffectToxicThread:
setstatchanger STAT_SPEED, 2, TRUE setstatchanger STAT_SPEED, 2, TRUE
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_SPEED, MIN_STAT_STAGE, BattleScript_ToxicThreadWorks 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: BattleScript_ToxicThreadWorks:
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
@ -2572,7 +2574,7 @@ BattleScript_EffectSpeedUpHit:
BattleScript_EffectMeFirst: BattleScript_EffectMeFirst:
attackcanceler attackcanceler
attackstring attackstring
trymefirst BattleScript_ButItFailedPpReduce trymefirst BattleScript_FailedFromPpReduce
attackanimation attackanimation
waitanimation waitanimation
setbyte sB_ANIM_TURN, 0 setbyte sB_ANIM_TURN, 0
@ -2738,7 +2740,7 @@ BattleScript_EffectSimpleBeam:
BattleScript_EffectSuckerPunch: BattleScript_EffectSuckerPunch:
attackcanceler attackcanceler
suckerpunchcheck BattleScript_ButItFailedAtkStringPpReduce suckerpunchcheck BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
goto BattleScript_HitFromAtkString goto BattleScript_HitFromAtkString
@ -2755,7 +2757,7 @@ BattleScript_EffectLuckyChant:
BattleScript_EffectMetalBurst: BattleScript_EffectMetalBurst:
attackcanceler attackcanceler
metalburstdamagecalculator BattleScript_ButItFailedAtkStringPpReduce metalburstdamagecalculator BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
ppreduce ppreduce
@ -2766,7 +2768,7 @@ BattleScript_EffectMetalBurst:
BattleScript_EffectHealingWish: BattleScript_EffectHealingWish:
attackcanceler attackcanceler
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_FailedFromAtkString
attackstring attackstring
ppreduce ppreduce
attackanimation attackanimation
@ -3126,9 +3128,9 @@ BattleScript_EffectRoost:
BattleScript_EffectCaptivate: BattleScript_EffectCaptivate:
setstatchanger STAT_SPATK, 2, TRUE setstatchanger STAT_SPATK, 2, TRUE
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
jumpifoppositegenders BattleScript_CaptivateCheckAcc jumpifoppositegenders BattleScript_CaptivateCheckAcc
goto BattleScript_ButItFailedAtkStringPpReduce goto BattleScript_FailedFromAtkString
BattleScript_CaptivateCheckAcc: BattleScript_CaptivateCheckAcc:
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
goto BattleScript_StatDownFromAttackString goto BattleScript_StatDownFromAttackString
@ -3706,7 +3708,7 @@ BattleScript_EffectEvasionDown:
setstatchanger STAT_EVASION, 1, TRUE setstatchanger STAT_EVASION, 1, TRUE
BattleScript_EffectStatDown: BattleScript_EffectStatDown:
attackcanceler attackcanceler
jumpifsubstituteblocks BattleScript_ButItFailedAtkStringPpReduce jumpifsubstituteblocks BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
BattleScript_StatDownFromAttackString: BattleScript_StatDownFromAttackString:
attackstring attackstring
@ -4601,7 +4603,7 @@ BattleScript_EffectPsywave::
BattleScript_EffectCounter:: BattleScript_EffectCounter::
attackcanceler attackcanceler
counterdamagecalculator BattleScript_ButItFailedAtkStringPpReduce counterdamagecalculator BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
ppreduce ppreduce
@ -4908,7 +4910,7 @@ BattleScript_DoGhostCurse::
BattleScript_EffectMatBlock:: BattleScript_EffectMatBlock::
attackcanceler attackcanceler
jumpifnotfirstturn BattleScript_ButItFailedAtkStringPpReduce jumpifnotfirstturn BattleScript_FailedFromAtkString
goto BattleScript_ProtectLikeAtkString goto BattleScript_ProtectLikeAtkString
BattleScript_EffectProtect:: BattleScript_EffectProtect::
@ -4926,7 +4928,7 @@ BattleScript_ProtectLikeAtkString:
BattleScript_EffectSpikes:: BattleScript_EffectSpikes::
attackcanceler attackcanceler
trysetspikes BattleScript_ButItFailedAtkStringPpReduce trysetspikes BattleScript_FailedFromAtkString
attackstring attackstring
ppreduce ppreduce
attackanimation attackanimation
@ -5324,7 +5326,7 @@ BattleScript_EffectPsychUp::
BattleScript_EffectMirrorCoat:: BattleScript_EffectMirrorCoat::
attackcanceler attackcanceler
mirrorcoatdamagecalculator BattleScript_ButItFailedAtkStringPpReduce mirrorcoatdamagecalculator BattleScript_FailedFromAtkString
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring attackstring
ppreduce ppreduce
@ -5542,15 +5544,13 @@ BattleScript_AlreadyAtFullHp::
BattleScript_EffectFakeOut:: BattleScript_EffectFakeOut::
attackcanceler attackcanceler
jumpifnotfirstturn BattleScript_ButItFailedAtkStringPpReduce jumpifnotfirstturn BattleScript_FailedFromAtkString
setmoveeffect MOVE_EFFECT_FLINCH setmoveeffect MOVE_EFFECT_FLINCH
goto BattleScript_EffectHit goto BattleScript_EffectHit
BattleScript_ButItFailedAtkCanceler:: BattleScript_FailedFromAtkString::
attackcanceler
BattleScript_ButItFailedAtkStringPpReduce::
attackstring attackstring
BattleScript_ButItFailedPpReduce:: BattleScript_FailedFromPpReduce::
ppreduce ppreduce
BattleScript_ButItFailed:: BattleScript_ButItFailed::
pause B_WAIT_TIME_SHORT pause B_WAIT_TIME_SHORT
@ -5940,7 +5940,7 @@ BattleScript_EffectWish::
BattleScript_EffectAssist: BattleScript_EffectAssist:
attackcanceler attackcanceler
attackstring attackstring
assistattackselect BattleScript_ButItFailedPpReduce assistattackselect BattleScript_FailedFromPpReduce
attackanimation attackanimation
waitanimation waitanimation
setbyte sB_ANIM_TURN, 0 setbyte sB_ANIM_TURN, 0
@ -5968,7 +5968,7 @@ BattleScript_EffectCloseCombat:
BattleScript_EffectMagicCoat: BattleScript_EffectMagicCoat:
attackcanceler attackcanceler
trysetmagiccoat BattleScript_ButItFailedAtkStringPpReduce trysetmagiccoat BattleScript_FailedFromAtkString
attackstring attackstring
ppreduce ppreduce
attackanimation attackanimation
@ -6126,7 +6126,7 @@ BattleScript_EffectGrudge:
BattleScript_EffectSnatch: BattleScript_EffectSnatch:
attackcanceler attackcanceler
trysetsnatch BattleScript_ButItFailedAtkStringPpReduce trysetsnatch BattleScript_FailedFromAtkString
attackstring attackstring
ppreduce ppreduce
attackanimation attackanimation

View File

@ -10,7 +10,8 @@ extern const u8 BattleScript_MakeMoveMissed[];
extern const u8 BattleScript_PrintMoveMissed[]; extern const u8 BattleScript_PrintMoveMissed[];
extern const u8 BattleScript_MoveMissedPause[]; extern const u8 BattleScript_MoveMissedPause[];
extern const u8 BattleScript_MoveMissed[]; 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_ButItFailed[];
extern const u8 BattleScript_StatUp[]; extern const u8 BattleScript_StatUp[];
extern const u8 BattleScript_StatDown[]; extern const u8 BattleScript_StatDown[];

View File

@ -190,7 +190,7 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId);
bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId); bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId);
u8 GetBattleMoveSplit(u32 moveId); u8 GetBattleMoveSplit(u32 moveId);
bool32 TestMoveFlags(u16 move, u32 flag); bool32 TestMoveFlags(u16 move, u32 flag);
bool32 CanFling(u8 battlerId); bool32 CanFling(u32 battlerId);
bool32 IsTelekinesisBannedSpecies(u16 species); bool32 IsTelekinesisBannedSpecies(u16 species);
bool32 IsHealBlockPreventingMove(u32 battler, u32 move); bool32 IsHealBlockPreventingMove(u32 battler, u32 move);
bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId); bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId);

View File

@ -230,7 +230,6 @@
#define VARIOUS_SET_SKY_DROP 138 #define VARIOUS_SET_SKY_DROP 138
#define VARIOUS_CLEAR_SKY_DROP 139 #define VARIOUS_CLEAR_SKY_DROP 139
#define VARIOUS_SKY_DROP_YAWN 140 #define VARIOUS_SKY_DROP_YAWN 140
#define VARIOUS_JUMP_IF_CANT_FLING 141
#define VARIOUS_JUMP_IF_HOLD_EFFECT 142 #define VARIOUS_JUMP_IF_HOLD_EFFECT 142
#define VARIOUS_CURE_CERTAIN_STATUSES 143 #define VARIOUS_CURE_CERTAIN_STATUSES 143
#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 144 #define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 144

View File

@ -1600,9 +1600,15 @@ static void Cmd_attackcanceler(void)
} }
gHitMarker |= HITMARKER_OBEYS; 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)) if (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
CancelMultiTurnMoves(gBattlerAttacker); CancelMultiTurnMoves(gBattlerAttacker);
return; return;
@ -10905,15 +10911,6 @@ static void Cmd_various(void)
gBattlescriptCurrInstr = cmd->failInstr; gBattlescriptCurrInstr = cmd->failInstr;
return; 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: case VARIOUS_CURE_CERTAIN_STATUSES:
{ {
VARIOUS_ARGS(); 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) void BS_JumpIfMoreThanHalfHP(void)
{ {
NATIVE_ARGS(u8 battler, const u8 *jumpInstr); 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) if (gBattleMons[battler].hp > (gBattleMons[battler].maxHP + 1) / 2)
gBattlescriptCurrInstr = cmd->jumpInstr; gBattlescriptCurrInstr = cmd->jumpInstr;
else else

View File

@ -6594,8 +6594,9 @@ static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split)
if (IsBattlerAlive(battlerId) if (IsBattlerAlive(battlerId)
&& TARGET_TURN_DAMAGED && TARGET_TURN_DAMAGED
&& CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && (gBattleScripting.overrideBerryRequirements
&& GetBattleMoveSplit(gCurrentMove) == split) || (!DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && GetBattleMoveSplit(gCurrentMove) == split))
)
{ {
BufferStatChange(battlerId, statId, STRINGID_STATROSE); BufferStatChange(battlerId, statId, STRINGID_STATROSE);
@ -6801,6 +6802,12 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect)
case HOLD_EFFECT_SP_DEFENSE_UP: case HOLD_EFFECT_SP_DEFENSE_UP:
effect = StatRaiseBerry(battlerId, gLastUsedItem, STAT_SPDEF, FALSE); effect = StatRaiseBerry(battlerId, gLastUsedItem, STAT_SPDEF, FALSE);
break; 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: case HOLD_EFFECT_RANDOM_STAT_UP:
effect = RandomStatRaiseBerry(battlerId, gLastUsedItem, FALSE); effect = RandomStatRaiseBerry(battlerId, gLastUsedItem, FALSE);
break; break;
@ -10493,11 +10500,9 @@ static u8 GetFlingPowerFromItemId(u16 itemId)
return ItemId_GetFlingPower(itemId); return ItemId_GetFlingPower(itemId);
} }
// Make sure the input bank is any bank on the specific mon's side bool32 CanFling(u32 battlerId)
bool32 CanFling(u8 battlerId)
{ {
u16 item = gBattleMons[battlerId].item; u16 item = gBattleMons[battlerId].item;
u16 itemEffect = ItemId_GetHoldEffect(item);
if (item == ITEM_NONE if (item == ITEM_NONE
#if B_KLUTZ_FLING_INTERACTION >= GEN_5 #if B_KLUTZ_FLING_INTERACTION >= GEN_5

View File

@ -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);
}
}
}