Skip to content

Make Multiple Secret Bases

voloved edited this page Apr 16, 2023 · 3 revisions

By devolov

Goal: Allow for more than one Secret Base to be made by the user. All Secret Bases will have a copy of the owned Secret Base inventory.
The game's save file is meant to store 20 Secret Bases. The first one if the one the player owns and the rest are ones that one gets from getting shared secret bases from friends.
While this code was not tested with sharing it, the logic is that sharing should still be possible, where the first made Secret Base gets shared and getting a friend's base is possible, so long as there are Secret Base slots open.
If all of the Secret Bases are used up and a new one is attempted to be made, then the game will ask to remove the last Secret Base the player made.

twobases

------------------------------ src/secret_base.c ------------------------------
index 1a4a0ac9cd..3bace19de3 100644
@@ -91,8 +91,10 @@ static void DeleteRegistry_Yes(u8);
 static void DeleteRegistry_No(u8);
 static void ReturnToMainRegistryMenu(u8);
 static void GoToSecretBasePCRegisterMenu(u8);
 static u8 GetSecretBaseOwnerType(u8);
+static s16 GetSecretBaseIndexFromId(u8);
+static s16 FindAvailableSecretBaseIndex(void);
 
 static const struct SecretBaseEntranceMetatiles sSecretBaseEntranceMetatiles[] =
 {
     {.closedMetatileId = METATILE_General_SecretBase_TreeLeft,  .openMetatileId = METATILE_General_SecretBase_VineLeft},
@@ -219,9 +221,9 @@ static const struct ListMenuTemplate sRegistryListMenuTemplate =
 
 static void ClearSecretBase(struct SecretBase *secretBase)
 {
     u16 i;
-    CpuFastFill16(0, secretBase, sizeof(struct SecretBase));
+    memset(secretBase, 0, sizeof(struct SecretBase));
     for (i = 0; i < PLAYER_NAME_LENGTH; i++)
         secretBase->trainerName[i] = EOS;
 }
 
@@ -252,12 +254,30 @@ void TrySetCurSecretBaseIndex(void)
         }
     }
 }
 
 void CheckPlayerHasSecretBase(void)
 {
-     // The player's secret base is always the first in the array.
-     if (gSaveBlock1Ptr->secretBases[0].secretBaseId)
-         gSpecialVar_Result = TRUE;
-     else
-         gSpecialVar_Result = FALSE;
+     u16 i;
+     for (i = 0; i < SECRET_BASES_COUNT; i++)
+     {
+         if (FlagGet(FLAG_SECRET_BASE_OWNED_00 + i)){
+             gSpecialVar_Result = TRUE;
+             return;
+         }   
+     }
+     gSpecialVar_Result = FALSE;
 }

+void CheckNoMoreSecretBases(void)
+{
+    if (FindAvailableSecretBaseIndex() == -1) // If we're out of Secret Bases
+        gSpecialVar_Result = TRUE;
+    else
+        gSpecialVar_Result = FALSE;
+}
+
@@ -361,18 +381,22 @@ static u8 GetNameLength(const u8 *secretBaseOwnerName)
 }
 
 void SetPlayerSecretBase(void)
 {
-    u16 i;
+    u16 i, baseNumber;
 
-    gSaveBlock1Ptr->secretBases[0].secretBaseId = sCurSecretBaseId;
+    baseNumber = FindAvailableSecretBaseIndex();
+    FlagSet(FLAG_SECRET_BASE_OWNED_00 + baseNumber);
+
+    gSaveBlock1Ptr->secretBases[baseNumber].secretBaseId = sCurSecretBaseId;
     for (i = 0; i < TRAINER_ID_LENGTH; i++)
-        gSaveBlock1Ptr->secretBases[0].trainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
+        gSaveBlock1Ptr->secretBases[baseNumber].trainerId[i] = gSaveBlock2Ptr->playerTrainerId[i];
 
-    VarSet(VAR_CURRENT_SECRET_BASE, 0);
-    StringCopyN(gSaveBlock1Ptr->secretBases[0].trainerName, gSaveBlock2Ptr->playerName, GetNameLength(gSaveBlock2Ptr->playerName));
-    gSaveBlock1Ptr->secretBases[0].gender = gSaveBlock2Ptr->playerGender;
-    gSaveBlock1Ptr->secretBases[0].language = GAME_LANGUAGE;
+    VarSet(VAR_CURRENT_SECRET_BASE, baseNumber);
+    StringCopyN(gSaveBlock1Ptr->secretBases[baseNumber].trainerName, gSaveBlock2Ptr->playerName, GetNameLength(gSaveBlock2Ptr->playerName));
+    gSaveBlock1Ptr->secretBases[baseNumber].gender = gSaveBlock2Ptr->playerGender;
+    gSaveBlock1Ptr->secretBases[baseNumber].language = GAME_LANGUAGE;
+    VarSet(VAR_LAST_MADE_SECRET_BASE, baseNumber);
     VarSet(VAR_SECRET_BASE_MAP, gMapHeader.regionMapSectionId);
 }
 
 // Set the 'open' entrance metatile for any occupied secret base on this map
@@ -531,9 +555,9 @@ void InitSecretBaseAppearance(bool8 hidePC)
             if (decorations[x] > 0 && decorations[x] <= NUM_DECORATIONS && gDecorations[decorations[x]].permission != DECORPERM_SPRITE)
                 ShowDecorationOnMap((decorPos[x] >> 4) + MAP_OFFSET, (decorPos[x] & 0xF) + MAP_OFFSET, decorations[x]);
         }
 
-        if (secretBaseIdx != 0)
+        if (IsSecretBaseOwnedByAnotherPlayerFromIndex(secretBaseIdx))
         {
             // Another player's secret base. Change PC type to the "Register" PC.
             FindMetatileIdMapCoords(&x, &y, METATILE_SecretBase_PC);
             MapGridSetMetatileIdAt(x + MAP_OFFSET, y + MAP_OFFSET, METATILE_SecretBase_RegisterPC | MAPGRID_COLLISION_MASK);
@@ -603,9 +627,9 @@ void InitSecretBaseDecorationSprites(void)
                 FlagClear(FLAG_DECORATION_1 + gSpecialVar_0x8004);
                 TrySpawnObjectEvent(gSpecialVar_Result, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
                 TryMoveObjectEventToMapCoords(gSpecialVar_Result, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, gSpecialVar_0x8006, gSpecialVar_0x8007);
                 TryOverrideObjectEventTemplateCoords(gSpecialVar_Result, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup);
-                if (CurMapIsSecretBase() == TRUE && VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+                if (CurMapIsSecretBase() == TRUE && IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 {
                     if (category == DECORCAT_DOLL)
                     {
                         OverrideSecretBaseDecorationSpriteScript(
@@ -716,12 +740,29 @@ static void WarpOutOfSecretBase(void)
 }
 
 void IsCurSecretBaseOwnedByAnotherPlayer(void)
 {
-    if (gSaveBlock1Ptr->secretBases[0].secretBaseId != sCurSecretBaseId)
-        gSpecialVar_Result = TRUE;
-    else
-        gSpecialVar_Result = FALSE;
+    
+    int i;
+    for (i = 0; i < SECRET_BASES_COUNT; i++)
+    {
+        if (FlagGet(FLAG_SECRET_BASE_OWNED_00 + i) &&  GetSecretBaseIndexFromId(sCurSecretBaseId) == i)
+        {
+            gSpecialVar_Result = FALSE;
+            return;
+        }
+    }
+    gSpecialVar_Result = TRUE;
+}
+
+bool8 IsSecretBaseOwnedByAnotherPlayerFromIndex(u16 secretBaseIdx){
+    int i;
+    for (i = 0; i < SECRET_BASES_COUNT; i++)
+    {
+        if (FlagGet(FLAG_SECRET_BASE_OWNED_00 + i) && secretBaseIdx == i)
+            return FALSE;
+    }
+    return TRUE;
 }
 
 static u8 *GetSecretBaseName(u8 *dest, u8 secretBaseIdx)
 {
@@ -806,11 +847,13 @@ void SetPlayerSecretBaseParty(void)
 }
 
 void ClearAndLeaveSecretBase(void)
 {
-    u16 temp = gSaveBlock1Ptr->secretBases[0].numSecretBasesReceived;
-    ClearSecretBase(&gSaveBlock1Ptr->secretBases[0]);
-    gSaveBlock1Ptr->secretBases[0].numSecretBasesReceived = temp;
+    u16 baseIndex = GetSecretBaseIndexFromId(sCurSecretBaseId);
+    u16 temp = gSaveBlock1Ptr->secretBases[baseIndex].numSecretBasesReceived;
+    FlagClear(FLAG_SECRET_BASE_OWNED_00 + baseIndex);
+    ClearSecretBase(&gSaveBlock1Ptr->secretBases[baseIndex]);
+    gSaveBlock1Ptr->secretBases[baseIndex].numSecretBasesReceived = temp;
     WarpOutOfSecretBase();
 }
 
 void MoveOutOfSecretBase(void)
@@ -818,9 +861,9 @@ void MoveOutOfSecretBase(void)
     IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE);
     ClearAndLeaveSecretBase();
 }
 
-static void ClosePlayerSecretBaseEntrance(void)
+static void ClosePlayerSecretBaseEntrance(u16 secretBaseIdx)
 {
     u16 i;
     u16 j;
     s16 metatileId;
@@ -828,9 +871,9 @@ static void ClosePlayerSecretBaseEntrance(void)
 
     for (i = 0; i < events->bgEventCount; i++)
     {
         if (events->bgEvents[i].kind == BG_EVENT_SECRET_BASE
-         && gSaveBlock1Ptr->secretBases[0].secretBaseId == events->bgEvents[i].bgUnion.secretBaseId)
+         && gSaveBlock1Ptr->secretBases[secretBaseIdx].secretBaseId == events->bgEvents[i].bgUnion.secretBaseId)
         {
             metatileId = MapGridGetMetatileIdAt(events->bgEvents[i].x + MAP_OFFSET, events->bgEvents[i].y + MAP_OFFSET);
             for (j = 0; j < ARRAY_COUNT(sSecretBaseEntranceMetatiles); j++)
             {
@@ -853,14 +896,15 @@ static void ClosePlayerSecretBaseEntrance(void)
 // entrance in the overworld.
 void MoveOutOfSecretBaseFromOutside(void)
 {
     u16 temp;
+    u16 secretBaseIdx = VarGet(VAR_LAST_MADE_SECRET_BASE);
 
-    ClosePlayerSecretBaseEntrance();
+    ClosePlayerSecretBaseEntrance(secretBaseIdx);
     IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE);
-    temp = gSaveBlock1Ptr->secretBases[0].numSecretBasesReceived;
-    ClearSecretBase(&gSaveBlock1Ptr->secretBases[0]);
-    gSaveBlock1Ptr->secretBases[0].numSecretBasesReceived = temp;
+    temp = gSaveBlock1Ptr->secretBases[secretBaseIdx].numSecretBasesReceived;
+    ClearSecretBase(&gSaveBlock1Ptr->secretBases[secretBaseIdx]);
+    gSaveBlock1Ptr->secretBases[secretBaseIdx].numSecretBasesReceived = temp;
 }
 
 static u8 GetNumRegisteredSecretBases(void)
 {
@@ -1108,9 +1152,9 @@ static void ReturnToMainRegistryMenu(u8 taskId)
 }
 
 static void GoToSecretBasePCRegisterMenu(u8 taskId)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) == 0)
+    if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
         ScriptContext_SetupScript(SecretBase_EventScript_PCCancel);
     else
         ScriptContext_SetupScript(SecretBase_EventScript_ShowRegisterMenu);
 
@@ -1204,9 +1248,9 @@ void SecretBasePerStepCallback(u8 taskId)
     data = gTasks[taskId].data;
     switch (tState)
     {
     case 0:
-        if (VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             sInFriendSecretBase = TRUE;
         else
             sInFriendSecretBase = FALSE;
 
@@ -1402,18 +1446,18 @@ static s16 GetSecretBaseIndexFromId(u8 secretBaseId)
 
     return -1;
 }
 
-static u8 FindAvailableSecretBaseIndex(void)
+static s16 FindAvailableSecretBaseIndex(void)
 {
     s16 i;
-    for (i = 1; i < SECRET_BASES_COUNT; i++)
+    for (i = 0; i < SECRET_BASES_COUNT; i++)
     {
         if (gSaveBlock1Ptr->secretBases[i].secretBaseId == 0)
             return i;
     }
 
-    return 0;
+    return -1;
 }
 
 static u8 FindUnregisteredSecretBaseIndex(void)
 {
@@ -1454,9 +1498,9 @@ static u8 TrySaveFriendsSecretBase(struct SecretBase *secretBase, u32 version, u
         // No secret base is using this location, find a spot to save it
         else
         {
             index = FindAvailableSecretBaseIndex();
-            if (index != 0)
+            if (index > 0)
             {
                 // Save in empty space
                 SaveSecretBase(index, secretBase, version, language);
                 return index;
@@ -1804,9 +1848,9 @@ void InitSecretBaseVars(void)
     VarSet(VAR_SECRET_BASE_STEP_COUNTER, 0);
     VarSet(VAR_SECRET_BASE_LAST_ITEM_USED, 0);
     VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, 0);
     VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, 0);
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
         VarSet(VAR_SECRET_BASE_IS_NOT_LOCAL, TRUE);
     else
         VarSet(VAR_SECRET_BASE_IS_NOT_LOCAL, FALSE);
 
@@ -1829,21 +1873,21 @@ void CheckLeftFriendsSecretBase(void)
 }
 
 void CheckInteractedWithFriendsDollDecor(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_DOLL);
 }
 
 void CheckInteractedWithFriendsCushionDecor(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_CUSHION);
 }
 
 void DeclinedSecretBaseBattle(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
     {
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) & ~(SECRET_BASE_BATTLED_WON | SECRET_BASE_BATTLED_LOST | SECRET_BASE_DECLINED_BATTLE));
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) & ~(SECRET_BASE_BATTLED_DRAW));
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_DECLINED_BATTLE);
@@ -1851,9 +1895,9 @@ void DeclinedSecretBaseBattle(void)
 }
 
 void WonSecretBaseBattle(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
     {
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) & ~(SECRET_BASE_BATTLED_WON | SECRET_BASE_BATTLED_LOST | SECRET_BASE_DECLINED_BATTLE));
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) & ~(SECRET_BASE_BATTLED_DRAW));
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_BATTLED_WON);
@@ -1861,9 +1905,9 @@ void WonSecretBaseBattle(void)
 }
 
 void LostSecretBaseBattle(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
     {
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) & ~(SECRET_BASE_BATTLED_WON | SECRET_BASE_BATTLED_LOST | SECRET_BASE_DECLINED_BATTLE));
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) & ~(SECRET_BASE_BATTLED_DRAW));
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_BATTLED_LOST);
@@ -1871,9 +1915,9 @@ void LostSecretBaseBattle(void)
 }
 
 void DrewSecretBaseBattle(void)
 {
-    if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+    if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
     {
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) & ~(SECRET_BASE_BATTLED_WON | SECRET_BASE_BATTLED_LOST | SECRET_BASE_DECLINED_BATTLE));
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) & ~(SECRET_BASE_BATTLED_DRAW));
         VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_BATTLED_DRAW);
@@ -1901,9 +1945,9 @@ void CheckInteractedWithFriendsPosterDecor(void)
         case METATILE_SecretBase_GreenPoster:
         case METATILE_SecretBase_RedPoster:
         case METATILE_SecretBase_BluePoster:
         case METATILE_SecretBase_CutePoster:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_POSTER);
             break;
     }
 }
@@ -1916,9 +1960,9 @@ void CheckInteractedWithFriendsFurnitureBottom(void)
     switch (MapGridGetMetatileIdAt(x, y))
     {
         case METATILE_SecretBase_GlassOrnament_Base1:
         case METATILE_SecretBase_GlassOrnament_Base2:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_GLASS_ORNAMENT);
             break;
         case METATILE_SecretBase_RedPlant_Base1:
         case METATILE_SecretBase_RedPlant_Base2:
@@ -1937,25 +1981,25 @@ void CheckInteractedWithFriendsFurnitureBottom(void)
         case METATILE_SecretBase_GorgeousPlant_BaseLeft1:
         case METATILE_SecretBase_GorgeousPlant_BaseRight1:
         case METATILE_SecretBase_GorgeousPlant_BaseLeft2:
         case METATILE_SecretBase_GorgeousPlant_BaseRight2:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_PLANT);
             break;
         case METATILE_SecretBase_Fence_Horizontal:
         case METATILE_SecretBase_Fence_Vertical:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_FENCE);
             break;
         case METATILE_SecretBase_Tire_BottomLeft:
         case METATILE_SecretBase_Tire_BottomRight:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_TIRE);
             break;
         case METATILE_SecretBase_RedBrick_Bottom:
         case METATILE_SecretBase_YellowBrick_Bottom:
         case METATILE_SecretBase_BlueBrick_Bottom:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_BRICK);
             break;
         case METATILE_SecretBase_SmallDesk:
         case METATILE_SecretBase_PokemonDesk:
@@ -1979,9 +2023,9 @@ void CheckInteractedWithFriendsFurnitureBottom(void)
         case METATILE_SecretBase_HardDesk_BottomRight:
         case METATILE_SecretBase_PrettyDesk_BottomLeft:
         case METATILE_SecretBase_PrettyDesk_BottomMid:
         case METATILE_SecretBase_PrettyDesk_BottomRight:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_DESK);
             break;
     }
 }
@@ -2003,9 +2047,9 @@ void CheckInteractedWithFriendsFurnitureMiddle(void)
         case METATILE_SecretBase_HardDesk_TopMid:
         case METATILE_SecretBase_HardDesk_Center:
         case METATILE_SecretBase_PrettyDesk_TopMid:
         case METATILE_SecretBase_PrettyDesk_Center:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_DESK);
             break;
     }
 }
@@ -2038,20 +2082,20 @@ void CheckInteractedWithFriendsFurnitureTop(void)
         case METATILE_SecretBase_PrettyDesk_TopLeft:
         case METATILE_SecretBase_PrettyDesk_TopRight:
         case METATILE_SecretBase_PrettyDesk_MidLeft:
         case METATILE_SecretBase_PrettyDesk_MidRight:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_DESK);
             break;
         case METATILE_SecretBase_Tire_TopLeft:
         case METATILE_SecretBase_Tire_TopRight:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_TIRE);
             break;
         case METATILE_SecretBase_RedBrick_Top:
         case METATILE_SecretBase_YellowBrick_Top:
         case METATILE_SecretBase_BlueBrick_Top:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_BRICK);
             break;
     }
 }
@@ -2064,9 +2108,9 @@ void CheckInteractedWithFriendsSandOrnament(void)
     switch ((int)MapGridGetMetatileIdAt(x, y))
     {
         case METATILE_SecretBase_SandOrnament_Base1:
         case METATILE_SecretBase_SandOrnament_Base2:
-            if (VarGet(VAR_CURRENT_SECRET_BASE) != 0)
+            if (IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
                 VarSet(VAR_SECRET_BASE_HIGH_TV_FLAGS, VarGet(VAR_SECRET_BASE_HIGH_TV_FLAGS) | SECRET_BASE_USED_SAND_ORNAMENT);
             break;
     }
 }
---------------------------- include/secret_base.h ----------------------------
index cb3b95ee78..e9f7f5f779 100644
@@ -22,9 +22,11 @@ void CheckLeftFriendsSecretBase(void);
 void ClearSecretBases(void);
 void SetCurSecretBaseIdFromPosition(const struct MapPosition *position, const struct MapEvents *events);
 void TrySetCurSecretBaseIndex(void);
 void CheckPlayerHasSecretBase(void);
+void CheckNoMoreSecretBases(void);
 void ToggleSecretBaseEntranceMetatile(void);
 void ScriptContext_Enable(void);
 void ReceiveSecretBasesData(void *records, size_t recordSize, u8 linkIdx);
+bool8 IsSecretBaseOwnedByAnotherPlayerFromIndex(u16 secretBaseIdx);
 
 #endif //GUARD_SECRET_BASE_H
------------------------- data/scripts/secret_base.inc -------------------------
index 17801e85a0..7020f7c679 100644
@@ -25,9 +25,9 @@ SecretBase_Text_DiscoveredSmallEntrance:
 	.include "data/text/secret_base_trainers.inc"
 
 SecretBase_EventScript_CheckEntrance::
 	special GetSecretBaseTypeInFrontOfPlayer
-	special CheckPlayerHasSecretBase
+	special CheckNoMoreSecretBases
 	goto_if_eq VAR_RESULT, TRUE, SecretBase_EventScript_AlreadyHasSecretBase
 	checkpartymove MOVE_SECRET_POWER
 	setfieldeffectargument 0, VAR_RESULT
 	buffermovename STR_VAR_2, MOVE_SECRET_POWER
@@ -728,9 +728,9 @@ SecretBase_Text_SkittyTV:
 	.string "A toy TV shaped like a SKITTY.\n"
 	.string "It looks ready to stroll away…$"
 
 SecretBase_Text_WouldYouLikeToMoveBases:
-	.string "You may only make one SECRET BASE.\p"
+	.string "You have to many SECRET BASES.\p"
 	.string "Would you like to move from the SECRET\n"
 	.string "BASE near {STR_VAR_1}?$"
 
 SecretBase_Text_MovingCompletedUseSecretPower:
------------------------------ data/specials.inc ------------------------------
index a863b6e137..f5c83825b2 100644
@@ -15,8 +15,9 @@ gSpecials::
 	def_special CleanupLinkRoomState
 	def_special ExitLinkRoom
 	def_special SetPlayerSecretBase
 	def_special CheckPlayerHasSecretBase
+	def_special CheckNoMoreSecretBases
 	def_special EnterSecretBase
 	def_special ClearAndLeaveSecretBase
 	def_special MoveOutOfSecretBase
 	def_special IsCurSecretBaseOwnedByAnotherPlayer
------------------------------- src/decoration.c -------------------------------
index b149c9d797..73946f4fff 100644
@@ -509,10 +509,11 @@ void InitDecorationContextItems(void)
         gCurDecorationItems = gDecorationInventories[sCurDecorationCategory].items;
 
     if (sDecorationContext.isPlayerRoom == FALSE)
     {
-        sDecorationContext.items = gSaveBlock1Ptr->secretBases[0].decorations;
-        sDecorationContext.pos = gSaveBlock1Ptr->secretBases[0].decorationPositions;
+        u16 currSecretBaseIdx = VarGet(VAR_CURRENT_SECRET_BASE);
+        sDecorationContext.items = gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorations;
+        sDecorationContext.pos = gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorationPositions;
     }
 
     if (sDecorationContext.isPlayerRoom == TRUE)
     {
@@ -570,11 +571,12 @@ static void InitDecorationActionsWindow(void)
 }
 
 void DoSecretBaseDecorationMenu(u8 taskId)
 {
+    u16 currSecretBaseIdx = VarGet(VAR_CURRENT_SECRET_BASE);
     InitDecorationActionsWindow();
-    sDecorationContext.items = gSaveBlock1Ptr->secretBases[0].decorations;
-    sDecorationContext.pos = gSaveBlock1Ptr->secretBases[0].decorationPositions;
+    sDecorationContext.items = gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorations;
+    sDecorationContext.pos = gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorationPositions;
     sDecorationContext.size = DECOR_MAX_SECRET_BASE;
     sDecorationContext.isPlayerRoom = FALSE;
     gTasks[taskId].func = HandleDecorationActionsMenuInput;
 }
@@ -1061,20 +1063,21 @@ static bool8 IsDecorationIndexInPlayersRoom(u8 idx)
 static void IdentifyOwnedDecorationsCurrentlyInUseInternal(u8 taskId)
 {
     u16 i, j, k;
     u16 count;
+    u16 currSecretBaseIdx = VarGet(VAR_CURRENT_SECRET_BASE);
 
     count = 0;
     memset(sSecretBaseItemsIndicesBuffer, 0, sizeof(sSecretBaseItemsIndicesBuffer));
     memset(sPlayerRoomItemsIndicesBuffer, 0, sizeof(sPlayerRoomItemsIndicesBuffer));
 
     for (i = 0; i < ARRAY_COUNT(sSecretBaseItemsIndicesBuffer); i++)
     {
-        if (gSaveBlock1Ptr->secretBases[0].decorations[i] != DECOR_NONE)
+        if (gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorations[i] != DECOR_NONE)
         {
             for (j = 0; j < gDecorationInventories[sCurDecorationCategory].size; j++)
             {
-                if (gCurDecorationItems[j] == gSaveBlock1Ptr->secretBases[0].decorations[i])
+                if (gCurDecorationItems[j] == gSaveBlock1Ptr->secretBases[currSecretBaseIdx].decorations[i])
                 {
                     for (k = 0; k < count && sSecretBaseItemsIndicesBuffer[k] != j + 1; k++)
                         ;
------------------------------ src/fldeff_misc.c ------------------------------
index 0b254b6af3..173840c437 100644
@@ -547,9 +547,9 @@ static void AdjustSecretPowerSpritePixelOffsets(void)
 bool8 SetUpFieldMove_SecretPower(void)
 {
     u8 mb;
 
-    CheckPlayerHasSecretBase();
+    CheckNoMoreSecretBases();
 
     if (gSpecialVar_Result == 1 || GetPlayerFacingDirection() != DIR_NORTH)
         return FALSE;
 
@@ -838,9 +838,9 @@ void DoSecretBasePCTurnOffEffect(void)
 
     GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
     PlaySE(SE_PC_OFF);
 
-    if (!VarGet(VAR_CURRENT_SECRET_BASE))
+    if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
         MapGridSetMetatileIdAt(x, y, METATILE_SecretBase_PC | MAPGRID_COLLISION_MASK);
     else
         MapGridSetMetatileIdAt(x, y, METATILE_SecretBase_RegisterPC | MAPGRID_COLLISION_MASK);
 
@@ -1132,9 +1132,9 @@ void InteractWithShieldOrTVDecoration(void)
         StringCopy(gStringVar2, gText_Gold);
 
         gSpecialVar_Result = 0;
 
-        if (!VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             return;
 
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_GOLD_SHIELD);
         break;
@@ -1143,33 +1143,33 @@ void InteractWithShieldOrTVDecoration(void)
         StringCopy(gStringVar2, gText_Silver);
 
         gSpecialVar_Result = 0;
 
-        if (!VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             return;
 
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_SILVER_SHIELD);
         break;
     case METATILE_SecretBase_TV:
         gSpecialVar_Result = 1;
 
-        if (!VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             return;
 
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
         break;
     case METATILE_SecretBase_RoundTV:
         gSpecialVar_Result = 2;
 
-        if (!VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             return;
 
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
         break;
     case METATILE_SecretBase_CuteTV:
         gSpecialVar_Result = 3;
 
-        if (!VarGet(VAR_CURRENT_SECRET_BASE))
+        if (!IsSecretBaseOwnedByAnotherPlayerFromIndex(VarGet(VAR_CURRENT_SECRET_BASE)))
             return;
 
         VarSet(VAR_SECRET_BASE_LOW_TV_FLAGS, VarGet(VAR_SECRET_BASE_LOW_TV_FLAGS) | SECRET_BASE_USED_TV);
         break;
------------------------------- src/overworld.c -------------------------------
index 7e96fcec32..e399c69975 100644
@@ -68,8 +68,9 @@
 #include "constants/trainer_hill.h"
 #include "constants/weather.h"
 #include "item.h"
 #include "constants/items.h"
+#include "decoration.h"
 
 struct CableClubPlayer
 {
     u8 playerId;
@@ -2072,8 +2073,9 @@ static void DoMapLoadLoop(u8 *state)
 static void ResetMirageTowerAndSaveBlockPtrs(void)
 {
     ClearMirageTowerPulseBlend();
     MoveSaveBlocks_ResetHeap();
+    InitDecorationContextItems();  // Runs this command again once the save file is loaded
 }
 
 static void ResetScreenForMapLoad(void)
 {
--------------------------- include/constants/vars.h ---------------------------
index e95e14b183..740ff6093c 100644
@@ -199,9 +199,9 @@
 #define VAR_SS_TIDAL_STATE                               0x40B4
 #define VAR_TRICK_HOUSE_ENTER_FROM_CORRIDOR              0x40B5
 #define VAR_TRICK_HOUSE_PUZZLE_7_STATE_2                 0x40B6 // Leftover from RS, never set
 #define VAR_SLATEPORT_FAN_CLUB_STATE                     0x40B7
-#define VAR_UNUSED_0x40B8                                0x40B8 // Unused Var
+#define VAR_LAST_MADE_SECRET_BASE                        0x40B8
 #define VAR_MT_PYRE_STATE                                0x40B9
 #define VAR_NEW_MAUVILLE_STATE                           0x40BA
 #define VAR_UNUSED_0x40BB                                0x40BB // Unused Var
 #define VAR_BRAVO_TRAINER_BATTLE_TOWER_ON                0x40BC
-------------------------- include/constants/flags.h --------------------------
index e123d5a09e..926c28a147 100644
@@ -1499,29 +1499,30 @@
 
 #define FLAG_UNUSED_0x8E3                           (SYSTEM_FLAGS + 0x83) // Unused Flag
 
 #define FLAG_RECEIVED_POKEDEX_FROM_BIRCH            (SYSTEM_FLAGS + 0x84)
+// Secret Bases
+#define FLAG_SECRET_BASE_OWNED_00                   (SYSTEM_FLAGS + 0x85)
+#define FLAG_SECRET_BASE_OWNED_01                   (SYSTEM_FLAGS + 0x86)
+#define FLAG_SECRET_BASE_OWNED_02                   (SYSTEM_FLAGS + 0x87)
+#define FLAG_SECRET_BASE_OWNED_03                   (SYSTEM_FLAGS + 0x88)
+#define FLAG_SECRET_BASE_OWNED_04                   (SYSTEM_FLAGS + 0x89)
+#define FLAG_SECRET_BASE_OWNED_05                   (SYSTEM_FLAGS + 0x8A)
+#define FLAG_SECRET_BASE_OWNED_06                   (SYSTEM_FLAGS + 0x8B)
+#define FLAG_SECRET_BASE_OWNED_07                   (SYSTEM_FLAGS + 0x8C)
+#define FLAG_SECRET_BASE_OWNED_08                   (SYSTEM_FLAGS + 0x8D)
+#define FLAG_SECRET_BASE_OWNED_09                   (SYSTEM_FLAGS + 0x8E)
+#define FLAG_SECRET_BASE_OWNED_10                   (SYSTEM_FLAGS + 0x8F)
+#define FLAG_SECRET_BASE_OWNED_11                   (SYSTEM_FLAGS + 0x90)
+#define FLAG_SECRET_BASE_OWNED_12                   (SYSTEM_FLAGS + 0x91)
+#define FLAG_SECRET_BASE_OWNED_13                   (SYSTEM_FLAGS + 0x92)
+#define FLAG_SECRET_BASE_OWNED_14                   (SYSTEM_FLAGS + 0x93)
+#define FLAG_SECRET_BASE_OWNED_15                   (SYSTEM_FLAGS + 0x94)
+#define FLAG_SECRET_BASE_OWNED_16                   (SYSTEM_FLAGS + 0x95)
+#define FLAG_SECRET_BASE_OWNED_17                   (SYSTEM_FLAGS + 0x96)
+#define FLAG_SECRET_BASE_OWNED_18                   (SYSTEM_FLAGS + 0x97)
+#define FLAG_SECRET_BASE_OWNED_19                   (SYSTEM_FLAGS + 0x98)
 
-#define FLAG_UNUSED_0x8E5                           (SYSTEM_FLAGS + 0x85) // Unused Flag
-#define FLAG_UNUSED_0x8E6                           (SYSTEM_FLAGS + 0x86) // Unused Flag
-#define FLAG_UNUSED_0x8E7                           (SYSTEM_FLAGS + 0x87) // Unused Flag
-#define FLAG_UNUSED_0x8E8                           (SYSTEM_FLAGS + 0x88) // Unused Flag
-#define FLAG_UNUSED_0x8E9                           (SYSTEM_FLAGS + 0x89) // Unused Flag
-#define FLAG_UNUSED_0x8EA                           (SYSTEM_FLAGS + 0x8A) // Unused Flag
-#define FLAG_UNUSED_0x8EB                           (SYSTEM_FLAGS + 0x8B) // Unused Flag
-#define FLAG_UNUSED_0x8EC                           (SYSTEM_FLAGS + 0x8C) // Unused Flag
-#define FLAG_UNUSED_0x8ED                           (SYSTEM_FLAGS + 0x8D) // Unused Flag
-#define FLAG_UNUSED_0x8EE                           (SYSTEM_FLAGS + 0x8E) // Unused Flag
-#define FLAG_UNUSED_0x8EF                           (SYSTEM_FLAGS + 0x8F) // Unused Flag
-#define FLAG_UNUSED_0x8F0                           (SYSTEM_FLAGS + 0x90) // Unused Flag
-#define FLAG_UNUSED_0x8F1                           (SYSTEM_FLAGS + 0x91) // Unused Flag
-#define FLAG_UNUSED_0x8F2                           (SYSTEM_FLAGS + 0x92) // Unused Flag
-#define FLAG_UNUSED_0x8F3                           (SYSTEM_FLAGS + 0x93) // Unused Flag
-#define FLAG_UNUSED_0x8F4                           (SYSTEM_FLAGS + 0x94) // Unused Flag
-#define FLAG_UNUSED_0x8F5                           (SYSTEM_FLAGS + 0x95) // Unused Flag
-#define FLAG_UNUSED_0x8F6                           (SYSTEM_FLAGS + 0x96) // Unused Flag
-#define FLAG_UNUSED_0x8F7                           (SYSTEM_FLAGS + 0x97) // Unused Flag
-#define FLAG_UNUSED_0x8F8                           (SYSTEM_FLAGS + 0x98) // Unused Flag
 #define FLAG_UNUSED_0x8F9                           (SYSTEM_FLAGS + 0x99) // Unused Flag
 #define FLAG_UNUSED_0x8FA                           (SYSTEM_FLAGS + 0x9A) // Unused Flag
 #define FLAG_UNUSED_0x8FB                           (SYSTEM_FLAGS + 0x9B) // Unused Flag
 #define FLAG_UNUSED_0x8FC                           (SYSTEM_FLAGS + 0x9C) // Unused Flag

Note: Changing CpuFastFill16 to memset isn't required, but allows for the Secret Bases to change size and this still work. This is because CpuFastFill16 is based off CpuFastSet, which is fast, but modifies data in chunks of 32 bytes.
For example: in global.h, if you change SECRET_BASES_COUNT from 20 to 16 and DECOR_MAX_SECRET_BASE from 16 to 36, you can have 36 items in your Secret Bases and 16 Secret Bases (though do this at your own risk, as this may break the gameSave size in some cases). This would work since the size of either would be the same in SaveBlock1, but the struct with 36 decorations is no longer cleanly divisible by 32.
This is a large tangent to say that keeping CpuFastFill16 in ClearSecretBase is fine so long as you keep your Secret Base struct the same size and don't modify the amount of decorations you can place.

Clone this wiki locally