Adds in-battle effect of Pickup, adds Harvest and Pickup tests (#5170)

* Adds Harvest tests

* Adds Pickup in-battle effect + tests

* Fix G-Max Replenish test (Munchlax activates Pickup before G-Max Replenish)

* Change canPickupItem to bit field

* Make RandomUniformExcept inclusive (higher end) + convert bitfield

* Use CantPickupItem in PickupHasValidTargetc check

* Review
This commit is contained in:
PhallenTree 2024-08-16 14:37:23 +01:00 committed by GitHub
parent 47356d181a
commit ec3a86dd9a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 610 additions and 18 deletions

View file

@ -7754,6 +7754,15 @@ BattleScript_CheekPouchActivates::
copybyte gBattlerAttacker, sSAVED_BATTLER
return
BattleScript_PickupActivates::
pause 5
tryrecycleitem BattleScript_PickupActivatesEnd
call BattleScript_AbilityPopUp
printstring STRINGID_XFOUNDONEY
waitmessage B_WAIT_TIME_LONG
BattleScript_PickupActivatesEnd:
end3
BattleScript_HarvestActivates::
pause 5
tryrecycleitem BattleScript_HarvestActivatesEnd

View file

@ -676,6 +676,7 @@ struct BattleStruct
u16 chosenItem[MAX_BATTLERS_COUNT];
u16 choicedMove[MAX_BATTLERS_COUNT];
u16 changedItems[MAX_BATTLERS_COUNT];
u8 canPickupItem;
u8 switchInBattlerCounter;
u8 arenaTurnCounter;
u8 turnSideTracker;

View file

@ -295,6 +295,7 @@ extern const u8 BattleScript_WeakArmorActivates[];
extern const u8 BattleScript_FellStingerRaisesStat[];
extern const u8 BattleScript_SnowWarningActivatesHail[];
extern const u8 BattleScript_SnowWarningActivatesSnow[];
extern const u8 BattleScript_PickupActivates[];
extern const u8 BattleScript_HarvestActivates[];
extern const u8 BattleScript_ImposterActivates[];
extern const u8 BattleScript_SelectingNotAllowedMoveAssaultVest[];

View file

@ -231,6 +231,8 @@ bool32 TryRoomService(u32 battler);
void BufferStatChange(u32 battler, u8 statId, u8 stringId);
bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 checkTarget);
u16 GetUsedHeldItem(u32 battler);
bool32 PickupHasValidTarget(u32 battler);
bool32 CantPickupItem(u32 battler);
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags);
u32 GetBattlerMoveTargetType(u32 battler, u32 move);
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);

View file

@ -173,12 +173,14 @@ enum RandomTag
RNG_G_MAX_BEFUDDLE,
RNG_G_MAX_REPLENISH,
RNG_G_MAX_SNOOZE,
RNG_HARVEST,
RNG_HITS,
RNG_HOLD_EFFECT_FLINCH,
RNG_INFATUATION,
RNG_LOADED_DICE,
RNG_METRONOME,
RNG_PARALYSIS,
RNG_PICKUP,
RNG_POISON_POINT,
RNG_POISON_TOUCH,
RNG_RAMPAGE_TURNS,

View file

@ -3219,6 +3219,7 @@ void SwitchInClearSetData(u32 battler)
gBattleStruct->lastMoveFailed &= ~(gBitTable[battler]);
gBattleStruct->palaceFlags &= ~(gBitTable[battler]);
gBattleStruct->boosterEnergyActivates &= ~(gBitTable[battler]);
gBattleStruct->canPickupItem &= ~(1u << battler);
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
{
@ -5112,6 +5113,7 @@ static void TurnValuesCleanUp(bool8 var0)
if (gDisableStructs[i].rechargeTimer == 0)
gBattleMons[i].status2 &= ~STATUS2_RECHARGE;
}
gBattleStruct->canPickupItem &= ~(1u << i);
}
if (gDisableStructs[i].substituteHP == 0)

View file

@ -8071,6 +8071,7 @@ static void Cmd_removeitem(void)
gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = itemId; // Remember if switched out
gBattleMons[battler].item = ITEM_NONE;
gBattleStruct->canPickupItem |= (1u << battler);
CheckSetUnburden(battler);
BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battler].item), &gBattleMons[battler].item);
@ -14853,7 +14854,10 @@ static void Cmd_tryrecycleitem(void)
u16 *usedHeldItem;
usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)];
if (gCurrentMove == MOVE_NONE && GetBattlerAbility(gBattlerAttacker) == ABILITY_PICKUP)
usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerTarget]][GetBattlerSide(gBattlerTarget)];
else
usedHeldItem = &gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gBattlerAttacker]][GetBattlerSide(gBattlerAttacker)];
if (*usedHeldItem != ITEM_NONE && gBattleMons[gBattlerAttacker].item == ITEM_NONE)
{
gLastUsedItem = *usedHeldItem;

View file

@ -4950,8 +4950,19 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattlerAttacker = battler;
switch (gLastUsedAbility)
{
case ABILITY_PICKUP:
if (gBattleMons[battler].item == ITEM_NONE
&& gBattleStruct->changedItems[battler] == ITEM_NONE // Will not inherit an item
&& PickupHasValidTarget(battler))
{
gBattlerTarget = RandomUniformExcept(RNG_PICKUP, 0, gBattlersCount - 1, CantPickupItem);
gLastUsedItem = GetUsedHeldItem(gBattlerTarget);
BattleScriptPushCursorAndCallback(BattleScript_PickupActivates);
effect++;
}
break;
case ABILITY_HARVEST:
if ((IsBattlerWeatherAffected(battler, B_WEATHER_SUN) || Random() % 2 == 0)
if ((IsBattlerWeatherAffected(battler, B_WEATHER_SUN) || RandomPercentage(RNG_HARVEST, 50))
&& gBattleMons[battler].item == ITEM_NONE
&& gBattleStruct->changedItems[battler] == ITEM_NONE // Will not inherit an item
&& ItemId_GetPocket(GetUsedHeldItem(battler)) == POCKET_BERRIES)
@ -11398,6 +11409,25 @@ u16 GetUsedHeldItem(u32 battler)
return gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)];
}
bool32 CantPickupItem(u32 battler)
{
// Used by RandomUniformExcept() for RNG_PICKUP
if (battler == gBattlerAttacker && gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))
return TRUE;
return !(IsBattlerAlive(battler) && GetUsedHeldItem(battler) && gBattleStruct->canPickupItem & (1u << battler));
}
bool32 PickupHasValidTarget(u32 battler)
{
u32 i;
for (i = 0; i < gBattlersCount; i++)
{
if (!CantPickupItem(i))
return TRUE;
}
return FALSE;
}
bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags)
{
if (gBattleWeather & weatherFlags && WEATHER_HAS_EFFECT)

View file

@ -1,18 +1,264 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Harvest has a 50% chance to restore a Berry at the end of the turn");
TO_DO_BATTLE_TEST("Harvest always restores a Berry in Sunlight");
TO_DO_BATTLE_TEST("Harvest doesn't always restore a Berry if Cloud Nine/Air Lock is on the field");
TO_DO_BATTLE_TEST("Harvest restores a Berry even after being switched out and back in");
TO_DO_BATTLE_TEST("Harvest restores a Berry consumed by Fling");
TO_DO_BATTLE_TEST("Harvest restores a Berry consumed by Natural Gift");
ASSUMPTIONS
{
ASSUME(gItemsInfo[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP);
ASSUME(I_SITRUS_BERRY_HEAL >= GEN_4);
ASSUME(gMovesInfo[MOVE_SUNNY_DAY].effect == EFFECT_SUNNY_DAY);
}
SINGLE_BATTLE_TEST("Harvest has a 50% chance to restore a Berry at the end of the turn")
{
PASSES_RANDOMLY(1, 2, RNG_HARVEST);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Harvest always restores a Berry in Sunlight")
{
PASSES_RANDOMLY(1, 1, RNG_HARVEST);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Harvest doesn't always restore a Berry if Cloud Nine/Air Lock is on the field")
{
PASSES_RANDOMLY(1, 2, RNG_HARVEST);
GIVEN {
PLAYER(SPECIES_GOLDUCK) { Ability(ABILITY_CLOUD_NINE); }
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Harvest restores a Berry even after being switched out and back in")
{
ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); }
TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 0); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Harvest restores a Berry consumed by Fling")
{
ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, MOVE_FLING); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, opponent);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Harvest restores a Berry consumed by Natural Gift")
{
ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, MOVE_NATURAL_GIFT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_NATURAL_GIFT, opponent);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_SITRUS_BERRY);
}
}
TO_DO_BATTLE_TEST("Harvest only works once per turn"); // Check for berries that are consumed immediately, like Pecha Berry
TO_DO_BATTLE_TEST("Harvest doesn't restore a Berry when destroyed by Incinerate");
TO_DO_BATTLE_TEST("Harvest doesn't restore a Berry when knocked off by Knock Off");
TO_DO_BATTLE_TEST("Harvest doesn't restore a Berry when eaten by Bug Bite/Pluck");
TO_DO_BATTLE_TEST("Harvest doesn't restore a Berry that's collected via Pickup");
TO_DO_BATTLE_TEST("Harvest order is affected by speed");
TO_DO_BATTLE_TEST("Harvest doesn't restore a Berry when transfered to another Pokémon");
TO_DO_BATTLE_TEST("Harvest can restore a Berry that was transferred from another Pokémon");
TO_DO_BATTLE_TEST("Harvest can only restore the newest berry consumed that was transferred from another Pokémon instead of its original Berry");
SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when destroyed by Incinerate")
{
PASSES_RANDOMLY(1, 1, RNG_HARVEST);
ASSUME(MoveHasAdditionalEffect(MOVE_INCINERATE, MOVE_EFFECT_INCINERATE));
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_INCINERATE); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_INCINERATE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when knocked off by Knock Off")
{
PASSES_RANDOMLY(1, 1, RNG_HARVEST);
ASSUME(MoveHasAdditionalEffect(MOVE_KNOCK_OFF, MOVE_EFFECT_KNOCK_OFF));
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when eaten by Bug Bite/Pluck")
{
PASSES_RANDOMLY(1, 1, RNG_HARVEST);
ASSUME(MoveHasAdditionalEffect(MOVE_BUG_BITE, MOVE_EFFECT_BUG_BITE));
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_BUG_BITE); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BITE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry that's collected via Pickup")
{
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Speed(50); Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_EXEGGUTOR) { Speed(10); Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(player->item, ITEM_SITRUS_BERRY);
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
DOUBLE_BATTLE_TEST("Harvest order is affected by speed")
{
GIVEN {
PLAYER(SPECIES_EXEGGUTOR) { Speed(2); Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
PLAYER(SPECIES_WOBBUFFET) { Speed(5); }
OPPONENT(SPECIES_EXEGGUTOR) { Speed(10); Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(50); }
} WHEN {
TURN { MOVE(playerRight, MOVE_BULLDOZE); MOVE(playerLeft, MOVE_SUNNY_DAY); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLDOZE, playerRight);
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, playerLeft);
ABILITY_POPUP(opponentLeft, ABILITY_HARVEST);
ABILITY_POPUP(playerLeft, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponentLeft->item, ITEM_SITRUS_BERRY);
EXPECT_EQ(playerLeft->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when transfered to another Pokémon")
{
ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, MOVE_TRICK); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK, opponent);
NOT ABILITY_POPUP(opponent, ABILITY_HARVEST);
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Harvest can restore a Berry that was transferred from another Pokémon")
{
ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK);
GIVEN {
PLAYER(SPECIES_TORKOAL) { Ability(ABILITY_DROUGHT); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); HP(100); MaxHP(500); }
} WHEN {
TURN { MOVE(opponent, MOVE_TRICK); MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
} THEN {
EXPECT_GT(opponent->hp, opponent->maxHP / 2); // eats 2 Sitrus
}
}
SINGLE_BATTLE_TEST("Harvest can only restore the newest berry consumed that was transferred from another Pokémon instead of its original Berry")
{
ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK);
ASSUME(gItemsInfo[ITEM_APICOT_BERRY].holdEffect == HOLD_EFFECT_SP_DEFENSE_UP);
GIVEN {
PLAYER(SPECIES_TORKOAL) { Ability(ABILITY_DROUGHT); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); HP(100); MaxHP(500); Item(ITEM_APICOT_BERRY); }
} WHEN {
TURN { MOVE(opponent, MOVE_TRICK); MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
ABILITY_POPUP(opponent, ABILITY_HARVEST);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
} THEN {
EXPECT_GT(opponent->hp, opponent->maxHP / 2); // eats 2 Sitrus
}
}

View file

@ -0,0 +1,295 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gItemsInfo[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP);
ASSUME(I_SITRUS_BERRY_HEAL >= GEN_4);
}
SINGLE_BATTLE_TEST("Pickup grants an item used by another Pokémon")
{
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
} THEN {
EXPECT_EQ(player->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant the user their item")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NONE_OF {
ABILITY_POPUP(opponent, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant another Pokémon's popped Air Balloon")
{
ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON);
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_AIR_BALLOON); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Air Balloon!");
}
} THEN {
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an item not used that turn")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); }
TURN { SWITCH(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an item after its holder faints")
{
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_MEMENTO); SEND_OUT(opponent, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an used item if holder is replaced")
{
ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT);
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(300); HP(151); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(300); HP(151); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); }
TURN { MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 0); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, opponent);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an item if it destroyed the item with Incinerate")
{
ASSUME(MoveHasAdditionalEffect(MOVE_INCINERATE, MOVE_EFFECT_INCINERATE));
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_INCINERATE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_INCINERATE, player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an item if it knocked off that item")
{
ASSUME(MoveHasAdditionalEffect(MOVE_KNOCK_OFF, MOVE_EFFECT_KNOCK_OFF));
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an item if the user eats it with Bug Bite/Pluck")
{
ASSUME(MoveHasAdditionalEffect(MOVE_BUG_BITE, MOVE_EFFECT_BUG_BITE));
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_BUG_BITE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BITE, player);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup doesn't grant an used item if its user already restored it")
{
ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE);
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_RECYCLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
ANIMATION(ANIM_TYPE_MOVE, MOVE_RECYCLE, opponent);
NONE_OF {
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
}
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickup restores an item that has been Flinged")
{
ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING);
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(opponent, MOVE_FLING); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLING, opponent);
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
} THEN {
EXPECT_EQ(player->item, ITEM_SITRUS_BERRY);
}
}
SINGLE_BATTLE_TEST("Pickup restores an item that was used by Natural Gift")
{
ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT);
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(opponent, MOVE_NATURAL_GIFT); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_NATURAL_GIFT, opponent);
ABILITY_POPUP(player, ABILITY_PICKUP);
MESSAGE("Zigzagoon found one Sitrus Berry!");
} THEN {
EXPECT_EQ(player->item, ITEM_SITRUS_BERRY);
}
}
DOUBLE_BATTLE_TEST("Pickup triggers based on Speed order")
{
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Speed(1); Ability(ABILITY_PICKUP); }
PLAYER(SPECIES_WOBBUFFET) { Speed(2); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(3); MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_ZIGZAGOON) { Speed(50); Ability(ABILITY_PICKUP); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft);
ABILITY_POPUP(opponentRight, ABILITY_PICKUP);
NOT ABILITY_POPUP(playerLeft, ABILITY_PICKUP);
} THEN {
EXPECT_EQ(opponentRight->item, ITEM_SITRUS_BERRY);
EXPECT_EQ(playerLeft->item, ITEM_NONE);
}
}
DOUBLE_BATTLE_TEST("Pickup grants a random item used by another Pokémon")
{
PASSES_RANDOMLY(1, 3, RNG_PICKUP);
ASSUME(gItemsInfo[ITEM_WHITE_HERB].holdEffect == HOLD_EFFECT_RESTORE_STATS);
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); }
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_BULLDOZE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLDOZE, playerLeft);
ABILITY_POPUP(playerLeft, ABILITY_PICKUP);
} THEN {
EXPECT_EQ(playerLeft->item, ITEM_SITRUS_BERRY);
}
}
DOUBLE_BATTLE_TEST("Pickup doesn't trigger more than once per turn")
{
GIVEN {
PLAYER(SPECIES_ZIGZAGOON) { HP(1); Ability(ABILITY_PICKUP); }
PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
} WHEN {
TURN { MOVE(playerLeft, MOVE_BULLDOZE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLDOZE, playerLeft);
ABILITY_POPUP(playerLeft, ABILITY_PICKUP);
NOT ABILITY_POPUP(playerLeft, ABILITY_PICKUP);
} THEN {
EXPECT_EQ(playerLeft->item, ITEM_NONE);
EXPECT_GT(playerLeft->hp, 1);
EXPECT_LT(playerLeft->hp, playerLeft->maxHP/2);
}
}

View file

@ -1234,7 +1234,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries 50\% of t
GIVEN {
ASSUME(gMovesInfo[MOVE_G_MAX_REPLENISH].argument == MAX_EFFECT_RECYCLE_BERRIES);
PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); }
PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); }
} WHEN {

View file

@ -410,7 +410,7 @@ u32 RandomUniformExcept(enum RandomTag tag, u32 lo, u32 hi, bool32 (*reject)(u32
if (STATE->trials == 1)
{
u32 n = 0, i;
for (i = lo; i < hi; i++)
for (i = lo; i <= hi; i++)
if (!reject(i))
n++;
STATE->trials = n;