diff --git a/data/layouts/BattleFrontier_BattleDomeBattleRoom/map.bin b/data/layouts/BattleFrontier_BattleDomeBattleRoom/map.bin
index ffb450f3c3..e0f2dc82f0 100644
--- a/data/layouts/BattleFrontier_BattleDomeBattleRoom/map.bin
+++ b/data/layouts/BattleFrontier_BattleDomeBattleRoom/map.bin
@@ -1,2 +1,2 @@
-ÐÐÑÐÐÐÐÐÐÐÑÐÐÐÐÐÑÐÐÐÐÐÑÐÐÐÐÐÐÐÑÐÐÐÐÐÑÐÐÐÒÒÓÒÒÒÒÒÒÒÓÒÒÒÒÒÓÒÒÒÔÕÖ×ØÙÚÔÕÖ×ØÙÚÔÕÖ×ØÙ		áâãäåæç						éêëìíîï						ñòóôõö÷ !"#$%&						ùúûüýþÿ()*+,-.						0123456							
-
89:;<=>>			
\ No newline at end of file
+Ð2Ð2ÑÐ2Ð2Ð2Ð2Ð2Ð2Ð2ÑÐ2Ð2Ð2Ð2Ð2ÑÐ2Ð2Ð2ÐRÐRÑÐRÐRÐRÐRÐRÐRÐRÑÐRÐRÐRÐRÐRÑÐRÐRÐRÒ2Ò2ÓÒ2Ò2Ò2Ò2Ò2Ò2Ò2ÓÒ2Ò2Ò2Ò2Ò2ÓÒ2Ò2Ò2ÔÕÖ×ØÙÚÔÕÖ×ØÙÚÔÕÖ×ØÙ	3	3á2â2ã2ä2å2æ2ç23333333	3	3	3	3	3	3é2êëìíBîBïBCCC3	3	3	3	3	3	3ñ2òBóBôBõBöB÷B C!C"C#C$C%C&3	3	3	3	3	3	3ù2úûüýBþBÿB(C)C*C+,-.3	3	3	3	3	3	3333301233435363	3	3	3	3	3	3	3
+333
3338393:3;3<3=3>3>3	3	3	3
\ No newline at end of file
diff --git a/data/maps/BattleFrontier_BattleDomeBattleRoom/map.json b/data/maps/BattleFrontier_BattleDomeBattleRoom/map.json
index c2b427cbe3..f4c52ce05f 100644
--- a/data/maps/BattleFrontier_BattleDomeBattleRoom/map.json
+++ b/data/maps/BattleFrontier_BattleDomeBattleRoom/map.json
@@ -12,7 +12,7 @@
   "allow_running": false,
   "show_map_name": false,
   "battle_scene": "MAP_BATTLE_SCENE_NORMAL",
-  "connections": null,
+  "connections": 0,
   "object_events": [
     {
       "graphics_id": "OBJ_EVENT_GFX_REPORTER_M",
@@ -210,7 +210,13 @@
       "flag": "0"
     }
   ],
-  "warp_events": [],
-  "coord_events": [],
-  "bg_events": []
+  "warp_events": [
+
+  ],
+  "coord_events": [
+
+  ],
+  "bg_events": [
+
+  ]
 }
diff --git a/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc b/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc
index def903b1df..31314b5982 100644
--- a/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc
+++ b/data/maps/BattleFrontier_BattleDomeBattleRoom/scripts.inc
@@ -17,6 +17,7 @@ BattleFrontier_BattleDomeBattleRoom_MapScripts::
 	.byte 0
 
 BattleFrontier_BattleDomeBattleRoom_OnTransition:
+  setflag FLAG_TEMP_HIDE_FOLLOWER
 	dome_setopponentgfx
 	frontier_get FRONTIER_DATA_BATTLE_NUM
 	copyvar VAR_TEMP_F, VAR_RESULT
diff --git a/data/maps/FortreeCity_Gym/scripts.inc b/data/maps/FortreeCity_Gym/scripts.inc
index 1c729bc44e..d52102ebf5 100644
--- a/data/maps/FortreeCity_Gym/scripts.inc
+++ b/data/maps/FortreeCity_Gym/scripts.inc
@@ -5,6 +5,7 @@ FortreeCity_Gym_MapScripts::
 
 FortreeCity_Gym_OnTransition:
 	special RotatingGate_InitPuzzle
+  setflag FLAG_TEMP_HIDE_FOLLOWER @ Hide follower bc of rotating gates
 	end
 
 FortreeCity_Gym_OnWarp:
diff --git a/data/maps/MossdeepCity_Gym/scripts.inc b/data/maps/MossdeepCity_Gym/scripts.inc
index b47011d680..3b56513df2 100644
--- a/data/maps/MossdeepCity_Gym/scripts.inc
+++ b/data/maps/MossdeepCity_Gym/scripts.inc
@@ -1,9 +1,14 @@
 MossdeepCity_Gym_MapScripts::
+  map_script MAP_SCRIPT_ON_TRANSITION, MossdeepCity_Gym_OnTransition
 	map_script MAP_SCRIPT_ON_LOAD, MossdeepCity_Gym_OnLoad
 	.byte 0
 
 @ NOTE: Mossdeep Gym was redesigned between R/S and E. Leftover (and now functionally unused) scripts are commented below
 
+MossdeepCity_Gym_OnTransition:
+  setflag FLAG_TEMP_HIDE_FOLLOWER @ Hide follower since it can collide with moving statues
+  end
+
 @ All the below checks are leftover from RS. FLAG_MOSSDEEP_GYM_SWITCH_X is never set
 MossdeepCity_Gym_OnLoad:
 	goto_if_set FLAG_MOSSDEEP_GYM_SWITCH_1, MossdeepCity_Gym_EventScript_SetSwitch1Metatiles
diff --git a/data/maps/Route123/map.json b/data/maps/Route123/map.json
index 695b50acd4..dd9a65201f 100644
--- a/data/maps/Route123/map.json
+++ b/data/maps/Route123/map.json
@@ -559,7 +559,7 @@
       "flag": "0"
     },
     {
-      "graphics_id": "OBJ_EVENT_GFX_YOUNGSTER",
+      "graphics_id": "OBJ_EVENT_GFX_BUG_CATCHER",
       "x": 14,
       "y": 12,
       "elevation": 3,
diff --git a/data/scripts/trainer_battle.inc b/data/scripts/trainer_battle.inc
index bbbcaf3ba3..66d4d6d5c0 100644
--- a/data/scripts/trainer_battle.inc
+++ b/data/scripts/trainer_battle.inc
@@ -10,6 +10,7 @@ EventScript_TrainerApproach::
 EventScript_TryDoNormalTrainerBattle::
 	lock
 	faceplayer
+  setflag FLAG_SAFE_FOLLOWER_MOVEMENT
 	applymovement VAR_LAST_TALKED, Movement_RevealTrainer
 	waitmovement 0
 	specialvar VAR_RESULT, GetTrainerFlag
@@ -44,6 +45,7 @@ EventScript_NoDoubleTrainerBattle::
 	gotopostbattlescript
 
 EventScript_DoNoIntroTrainerBattle::
+  setflag FLAG_SAFE_FOLLOWER_MOVEMENT
 	applymovement VAR_LAST_TALKED, Movement_RevealTrainer
 	waitmovement 0
 	special PlayTrainerEncounterMusic
@@ -93,6 +95,7 @@ EventScript_NotEnoughMonsForDoubleRematchBattle::
 	end
 
 EventScript_RevealTrainer::
+  setflag FLAG_SAFE_FOLLOWER_MOVEMENT
 	applymovement VAR_LAST_TALKED, Movement_RevealTrainer
 	waitmovement 0
 	return
diff --git a/graphics/object_events/pics/pokemon/magnemite.png b/graphics/object_events/pics/pokemon/magnemite.png
index 8d18a7e34f..b35e1fef56 100644
Binary files a/graphics/object_events/pics/pokemon/magnemite.png and b/graphics/object_events/pics/pokemon/magnemite.png differ
diff --git a/graphics/object_events/pics/pokemon/magneton.png b/graphics/object_events/pics/pokemon/magneton.png
index 1a09cf6800..bf15d01a9c 100644
Binary files a/graphics/object_events/pics/pokemon/magneton.png and b/graphics/object_events/pics/pokemon/magneton.png differ
diff --git a/include/battle_main.h b/include/battle_main.h
index 449131e534..2a6e4bf3d7 100644
--- a/include/battle_main.h
+++ b/include/battle_main.h
@@ -61,6 +61,7 @@ void SpriteCB_FaintSlideAnim(struct Sprite *sprite);
 void DoBounceEffect(u8 battlerId, u8 b, s8 c, s8 d);
 void EndBounceEffect(u8 battlerId, bool8 b);
 void SpriteCB_PlayerMonFromBall(struct Sprite *sprite);
+void SpriteCB_PlayerMonSlideIn(struct Sprite *sprite);
 void SpriteCB_TrainerThrowObject(struct Sprite *sprite);
 void AnimSetCenterToCornerVecX(struct Sprite *sprite);
 void BeginBattleIntroDummy(void);
diff --git a/include/constants/flags.h b/include/constants/flags.h
index 5a2a12bbe3..708f4e8935 100644
--- a/include/constants/flags.h
+++ b/include/constants/flags.h
@@ -21,7 +21,7 @@
 #define FLAG_TEMP_B      (TEMP_FLAGS_START + 0xB)  // Unused Flag
 #define FLAG_TEMP_C      (TEMP_FLAGS_START + 0xC)  // Unused Flag
 #define FLAG_TEMP_D      (TEMP_FLAGS_START + 0xD)  // Unused Flag
-#define FLAG_TEMP_E      (TEMP_FLAGS_START + 0xE)  // Unused Flag
+#define FLAG_TEMP_HIDE_FOLLOWER      (TEMP_FLAGS_START + 0xE)  // When set, follower pokemon won't be spawned
 #define FLAG_TEMP_F      (TEMP_FLAGS_START + 0xF)  // Unused Flag
 #define FLAG_TEMP_10     (TEMP_FLAGS_START + 0x10) // Unused Flag
 #define FLAG_TEMP_11     (TEMP_FLAGS_START + 0x11)
diff --git a/include/party_menu.h b/include/party_menu.h
index 7f51d08c9f..8542b9ea43 100644
--- a/include/party_menu.h
+++ b/include/party_menu.h
@@ -44,6 +44,7 @@ u8 GetAilmentFromStatus(u32 status);
 u8 GetMonAilment(struct Pokemon *mon);
 void DisplayPartyMenuStdMessage(u32 stringId);
 bool8 FieldCallback_PrepareFadeInFromMenu(void);
+bool8 FieldCallback_PrepareFadeInForTeleport(void);
 void CB2_ReturnToPartyMenuFromFlyMap(void);
 void LoadHeldItemIcons(void);
 void DrawHeldItemIconsForTrade(u8 *partyCounts, u8 *partySpriteIds, u8 whichParty);
diff --git a/include/pokeball.h b/include/pokeball.h
index 1149791b86..3dbd80527f 100644
--- a/include/pokeball.h
+++ b/include/pokeball.h
@@ -32,6 +32,7 @@ extern const struct SpriteTemplate gBallSpriteTemplates[];
 
 #define POKEBALL_PLAYER_SENDOUT     0xFF
 #define POKEBALL_OPPONENT_SENDOUT   0xFE
+#define POKEBALL_PLAYER_SLIDEIN     0xFD
 
 u8 DoPokeballSendOutAnimation(s16 pan, u8 kindOfThrow);
 void CreatePokeballSpriteToReleaseMon(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 oamPriority, u8 subpriortiy, u8 delay, u32 fadePalettes, u16 species);
diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c
index 954192f0ab..c0e2ff7265 100644
--- a/src/battle_controller_player.c
+++ b/src/battle_controller_player.c
@@ -10,6 +10,7 @@
 #include "battle_tv.h"
 #include "bg.h"
 #include "data.h"
+#include "event_object_movement.h"
 #include "item.h"
 #include "item_menu.h"
 #include "link.h"
@@ -114,7 +115,7 @@ static void Task_UpdateLvlInHealthbox(u8);
 static void PrintLinkStandbyMsg(void);
 static u32 CopyPlayerMonData(u8, u8 *);
 static void SetPlayerMonData(u8);
-static void StartSendOutAnim(u8, bool8);
+static void StartSendOutAnim(u8, bool8, bool8);
 static void DoSwitchOutAnimation(void);
 static void PlayerDoMoveAnimation(void);
 static void Task_StartSendOutAnim(u8);
@@ -2189,11 +2190,29 @@ static void PlayerHandleSwitchInAnim(void)
     BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
     gActionSelectionCursor[gActiveBattler] = 0;
     gMoveSelectionCursor[gActiveBattler] = 0;
-    StartSendOutAnim(gActiveBattler, gBattleBufferA[gActiveBattler][2]);
+    #ifdef BATTLE_ENGINE
+    StartSendOutAnim(gActiveBattler, gBattleResources->bufferA[gActiveBattler][2], FALSE);
+    #else
+    StartSendOutAnim(gActiveBattler, gBattleBufferA[gActiveBattler][2], FALSE);
+    #endif
     gBattlerControllerFuncs[gActiveBattler] = SwitchIn_TryShinyAnimShowHealthbox;
 }
 
-static void StartSendOutAnim(u8 battlerId, bool8 dontClearSubstituteBit)
+// In normal singles, if follower pokemon is out, have it slide in instead of being thrown
+static bool8 ShouldDoSlideInAnim(void) {
+    struct ObjectEvent *followerObj = GetFollowerObject();
+    if (!followerObj || followerObj->invisible)
+        return FALSE;
+    if (gBattleTypeFlags & (
+        BATTLE_TYPE_LINK | BATTLE_TYPE_DOUBLE | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_FIRST_BATTLE |
+        BATTLE_TYPE_SAFARI | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_TWO_OPPONENTS |
+        BATTLE_TYPE_INGAME_PARTNER | BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL)
+    )
+        return FALSE;
+    return TRUE;
+}
+
+static void StartSendOutAnim(u8 battlerId, bool8 dontClearSubstituteBit, bool8 doSlideIn)
 {
     u16 species;
 
@@ -2221,7 +2240,7 @@ static void StartSendOutAnim(u8 battlerId, bool8 dontClearSubstituteBit)
     gSprites[gBattlerSpriteIds[battlerId]].invisible = TRUE;
     gSprites[gBattlerSpriteIds[battlerId]].callback = SpriteCallbackDummy;
 
-    gSprites[gBattleControllerData[battlerId]].data[0] = DoPokeballSendOutAnimation(0, POKEBALL_PLAYER_SENDOUT);
+    gSprites[gBattleControllerData[battlerId]].data[0] = DoPokeballSendOutAnimation(0, doSlideIn ? POKEBALL_PLAYER_SLIDEIN : POKEBALL_PLAYER_SENDOUT);
 }
 
 static void PlayerHandleReturnMonToBall(void)
@@ -2957,7 +2976,7 @@ static void PlayerHandleIntroTrainerBallThrow(void)
     gSprites[gBattlerSpriteIds[gActiveBattler]].sBattlerId = gActiveBattler;
 
     StoreSpriteCallbackInData6(&gSprites[gBattlerSpriteIds[gActiveBattler]], SpriteCB_FreePlayerSpriteLoadMonSprite);
-    StartSpriteAnim(&gSprites[gBattlerSpriteIds[gActiveBattler]], 1);
+    StartSpriteAnim(&gSprites[gBattlerSpriteIds[gActiveBattler]], ShouldDoSlideInAnim() ? 2 : 1);
 
     paletteNum = AllocSpritePalette(0xD6F8);
     LoadCompressedPalette(gTrainerBackPicPaletteTable[gSaveBlock2Ptr->playerGender].data, 0x100 + paletteNum * 16, 32);
@@ -3004,16 +3023,16 @@ static void Task_StartSendOutAnim(u8 taskId)
         if (!IsDoubleBattle() || (gBattleTypeFlags & BATTLE_TYPE_MULTI))
         {
             gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
-            StartSendOutAnim(gActiveBattler, FALSE);
+            StartSendOutAnim(gActiveBattler, FALSE, ShouldDoSlideInAnim());
         }
         else
         {
             gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
-            StartSendOutAnim(gActiveBattler, FALSE);
+            StartSendOutAnim(gActiveBattler, FALSE, ShouldDoSlideInAnim());
             gActiveBattler ^= BIT_FLANK;
             gBattleBufferA[gActiveBattler][1] = gBattlerPartyIndexes[gActiveBattler];
             BattleLoadPlayerMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], gActiveBattler);
-            StartSendOutAnim(gActiveBattler, FALSE);
+            StartSendOutAnim(gActiveBattler, FALSE, ShouldDoSlideInAnim());
             gActiveBattler ^= BIT_FLANK;
         }
         gBattlerControllerFuncs[gActiveBattler] = Intro_TryShinyAnimShowHealthbox;
diff --git a/src/battle_main.c b/src/battle_main.c
index f61d5eaae0..6251fa3e81 100644
--- a/src/battle_main.c
+++ b/src/battle_main.c
@@ -2978,6 +2978,29 @@ void SpriteCB_PlayerMonFromBall(struct Sprite *sprite)
         BattleAnimateBackSprite(sprite, sprite->sSpeciesId);
 }
 
+void SpriteCB_PlayerMonSlideIn(struct Sprite *sprite) {
+    if (sprite->data[3] == 0) {
+        PlaySE(SE_BALL_TRAY_ENTER);
+        sprite->data[3]++;
+    } else if (sprite->data[3] == 1) {
+        if (sprite->animEnded)
+            return;
+        sprite->data[4] = sprite->x;
+        sprite->x = -33;
+        sprite->invisible = FALSE;
+        sprite->data[3]++;
+    } else if (sprite->data[3] < 27) {
+        sprite->x += 4;
+        sprite->data[3]++;
+    } else {
+        sprite->data[3] = 0;
+        sprite->x = sprite->data[4];
+        sprite->data[4] = 0;
+        sprite->callback = SpriteCB_PlayerMonFromBall;
+        PlayCry_ByMode(sprite->sSpeciesId, -25, CRY_MODE_NORMAL);
+    }
+}
+
 static void SpriteCB_TrainerThrowObject_Main(struct Sprite *sprite)
 {
     AnimSetCenterToCornerVecX(sprite);
diff --git a/src/data/object_events/object_event_graphics_info.h b/src/data/object_events/object_event_graphics_info.h
index 71d98268bb..e1098dc0ea 100755
--- a/src/data/object_events/object_event_graphics_info.h
+++ b/src/data/object_events/object_event_graphics_info.h
@@ -213,7 +213,7 @@ const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Zigzagoon = {TAG_N
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Pikachu = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_2, OBJ_EVENT_PAL_TAG_NONE, 128, 16, 16, 3, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_PikachuOld, gDummySpriteAffineAnimTable};
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Azumarill = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_1, OBJ_EVENT_PAL_TAG_NONE, 128, 16, 16, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_AzumarillOld, gDummySpriteAffineAnimTable};
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Wingull = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_1, OBJ_EVENT_PAL_TAG_NONE, 128, 16, 16, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_WingullOld, gDummySpriteAffineAnimTable};
-const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_KecleonBridgeShadow = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_3, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 128, 16, 16, 10, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_Kecleon, gDummySpriteAffineAnimTable};
+const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_KecleonBridgeShadow = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_3, OBJ_EVENT_PAL_TAG_BRIDGE_REFLECTION, 128, 16, 16, 10, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_KecleonOld, gDummySpriteAffineAnimTable};
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_TuberMSwimming = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_2, OBJ_EVENT_PAL_TAG_NONE, 128, 16, 16, 3, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_TuberMSwimming, gDummySpriteAffineAnimTable};
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Azurill = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_1, OBJ_EVENT_PAL_TAG_NONE, 128, 16, 16, 2, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x16, sOamTables_16x16, sAnimTable_Standard, sPicTable_AzurillOld, gDummySpriteAffineAnimTable};
 const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Mom = {TAG_NONE, OBJ_EVENT_PAL_TAG_NPC_4, OBJ_EVENT_PAL_TAG_NONE, 256, 16, 32, 5, SHADOW_SIZE_M, FALSE, FALSE, TRACKS_FOOT, &gObjectEventBaseOam_16x32, sOamTables_16x32, sAnimTable_Standard, sPicTable_Mom, gDummySpriteAffineAnimTable};
diff --git a/src/data/object_events/object_event_pic_tables.h b/src/data/object_events/object_event_pic_tables.h
index b4ceb72904..bde5041803 100755
--- a/src/data/object_events/object_event_pic_tables.h
+++ b/src/data/object_events/object_event_pic_tables.h
@@ -5354,7 +5354,7 @@ static const struct SpriteFrameImage sPicTable_DusclopsOld[] = {
     overworld_frame(gObjectEventPic_DusclopsOld, 2, 4, 5),
     overworld_frame(gObjectEventPic_DusclopsOld, 2, 4, 6),
     overworld_frame(gObjectEventPic_DusclopsOld, 2, 4, 7),
-    overworld_frame(gObjectEventPic_Dusclops, 2, 4, 8),
+    overworld_frame(gObjectEventPic_DusclopsOld, 2, 4, 8),
 };
 
 static const struct SpriteFrameImage sPicTable_AzurillOld[] = {
diff --git a/src/data/trainer_graphics/back_pic_anims.h b/src/data/trainer_graphics/back_pic_anims.h
index ed12e0cb41..fa55ed7197 100644
--- a/src/data/trainer_graphics/back_pic_anims.h
+++ b/src/data/trainer_graphics/back_pic_anims.h
@@ -18,6 +18,16 @@ static const union AnimCmd sAnimCmd_May_Steven_1[] =
     ANIMCMD_END,
 };
 
+static const union AnimCmd sAnimCmd_Point_HGSS[] =
+{
+    ANIMCMD_FRAME(3, 9),
+    ANIMCMD_FRAME(0, 9),
+    ANIMCMD_FRAME(2, 24),
+    ANIMCMD_FRAME(2, 24),
+    ANIMCMD_FRAME(3, 50),
+    ANIMCMD_END,
+};
+
 static const union AnimCmd sAnimCmd_Wally_1[] =
 {
     ANIMCMD_FRAME(0, 24),
@@ -48,6 +58,16 @@ static const union AnimCmd sAnimCmd_Leaf_1[] =
     ANIMCMD_END,
 };
 
+static const union AnimCmd sAnimCmd_Point_HGSS_Red_Leaf[] =
+{
+    ANIMCMD_FRAME(0, 9),
+    ANIMCMD_FRAME(1, 9),
+    ANIMCMD_FRAME(3, 24),
+    ANIMCMD_FRAME(3, 24),
+    ANIMCMD_FRAME(0, 50),
+    ANIMCMD_END,
+};
+
 static const union AnimCmd sAnimCmd_RubySapphireBrendan_1[] =
 {
     ANIMCMD_FRAME(0, 24),
@@ -72,48 +92,56 @@ static const union AnimCmd *const sBackAnims_Brendan[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_Brendan_1,
+    sAnimCmd_Point_HGSS,
 };
 
 static const union AnimCmd *const sBackAnims_May[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_May_Steven_1,
+    sAnimCmd_Point_HGSS,
 };
 
 static const union AnimCmd *const sBackAnims_Red[] =
 {
     sAnim_GeneralFrame0,
     sAnimCmd_Red_1,
+    sAnimCmd_Point_HGSS_Red_Leaf,
 };
 
 static const union AnimCmd *const sBackAnims_Leaf[] =
 {
     sAnim_GeneralFrame0,
     sAnimCmd_Leaf_1,
+    sAnimCmd_Point_HGSS_Red_Leaf,
 };
 
 static const union AnimCmd *const sBackAnims_RubySapphireBrendan[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_RubySapphireBrendan_1,
+    sAnimCmd_Point_HGSS,
 };
 
 static const union AnimCmd *const sBackAnims_RubySapphireMay[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_RubySapphireMay_1,
+    sAnimCmd_Point_HGSS,
 };
 
 static const union AnimCmd *const sBackAnims_Wally[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_Wally_1,
+    sAnimCmd_Point_HGSS,
 };
 
 static const union AnimCmd *const sBackAnims_Steven[] =
 {
     sAnim_GeneralFrame3,
     sAnimCmd_May_Steven_1,
+    sAnimCmd_Point_HGSS,
 };
 
 const union AnimCmd *const *const gTrainerBackAnimsPtrTable[] =
diff --git a/src/event_object_movement.c b/src/event_object_movement.c
index 82e4793fab..818f950a8c 100644
--- a/src/event_object_movement.c
+++ b/src/event_object_movement.c
@@ -1656,10 +1656,12 @@ u8 CreateVirtualObject(u8 graphicsId, u8 virtualObjId, s16 x, s16 y, u8 elevatio
 
     graphicsInfo = GetObjectEventGraphicsInfo(graphicsId);
     CopyObjectGraphicsInfoToSpriteTemplate(graphicsId, SpriteCB_VirtualObject, &spriteTemplate, &subspriteTables);
-    *(u16 *)&spriteTemplate.paletteTag = TAG_NONE;
     x += MAP_OFFSET;
     y += MAP_OFFSET;
     SetSpritePosToOffsetMapCoords(&x, &y, 8, 16);
+    if (spriteTemplate.paletteTag != TAG_NONE)
+        LoadObjectEventPalette(spriteTemplate.paletteTag);
+
     spriteId = CreateSpriteAtEnd(&spriteTemplate, x, y, 0);
     if (spriteId != MAX_SPRITES)
     {
@@ -1667,17 +1669,10 @@ u8 CreateVirtualObject(u8 graphicsId, u8 virtualObjId, s16 x, s16 y, u8 elevatio
         sprite->centerToCornerVecX = -(graphicsInfo->width >> 1);
         sprite->centerToCornerVecY = -(graphicsInfo->height >> 1);
         sprite->y += sprite->centerToCornerVecY;
-        sprite->oam.paletteNum = graphicsInfo->paletteSlot;
-        if (sprite->oam.paletteNum >= 16)
-            sprite->oam.paletteNum -= 16;
 
         sprite->coordOffsetEnabled = TRUE;
         sprite->sVirtualObjId = virtualObjId;
         sprite->sVirtualObjElev = elevation;
-        if (graphicsInfo->paletteSlot == 10)
-            LoadSpecialObjectReflectionPalette(graphicsInfo->paletteTag, graphicsInfo->paletteSlot);
-        else if (graphicsInfo->paletteSlot >= 16)
-            _PatchObjectPalette(graphicsInfo->paletteTag, graphicsInfo->paletteSlot | 0xf0);
 
         if (subspriteTables != NULL)
         {
@@ -1844,11 +1839,12 @@ void UpdateFollowingPokemon(void) { // Update following pokemon if any
   bool8 shiny;
   u8 form;
   // Avoid spawning large (64x64) follower pokemon inside buildings
-  if (GetFollowerInfo(&species, &form, &shiny) && !(gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, 0)->height == 64)) {
+  if (GetFollowerInfo(&species, &form, &shiny) && !(gMapHeader.mapType == MAP_TYPE_INDOOR && SpeciesToGraphicsInfo(species, 0)->height == 64) && !FlagGet(FLAG_TEMP_HIDE_FOLLOWER)) {
     if (objEvent == NULL) { // Spawn follower
       struct ObjectEventTemplate template = {
         .localId = OBJ_EVENT_ID_FOLLOWER,
         .graphicsId = OBJ_EVENT_GFX_OW_MON,
+        .flagId = 0,
         .x = gSaveBlock1Ptr->pos.x,
         .y = gSaveBlock1Ptr->pos.y,
         // If player active, copy player elevation
@@ -9821,10 +9817,12 @@ void SetVirtualObjectGraphics(u8 virtualObjId, u8 graphicsId)
         struct Sprite *sprite = &gSprites[spriteId];
         const struct ObjectEventGraphicsInfo *graphicsInfo = GetObjectEventGraphicsInfo(graphicsId);
         u16 tileNum = sprite->oam.tileNum;
+        u8 i = FindObjectEventPaletteIndexByTag(graphicsInfo->paletteTag);
+        if (i != 0xFF)
+            UpdateSpritePalette(&sObjectEventSpritePalettes[i], sprite);
 
         sprite->oam = *graphicsInfo->oam;
         sprite->oam.tileNum = tileNum;
-        sprite->oam.paletteNum = graphicsInfo->paletteSlot;
         sprite->images = graphicsInfo->images;
 
         if (graphicsInfo->subspriteTables == NULL)
diff --git a/src/fldeff_teleport.c b/src/fldeff_teleport.c
index 3f087e5dab..c17dc9360b 100644
--- a/src/fldeff_teleport.c
+++ b/src/fldeff_teleport.c
@@ -14,7 +14,7 @@ bool8 SetUpFieldMove_Teleport(void)
 {
     if (Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE)
     {
-        gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
+        gFieldCallback2 = FieldCallback_PrepareFadeInForTeleport;
         gPostMenuFieldCallback = FieldCallback_Teleport;
         return TRUE;
     }
diff --git a/src/party_menu.c b/src/party_menu.c
index 016c359cb9..357dce33d0 100755
--- a/src/party_menu.c
+++ b/src/party_menu.c
@@ -14,6 +14,7 @@
 #include "decompress.h"
 #include "easy_chat.h"
 #include "event_data.h"
+#include "event_object_movement.h"
 #include "evolution_scene.h"
 #include "field_control_avatar.h"
 #include "field_effect.h"
@@ -3742,6 +3743,11 @@ bool8 FieldCallback_PrepareFadeInFromMenu(void)
     return TRUE;
 }
 
+bool8 FieldCallback_PrepareFadeInForTeleport(void) { // same as above, but removes follower pokemon
+    RemoveFollowingPokemon();
+    return FieldCallback_PrepareFadeInFromMenu();
+}
+
 static void Task_FieldMoveWaitForFade(u8 taskId)
 {
     if (IsWeatherNotFadingIn() == TRUE)
diff --git a/src/pokeball.c b/src/pokeball.c
index f203633a58..82ae0ee72b 100644
--- a/src/pokeball.c
+++ b/src/pokeball.c
@@ -380,6 +380,11 @@ static void Task_DoPokeballSendOutAnim(u8 taskId)
 
     switch (throwCaseId)
     {
+    case POKEBALL_PLAYER_SLIDEIN: // don't actually send out, trigger the slide-in animation
+        gBattlerTarget = battlerId;
+        gSprites[ballSpriteId].callback = HandleBallAnimEnd;
+        gSprites[ballSpriteId].invisible = TRUE;
+        break;
     case POKEBALL_PLAYER_SENDOUT:
         gBattlerTarget = battlerId;
         gSprites[ballSpriteId].x = 24;
@@ -845,6 +850,12 @@ static void HandleBallAnimEnd(struct Sprite *sprite)
     bool8 affineAnimEnded = FALSE;
     u8 battlerId = sprite->sBattler;
 
+    if (sprite->data[7] == POKEBALL_PLAYER_SLIDEIN) {
+        gSprites[gBattlerSpriteIds[sprite->sBattler]].callback = SpriteCB_PlayerMonSlideIn;
+        AnimateSprite(&gSprites[gBattlerSpriteIds[sprite->sBattler]]);
+        gSprites[gBattlerSpriteIds[sprite->sBattler]].data[1] = 0x1000;
+    }
+
     gSprites[gBattlerSpriteIds[battlerId]].invisible = FALSE;
     if (sprite->animEnded)
         sprite->invisible = TRUE;
