Fixed Ball Fetch Ability (#7764)

This commit is contained in:
bassforte123 2025-09-21 07:16:53 -04:00 committed by GitHub
parent 02824009d9
commit abc471e9bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 129 additions and 8 deletions

View File

@ -1124,7 +1124,7 @@ extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
extern u8 gMultiUsePlayerCursor;
extern u8 gNumberOfMovesToChoose;
extern bool8 gHasFetchedBall;
extern u8 gLastUsedBall;
extern u16 gLastUsedBall;
extern u16 gLastThrownBall;
extern u16 gBallToDisplay;
extern bool8 gLastUsedBallMenuPresent;

View File

@ -236,7 +236,7 @@ EWRAM_DATA u16 gBattleTurnCounter = 0;
EWRAM_DATA u8 gBattlerAbility = 0;
EWRAM_DATA struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA bool8 gHasFetchedBall = FALSE;
EWRAM_DATA u8 gLastUsedBall = 0;
EWRAM_DATA u16 gLastUsedBall = 0;
EWRAM_DATA u16 gLastThrownBall = 0;
EWRAM_DATA u16 gBallToDisplay = 0;
EWRAM_DATA bool8 gLastUsedBallMenuPresent = FALSE;

View File

@ -13950,6 +13950,13 @@ static void Cmd_handleballthrow(void)
BtlController_EmitBallThrowAnim(gBattlerAttacker, B_COMM_TO_CONTROLLER, shakes);
MarkBattlerForControllerExec(gBattlerAttacker);
#if TESTING
if (gTestRunnerEnabled)
{
shakes = 0; // Force failure for tests. TODO: make capture RNG flag
}
#endif
if (shakes == maxShakes) // mon caught, copy of the code above
{
if (IsCriticalCapture())

View File

@ -4398,14 +4398,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case ABILITY_BALL_FETCH:
if (gBattleMons[battler].item == ITEM_NONE
&& gBattleResults.catchAttempts[gLastUsedBall - ITEM_ULTRA_BALL] >= 1
&& gBattleResults.catchAttempts[ItemIdToBallId(gLastUsedBall)] >= 1
&& !gHasFetchedBall)
{
gLastUsedItem = gLastUsedBall;
gBattleScripting.battler = battler;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedBall);
gBattleMons[battler].item = gLastUsedItem;
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, 2, &gLastUsedItem);
MarkBattlerForControllerExec(battler);
gHasFetchedBall = TRUE;
gLastUsedItem = gLastUsedBall;
BattleScriptPushCursorAndCallback(BattleScript_BallFetch);
effect++;
}

View File

@ -1,7 +1,120 @@
#include "global.h"
#include "test/battle.h"
TO_DO_BATTLE_TEST("Ball Fetch causes the Pokémon to pick up the last failed Ball at the end of the turn");
TO_DO_BATTLE_TEST("Ball Fetch doesn't trigger if the Pokémon is already holding an item");
TO_DO_BATTLE_TEST("Ball Fetch only picks up the first failed ball, once per battle"); // Bestow can help test this
WILD_BATTLE_TEST("Ball Fetch causes the Pokémon to pick up the last failed Ball at the end of the turn")
{
u32 item = 0;
PARAMETRIZE { item = ITEM_POKE_BALL; }
PARAMETRIZE { item = ITEM_GREAT_BALL; }
PARAMETRIZE { item = ITEM_ULTRA_BALL; }
PARAMETRIZE { item = ITEM_STRANGE_BALL; }
PARAMETRIZE { item = ITEM_X_ACCURACY; }
GIVEN {
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
OPPONENT(SPECIES_METAGROSS);
} WHEN {
TURN { USE_ITEM(player, item); }
} SCENE {
if (item != ITEM_X_ACCURACY)
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
else
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
} THEN {
if (item != ITEM_X_ACCURACY)
EXPECT_EQ(player->item, item);
else
EXPECT_EQ(player->item, ITEM_NONE);
}
}
WILD_BATTLE_TEST("Ball Fetch doesn't trigger if the Pokémon is already holding an item")
{
u32 item = 0;
PARAMETRIZE { item = ITEM_NONE; }
PARAMETRIZE { item = ITEM_NUGGET; }
GIVEN {
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); Item(item); }
OPPONENT(SPECIES_METAGROSS);
} WHEN {
TURN { USE_ITEM(player, ITEM_GREAT_BALL); }
} SCENE {
if (item == ITEM_NONE)
{
MESSAGE("You used Great Ball!");
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
MESSAGE("Yamper found a Great Ball!");
}
else
{
NONE_OF
{
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
MESSAGE("Yamper found a Great Ball!");
}
}
} THEN {
if (item == ITEM_NONE)
EXPECT_EQ(player->item, ITEM_GREAT_BALL);
else
EXPECT_EQ(player->item, item);
}
}
WILD_BATTLE_TEST("Ball Fetch only picks up the first failed ball, once per battle")
{
u32 item = 0;
u32 item2 = 0;
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_X_ACCURACY; }
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_ULTRA_BALL; }
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_FAST_BALL; }
PARAMETRIZE { item = ITEM_GREAT_BALL; item2 = ITEM_STRANGE_BALL; }
GIVEN {
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
OPPONENT(SPECIES_METAGROSS);
} WHEN {
TURN { USE_ITEM(player, item); }
TURN { MOVE(player, MOVE_BESTOW); }
TURN { USE_ITEM(player, item2); }
} SCENE {
MESSAGE("You used Great Ball!");
ABILITY_POPUP(player, ABILITY_BALL_FETCH);
MESSAGE("Yamper found a Great Ball!");
MESSAGE("Yamper used Bestow!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_BESTOW, player);
MESSAGE("The wild Metagross received Great Ball from Yamper!");
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Ball Fetch doesn't trigger in Trainer Battles")
{
u32 item = 0;
PARAMETRIZE { item = ITEM_POKE_BALL; }
PARAMETRIZE { item = ITEM_GREAT_BALL; }
PARAMETRIZE { item = ITEM_ULTRA_BALL; }
PARAMETRIZE { item = ITEM_STRANGE_BALL; }
PARAMETRIZE { item = ITEM_X_ACCURACY; }
GIVEN {
PLAYER(SPECIES_YAMPER) { Ability(ABILITY_BALL_FETCH); }
OPPONENT(SPECIES_METAGROSS);
} WHEN {
TURN { USE_ITEM(player, item); }
} SCENE {
NOT ABILITY_POPUP(player, ABILITY_BALL_FETCH);
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
}
}
TO_DO_BATTLE_TEST("Ball Fetch doesn't trigger in Max Raid Battles");