Fix Pickpocket moveend target checks and Thief/Covet handoff (#9037)
This commit is contained in:
parent
08dd7da30c
commit
6928d54d46
@ -7003,11 +7003,21 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_PICKPOCKET:
|
||||
{
|
||||
u16 attackerItem = gBattleMons[gBattlerAttacker].item;
|
||||
bool32 hasPendingStolenItem = FALSE;
|
||||
|
||||
if (attackerItem == ITEM_NONE
|
||||
&& GetMoveEffect(gCurrentMove) == EFFECT_STEAL_ITEM
|
||||
&& gBattleStruct->changedItems[gBattlerAttacker] != ITEM_NONE)
|
||||
{
|
||||
attackerItem = gBattleStruct->changedItems[gBattlerAttacker];
|
||||
hasPendingStolenItem = TRUE;
|
||||
}
|
||||
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
|
||||
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker])) // But not knocked off
|
||||
&& IsMoveMakingContact(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Obviously attack needs to have worked
|
||||
&& attackerItem != ITEM_NONE // Attacker must have an item (including pending stolen item)
|
||||
&& !(gWishFutureKnock.knockedOffMons[GetBattlerSide(gBattlerAttacker)] & (1u << gBattlerPartyIndexes[gBattlerAttacker]))) // But not knocked off
|
||||
{
|
||||
u8 battlers[4] = {0, 1, 2, 3};
|
||||
SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item
|
||||
@ -7018,12 +7028,19 @@ static void Cmd_moveend(void)
|
||||
if (battler != gBattlerAttacker // Cannot pickpocket yourself
|
||||
&& GetBattlerAbility(battler) == ABILITY_PICKPOCKET // Target must have pickpocket ability
|
||||
&& IsBattlerTurnDamaged(battler) // Target needs to have been damaged
|
||||
&& IsMoveMakingContact(gBattlerAttacker, battler, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove) // Pickpocket requires contact
|
||||
&& !(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT) // Move needs to have affected this battler
|
||||
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) // Subsitute unaffected
|
||||
&& IsBattlerAlive(battler) // Battler must be alive to pickpocket
|
||||
&& gBattleMons[battler].item == ITEM_NONE // Pickpocketer can't have an item already
|
||||
&& CanStealItem(battler, gBattlerAttacker, gBattleMons[gBattlerAttacker].item)) // Cannot steal plates, mega stones, etc
|
||||
&& CanStealItem(battler, gBattlerAttacker, attackerItem)) // Cannot steal plates, mega stones, etc
|
||||
{
|
||||
gBattlerTarget = gBattlerAbility = battler;
|
||||
if (hasPendingStolenItem)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].item = attackerItem;
|
||||
gBattleStruct->changedItems[gBattlerAttacker] = ITEM_NONE;
|
||||
}
|
||||
// Battle scripting is super brittle so we shall do the item exchange now (if possible)
|
||||
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
|
||||
StealTargetItem(gBattlerTarget, gBattlerAttacker); // Target takes attacker's item
|
||||
@ -7037,6 +7054,7 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
case MOVEEND_THIRD_MOVE_BLOCK:
|
||||
switch (moveEffect)
|
||||
{
|
||||
|
||||
@ -1,4 +1,312 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
TO_DO_BATTLE_TEST("TODO: Write Pickpocket (Ability) test titles")
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(MoveMakesContact(MOVE_BREAKING_SWIPE));
|
||||
ASSUME(MoveMakesContact(MOVE_SCRATCH));
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Pickpocket checks contact/effect per target for spread moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY);
|
||||
ASSUME(GetMoveType(MOVE_BREAKING_SWIPE) == TYPE_DRAGON);
|
||||
ASSUME(GetMoveTarget(MOVE_BREAKING_SWIPE) == MOVE_TARGET_BOTH);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
OPPONENT(SPECIES_CLEFAIRY);
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_BREAKING_SWIPE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponentLeft->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(playerLeft->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Pickpocket activates for the fastest itemless target when both are hit by a contact spread move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveTarget(MOVE_BREAKING_SWIPE) == MOVE_TARGET_BOTH);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_MAGOST_BERRY); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(10); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Speed(40); Ability(ABILITY_PICKPOCKET); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Speed(30); Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(playerLeft, MOVE_BREAKING_SWIPE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponentLeft->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(opponentRight->item == ITEM_NONE);
|
||||
EXPECT(playerLeft->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket steals the attacker's item unless it already has one")
|
||||
{
|
||||
bool32 targetHasItem;
|
||||
PARAMETRIZE { targetHasItem = FALSE; }
|
||||
PARAMETRIZE { targetHasItem = TRUE; }
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(targetHasItem ? ITEM_EVIOLITE : ITEM_NONE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
if (targetHasItem) {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
}
|
||||
} else {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
}
|
||||
} THEN {
|
||||
if (targetHasItem) {
|
||||
EXPECT(opponent->item == ITEM_EVIOLITE);
|
||||
EXPECT(player->item == ITEM_MAGOST_BERRY);
|
||||
} else {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket does not activate if the user faints")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
}
|
||||
MESSAGE("The opposing Sneasel fainted!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
EXPECT(player->item == ITEM_MAGOST_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket cannot steal from Sticky Hold")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_GRIMER) { Ability(ABILITY_STICKY_HOLD); Item(ITEM_MAGOST_BERRY); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
ABILITY_POPUP(player, ABILITY_STICKY_HOLD);
|
||||
MESSAGE("Grimer's item cannot be removed!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
EXPECT(player->item == ITEM_MAGOST_BERRY);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket cannot steal restricted held items")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_NORMALIUM_Z].holdEffect == HOLD_EFFECT_Z_CRYSTAL);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
}
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_NONE);
|
||||
EXPECT(player->item == ITEM_NORMALIUM_Z);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after the final hit of a multi-strike move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_FURY_SWIPES) == EFFECT_MULTI_HIT);
|
||||
ASSUME(MoveMakesContact(MOVE_FURY_SWIPES));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FURY_SWIPES, WITH_RNG(RNG_HITS, 3)); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player);
|
||||
MESSAGE("The Pokémon was hit 3 time(s)!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after Magician steals an item")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_DELPHOX) { Ability(ABILITY_MAGICIAN); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_MAGOST_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MAGICIAN);
|
||||
MESSAGE("Delphox stole the opposing Sneasel's Magost Berry!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Delphox's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after Sticky Barb transfers")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_STICKY_BARB].holdEffect == HOLD_EFFECT_STICKY_BARB);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_STICKY_BARB); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
MESSAGE("The Sticky Barb attached itself to Wobbuffet!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Sticky Barb!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_STICKY_BARB);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after Thief or Covet steals an item")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_THIEF; }
|
||||
PARAMETRIZE { move = MOVE_COVET; }
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(move) == EFFECT_STEAL_ITEM);
|
||||
ASSUME(MoveMakesContact(move));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_MAGOST_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet stole the opposing Sneasel's Magost Berry!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after Focus Sash is consumed")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(MOVE_SEISMIC_TOSS));
|
||||
ASSUME(gItemsInfo[ITEM_FOCUS_SASH].holdEffect == HOLD_EFFECT_FOCUS_SASH);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); Level(100); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_FOCUS_SASH); MaxHP(6); HP(6); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SEISMIC_TOSS); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player);
|
||||
MESSAGE("The opposing Sneasel hung on using its Focus Sash!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket activates after Knock Off, Bug Bite, or Pluck")
|
||||
{
|
||||
u16 move;
|
||||
PARAMETRIZE { move = MOVE_KNOCK_OFF; }
|
||||
PARAMETRIZE { move = MOVE_BUG_BITE; }
|
||||
PARAMETRIZE { move = MOVE_PLUCK; }
|
||||
GIVEN {
|
||||
ASSUME(MoveMakesContact(move));
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MAGOST_BERRY); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); Item(ITEM_ORAN_BERRY); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, move); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Magost Berry!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_MAGOST_BERRY);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket steals Life Orb after it activates")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet was hurt by the Life Orb!");
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Life Orb!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_LIFE_ORB);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket steals Shell Bell after it heals the user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_SHELL_BELL].holdEffect == HOLD_EFFECT_SHELL_BELL);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHELL_BELL); MaxHP(100); HP(66); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent);
|
||||
HP_BAR(player);
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's Shell Bell!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_SHELL_BELL);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Pickpocket does not prevent King's Rock or Razor Fang flinches")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gItemsInfo[ITEM_KINGS_ROCK].holdEffect == HOLD_EFFECT_FLINCH);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_KINGS_ROCK); }
|
||||
OPPONENT(SPECIES_SNEASEL) { Speed(10); Ability(ABILITY_PICKPOCKET); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCRATCH, WITH_RNG(RNG_HOLD_EFFECT_FLINCH, 1)); MOVE(opponent, MOVE_SCRATCH); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
|
||||
MESSAGE("The opposing Sneasel stole Wobbuffet's King's Rock!");
|
||||
MESSAGE("The opposing Sneasel flinched and couldn't move!");
|
||||
} THEN {
|
||||
EXPECT(opponent->item == ITEM_KINGS_ROCK);
|
||||
EXPECT(player->item == ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user