Skip to content

Commit

Permalink
Adds Thief/Covet config to send stolen item to bag and Pickup config …
Browse files Browse the repository at this point in the history
…to pickup user's item in wild battles (#5829)
  • Loading branch information
PhallenTree authored Dec 19, 2024
1 parent 8f59d9c commit f4a0cc0
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 12 deletions.
2 changes: 2 additions & 0 deletions include/config/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
#define B_ABILITY_TRIGGER_CHANCE GEN_LATEST // In Gen3, Shed Skin, Cute Charm, Flame Body, Static and Poison Point have a 1/3 chance to trigger. In Gen 4+ it's 30%.
// In Gen3, Effect Spore has a 10% chance to sleep, poison or paralyze, with an equal chance.
// In Gen4, it's 30%. In Gen5+ it has 11% to sleep, 9% chance to poison and 10% chance to paralyze.
#define B_PICKUP_WILD GEN_LATEST // In Gen9+, Pickup allows its user to pickup its own used item at the end of the turn in wild battles.

// Item settings
#define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn.
Expand All @@ -163,6 +164,7 @@
#define B_MENTAL_HERB GEN_LATEST // In Gen5+, the Mental Herb cures Taunt, Encore, Torment, Heal Block, and Disable in addition to Infatuation from before.
#define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items.
#define B_RETURN_STOLEN_NPC_ITEMS GEN_LATEST // In Gen5+, Thief and Covet no longer steal items from NPCs.
#define B_STEAL_WILD_ITEMS GEN_LATEST // In Gen9, Thief and Covet steal a wild pokemon's item and send it to the bag. Before Gen9, the stolen item would be held by the Thief/Covet user.
#define B_RESTORE_HELD_BATTLE_ITEMS GEN_LATEST // In Gen9, all non-berry items are restored after battle.
#define B_SOUL_DEW_BOOST GEN_LATEST // In Gens3-6, Soul Dew boosts Latis' Sp. Atk and Sp. Def. In Gen7+ it boosts the power of their Psychic and Dragon type moves instead.
#define B_NET_BALL_MODIFIER GEN_LATEST // In Gen7+, Net Ball's catch multiplier is x5 instead of x3.
Expand Down
34 changes: 24 additions & 10 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -2852,17 +2852,26 @@ static void CheckSetUnburden(u8 battler)
void StealTargetItem(u8 battlerStealer, u8 battlerItem)
{
gLastUsedItem = gBattleMons[battlerItem].item;
gBattleMons[battlerItem].item = 0;
gBattleMons[battlerItem].item = ITEM_NONE;

RecordItemEffectBattle(battlerItem, 0);
RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem));
gBattleMons[battlerStealer].item = gLastUsedItem;
if (B_STEAL_WILD_ITEMS >= GEN_9
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE))
&& MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_STEAL_ITEM)
&& battlerStealer == gBattlerAttacker) // ensure that Pickpocket isn't activating this
{
AddBagItem(gLastUsedItem, 1);
}
else
{
RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem));
gBattleMons[battlerStealer].item = gLastUsedItem;
gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN;
BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item
MarkBattlerForControllerExec(battlerStealer);
}

RecordItemEffectBattle(battlerItem, ITEM_NONE);
CheckSetUnburden(battlerItem);
gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN;

BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item
MarkBattlerForControllerExec(battlerStealer);

BtlController_EmitSetMonData(battlerItem, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item
MarkBattlerForControllerExec(battlerItem);
Expand Down Expand Up @@ -3544,8 +3553,13 @@ void SetMoveEffect(bool32 primary, bool32 certain)
else
{
StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker steals target item
gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS)
gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later

if (!(B_STEAL_WILD_ITEMS >= GEN_9
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE))))
{
gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS)
gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later
}
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_ItemSteal;
}
Expand Down
2 changes: 1 addition & 1 deletion src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -11557,7 +11557,7 @@ u16 GetUsedHeldItem(u32 battler)
bool32 CantPickupItem(u32 battler)
{
// Used by RandomUniformExcept() for RNG_PICKUP
if (battler == gBattlerAttacker && gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))
if (battler == gBattlerAttacker && (B_PICKUP_WILD < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK)))
return TRUE;
return !(IsBattlerAlive(battler) && GetUsedHeldItem(battler) && gBattleStruct->canPickupItem & (1u << battler));
}
Expand Down
19 changes: 18 additions & 1 deletion test/battle/ability/pickup.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,24 @@ SINGLE_BATTLE_TEST("Pickup grants an item used by another Pokémon")
}
}

SINGLE_BATTLE_TEST("Pickup doesn't grant the user their item")
WILD_BATTLE_TEST("Pickup grants an item used by itself in wild battles (Gen 9)")
{
GIVEN {
ASSUME(B_PICKUP_WILD >= GEN_9);
PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
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 outside wild battles")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
Expand Down
129 changes: 129 additions & 0 deletions test/battle/move_effect_secondary/steal_item.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "global.h"
#include "test/battle.h"

ASSUMPTIONS
{
ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE);
ASSUME(MoveHasAdditionalEffect(MOVE_COVET, MOVE_EFFECT_STEAL_ITEM) == TRUE);
}

SINGLE_BATTLE_TEST("Thief and Covet steal target's held item")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent);
} THEN {
EXPECT_EQ(player->item, ITEM_HYPER_POTION);
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}

SINGLE_BATTLE_TEST("Thief and Covet steal player's held item if opponent is a trainer")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
ASSUME(B_TRAINERS_KNOCK_OFF_ITEMS == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, player);
} THEN {
EXPECT_EQ(opponent->item, ITEM_HYPER_POTION);
EXPECT_EQ(player->item, ITEM_NONE);
}
}

WILD_BATTLE_TEST("Thief and Covet don't steal player's held item if opponent is a wild mon")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
ASSUME(B_TRAINERS_KNOCK_OFF_ITEMS == TRUE);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
HP_BAR(player);
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, player);
} THEN {
EXPECT_EQ(player->item, ITEM_HYPER_POTION);
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}

SINGLE_BATTLE_TEST("Thief and Covet don't steal target's held item if user is holding an item")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POTION); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent);
} THEN {
EXPECT_EQ(player->item, ITEM_POTION);
EXPECT_EQ(opponent->item, ITEM_HYPER_POTION);
}
}

SINGLE_BATTLE_TEST("Thief and Covet don't steal target's held item if target has no item")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent);
}
}

// Test can't currently verify if the item is sent to Bag
WILD_BATTLE_TEST("Thief and Covet steal target's held item and it's added to Bag in wild battles (Gen 9)")
{
u32 move;
PARAMETRIZE { move = MOVE_THIEF; }
PARAMETRIZE { move = MOVE_COVET; }
GIVEN {
ASSUME(B_STEAL_WILD_ITEMS >= GEN_9);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); }
} WHEN {
TURN { MOVE(player, move); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, move, player);
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent);
} THEN {
EXPECT_EQ(player->item, ITEM_NONE);
EXPECT_EQ(opponent->item, ITEM_NONE);
}
}

0 comments on commit f4a0cc0

Please sign in to comment.