Skip to content
voloved edited this page Sep 10, 2023 · 20 revisions

by devolov
Branch of this addition

Note: Before I go into this tutorial, I want to credit ellabrella. Their work on avoiding bad eggs and battle continuation was a huge help.

Goal: To add a ball that allows stealing other trainer's Pokemon. It behaves like a Pokeball in wild encounters, but a 2.5x modifier on trainers' Pokemon.
The ball will record the OT as the trainer you stole from.
The rival's, Elite Four's, and Wally's Pokemon will be stolen. As in: you steal their Torchic in the first battle and they will not have a Blaziken in their last battle.

Thief ball use Thief ball in storage

Contents

Limits.

  • I made it not work in the Battle Frontier - I don't want to test and debug that.
  • Doesn't work in double battles - Writing the code to select the correct Pokemon didn't seem fun. Besides, there's too many witnesses.
  • I made it not work in link battles, secret base battles, nor eReader battles.
  • The Pokemon are not considered valid. From what I understand when looking at the Pokemon in PKHex, because they get caught in routes that they aren't naturally found in, they won't be valid. No big deal since they work fine in the game, but fyi if you're trying to trade use them competitively (don't).
  • It does not allow you to see the Pokedex entry and nickname the caught Pokemon when catching. Believe me, I tried. I keep got it working 95% of the way, but there are sometimes graphical glitches and if you use the ball multiple times and fail, then catch successfully, then the next Pokemon will never use their next move after announcing it. Three hours of testing with breakpoints without finding a cause. If you're curious in looking at this issue and root causing it, HMU on Discord (devolov#4853).
  • Since a flag is needed for every Pokemon stolen, there's only a few that I made permanently stolen. I made those be the rival, Wally, and Norman's Slaking due to another hack I made.

Since I care about the game working with standard save editors, like PKHex, I am making this by replacing the Premier Ball, so there will be no Premier ball in the game. I also renamed all instances of Premier ball to Thief ball in my code to keep it organized, but if you don't care, you can leave all of the variable names as Premier.

Adding Graphics.

I made graphics of the Thief Ball based off Mewtwo Balls from the First Movie since he used them to steal Pokemon that weren't his (I'm guessing, I haven't seen that movie in a decade).

-------------------------- graphics/balls/premier.png --------------------------
deleted file mode 100644
index f5aaadbaf..000000000
Binary files a/graphics/balls/premier.png and /dev/null differ

--------------------------- graphics/balls/thief.png ---------------------------
new file mode 100644
index 000000000..c71ac65cc
Binary files /dev/null and b/graphics/balls/thief.png differ

ball icon

-------------------- graphics/items/icons/premier_ball.png --------------------
deleted file mode 100644
index 9dec98af9..000000000
Binary files a/graphics/items/icons/premier_ball.png and /dev/null differ

--------------------- graphics/items/icons/thief_ball.png ---------------------
new file mode 100644
index 000000000..e81c1f996
Binary files /dev/null and b/graphics/items/icons/thief_ball.png differ

item icon
This ball reuses the palette of the Ultra Ball, so no need to remake the palette!

Adding and Renaming Variables

------------------------------- include/battle.h -------------------------------
index c1c713691..e6c82f770 100644
@@ -643,8 +643,9 @@ extern u16 gCalledMove;
 extern s32 gBattleMoveDamage;
 extern s32 gHpDealt;
 extern s32 gTakenDmg[MAX_BATTLERS_COUNT];
 extern u16 gLastUsedItem;
+extern u8 gUsingThiefBall;
 extern u8 gLastUsedAbility;
 extern u8 gBattlerAttacker;

---------------------------- include/battle_main.h ----------------------------
index e3e0cb7ea..54c0e6785 100644
@@ -40,8 +40,22 @@ struct MultiPartnerMenuPokemon
 // defines for the 'DoBounceEffect' function
 #define BOUNCE_MON          0x0
 #define BOUNCE_HEALTHBOX    0x1
 
+// Rival's Stolen Pokemon
+#define STOLE_STARTER      (1 << 0)
+#define STOLE_WINGULL      (1 << 1)
+#define STOLE_SLUGMA       (1 << 2)
+#define STOLE_LOTAD        (1 << 3)
+#define STOLE_TROPIUS      (1 << 4)
+#define STOLE_TORKOAL      (1 << 5)
+#define STOLE_LEGENDARY    (1 << 6)
+#define STOLE_RALTS        (1 << 7)
+#define STOLE_ALTARIA      (1 << 8)
+#define STOLE_DELCATTY     (1 << 9)
+#define STOLE_ROSELIA      (1 << 10)
+#define STOLE_MAGNETON     (1 << 11)
+#define STOLE_SLAKING      (1 << 12)
+
+#define STOLE_SIDNEY_START     0
+#define STOLE_PHEOBE_START     5
+#define STOLE_GLACIA_START     10
+#define STOLE_DRAKE_START      0
+
 void CB2_InitBattle(void);
 void BattleMainCB2(void);
 void CB2_QuitRecordedBattle(void);
 void VBlankCB_Battle(void);
@@ -75,8 +89,9 @@ u8 GetWhoStrikesFirst(u8 battlerId1, u8 battlerId2, bool8 ignoreChosenMoves);
 void RunBattleScriptCommands_PopCallbacksStack(void);
 void RunBattleScriptCommands(void);
 bool8 TryRunFromBattle(u8 battlerId);
 void SpecialStatusesClear(void);
+u16 checkStolenPokemon(u16 trainerNum, u16 speciesType, u16 partyIndex, bool8 set);
 
 extern struct MultiPartnerMenuPokemon gMultiPartnerParty[MULTI_PARTY_SIZE];
 
 extern const struct SpriteTemplate gUnusedBattleInitSprite;

-------------------------- include/constants/battle.h --------------------------
index ac83feb3a..462fc3812 100644
@@ -97,8 +97,14 @@
 #define B_OUTCOME_FORFEITED            9
 #define B_OUTCOME_MON_TELEPORTED       10
 #define B_OUTCOME_LINK_BATTLE_RAN      (1 << 7) // 128
 
+//Thief Ball Defines
+#define THIEF_BALL_NOT_USING           0
+#define THIEF_BALL_CATCHING            1
+#define THIEF_BALL_CAUGHT              2
+#define THIEF_BALL_CANNOT_USE          3
+
 // Non-volatile status conditions
 // These persist remain outside of battle and after switching out
 #define STATUS1_NONE             0
 #define STATUS1_SLEEP            (1 << 0 | 1 << 1 | 1 << 2) // First 3 bits (Number of turns to sleep)

-------------------- include/constants/battle_string_ids.h --------------------
index 56e45cb8e..18d495d79 100644
@@ -379,10 +379,12 @@
 #define STRINGID_TRAINER1WINTEXT            379
 #define STRINGID_TRAINER2WINTEXT            380
 #define STRINGID_PLAYERLOSTTOENEMYTRAINER   381
 #define STRINGID_PLAYERPAIDPRIZEMONEY       382
+#define STRINGID_CANTWITHTHIEF              383
+#define STRINGID_TOOMANYWITNESSES           384
+#define STRINGID_GOTCHAPKMNCAUGHTNOBGM      385
 
-#define BATTLESTRINGS_COUNT                 383
+#define BATTLESTRINGS_COUNT                 386
 
 // This is the string id that gBattleStringsTable starts with.
 // String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
 // and are instead handled explicitly by BufferStringBattle.

-------------------------- include/constants/items.h --------------------------
index daf129c76..10f3f4d26 100644
@@ -14,15 +14,15 @@
 #define ITEM_NEST_BALL 8
 #define ITEM_REPEAT_BALL 9
 #define ITEM_TIMER_BALL 10
 #define ITEM_LUXURY_BALL 11
-#define ITEM_PREMIER_BALL 12
+#define ITEM_THIEF_BALL 12
 
 // Note: If moving ball IDs around, updating FIRST_BALL/LAST_BALL is not sufficient
 //       Several places expect the ball IDs to be first and contiguous (e.g. gBattlescriptsForBallThrow and MON_DATA_POKEBALL)
 //       If adding new balls, it's easiest to insert them after the last ball and increment the below IDs (and removing ITEM_034 for example)
 #define FIRST_BALL ITEM_MASTER_BALL
-#define LAST_BALL  ITEM_PREMIER_BALL
+#define LAST_BALL  ITEM_THIEF_BALL
 
 // Pokemon Items
 #define ITEM_POTION 13
 #define ITEM_ANTIDOTE 14

--------------------------- include/constants/vars.h ---------------------------
index 35ffb0714..f26ee2186 100644
@@ -146,23 +146,23 @@
 #define VAR_ROUTE132_STATE                               0x407F // Unused Var
 #define VAR_ROUTE133_STATE                               0x4080 // Unused Var
 #define VAR_ROUTE134_STATE                               0x4081 // Unused Var
 #define VAR_LITTLEROOT_HOUSES_STATE_MAY                  0x4082
-#define VAR_RIVAL_PKMN_STOLE                             0x4083
+#define VAR_PKMN_STOLE_RIVAL                             0x4083
 #define VAR_BIRCH_LAB_STATE                              0x4084
 #define VAR_PETALBURG_GYM_STATE                          0x4085 // 0-1: Wally tutorial, 2-6: 0-4 badges, 7: Defeated Norman, 8: Rematch Norman
 #define VAR_CONTEST_HALL_STATE                           0x4086
 #define VAR_CABLE_CLUB_STATE                             0x4087
 #define VAR_CONTEST_TYPE                                 0x4088
 #define VAR_SECRET_BASE_INITIALIZED                      0x4089
 #define VAR_CONTEST_PRIZE_PICKUP                         0x408A
-#define VAR_UNUSED_0x408B                                0x408B // Unused Var
+#define VAR_PKMN_STOLE_ELITE4_A                          0x408B
 #define VAR_LITTLEROOT_HOUSES_STATE_BRENDAN              0x408C
 #define VAR_LITTLEROOT_RIVAL_STATE                       0x408D
 #define VAR_BOARD_BRINEY_BOAT_STATE                      0x408E
 #define VAR_DEVON_CORP_3F_STATE                          0x408F
 #define VAR_BRINEY_HOUSE_STATE                           0x4090
-#define VAR_UNUSED_0x4091                                0x4091 // Unused Var
+#define VAR_PKMN_STOLE_ELITE4_B                          0x4091
 #define VAR_LITTLEROOT_INTRO_STATE                       0x4092
 #define VAR_MAUVILLE_GYM_STATE                           0x4093
 #define VAR_LILYCOVE_MUSEUM_2F_STATE                     0x4094
 #define VAR_LILYCOVE_FAN_CLUB_STATE                      0x4095
------------------------------ include/graphics.h ------------------------------
index 8bdc85dc4..f93a0eb12 100644
@@ -27,10 +27,10 @@ extern const u32 gBallPal_Repeat[];
 extern const u32 gBallGfx_Timer[];
 extern const u32 gBallPal_Timer[];
 extern const u32 gBallGfx_Luxury[];
 extern const u32 gBallPal_Luxury[];
-extern const u32 gBallGfx_Premier[];
-extern const u32 gBallPal_Premier[];
+extern const u32 gBallGfx_Thief[];
+extern const u32 gBallPal_Thief[];
 extern const u32 gOpenPokeballGfx[];
 
 // pokemon gfx
 extern const u32 gMonFrontPic_Bulbasaur[];
@@ -3383,9 +3383,9 @@ extern const u32 gItemIcon_RepeatBall[];
 extern const u32 gItemIconPalette_RepeatBall[];
 extern const u32 gItemIcon_TimerBall[];
 extern const u32 gItemIcon_LuxuryBall[];
 extern const u32 gItemIconPalette_LuxuryBall[];
-extern const u32 gItemIcon_PremierBall[];
+extern const u32 gItemIcon_ThiefBall[];
 // Medicine
 extern const u32 gItemIcon_Potion[];
 extern const u32 gItemIconPalette_Potion[];
 extern const u32 gItemIcon_Antidote[];

------------------------------ include/pokeball.h ------------------------------
index 1149791b8..d2598c725 100644
@@ -13,9 +13,9 @@ enum
     BALL_NEST,
     BALL_REPEAT,
     BALL_TIMER,
     BALL_LUXURY,
-    BALL_PREMIER,
+    BALL_THIEF,
     POKEBALL_COUNT
 };
 
 enum {

------------------------------ include/strings.h ------------------------------
index 49e978447..10043318b 100644
@@ -1019,9 +1019,9 @@ extern const u8 gText_HereYouGoThankYou[];
 extern const u8 gText_NoMoreRoomForThis[];
 extern const u8 gText_ThankYouIllSendItHome[];
 extern const u8 gText_ThanksIllSendItHome[];
 extern const u8 gText_SpaceForVar1Full[];
-extern const u8 gText_ThrowInPremierBall[];
+extern const u8 gText_ThrowInThiefBall[];
 extern const u8 gText_ShopBuy[];
 extern const u8 gText_ShopSell[];
 extern const u8 gText_ShopQuit[];

--------------------------- src/battle_anim_throw.c ---------------------------
index d81b532c5..f0fcee89c 100755
@@ -78,9 +78,9 @@ static void PokeBallOpenParticleAnimation_Step1(struct Sprite *);
 static void PokeBallOpenParticleAnimation_Step2(struct Sprite *);
 static void DestroyBallOpenAnimationParticle(struct Sprite *);
 static void FanOutBallOpenParticles_Step1(struct Sprite *);
 static void RepeatBallOpenParticleAnimation_Step1(struct Sprite *);
-static void PremierBallOpenParticleAnimation_Step1(struct Sprite *);
+static void ThiefBallOpenParticleAnimation_Step1(struct Sprite *);
 static void Task_FadeMon_ToBallColor(u8);
 static void Task_FadeMon_ToNormal(u8);
 static void Task_FadeMon_ToNormal_Step(u8);
 static void Task_ShinyStars(u8);
@@ -97,9 +97,9 @@ static void UltraBallOpenParticleAnimation(u8);
 static void MasterBallOpenParticleAnimation(u8);
 static void DiveBallOpenParticleAnimation(u8);
 static void RepeatBallOpenParticleAnimation(u8);
 static void TimerBallOpenParticleAnimation(u8);
-static void PremierBallOpenParticleAnimation(u8);
+static void ThiefBallOpenParticleAnimation(u8);
 static void SpriteCB_PokeBlock_Throw(struct Sprite *);
 
 struct CaptureStar
 {
@@ -137,9 +137,9 @@ static const struct CaptureStar sCaptureStars[] =
 #define TAG_PARTICLES_NESTBALL    55027
 #define TAG_PARTICLES_REPEATBALL  55028
 #define TAG_PARTICLES_TIMERBALL   55029
 #define TAG_PARTICLES_LUXURYBALL  55030
-#define TAG_PARTICLES_PREMIERBALL 55031
+#define TAG_PARTICLES_THIEFBALL   55031
 
 static const struct CompressedSpriteSheet sBallParticleSpriteSheets[POKEBALL_COUNT] =
 {
     [BALL_POKE]    = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_POKEBALL},
@@ -152,9 +152,9 @@ static const struct CompressedSpriteSheet sBallParticleSpriteSheets[POKEBALL_COU
     [BALL_NEST]    = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_NESTBALL},
     [BALL_REPEAT]  = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_REPEATBALL},
     [BALL_TIMER]   = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_TIMERBALL},
     [BALL_LUXURY]  = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_LUXURYBALL},
-    [BALL_PREMIER] = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_PREMIERBALL},
+    [BALL_THIEF] = {gBattleAnimSpriteGfx_Particles, 0x100, TAG_PARTICLES_THIEFBALL},
 };
 
 static const struct CompressedSpritePalette sBallParticlePalettes[POKEBALL_COUNT] =
 {
@@ -168,9 +168,9 @@ static const struct CompressedSpritePalette sBallParticlePalettes[POKEBALL_COUNT
     [BALL_NEST]    = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_NESTBALL},
     [BALL_REPEAT]  = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_REPEATBALL},
     [BALL_TIMER]   = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_TIMERBALL},
     [BALL_LUXURY]  = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_LUXURYBALL},
-    [BALL_PREMIER] = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_PREMIERBALL},
+    [BALL_THIEF] = {gBattleAnimSpritePal_CircleImpact, TAG_PARTICLES_THIEFBALL},
 };
 
 static const union AnimCmd sAnim_RegularBall[] =
 {
@@ -200,9 +200,9 @@ static const union AnimCmd sAnim_NestBall[] =
     ANIMCMD_FRAME(5, 1),
     ANIMCMD_END,
 };
 
-static const union AnimCmd sAnim_LuxuryPremierBall[] =
+static const union AnimCmd sAnim_LuxuryThiefBall[] =
 {
     ANIMCMD_FRAME(6, 4),
     ANIMCMD_FRAME(7, 4),
     ANIMCMD_JUMP(0),
@@ -219,9 +219,9 @@ static const union AnimCmd *const sAnims_BallParticles[] =
     sAnim_RegularBall,
     sAnim_MasterBall,
     sAnim_NetDiveBall,
     sAnim_NestBall,
-    sAnim_LuxuryPremierBall,
+    sAnim_LuxuryThiefBall,
     sAnim_UltraRepeatTimerBall,
 };
 
 static const u8 sBallParticleAnimNums[POKEBALL_COUNT] =
@@ -236,9 +236,9 @@ static const u8 sBallParticleAnimNums[POKEBALL_COUNT] =
     [BALL_NEST]    = 3,
     [BALL_REPEAT]  = 5,
     [BALL_TIMER]   = 5,
     [BALL_LUXURY]  = 4,
-    [BALL_PREMIER] = 4,
+    [BALL_THIEF]   = 4,
 };
 
 static const TaskFunc sBallParticleAnimationFuncs[POKEBALL_COUNT] =
 {
@@ -252,9 +252,9 @@ static const TaskFunc sBallParticleAnimationFuncs[POKEBALL_COUNT] =
     [BALL_NEST]    = UltraBallOpenParticleAnimation,
     [BALL_REPEAT]  = RepeatBallOpenParticleAnimation,
     [BALL_TIMER]   = TimerBallOpenParticleAnimation,
     [BALL_LUXURY]  = GreatBallOpenParticleAnimation,
-    [BALL_PREMIER] = PremierBallOpenParticleAnimation,
+    [BALL_THIEF] = ThiefBallOpenParticleAnimation,
 };
 
 static const struct SpriteTemplate sBallParticleSpriteTemplates[POKEBALL_COUNT] =
 {
@@ -356,11 +356,11 @@ static const struct SpriteTemplate sBallParticleSpriteTemplates[POKEBALL_COUNT]
         .images = NULL,
         .affineAnims = gDummySpriteAffineAnimTable,
         .callback = SpriteCallbackDummy,
     },
-    [BALL_PREMIER] = {
-        .tileTag = TAG_PARTICLES_PREMIERBALL,
-        .paletteTag = TAG_PARTICLES_PREMIERBALL,
+    [BALL_THIEF] = {
+        .tileTag = TAG_PARTICLES_THIEFBALL,
+        .paletteTag = TAG_PARTICLES_THIEFBALL,
         .oam = &gOamData_AffineOff_ObjNormal_8x8,
         .anims = sAnims_BallParticles,
         .images = NULL,
         .affineAnims = gDummySpriteAffineAnimTable,
@@ -380,9 +380,9 @@ const u16 gBallOpenFadeColors[] =
     [BALL_NEST] = RGB(30, 27, 10),
     [BALL_REPEAT] = RGB(31, 24, 16),
     [BALL_TIMER] = RGB(29, 30, 30),
     [BALL_LUXURY] = RGB(31, 17, 10),
-    [BALL_PREMIER] = RGB(31, 9, 10),
+    [BALL_THIEF] = RGB(31, 9, 10),
 
     // Garbage data
     RGB(0, 0, 0),
     RGB(1, 16, 0),
@@ -748,10 +748,10 @@ u8 ItemIdToBallId(u16 ballItem)
     case ITEM_TIMER_BALL:
         return BALL_TIMER;
     case ITEM_LUXURY_BALL:
         return BALL_LUXURY;
-    case ITEM_PREMIER_BALL:
-        return BALL_PREMIER;
+    case ITEM_THIEF_BALL:
+        return BALL_THIEF;
     case ITEM_POKE_BALL:
     default:
         return BALL_POKE;
     }
@@ -1927,9 +1927,9 @@ static void MasterBallOpenParticleAnimation(u8 taskId)
 
     DestroyTask(taskId);
 }
 
-static void PremierBallOpenParticleAnimation(u8 taskId)
+static void ThiefBallOpenParticleAnimation(u8 taskId)
 {
     u8 i;
     u8 x, y, priority, subpriority, ballId;
     u8 spriteId;
@@ -1946,9 +1946,9 @@ static void PremierBallOpenParticleAnimation(u8 taskId)
         if (spriteId != MAX_SPRITES)
         {
             IncrBallParticleCount();
             StartSpriteAnim(&gSprites[spriteId], sBallParticleAnimNums[ballId]);
-            gSprites[spriteId].callback = PremierBallOpenParticleAnimation_Step1;
+            gSprites[spriteId].callback = ThiefBallOpenParticleAnimation_Step1;
             gSprites[spriteId].oam.priority = priority;
             gSprites[spriteId].data[0] = i * 32;
         }
     }
@@ -1958,9 +1958,9 @@ static void PremierBallOpenParticleAnimation(u8 taskId)
 
     DestroyTask(taskId);
 }
 
-static void PremierBallOpenParticleAnimation_Step1(struct Sprite *sprite)
+static void ThiefBallOpenParticleAnimation_Step1(struct Sprite *sprite)
 {
     sprite->x2 = Sin(sprite->data[0], sprite->data[1]);
     sprite->y2 = Cos(sprite->data[0], Sin(sprite->data[0] & 0x3F, sprite->data[2]));
     sprite->data[0] = (sprite->data[0] + 10) & 0xFF;


----------------------------- src/battle_message.c -----------------------------
index 8ec34b0fe..dfad229c0 100644
@@ -464,8 +464,9 @@ static const u8 sText_PlayerUsedItem[] = _("{B_PLAYER_NAME} used\n{B_LAST_ITEM}!
 static const u8 sText_WallyUsedItem[] = _("WALLY used\n{B_LAST_ITEM}!");
 static const u8 sText_Trainer1UsedItem[] = _("{B_TRAINER1_CLASS} {B_TRAINER1_NAME}\nused {B_LAST_ITEM}!");
 static const u8 sText_TrainerBlockedBall[] = _("The TRAINER blocked the BALL!");
 static const u8 sText_DontBeAThief[] = _("Don't be a thief!");
+static const u8 sText_CantWithThief[] = _("Thief balls don't work in\nthis kind of battle!");
+static const u8 sText_TooManyWitnesses[] = _("There's too many\nwitnesses...");
 static const u8 sText_ItDodgedBall[] = _("It dodged the thrown BALL!\nThis POKéMON can't be caught!");
 static const u8 sText_YouMissedPkmn[] = _("You missed the POKéMON!");
 static const u8 sText_PkmnBrokeFree[] = _("Oh, no!\nThe POKéMON broke free!");
 static const u8 sText_ItAppearedCaught[] = _("Aww!\nIt appeared to be caught!");
@@ -514,8 +515,9 @@ static const u8 sText_ForfeitedMatch[];
 static const u8 sText_Trainer1WinText[];
 static const u8 sText_Trainer2WinText[];
 static const u8 sText_TwoInGameTrainersDefeated[];
 static const u8 sText_Trainer2LoseText[];
+static const u8 sText_GotchaPkmnCaughtNoBgm[];
 
 const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_START] =
 {
     [STRINGID_TRAINER1LOSETEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1LoseText,
@@ -888,8 +890,10 @@ const u8 * const gBattleStringsTable[BATTLESTRINGS_COUNT - BATTLESTRINGS_TABLE_S
     [STRINGID_TRAINER1WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer1WinText,
     [STRINGID_TRAINER2WINTEXT - BATTLESTRINGS_TABLE_START] = sText_Trainer2WinText,
     [STRINGID_PLAYERLOSTTOENEMYTRAINER - BATTLESTRINGS_TABLE_START] = sText_PlayerLostToEnemyTrainer,
     [STRINGID_PLAYERPAIDPRIZEMONEY - BATTLESTRINGS_TABLE_START] = sText_PlayerPaidPrizeMoney,
+    [STRINGID_CANTWITHTHIEF - BATTLESTRINGS_TABLE_START] = sText_CantWithThief,
+    [STRINGID_TOOMANYWITNESSES - BATTLESTRINGS_TABLE_START] = sText_TooManyWitnesses,
+    [STRINGID_GOTCHAPKMNCAUGHTNOBGM - BATTLESTRINGS_TABLE_START] = sText_GotchaPkmnCaughtNoBgm,
 };
 
 const u16 gMissStringIds[] =
 {
@@ -1386,8 +1390,9 @@ static const u8 sText_PkmnIncapableOfPower[] = _("{B_ATK_NAME_WITH_PREFIX} appea
 static const u8 sText_GlintAppearsInEye[] = _("A glint appears in\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s eyes!");
 static const u8 sText_PkmnGettingIntoPosition[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is getting into\nposition!");
 static const u8 sText_PkmnBeganGrowlingDeeply[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} began growling deeply!");
 static const u8 sText_PkmnEagerForMore[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is eager for more!");
+static const u8 sText_GotchaPkmnCaughtNoBgm[] = _("Gotcha! {B_TRAINER1_CLASS}\n{B_TRAINER1_NAME}'s {B_OPPONENT_MON1_NAME} was caught!{WAIT_SE}{RESUME_MUSIC}\p");
 
 const u16 gBattlePalaceFlavorTextTable[] =
 {
     [B_MSG_GLINT_IN_EYE]   = STRINGID_GLINTAPPEARSINEYE,


-------------------------- src/data/graphics/items.h --------------------------
index 26da9061d..6f53552b8 100644
@@ -37,9 +37,9 @@ const u32 gItemIcon_TimerBall[] = INCBIN_U32("graphics/items/icons/timer_ball.4b
 
 const u32 gItemIcon_LuxuryBall[] = INCBIN_U32("graphics/items/icons/luxury_ball.4bpp.lz");
 const u32 gItemIconPalette_LuxuryBall[] = INCBIN_U32("graphics/items/icon_palettes/luxury_ball.gbapal.lz");
 
-const u32 gItemIcon_PremierBall[] = INCBIN_U32("graphics/items/icons/premier_ball.4bpp.lz");
+const u32 gItemIcon_ThiefBall[] = INCBIN_U32("graphics/items/icons/thief_ball.4bpp.lz");
 
 // Medicine
 
 const u32 gItemIcon_Potion[] = INCBIN_U32("graphics/items/icons/potion.4bpp.lz");

------------------------ src/data/graphics/pokeballs.h ------------------------
index 8203fca53..f23362740 100644
@@ -30,8 +30,8 @@ const u32 gBallPal_Timer[] = INCBIN_U32("graphics/balls/timer.gbapal.lz");
 
 const u32 gBallGfx_Luxury[] = INCBIN_U32("graphics/balls/luxury.4bpp.lz");
 const u32 gBallPal_Luxury[] = INCBIN_U32("graphics/balls/luxury.gbapal.lz");
 
-const u32 gBallGfx_Premier[] = INCBIN_U32("graphics/balls/premier.4bpp.lz");
-const u32 gBallPal_Premier[] = INCBIN_U32("graphics/balls/premier.gbapal.lz");
+const u32 gBallGfx_Thief[] = INCBIN_U32("graphics/balls/thief.4bpp.lz");
+const u32 gBallPal_Thief[] = INCBIN_U32("graphics/balls/thief.gbapal.lz");
 
 const u32 gOpenPokeballGfx[] = INCBIN_U32("graphics/balls/open.4bpp.lz");

-------------------------- src/data/item_icon_table.h --------------------------
index 64328f7b1..9276a9719 100644
@@ -12,9 +12,9 @@ const u32 *const gItemIconTable[ITEMS_COUNT + 1][2] =
     [ITEM_NEST_BALL] = {gItemIcon_NestBall, gItemIconPalette_NestBall},
     [ITEM_REPEAT_BALL] = {gItemIcon_RepeatBall, gItemIconPalette_RepeatBall},
     [ITEM_TIMER_BALL] = {gItemIcon_TimerBall, gItemIconPalette_RepeatBall},
     [ITEM_LUXURY_BALL] = {gItemIcon_LuxuryBall, gItemIconPalette_LuxuryBall},
-    [ITEM_PREMIER_BALL] = {gItemIcon_PremierBall, gItemIconPalette_LuxuryBall},
+    [ITEM_THIEF_BALL] = {gItemIcon_ThiefBall, gItemIconPalette_UltraBall},
     // Medicine
     [ITEM_POTION] = {gItemIcon_Potion, gItemIconPalette_Potion},
     [ITEM_ANTIDOTE] = {gItemIcon_Antidote, gItemIconPalette_Antidote},
     [ITEM_BURN_HEAL] = {gItemIcon_StatusHeal, gItemIconPalette_BurnHeal},

------------------------------- src/data/items.h -------------------------------
index 072ec1bf5..35d7167c1 100644
@@ -155,19 +155,19 @@ const struct Item gItems[] =
         .battleUseFunc = ItemUseInBattle_PokeBall,
         .secondaryId = ITEM_LUXURY_BALL - FIRST_BALL,
     },
 
-    [ITEM_PREMIER_BALL] =
+    [ITEM_THIEF_BALL] =
     {
-        .name = _("PREMIER BALL"),
-        .itemId = ITEM_PREMIER_BALL,
-        .price = 200,
-        .description = sPremierBallDesc,
+        .name = _("THIEF BALL"),
+        .itemId = ITEM_THIEF_BALL,
+        .price = 2000,
+        .description = sThiefBallDesc,
         .pocket = POCKET_POKE_BALLS,
-        .type = ITEM_PREMIER_BALL - FIRST_BALL,
+        .type = ITEM_THIEF_BALL - FIRST_BALL,
         .battleUsage = ITEM_B_USE_OTHER,
         .battleUseFunc = ItemUseInBattle_PokeBall,
-        .secondaryId = ITEM_PREMIER_BALL - FIRST_BALL,
+        .secondaryId = ITEM_THIEF_BALL - FIRST_BALL,
     },
 
 // Medicine
---------------------- src/data/text/item_descriptions.h ----------------------
index 5f79efc57..f9f05e5f6 100644
@@ -56,12 +56,12 @@ static const u8 sLuxuryBallDesc[] = _(
     "A cozy BALL that\n"
     "makes POKéMON\n"
     "more friendly.");
 
-static const u8 sPremierBallDesc[] = _(
-    "A rare BALL made\n"
-    "in commemoration\n"
-    "of some event.");
+static const u8 sThiefBallDesc[] = _(
+    "A  BALL that allows\n"
+    "the stealing of\n"
+    "others' POKéMON.");
 
 // Medicine
 static const u8 sPotionDesc[] = _(
     "Restores the HP of\n"

-------------------------------- src/pokeball.c --------------------------------
index 2633fd574..fd7c421a8 100644
@@ -54,9 +54,9 @@ static u16 GetBattlerPokeballItemId(u8 battlerId);
 #define GFX_TAG_NEST_BALL    55007
 #define GFX_TAG_REPEAT_BALL  55008
 #define GFX_TAG_TIMER_BALL   55009
 #define GFX_TAG_LUXURY_BALL  55010
-#define GFX_TAG_PREMIER_BALL 55011
+#define GFX_TAG_THIEF_BALL   55011
 
 const struct CompressedSpriteSheet gBallSpriteSheets[POKEBALL_COUNT] =
 {
     [BALL_POKE]    = {gBallGfx_Poke,    384, GFX_TAG_POKE_BALL},
@@ -69,9 +69,9 @@ const struct CompressedSpriteSheet gBallSpriteSheets[POKEBALL_COUNT] =
     [BALL_NEST]    = {gBallGfx_Nest,    384, GFX_TAG_NEST_BALL},
     [BALL_REPEAT]  = {gBallGfx_Repeat,  384, GFX_TAG_REPEAT_BALL},
     [BALL_TIMER]   = {gBallGfx_Timer,   384, GFX_TAG_TIMER_BALL},
     [BALL_LUXURY]  = {gBallGfx_Luxury,  384, GFX_TAG_LUXURY_BALL},
-    [BALL_PREMIER] = {gBallGfx_Premier, 384, GFX_TAG_PREMIER_BALL},
+    [BALL_THIEF] = {gBallGfx_Thief, 384, GFX_TAG_THIEF_BALL},
 };
 
 const struct CompressedSpritePalette gBallSpritePalettes[POKEBALL_COUNT] =
 {
@@ -85,9 +85,9 @@ const struct CompressedSpritePalette gBallSpritePalettes[POKEBALL_COUNT] =
     [BALL_NEST]    = {gBallPal_Nest,    GFX_TAG_NEST_BALL},
     [BALL_REPEAT]  = {gBallPal_Repeat,  GFX_TAG_REPEAT_BALL},
     [BALL_TIMER]   = {gBallPal_Timer,   GFX_TAG_TIMER_BALL},
     [BALL_LUXURY]  = {gBallPal_Luxury,  GFX_TAG_LUXURY_BALL},
-    [BALL_PREMIER] = {gBallPal_Premier, GFX_TAG_PREMIER_BALL},
+    [BALL_THIEF] = {gBallPal_Thief, GFX_TAG_THIEF_BALL},
 };
 
 static const struct OamData sBallOamData =
 {
@@ -313,12 +313,12 @@ const struct SpriteTemplate gBallSpriteTemplates[POKEBALL_COUNT] =
         .images = NULL,
         .affineAnims = sAffineAnim_BallRotate,
         .callback = SpriteCB_BallThrow,
     },
-    [BALL_PREMIER] =
+    [BALL_THIEF] =
     {
-        .tileTag = GFX_TAG_PREMIER_BALL,
-        .paletteTag = GFX_TAG_PREMIER_BALL,
+        .tileTag = GFX_TAG_THIEF_BALL,
+        .paletteTag = GFX_TAG_THIEF_BALL,
         .oam = &sBallOamData,
         .anims = sBallAnimSequences,
         .images = NULL,
         .affineAnims = sAffineAnim_BallRotate,
@@ -1319,9 +1319,9 @@ void LoadBallGfx(u8 ballId)
     switch (ballId)
     {
     case BALL_DIVE:
     case BALL_LUXURY:
-    case BALL_PREMIER:
+    case BALL_THIEF:
         break;
     default:
         var = GetSpriteTileStartByTag(gBallSpriteSheets[ballId].tag);
         LZDecompressVram(gOpenPokeballGfx, (void *)(OBJ_VRAM0 + 0x100 + var * 32));

-------------------------------- src/strings.c --------------------------------
index 622d7613e..eeb7b1e7b 100644
@@ -354,9 +354,9 @@ const u8 gText_YouDontHaveMoney[] = _("You don't have enough money.{PAUSE_UNTIL_
 const u8 gText_NoMoreRoomForThis[] = _("You have no more room for this\nitem.{PAUSE_UNTIL_PRESS}");
 const u8 gText_SpaceForVar1Full[] = _("The space for {STR_VAR_1} is full.{PAUSE_UNTIL_PRESS}");
 const u8 gText_AnythingElseICanHelp[] = _("Is there anything else I can help\nyou with?");
 const u8 gText_CanIHelpWithAnythingElse[] = _("Can I help you with anything else?");
-const u8 gText_ThrowInPremierBall[] = _("I'll throw in a PREMIER BALL, too.{PAUSE_UNTIL_PRESS}");
+const u8 gText_ThrowInThiefBall[] = _("I'll throw in a PREMIER BALL, too.{PAUSE_UNTIL_PRESS}");
 const u8 gText_CantBuyKeyItem[] = _("{STR_VAR_2}? Oh, no.\nI can't buy that.{PAUSE_UNTIL_PRESS}");
 const u8 gText_HowManyToSell[] = _("{STR_VAR_2}?\nHow many would you like to sell?");
 const u8 gText_ICanPayVar1[] = _("I can pay ¥{STR_VAR_1}.\nWould that be okay?");
 const u8 gText_TurnedOverVar1ForVar2[] = _("Turned over the {STR_VAR_2}\nand received ¥{STR_VAR_1}.");

The Logic:

------------------------- src/battle_script_commands.c -------------------------
index b22577455..b8605454e 100644
@@ -3234,13 +3235,17 @@ static void Cmd_getexp(void)
     u16 *exp = &gBattleStruct->expValue;
 
     gBattlerFainted = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]);
     sentIn = gSentPokesToOpponent[(gBattlerFainted & 2) >> 1];
    
     switch (gBattleScripting.getexpState)
     {
     case 0: // check if should receive exp at all
-        if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT || (gBattleTypeFlags &
+        if (gUsingThiefBall == THIEF_BALL_CAUGHT){
+            gUsingThiefBall = THIEF_BALL_NOT_USING;
+            gBattleScripting.getexpState = 6; // goto last case
+        }
+        else if (GetBattlerSide(gBattlerFainted) != B_SIDE_OPPONENT || (gBattleTypeFlags &
              (BATTLE_TYPE_LINK
               | BATTLE_TYPE_RECORDED_LINK
               | BATTLE_TYPE_TRAINER_HILL
               | BATTLE_TYPE_FRONTIER
@@ -9820,11 +9825,25 @@ static void Cmd_handleballthrow(void)
     if (gBattleControllerExecFlags)
         return;
 
     gActiveBattler = gBattlerAttacker;
-    gBattlerTarget = BATTLE_OPPOSITE(gBattlerAttacker);
 
-    if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
+    gBattlerTarget = BATTLE_OPPOSITE(gBattlerAttacker);
+    if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gLastUsedItem == ITEM_THIEF_BALL){
+        if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | 
+        BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_FRONTIER | 
+        BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED_LINK)){
+            gUsingThiefBall = THIEF_BALL_CANNOT_USE;
+        }
+        else{
+            gUsingThiefBall = THIEF_BALL_CATCHING;
+        }
+    }
+    else{
+        gUsingThiefBall = THIEF_BALL_NOT_USING;
+    }
+    if (gBattleTypeFlags & BATTLE_TYPE_TRAINER &&
+    (gUsingThiefBall == THIEF_BALL_NOT_USING || gUsingThiefBall == THIEF_BALL_CANNOT_USE))
     {
         BtlController_EmitBallThrowAnim(BUFFER_A, BALL_TRAINER_BLOCK);
         MarkBattlerForControllerExec(gActiveBattler);
         gBattlescriptCurrInstr = BattleScript_TrainerBallBlock;
@@ -9884,11 +9903,16 @@ static void Cmd_handleballthrow(void)
                 if (ballMultiplier > 40)
                     ballMultiplier = 40;
                 break;
             case ITEM_LUXURY_BALL:
-            case ITEM_PREMIER_BALL:
                 ballMultiplier = 10;
                 break;
+            case ITEM_THIEF_BALL:  // If used on trainer, it's 2.5x; if used on a wild Pokemon, it's 1x
+                if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
+                    ballMultiplier = 25;
+                else
+                    ballMultiplier = 10;
+                break;
             }
         }
         else
             ballMultiplier = sBallCatchBonuses[gLastUsedItem - ITEM_ULTRA_BALL];
@@ -9918,8 +9942,11 @@ static void Cmd_handleballthrow(void)
         if (odds > 254) // mon caught
         {
             BtlController_EmitBallThrowAnim(BUFFER_A, BALL_3_SHAKES_SUCCESS);
             MarkBattlerForControllerExec(gActiveBattler);
+            if (gUsingThiefBall == THIEF_BALL_CATCHING){
+                gUsingThiefBall = THIEF_BALL_CAUGHT;
+            }
             gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
             SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
 
             if (CalculatePlayerPartyCount() == PARTY_SIZE)
@@ -9940,11 +9967,13 @@ static void Cmd_handleballthrow(void)
                 shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check?
 
             BtlController_EmitBallThrowAnim(BUFFER_A, shakes);
             MarkBattlerForControllerExec(gActiveBattler);
             if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above
             {
+                if (gUsingThiefBall == THIEF_BALL_CATCHING){
+                    gUsingThiefBall = THIEF_BALL_CAUGHT;
+                }
                 gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
                 SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
 
                 if (CalculatePlayerPartyCount() == PARTY_SIZE)
@@ -9953,8 +9982,9 @@ static void Cmd_handleballthrow(void)
                     gBattleCommunication[MULTISTRING_CHOOSER] = 1;
             }
             else // not caught
             {
+                gUsingThiefBall = THIEF_BALL_NOT_USING;
                 gBattleCommunication[MULTISTRING_CHOOSER] = shakes;
                 gBattlescriptCurrInstr = BattleScript_ShakeBallThrow;
             }
         }
@@ -9986,15 +10016,22 @@ static void Cmd_givecaughtmon(void)
 
     gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_SPECIES, NULL);
     GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick);
     gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_POKEBALL, NULL);
+    if (gUsingThiefBall == THIEF_BALL_CAUGHT)
+    {
+        u16 partyIndex = gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]; 
+        checkStolenPokemon(gTrainerBattleOpponent_A, gBattleMons[gBattlerTarget].species, partyIndex, TRUE);
+        gBattleMons[gBattlerTarget].hp = 0;
+        SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerAttacker ^ BIT_SIDE]], MON_DATA_HP, &gBattleMons[gBattlerTarget].hp);
+        gBattlerFainted = gBattlerTarget;
+        SetHealthboxSpriteInvisible(gHealthboxSpriteIds[gBattlerTarget]);
+    }
 
     gBattlescriptCurrInstr++;
 }
 
 static void Cmd_trysetcaughtmondexflags(void)
 {
-    u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
-    u32 personality = GetMonData(&gEnemyParty[0], MON_DATA_PERSONALITY, NULL);
+    u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_SPECIES, NULL);
+    u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_PERSONALITY, NULL);
 
     if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
     {
         gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
     }
     else if (!FlagGet(FLAG_SYS_POKEDEX_GET))
     {
         HandleSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_SET_CAUGHT, personality);
         gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
     }
     else
@@ -10008,16 +10045,14 @@ static void Cmd_trysetcaughtmondexflags(void)
 }
 
 static void Cmd_displaydexinfo(void)
 {
-    u16 species = GetMonData(&gEnemyParty[0], MON_DATA_SPECIES, NULL);
+    u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[BATTLE_OPPOSITE(gBattlerAttacker)]], MON_DATA_SPECIES, NULL);
     switch (gBattleCommunication[0])
     {
     case 0:
         BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
         gBattleCommunication[0]++;
         break;
     case 1:
         if (!gPaletteFade.active)
         {
             FreeAllWindowBuffers();
@@ -10232,4 +10267,20 @@ static void Cmd_trainerslideout(void)
     MarkBattlerForControllerExec(gActiveBattler);
 
     gBattlescriptCurrInstr += 2;
 }

--------------------------- data/battle_scripts_2.s ---------------------------
index b7f0f693f..d1881fcf0 100644
@@ -24,9 +24,9 @@ gBattlescriptsForBallThrow::
 	.4byte BattleScript_BallThrow        @ ITEM_NEST_BALL
 	.4byte BattleScript_BallThrow        @ ITEM_REPEAT_BALL
 	.4byte BattleScript_BallThrow        @ ITEM_TIMER_BALL
 	.4byte BattleScript_BallThrow        @ ITEM_LUXURY_BALL
-	.4byte BattleScript_BallThrow        @ ITEM_PREMIER_BALL
+	.4byte BattleScript_BallThrow        @ ITEM_THIEF_BALL
 
 	.align 2
 gBattlescriptsForUsingItem::
 	.4byte BattleScript_PlayerUsesItem
@@ -63,8 +63,9 @@ BattleScript_SafariBallThrow::
 
 BattleScript_SuccessBallThrow::
 	jumpifhalfword CMP_EQUAL, gLastUsedItem, ITEM_SAFARI_BALL, BattleScript_PrintCaughtMonInfo
 	incrementgamestat GAME_STAT_POKEMON_CAPTURES
+	jumpifbyte CMP_EQUAL, gUsingThiefBall, THIEF_BALL_CAUGHT, BattleScript_SuccessBallThrowThief
 BattleScript_PrintCaughtMonInfo::
 	printstring STRINGID_GOTCHAPKMNCAUGHT
 	trysetcaughtmondexflags BattleScript_TryNicknameCaughtMon
 	printstring STRINGID_PKMNDATAADDEDTODEX
@@ -78,14 +79,18 @@ BattleScript_TryNicknameCaughtMon::
 	trygivecaughtmonnick BattleScript_GiveCaughtMonEnd
 	givecaughtmon
 	printfromtable gCaughtMonStringIds
 	waitmessage B_WAIT_TIME_LONG
 	goto BattleScript_SuccessBallThrowEnd
 BattleScript_GiveCaughtMonEnd::
 	givecaughtmon
 BattleScript_SuccessBallThrowEnd::
 	setbyte gBattleOutcome, B_OUTCOME_CAUGHT
 	finishturn
+BattleScript_SuccessBallThrowThief::
+	printstring STRINGID_GOTCHAPKMNCAUGHTNOBGM
+	trysetcaughtmondexflags BattleScript_SuccessBallThrowEndThiefGive
+	printstring STRINGID_PKMNDATAADDEDTODEX
+	waitstate
+BattleScript_SuccessBallThrowEndThiefGive::
+	setbyte gBattleCommunication, 4
+	trygivecaughtmonnick BattleScript_GiveCaughtMonEndThief
+	givecaughtmon
+	printfromtable gCaughtMonStringIds
+	waitmessage B_WAIT_TIME_LONG
+	goto BattleScript_SuccessBallThrowEndThief
+BattleScript_GiveCaughtMonEndThief::
+	givecaughtmon
+BattleScript_SuccessBallThrowEndThief::
+	cleareffectsonfaint BS_TARGET
+	goto BattleScript_HandleFaintedMon
 
 BattleScript_WallyBallThrow::
 	printstring STRINGID_GOTCHAPKMNCAUGHT2
 	setbyte gBattleOutcome, B_OUTCOME_CAUGHT
@@ -105,12 +110,19 @@ BattleScript_ShakeBallThrowEnd::
 BattleScript_TrainerBallBlock::
 	waitmessage B_WAIT_TIME_LONG
 	printstring STRINGID_TRAINERBLOCKEDBALL
 	waitmessage B_WAIT_TIME_LONG
+	jumpifbyte CMP_EQUAL, gUsingThiefBall, THIEF_BALL_CANNOT_USE, BattleScript_TrainerBallBlockThiefBall
 	printstring STRINGID_DONTBEATHIEF
+	goto BattleScript_TrainerBallBlockEnd
+BattleScript_TrainerBallBlockThiefBall::
+	setbyte gUsingThiefBall, THIEF_BALL_NOT_USING
+	printstring STRINGID_CANTWITHTHIEF
+	jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_TrainerBallBlockEnd
+	waitmessage B_WAIT_TIME_LONG
+	printstring STRINGID_TOOMANYWITNESSES
+BattleScript_TrainerBallBlockEnd::
 	waitmessage B_WAIT_TIME_LONG
 	finishaction
 
+
 BattleScript_PlayerUsesItem::
 	moveendcase MOVEEND_MIRROR_MOVE
 	end

 -------------------------------- src/pokemon.c --------------------------------
index 06f30130d..7f73cb01e 100644
@@ -4373,11 +4373,13 @@ void CopyMon(void *dest, void *src, size_t size)
 u8 GiveMonToPlayer(struct Pokemon *mon)
 {
     s32 i;
 
-    SetMonData(mon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName);
-    SetMonData(mon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender);
-    SetMonData(mon, MON_DATA_OT_ID, gSaveBlock2Ptr->playerTrainerId);
+    if(gUsingThiefBall == THIEF_BALL_NOT_USING){
+        SetMonData(mon, MON_DATA_OT_NAME, gSaveBlock2Ptr->playerName);
+        SetMonData(mon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender);
+        SetMonData(mon, MON_DATA_OT_ID, gSaveBlock2Ptr->playerTrainerId);
+    }
+    else{ // Randomizes the IVs for the stolen Pokemon
+        u32 iv;
+        u16 value = Random();
+        iv = value & MAX_IV_MASK;
+        SetMonData(mon, MON_DATA_HP_IV, &iv);
+        iv = (value & (MAX_IV_MASK << 5)) >> 5;
+        SetMonData(mon, MON_DATA_ATK_IV, &iv);
+        iv = (value & (MAX_IV_MASK << 10)) >> 10;
+        SetMonData(mon, MON_DATA_DEF_IV, &iv);
+        value = Random();
+        iv = value & MAX_IV_MASK;
+        SetMonData(mon, MON_DATA_SPEED_IV, &iv);
+        iv = (value & (MAX_IV_MASK << 5)) >> 5;
+        SetMonData(mon, MON_DATA_SPATK_IV, &iv);
+        iv = (value & (MAX_IV_MASK << 10)) >> 10;
+        SetMonData(mon, MON_DATA_SPDEF_IV, &iv);
+    }
 
     for (i = 0; i < PARTY_SIZE; i++)
     {
         if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, NULL) == SPECIES_NONE)

------------------------------ src/battle_main.c ------------------------------
index b28b41f3b..59c07b924 100644
@@ -60,8 +60,9 @@
 #include "constants/rgb.h"
 #include "constants/songs.h"
 #include "constants/trainers.h"
 #include "cable_club.h"
 
 extern const struct BgTemplate gBattleBgTemplates[];
 extern const struct WindowTemplate *const gBattleWindowTemplates[];
 
@@ -172,8 +173,9 @@ EWRAM_DATA u16 gCalledMove = 0;
 EWRAM_DATA s32 gBattleMoveDamage = 0;
 EWRAM_DATA s32 gHpDealt = 0;
 EWRAM_DATA s32 gTakenDmg[MAX_BATTLERS_COUNT] = {0};
 EWRAM_DATA u16 gLastUsedItem = 0;
+EWRAM_DATA u8 gUsingThiefBall = THIEF_BALL_NOT_USING;
 EWRAM_DATA u8 gLastUsedAbility = 0;
 EWRAM_DATA u8 gBattlerAttacker = 0;
 EWRAM_DATA u8 gBattlerTarget = 0;
 EWRAM_DATA u8 gBattlerFainted = 0;
@@ -198,9 +200,8 @@ EWRAM_DATA u16 gChosenMoveByBattler[MAX_BATTLERS_COUNT] = {0};
 EWRAM_DATA u8 gMoveResultFlags = 0;
 EWRAM_DATA u32 gHitMarker = 0;
 EWRAM_DATA static u8 sUnusedBattlersArray[MAX_BATTLERS_COUNT] = {0};
 EWRAM_DATA u8 gTakenDmgByBattler[MAX_BATTLERS_COUNT] = {0};
-EWRAM_DATA u8 gUnusedFirstBattleVar2 = 0; // Never read
 EWRAM_DATA u16 gSideStatuses[NUM_BATTLE_SIDES] = {0};
 EWRAM_DATA struct SideTimer gSideTimers[NUM_BATTLE_SIDES] = {0};
 EWRAM_DATA u32 gStatuses3[MAX_BATTLERS_COUNT] = {0};
 EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0};
@@ -1941,15 +1942,74 @@ static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite)
         break;
     }
 }
 
+u16 checkStolenPokemon(u16 trainerNum, u16 speciesType, u16 partyIndex, bool8 set){
+    u8 trainerClass = gTrainers[trainerNum].trainerClass;
+    u8 trainerPic = gTrainers[trainerNum].trainerPic;
+    u8 varToCheck; // 1 = VAR_PKMN_STOLE_RIVAL; 2 = VAR_PKMN_STOLE_ELITE4_A; 3 = VAR_PKMN_STOLE_ELITE4_B
+    u16 monStolen = 0;
+    switch (trainerClass)
+    {
+    case TRAINER_CLASS_RIVAL:
+        switch (speciesType)
+        {
+        case SPECIES_TREECKO:
+        case SPECIES_GROVYLE:
+        case SPECIES_SCEPTILE:
+        case SPECIES_TORCHIC:
+        case SPECIES_COMBUSKEN:
+        case SPECIES_BLAZIKEN:
+        case SPECIES_MUDKIP:
+        case SPECIES_MARSHTOMP:
+        case SPECIES_SWAMPERT:
+            monStolen = STOLE_STARTER;
+            break;
+        case SPECIES_WINGULL:
+        case SPECIES_PELIPPER:
+            monStolen = STOLE_WINGULL;
+            break;
+        case SPECIES_SLUGMA:
+        case SPECIES_MAGCARGO:
+            monStolen = STOLE_SLUGMA;
+            break;
+        case SPECIES_LOTAD:
+        case SPECIES_LOMBRE:
+        case SPECIES_LUDICOLO:
+            monStolen = STOLE_LOTAD;
+            break;
+        case SPECIES_TROPIUS:
+            monStolen = STOLE_TROPIUS;
+            break;
+        case SPECIES_TORKOAL:
+            monStolen = STOLE_TORKOAL;
+            break;
+        case SPECIES_GROUDON:
+        case SPECIES_KYOGRE:
+            monStolen = STOLE_LEGENDARY;
+            break;
+        case SPECIES_RALTS:
+        case SPECIES_KIRLIA:
+        case SPECIES_GARDEVOIR:
+            monStolen = STOLE_RALTS;
+            break;
+        case SPECIES_ALTARIA:
+            monStolen = STOLE_ALTARIA;
+            break;
+        case SPECIES_DELCATTY:
+            monStolen = STOLE_DELCATTY;
+            break;
+        case SPECIES_ROSELIA:
+            monStolen = STOLE_ROSELIA;
+            break;
+        case SPECIES_MAGNETON:
+            monStolen = STOLE_MAGNETON;
+            break;
+        }
+        varToCheck = 1;
+        break;
+    case TRAINER_CLASS_LEADER:
+        switch (trainerPic)
+        {
+        case TRAINER_PIC_LEADER_NORMAN:
+            switch (speciesType)
+            {
+            case SPECIES_SLAKING:
+                monStolen = STOLE_SLAKING;
+                break;
+            }
+            varToCheck = 1;
+            break;
+        }
+        break;
+    case TRAINER_CLASS_ELITE_FOUR:
+    // Elite Four party is always the same, so the party order can be used. This also allows picking same-species mon in their party uniquely
+        switch (trainerPic)
+        {
+        case TRAINER_PIC_ELITE_FOUR_SIDNEY:
+            monStolen = (1 << (partyIndex + STOLE_SIDNEY_START));
+            varToCheck = 2;
+            break;
+        case TRAINER_PIC_ELITE_FOUR_PHOEBE:
+            monStolen = (1 << (partyIndex + STOLE_PHEOBE_START));
+            varToCheck = 2;
+            break;
+        case TRAINER_PIC_ELITE_FOUR_GLACIA:
+            monStolen = (1 << (partyIndex + STOLE_GLACIA_START));
+            varToCheck = 2;
+            break;
+        case TRAINER_PIC_ELITE_FOUR_DRAKE:
+            monStolen = (1 << (partyIndex + STOLE_DRAKE_START));
+            varToCheck = 3;
+            break;
+        }
+        break;
+    default:
+        monStolen = 0;
+        break;
+    }
+    if (set){  // Sets the variable on whether the pokemon was stolen.
+        if (monStolen != 0){
+            switch (varToCheck)
+            {
+            case 1:
+                VarSet(VAR_PKMN_STOLE_RIVAL, VarGet(VAR_PKMN_STOLE_RIVAL) | monStolen);
+                break;
+            case 2:
+                VarSet(VAR_PKMN_STOLE_ELITE4_A, VarGet(VAR_PKMN_STOLE_ELITE4_A) | monStolen);
+                break;
+            case 3:
+                VarSet(VAR_PKMN_STOLE_ELITE4_B, VarGet(VAR_PKMN_STOLE_ELITE4_B) | monStolen);
+                break;
+            default:
+                break;
+            }
+        }
+        return monStolen;
+    }
+    else{  // Used to return if the Pokemon was stolen
+        switch (varToCheck)
+        {
+        case 1:
+            return monStolen & VarGet(VAR_PKMN_STOLE_RIVAL);
+            break;
+        case 2:
+            return monStolen & VarGet(VAR_PKMN_STOLE_ELITE4_A);
+            break;
+        case 3:
+            return monStolen & VarGet(VAR_PKMN_STOLE_ELITE4_B);
+            break;
+        default:
+            return 0;
+            break;
+        }
+    }
+}
+
 static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 firstTrainer)
 {
     u32 nameHash = 0;
     u32 personalityValue;
     u8 fixedIV;
     s32 i, j;
     u8 monsCount;
+    u16 species_check;  
+    u32 fixedOTID;
+    u8 otGender;
 
     if (trainerNum == TRAINER_SECRET_BASE)
         return 0;
 
@@ -1971,18 +2031,28 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
         {
             monsCount = gTrainers[trainerNum].partySize;
         }
 
+        fixedOTID = Random32();
+
         for (i = 0; i < monsCount; i++)
         {
-            if (gTrainers[trainerNum].doubleBattle == TRUE)
+            if (gTrainers[trainerNum].doubleBattle == TRUE){
                 personalityValue = 0x80;
-            else if (gTrainers[trainerNum].encounterMusic_gender & F_TRAINER_FEMALE)
+                otGender = gSaveBlock2Ptr->playerGender;
+            }
+            else if (gTrainers[trainerNum].encounterMusic_gender & F_TRAINER_FEMALE){
                 personalityValue = 0x78; // Use personality more likely to result in a female Pokémon
-            else
-                personalityValue = 0x88; // Use personality more likely to result in a male Pokémon
-
+                otGender = FEMALE;
+            }
+            else{
+                personalityValue = 0x88; // Use personality more likely to result in a male Pokémon}
+                otGender = MALE;
+            }
             for (j = 0; gTrainers[trainerNum].trainerName[j] != EOS; j++)
                 nameHash += gTrainers[trainerNum].trainerName[j];
 
             switch (gTrainers[trainerNum].partyFlags)
@@ -2059,9 +2062,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
             {
             case 0:
             {
                 const struct TrainerMonNoItemDefaultMoves *partyData = gTrainers[trainerNum].party.NoItemDefaultMoves;
+                if (checkStolenPokemon(trainerNum, species, i, FALSE)){
+                    continue;
+                }
                 for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
                 personalityValue += nameHash << 8;
@@ -2073,8 +2078,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
             }
             case F_TRAINER_PARTY_CUSTOM_MOVESET:
             {
                 const struct TrainerMonNoItemCustomMoves *partyData = gTrainers[trainerNum].party.NoItemCustomMoves;
+                if (checkStolenPokemon(trainerNum, species, i, FALSE)){
+                    continue;
+                }
 
                 for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
@@ -2093,8 +2101,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
             }
             case F_TRAINER_PARTY_HELD_ITEM:
             {
                 const struct TrainerMonItemDefaultMoves *partyData = gTrainers[trainerNum].party.ItemDefaultMoves;
+                if (checkStolenPokemon(trainerNum, species, i, FALSE)){
+                    continue;
+                }
 
                 for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
@@ -2109,8 +2120,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
             }
             case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM:
             {
                 const struct TrainerMonItemCustomMoves *partyData = gTrainers[trainerNum].party.ItemCustomMoves;
+                if (checkStolenPokemon(trainerNum, species, i, FALSE)){
+                    continue;
+                }
 
                 for (j = 0; gSpeciesNames[partyData[i].species][j] != EOS; j++)
                     nameHash += gSpeciesNames[partyData[i].species][j];
@@ -1995,9 +2065,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
                 personalityValue += nameHash << 8;
                 fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
-                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
+                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+                SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
+                SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
                 break;
             }
             case F_TRAINER_PARTY_CUSTOM_MOVESET:
             {
@@ -2007,9 +2079,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
                 personalityValue += nameHash << 8;
                 fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
-                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
+                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+                SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
+                SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
 
                 for (j = 0; j < MAX_MON_MOVES; j++)
                 {
                     SetMonData(&party[i], MON_DATA_MOVE1 + j, &partyData[i].moves[j]);
@@ -2025,9 +2099,11 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
                 personalityValue += nameHash << 8;
                 fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
-                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
+                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+                SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
+                SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
 
                 SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
                 break;
             }
@@ -2039,10 +2115,12 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
                     nameHash += gSpeciesNames[partyData[i].species][j];
 
                 personalityValue += nameHash << 8;
                 fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
-                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_RANDOM_NO_SHINY, 0);
+                CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+                SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
+                SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
+                
                 SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
 
                 for (j = 0; j < MAX_MON_MOVES; j++)  

This makes it so if you have a Thief Ball, it'll display if you have the opponent's Pokemon in your Dex.

Notice the Pokemon icon. By default, trainers' Pokemon won't show that. Pokemon Caught

---------------------------- src/battle_interface.c ----------------------------
index 72409d3e4..fd1e78dcd 100644
@@ -14,8 +14,9 @@
 #include "util.h"
 #include "gpu_regs.h"
 #include "battle_message.h"
 #include "pokedex.h"
+#include "item.h"
 #include "palette.h"
 #include "international_string_util.h"
 #include "safari_zone.h"
 #include "battle_anim.h"
@@ -24,8 +25,9 @@
 #include "strings.h"
 #include "constants/battle_anim.h"
 #include "constants/rgb.h"
 #include "constants/songs.h"
+#include "constants/items.h"
 
 struct TestingBar
 {
     s32 maxValue;
@@ -1973,9 +1975,18 @@ static void TryAddPokeballIconToHealthbox(u8 healthboxSpriteId, bool8 noStatus)
     u8 battlerId, healthBarSpriteId;
 
     if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
         return;
-    if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
+    if (gBattleTypeFlags & BATTLE_TYPE_TRAINER){
+        if (!CheckBagHasItem(ITEM_THIEF_BALL, 1))
+            return;
+        if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER |
+        BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED_LINK))
+            return;
+    }
+    
+    if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER |
+    BATTLE_TYPE_SECRET_BASE | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED_LINK))
         return;
 
     battlerId = gSprites[healthboxSpriteId].hMain_Battler;
     if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)

These are additions to add these balls to Aqua and Magma hideouts and to remove it from what you'd normally get a Premier. You can ignore these if you want the Thief ball to be as common as the Premier ball.

---------------------------------- src/shop.c ----------------------------------
index d5e954635..e7092eb41 100644
@@ -1146,14 +1146,9 @@ static void Task_ReturnToItemListAfterItemPurchase(u8 taskId)
 
     if (JOY_NEW(A_BUTTON | B_BUTTON))
     {
         PlaySE(SE_SELECT);
-
-        // Purchasing 10+ Poke Balls gets the player a Premier Ball
-        if (tItemId == ITEM_POKE_BALL && tItemCount >= 10 && AddBagItem(ITEM_PREMIER_BALL, 1) == TRUE)
-            BuyMenuDisplayMessage(taskId, gText_ThrowInPremierBall, BuyMenuReturnToItemList);
-        else
-            BuyMenuReturnToItemList(taskId);
+        BuyMenuReturnToItemList(taskId);
     }
 }
 
 static void Task_ReturnToItemListAfterDecorationPurchase(u8 taskId)

---------------------- data/maps/AquaHideout_B2F/map.json ----------------------
index bc58b8d6b..0d6b36e6c 100644
@@ -49,10 +49,10 @@
       "movement_range_x": 0,
       "movement_range_y": 0,
       "trainer_type": "TRAINER_TYPE_NONE",
       "trainer_sight_or_berry_tree_id": "0",
-      "script": "AquaHideout_B2F_EventScript_ItemNestBall",
-      "flag": "FLAG_ITEM_AQUA_HIDEOUT_B2F_NEST_BALL"
+      "script": "AquaHideout_B2F_EventScript_ItemThiefBall",
+      "flag": "FLAG_ITEM_AQUA_HIDEOUT_B2F_THIEF_BALL"
     },
     {
       "graphics_id": "OBJ_EVENT_GFX_SUBMARINE_SHADOW",
       "x": 19,

---------------------- data/maps/MagmaHideout_4F/map.json ----------------------
index d426affde..39e441a2a 100644
@@ -114,10 +114,10 @@
       "movement_range_x": 1,
       "movement_range_y": 1,
       "trainer_type": "TRAINER_TYPE_NONE",
       "trainer_sight_or_berry_tree_id": "0",
-      "script": "MagmaHideout_4F_EventScript_ItemMaxRevive",
-      "flag": "FLAG_ITEM_MAGMA_HIDEOUT_4F_MAX_REVIVE"
+      "script": "MagmaHideout_4F_EventScript_ItemThiefBall",
+      "flag": "FLAG_ITEM_MAGMA_HIDEOUT_4F_THIEF_BALL"
     }
   ],
   "warp_events": [
     {

----------------- data/maps/RustboroCity_Flat2_2F/scripts.inc -----------------
index 97145ce8f..5468fefa0 100644
@@ -7,17 +7,17 @@ RustboroCity_Flat2_2F_EventScript_OldMan::
 
 RustboroCity_Flat2_2F_EventScript_NinjaBoy::
 	lock
 	faceplayer
-	goto_if_set FLAG_RECEIVED_PREMIER_BALL_RUSTBORO, RustboroCity_Flat2_2F_EventScript_GavePremierBall
+	goto_if_set FLAG_RECEIVED_LUXARY_BALL_RUSTBORO, RustboroCity_Flat2_2F_EventScript_GaveLuxaryBall
 	msgbox RustboroCity_Flat2_2F_Text_MyDaddyMadeThisYouCanHaveIt, MSGBOX_DEFAULT
-	giveitem ITEM_PREMIER_BALL
+	giveitem ITEM_LUXURY_BALL
 	goto_if_eq VAR_RESULT, FALSE, Common_EventScript_ShowBagIsFull
-	setflag FLAG_RECEIVED_PREMIER_BALL_RUSTBORO
+	setflag FLAG_RECEIVED_LUXARY_BALL_RUSTBORO
 	release
 	end
 
-RustboroCity_Flat2_2F_EventScript_GavePremierBall::
+RustboroCity_Flat2_2F_EventScript_GaveLuxaryBall::
 	msgbox RustboroCity_Flat2_2F_Text_GoingToWorkAtDevonToo, MSGBOX_DEFAULT
 	release
 	end
 

---------------------- data/scripts/item_ball_scripts.inc ----------------------
index 683c383df..3b5c8192a 100644
@@ -521,10 +521,10 @@ AquaHideout_B1F_EventScript_ItemNugget::
 AquaHideout_B1F_EventScript_ItemMaxElixir::
 	finditem ITEM_MAX_ELIXIR
 	end
 
-AquaHideout_B2F_EventScript_ItemNestBall::
-	finditem ITEM_NEST_BALL
+AquaHideout_B2F_EventScript_ItemThiefBall::
+	finditem ITEM_THIEF_BALL
 	end
 
 AquaHideout_B2F_EventScript_ItemMasterBall::
 	finditem ITEM_MASTER_BALL      // Unused
@@ -649,10 +649,10 @@ MagmaHideout_3F_1R_EventScript_ItemNugget::
 MagmaHideout_3F_2R_EventScript_ItemPPMax::
 	finditem ITEM_PP_MAX
 	end
 
-MagmaHideout_4F_EventScript_ItemMaxRevive::
-	finditem ITEM_MAX_REVIVE
+MagmaHideout_4F_EventScript_ItemThiefBall::
+	finditem ITEM_THIEF_BALL
 	end
 
 MagmaHideout_3F_3R_EventScript_ItemEscapeRope::
 	finditem ITEM_ESCAPE_ROPE

-------------------------- include/constants/flags.h --------------------------
index b230e5e98..31509b764 100644
@@ -229,9 +229,9 @@
 #define FLAG_GOT_TM24_FROM_WATTSON           0xD1
 #define FLAG_FAN_CLUB_STRENGTH_SHARED        0xD2 // Set when you rate the strength of another trainer in Lilycove's Trainer Fan Club.
 #define FLAG_DEFEATED_RIVAL_RUSTBORO         0xD3
 #define FLAG_RECEIVED_RED_OR_BLUE_ORB        0xD4
-#define FLAG_RECEIVED_PREMIER_BALL_RUSTBORO  0xD5
+#define FLAG_RECEIVED_LUXARY_BALL_RUSTBORO   0xD5
 #define FLAG_ENABLE_WALLY_MATCH_CALL         0xD6
 #define FLAG_ENABLE_SCOTT_MATCH_CALL         0xD7
 #define FLAG_ENABLE_MOM_MATCH_CALL           0xD8
 #define FLAG_MET_DIVING_TREASURE_HUNTER      0xD9
@@ -1116,9 +1116,9 @@
 #define FLAG_ITEM_TRICK_HOUSE_PUZZLE_7_TROPIC_MAIL                  0x42C
 #define FLAG_ITEM_TRICK_HOUSE_PUZZLE_8_BEAD_MAIL                    0x42D
 #define FLAG_ITEM_JAGGED_PASS_BURN_HEAL                             0x42E
 #define FLAG_ITEM_AQUA_HIDEOUT_B1F_MAX_ELIXIR                       0x42F
-#define FLAG_ITEM_AQUA_HIDEOUT_B2F_NEST_BALL                        0x430
+#define FLAG_ITEM_AQUA_HIDEOUT_B2F_THIEF_BALL                       0x430
 #define FLAG_ITEM_MT_PYRE_EXTERIOR_MAX_POTION                       0x431
 #define FLAG_ITEM_MT_PYRE_EXTERIOR_TM48                             0x432
 #define FLAG_ITEM_NEW_MAUVILLE_ULTRA_BALL                           0x433
 #define FLAG_ITEM_NEW_MAUVILLE_ESCAPE_ROPE                          0x434
@@ -1212,9 +1212,9 @@
 #define FLAG_ITEM_MAGMA_HIDEOUT_2F_2R_MAX_ELIXIR                    0x48C
 #define FLAG_ITEM_MAGMA_HIDEOUT_2F_2R_FULL_RESTORE                  0x48D
 #define FLAG_ITEM_MAGMA_HIDEOUT_3F_1R_NUGGET                        0x48E
 #define FLAG_ITEM_MAGMA_HIDEOUT_3F_2R_PP_MAX                        0x48F
-#define FLAG_ITEM_MAGMA_HIDEOUT_4F_MAX_REVIVE                       0x490
+#define FLAG_ITEM_MAGMA_HIDEOUT_4F_THIEF_BALL                       0x490
 #define FLAG_ITEM_SAFARI_ZONE_NORTH_EAST_NUGGET                     0x491
 #define FLAG_ITEM_SAFARI_ZONE_SOUTH_EAST_BIG_PEARL                  0x492

--------------------------- src/data/lilycove_lady.h ---------------------------
index 4a3a7a719..eeb11d2ad 100644
@@ -283,9 +283,9 @@ static const u16 sQuizLadyPrizes[] =
     ITEM_BIG_PEARL,
     ITEM_STAR_PIECE,
     ITEM_RARE_CANDY,
     ITEM_RARE_CANDY,
-    ITEM_PREMIER_BALL
+    ITEM_GREAT_BALL
 };
 
 // Favor Lady data
 static const u8 *const sFavorLadyRequests[] =
@@ -375,9 +375,9 @@ static const u16 sFavorLadyAcceptedItems_Shiny[] =
     ITEM_TWISTED_SPOON,
     ITEM_SILVER_POWDER,
     ITEM_BRIGHT_POWDER,
     ITEM_LUXURY_BALL,
-    ITEM_PREMIER_BALL,
+    ITEM_GREAT_BALL,
     ITEM_NONE
 };
 
 static const u16 sFavorLadyAcceptedItems_Sticky[] =

Norman's Slaking caught as an example. It has intimidate from another hack.

Norman's Slaking caught

Clone this wiki locally