/// <summary>Registers the item into it's registry</summary>
        public override IdentifiableItem Register()
        {
            Build();

            foreach (Identifiable.Id id in Prefabs.Keys)
            {
                IdentifiableRegistry.CategorizeId(id);

                if (GameContext.Instance.MessageDirector.Get("actor", "l." + id.ToString().ToLower()) == null)
                {
                    LanguageController.AddActorTranslation("l." + id.ToString().ToLower(), DefTranslation[id]);
                }

                LookupRegistry.RegisterIdentifiablePrefab(Prefabs[id]);

                VacEntry = VacItemDefinition.CreateVacItemDefinition(id, Color, Icon ? Icon : SRObjects.MissingIcon);
                LookupRegistry.RegisterVacEntry(VacEntry);
                VacEntries.Add(id, VacEntry);

                if (IsVacuumableOverride || Size == Vacuumable.Size.NORMAL)
                {
                    AmmoRegistry.RegisterPlayerAmmo(PlayerState.AmmoMode.DEFAULT, id);
                }

                if (IsRefineryResource)
                {
                    AmmoRegistry.RegisterRefineryResource(id);
                }

                AmmoRegistry.RegisterSiloAmmo(ValidSiloAmmo, id);
            }

            VacEntry = null;
            return(this);
        }
 private static void Awake_Postfix(LookupDirector @this, Dictionary <Identifiable.Id, GameObject> p_identifiablePrefabDict,
                                   Dictionary <Gadget.Id, GadgetDefinition> p_gadgetDefinitionDict, Dictionary <Identifiable.Id, VacItemDefinition> p_vacItemDict)
 {
     //& Injects main game content
     IdentifiableRegistry.InjectPrefabs(p_identifiablePrefabDict);
     GadgetRegistry.InjectGadgets(p_gadgetDefinitionDict);
     IdentifiableRegistry.InjectVacEntries(p_vacItemDict);
 }
        private static void RegisterActor_Postfix(long actorId, GameObject gameObj, Dictionary <long, ActorModel> p_actors)
        {
            Identifiable.Id id = Identifiable.GetId(gameObj);
            if (!IdentifiableRegistry.IsIdentifiableRegistered(id))
            {
                return;
            }

            IDRegistry.RegisterActor(actorId);
        }
    public static Identifiable.Id CraftLargo(this LookupDirector director, Identifiable.Id slimeA, Identifiable.Id slimeB, Action <SlimeDefinition> extraLargoBehaviour = null, Predicate <Identifiable.Id> canBeTarr = null, Predicate <Identifiable.Id> forceLargo = null)
    {
        if (director.LargoExists(slimeA, slimeB))
        {
            return(Identifiable.Id.NONE);
        }

        string prefabName = "slime" +
                            slimeA.ToString().Replace("_SLIME", "").ToUpper()[0] + slimeA.ToString().Replace("_SLIME", "").ToLower().Substring(1) +
                            slimeB.ToString().Replace("_SLIME", "").ToUpper()[0] + slimeB.ToString().Replace("_SLIME", "").ToLower().Substring(1);

        string name = slimeA.ToString().Replace("_SLIME", "") + slimeB.ToString().Replace("_SLIME", "") + "_LARGO";

        Identifiable.Id largoID = IdentifiableRegistry.CreateIdentifiableId(EnumPatcher.GetFirstFreeValue(typeof(Identifiable.Id)), name);

        SlimeDefinitions defs = GameContext.Instance.SlimeDefinitions;

        SlimeDefinition curr  = defs.GetSlimeByIdentifiableId(slimeA);
        SlimeDefinition other = defs.GetSlimeByIdentifiableId(slimeB);

        bool largofyState = curr.CanLargofy;

        curr.CanLargofy = true;

        if (!other.CanLargofy && !(forceLargo?.Invoke(slimeB) ?? false))
        {
            return(Identifiable.Id.NONE);
        }

        bool largofyStateB = other.CanLargofy;

        other.CanLargofy = true;

        SlimeDefinition largoDef = defs.GetLargoByBaseSlimes(curr, other);

        largoDef.IdentifiableId = largoID;

        curr.CanLargofy  = largofyState;
        other.CanLargofy = largofyStateB;

        if (!(canBeTarr?.Invoke(slimeB) ?? true))
        {
            largoDef.Diet.EatMap.RemoveAll((entry) => entry.becomesId == Identifiable.Id.TARR_SLIME);
            largoDef.Diet.EatMap.RemoveAll((entry) => entry.becomesId == Identifiable.Id.GLITCH_TARR_SLIME);
        }

        extraLargoBehaviour?.Invoke(largoDef);

        SlimeTemplate largoTemplate = new SlimeTemplate(prefabName, largoDef).SetVacSize(Vacuumable.Size.LARGE)
                                      .SetTranslation(curr.Name + " " + other.Name + " Largo").Create();

        LookupRegistry.RegisterIdentifiablePrefab(largoTemplate.ToPrefab());

        return(largoID);
    }
Beispiel #5
0
        /// <summary>
        /// Called before GameContext.Awake()
        /// </summary>
        internal static void PreLoad()
        {
            if (isPreInitialized)
            {
                return;
            }
            isPreInitialized = true;
            Debug.Log("SRML has successfully invaded the game!");

            prefabParent = new GameObject("PrefabParent").transform;
            prefabParent.gameObject.SetActive(false);
            GameObject.DontDestroyOnLoad(prefabParent.gameObject);
            foreach (var v in Assembly.GetExecutingAssembly().GetTypes())
            {
                System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(v.TypeHandle);
            }

            HarmonyPatcher.PatchAll();

            try
            {
                SRModLoader.InitializeMods();
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                ErrorGUI.CreateError($"{e.GetType().Name}: {e.Message}");
                return;
            }
            FileLogger.Init();
            Console.Console.Init();
            HarmonyOverrideHandler.PatchAll();
            try
            {
                SRModLoader.PreLoadMods();
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                ErrorGUI.CreateError($"{e.Message}");
                return;
            }
            IdentifiableRegistry.CategorizeAllIds();
            GadgetRegistry.CategorizeAllIds();
            ReplacerCache.ClearCache();

            HarmonyPatcher.Instance.Patch(typeof(GameContext).GetMethod("Start"),
                                          prefix: new HarmonyMethod(typeof(Main).GetMethod("Load", BindingFlags.NonPublic | BindingFlags.Static)));
        }
Beispiel #6
0
        /// <summary>
        /// Generates all the IDs for the largos.
        /// <para>NOTE that all IDs are generated even if they don't get used.</para>
        /// </summary>
        /// <param name="slimeToLargo">ID of the slime to create largos</param>
        public static void GenerateLargoIDs(Identifiable.Id slimeToLargo)
        {
            foreach (Identifiable.Id id in Identifiable.SLIME_CLASS)
            {
                if (GetLargoID(slimeToLargo, id) != Identifiable.Id.NONE)
                {
                    continue;
                }

                string name = $"{slimeToLargo.ToString().Replace("_SLIME", "")}_{id.ToString().Replace("_SLIME", "")}_LARGO";

                var newVal = EnumPatcher.GetFirstFreeValue(typeof(Identifiable.Id));
                IdentifiableRegistry.CreateIdentifiableId(newVal, name, false);
            }
        }
Beispiel #7
0
        private static bool GetContents_Prefix(SiloStorage.StorageType type, ref HashSet <Identifiable.Id> @return)
        {
            FieldInfo cacheField = typeof(StorageTypeExtensions).GetField("getContentsCache", BindingFlags.Static | BindingFlags.NonPublic);
            Dictionary <SiloStorage.StorageType, HashSet <Identifiable.Id> > cache = cacheField?.GetValue(null) as Dictionary <SiloStorage.StorageType, HashSet <Identifiable.Id> >;

            if (cache != null && cache.ContainsKey(type))
            {
                @return = cache[type];
                return(false);
            }

            HashSet <Identifiable.Id> idSet = new HashSet <Identifiable.Id>(Identifiable.idComparer);

            switch (type)
            {
            case SiloStorage.StorageType.NON_SLIMES:
                IdentifiableRegistry.PopulateHashSet(idSet, IdentifiableType.NON_SLIME, IdentifiableType.ORNAMENT, IdentifiableType.ECHO, IdentifiableType.ECHO_NOTE);
                break;

            case SiloStorage.StorageType.PLORT:
                IdentifiableRegistry.PopulateHashSet(idSet, IdentifiableType.PLORT);
                break;

            case SiloStorage.StorageType.FOOD:
                IdentifiableRegistry.PopulateHashSet(idSet, IdentifiableType.FOOD, IdentifiableType.CHICK);
                break;

            case SiloStorage.StorageType.CRAFTING:
                IdentifiableRegistry.PopulateHashSet(idSet, IdentifiableType.PLORT, IdentifiableType.CRAFT);
                break;

            case SiloStorage.StorageType.ELDER:
                IdentifiableRegistry.PopulateHashSet(idSet, IdentifiableType.ELDER);
                break;
            }

            idSet.Remove(Identifiable.Id.QUICKSILVER_PLORT);
            AmmoRegistry.InjectStorageAmmo(type, idSet);

            cache?.Add(type, idSet);
            cacheField?.SetValue(null, cache);
            @return = idSet;
            return(false);
        }
Beispiel #8
0
 internal static void PreLoadMods()
 {
     CurrentLoadingStep      = LoadingStep.PRELOAD;
     Console.Console.Reload += Main.Reload;
     foreach (var modid in loadOrder)
     {
         var mod = Mods[modid];
         try
         {
             EnumHolderResolver.RegisterAllEnums(mod.EntryType.Module);
             ConfigManager.PopulateConfigs(mod);
             mod.PreLoad();
         }
         catch (Exception e)
         {
             throw new Exception($"Error pre-loading mod '{modid}'!\n{e.GetType().Name}: {e}");
         }
     }
     IdentifiableRegistry.CategorizeAllIds();
     GadgetRegistry.CategorizeAllIds();
 }
Beispiel #9
0
        internal Identifiable.Id CraftLargo(bool canBeTarr, Identifiable.Id slimeA, Identifiable.Id slimeB, System.Action <SlimeDefinition> extraLargoBehaviour = null)
        {
            if (GameContext.Instance.LookupDirector.LargoExists(slimeA, slimeB))
            {
                return(Identifiable.Id.NONE);
            }

            string prefabName = mainObject.Name + slimeB.ToString().Replace("_SLIME", "").ToUpper()[0] + slimeB.ToString().Replace("_SLIME", "").ToLower().Substring(1);
            string name       = slimeA.ToString().Replace("_SLIME", "") + slimeB.ToString().Replace("_SLIME", "") + "_LARGO";

            Identifiable.Id largoID = IdentifiableRegistry.CreateIdentifiableId(EnumPatcher.GetFirstFreeValue(typeof(Identifiable.Id)), name);

            SlimeDefinitions defs = GameContext.Instance.SlimeDefinitions;

            SlimeDefinition other = defs.GetSlimeByIdentifiableId(slimeB);

            if (!other.CanLargofy)
            {
                return(Identifiable.Id.NONE);
            }

            SlimeDefinition largoDef = defs.GetLargoByBaseSlimes(definition, other);

            largoDef.IdentifiableId = largoID;

            if (!canBeTarr)
            {
                largoDef.Diet.EatMap.RemoveAll((entry) => entry.becomesId == Identifiable.Id.TARR_SLIME);
                largoDef.Diet.EatMap.RemoveAll((entry) => entry.becomesId == Identifiable.Id.GLITCH_TARR_SLIME);
            }

            extraLargoBehaviour?.Invoke(largoDef);

            SlimeTemplate largoTemplate = new SlimeTemplate(prefabName, largoDef).SetFeralState(canBeFeral).SetGlitchState(canBeAGlitch)
                                          .SetVacSize(Vacuumable.Size.LARGE).SetTranslation(definition.Name + " " + other.Name + " Largo").Create();

            LookupRegistry.RegisterIdentifiablePrefab(largoTemplate.ToPrefab());

            return(largoID);
        }
Beispiel #10
0
 private static bool IsGuuIdentifiable(Identifiable.Id id) => IdentifiableRegistry.IsIdentifiableRegistered(id);
Beispiel #11
0
 private static bool IsGuuIdentifiable <V>(KeyValuePair <Identifiable.Id, V> pair) => IdentifiableRegistry.IsIdentifiableRegistered(pair.Key);
Beispiel #12
0
        //! Patch: SavedGame.Save
        internal static void Save(GameV12 original)
        {
            GuuCore.LOGGER.Log("Attempting to save modded save file");
            gameState = new GameV12();

            //& Strip Summary
            if (IdentifiableRegistry.IsIdentifiableRegistered(original.summary.iconId))
            {
                gameState.summary.iconId = original.summary.iconId;
                original.summary.iconId  = FALLBACK_ICON;
            }

            //# Strip Game Mode

            //& Strip World
            StripByMatch(original.world.lastOfferRancherIds, gameState.world.lastOfferRancherIds, IsGuuID);
            StripByMatch(original.world.pendingOfferRancherIds, gameState.world.pendingOfferRancherIds, IsGuuID);
            //# Strip Weather

            StripByMatch(original.world.offers, gameState.world.offers, pair => IsGuuID(pair.Value.rancherId) || IsGuuID(pair.Value.offerId) || ExchangeRegistry.IsOfferTypeRegistered(pair.Key));
            foreach (ExchangeDirector.OfferType type in original.world.offers.Keys)
            {
                ExchangeOfferV04 ori = original.world.offers[type];
                ExchangeOfferV04 mod = new ExchangeOfferV04();

                StripByMatch(ori.requests, mod.requests, request => IsGuuIdentifiable(request.id) || ExchangeRegistry.IsNonIdenRegistered(request.nonIdentReward));
                StripByMatch(ori.rewards, mod.rewards, reward => IsGuuIdentifiable(reward.id) || ExchangeRegistry.IsNonIdenRegistered(reward.nonIdentReward));

                gameState.world.offers.Add(type, mod);
            }

            StripByMatch(original.world.econSaturations, gameState.world.econSaturations, IsGuuIdentifiable);
            StripByMatch(original.world.teleportNodeActivations, gameState.world.teleportNodeActivations, IsGuuID);
            StripByMatch(original.world.liquidSourceUnits, gameState.world.liquidSourceUnits, IsGuuID);

            StripByMatch(original.world.gordos, gameState.world.gordos, IsGuuID);
            foreach (KeyValuePair <string, GordoV01> gordo in original.world.gordos.Where(pair => pair.Value.fashions.Exists(IsGuuIdentifiable)))
            {
                gameState.world.gordos.Add(gordo.Key, new GordoV01());
                StripByMatch(gordo.Value.fashions, gameState.world.gordos[gordo.Key].fashions, IsGuuIdentifiable);
            }

            StripByMatch(original.world.placedGadgets, gameState.world.placedGadgets, IsGuuID);
            foreach (string id in original.world.placedGadgets.Keys)
            {
                PlacedGadgetV08 ori = original.world.placedGadgets[id];
                PlacedGadgetV08 mod = new PlacedGadgetV08();

                if (IsGuuGadget(ori.gadgetId))
                {
                    mod.gadgetId = ori.gadgetId;
                    ori.gadgetId = Gadget.Id.NONE;
                }

                foreach (AmmoDataV02 ammo in ori.ammo)
                {
                    AmmoDataV02 mAmmo = new AmmoDataV02();

                    if (IsGuuIdentifiable(ammo.id))
                    {
                        mAmmo.id = ammo.id;
                        ammo.id  = Identifiable.Id.NONE;
                    }

                    //# Strip Emotion Data
                }

                if (IsGuuIdentifiable(ori.baitTypeId))
                {
                    mod.baitTypeId = ori.baitTypeId;
                    ori.baitTypeId = Identifiable.Id.NONE;
                }

                if (IsGuuIdentifiable(ori.gordoTypeId))
                {
                    mod.gordoTypeId = ori.gordoTypeId;
                    ori.gordoTypeId = Identifiable.Id.NONE;
                }

                StripByMatch(ori.fashions, mod.fashions, IsGuuIdentifiable);

                if (ori.drone != null)
                {
                    mod.drone = new DroneGadgetV01
                    {
                        drone = new DroneV05()
                    };

                    AmmoDataV02 ammo  = ori.drone.drone.ammo;
                    AmmoDataV02 mAmmo = mod.drone.drone.ammo;

                    if (IsGuuIdentifiable(ammo.id))
                    {
                        mAmmo.id = ammo.id;
                        ammo.id  = Identifiable.Id.NONE;
                    }

                    //# Strip Emotion Data

                    StripByMatch(ori.drone.drone.fashions, mod.drone.drone.fashions, IsGuuIdentifiable);
                }

                gameState.world.placedGadgets.Add(id, mod);
            }

            StripByMatch(original.world.treasurePods, gameState.world.treasurePods, IsGuuID);
            foreach (KeyValuePair <string, TreasurePodV01> pod in original.world.treasurePods.Where(pair => pair.Value.spawnQueue.Exists(IsGuuIdentifiable)))
            {
                gameState.world.treasurePods.Add(pod.Key, new TreasurePodV01());
                StripByMatch(pod.Value.spawnQueue, gameState.world.treasurePods[pod.Key].spawnQueue, IsGuuIdentifiable);
            }

            StripByMatch(original.world.switches, gameState.world.switches, IsGuuID);
            StripByMatch(original.world.puzzleSlotsFilled, gameState.world.puzzleSlotsFilled, IsGuuID);
            StripByMatch(original.world.occupiedPhaseSites, gameState.world.occupiedPhaseSites, IsGuuID);
            StripByMatch(original.world.quicksilverEnergyGenerators, gameState.world.quicksilverEnergyGenerators, IsGuuID);
            StripByMatch(original.world.oasisStates, gameState.world.oasisStates, IsGuuID);
            StripByMatch(original.world.activeGingerPatches, gameState.world.activeGingerPatches, IsGuuID);
            StripByMatch(original.world.echoNoteGordos, gameState.world.echoNoteGordos, IsGuuID);

            //? Slimeulation
            StripByMatch(original.world.glitch.teleporters, gameState.world.glitch.teleporters, IsGuuID);
            StripByMatch(original.world.glitch.nodes, gameState.world.glitch.nodes, IsGuuID);
            StripByMatch(original.world.glitch.impostoDirectors, gameState.world.glitch.impostoDirectors, IsGuuID);
            StripByMatch(original.world.glitch.impostos, gameState.world.glitch.impostos, IsGuuID);
            StripByMatch(original.world.glitch.slimes, gameState.world.glitch.slimes, IsGuuID);
            StripByMatch(original.world.glitch.storage, gameState.world.glitch.storage, IsGuuID);
            StripByMatch(original.world.glitch.storage, gameState.world.glitch.storage, pair => IsGuuIdentifiable(pair.Value.id));

            //& Strip Player
            //# Strip Game Mode

            if (IsGuuIdentifiable(original.player.gameIconId))
            {
                gameState.player.gameIconId = original.player.gameIconId;
                original.player.gameIconId  = FALLBACK_ICON;
            }

            StripByMatch(original.player.upgrades, gameState.player.upgrades, IsGuuUpgrade);

            StripByMatch(original.player.ammo, gameState.player.ammo, pair => AmmoRegistry.IsAmmoModeRegistered(pair.Key));
            foreach (KeyValuePair <PlayerState.AmmoMode, List <AmmoDataV02> > ammoList in original.player.ammo)
            {
                List <AmmoDataV02> moddedList = new List <AmmoDataV02>();
                foreach (AmmoDataV02 ammo in ammoList.Value)
                {
                    AmmoDataV02 data = new AmmoDataV02();

                    if (IsGuuIdentifiable(ammo.id))
                    {
                        data.id = ammo.id;
                        ammo.id = Identifiable.Id.NONE;
                    }

                    //# Strip Emotions

                    moddedList.Add(data);
                }

                if (moddedList.Count > 0)
                {
                    gameState.player.ammo[ammoList.Key] = moddedList;
                }
            }

            foreach (MailV02 mail in original.player.mail)
            {
                MailV02 mod = new MailV02
                {
                    messageKey = string.Empty,
                    mailType   = MailDirector.Type.UPGRADE
                };

                if (MailRegistry.IsTypeRegistered(mail.mailType))
                {
                    mod.mailType  = mail.mailType;
                    mail.mailType = MailDirector.Type.PERSONAL;
                }

                if (MailRegistry.IsMailRegistered(mail.messageKey))
                {
                    mod.messageKey = mail.messageKey;
                    if (mod.mailType == MailDirector.Type.UPGRADE)
                    {
                        mod.mailType = mail.mailType;
                    }
                    mail.mailType = MailDirector.Type.UPGRADE;
                }

                gameState.player.mail.Add(mod);
            }

            StripByMatch(original.player.availUpgrades, gameState.player.availUpgrades, IsGuuUpgrade);
            StripByMatch(original.player.upgradeLocks, gameState.player.upgradeLocks, IsGuuUpgrade);
            StripByMatch(original.player.progress, gameState.player.progress, pair => ProgressRegistry.IsTypeRegistered(pair.Key));
            StripByMatch(original.player.delayedProgress, gameState.player.delayedProgress, pair => ProgressRegistry.IsTrackerRegistered(pair.Key));
            StripByMatch(original.player.blueprints, gameState.player.blueprints, IsGuuGadget);
            StripByMatch(original.player.availBlueprints, gameState.player.availBlueprints, IsGuuGadget);
            StripByMatch(original.player.blueprintLocks, gameState.player.blueprintLocks, IsGuuGadget);
            StripByMatch(original.player.gadgets, gameState.player.gadgets, IsGuuGadget);
            StripByMatch(original.player.craftMatCounts, gameState.player.craftMatCounts, IsGuuIdentifiable);

            //# Strip Region Set ID && Player Pos
            //# Strip Unlocked Zone

            //? Decorizer
            StripByMatch(original.player.decorizer.contents, gameState.player.decorizer.contents, IsGuuIdentifiable);
            StripByMatch(original.player.decorizer.settings, gameState.player.decorizer.settings, IsGuuID);
            StripByMatch(original.player.decorizer.settings, gameState.player.decorizer.settings, pair => IsGuuIdentifiable(pair.Value.selected));

            //& Strip Ranch
            //# Strip Plots

            StripByMatch(original.ranch.accessDoorStates, gameState.ranch.accessDoorStates, IsGuuID);
            StripByMatch(original.ranch.palettes, gameState.ranch.palettes, pair => ChromaPackRegistry.IsTypeRegistered(pair.Key) || ChromaPackRegistry.IsPaletteRegistered(pair.Value));
            StripByMatch(original.ranch.ranchFastForward, gameState.ranch.ranchFastForward, IsGuuID);

            //& Strip Actors
            StripByMatch(original.actors, gameState.actors, actor => IsGuuID(actor.actorId));
            foreach (ActorDataV09 actor in original.actors)
            {
                ActorDataV09 newActor = new ActorDataV09();
                // ReSharper disable once ReplaceWithSingleAssignment.False
                bool hasData = false;

                //# Strip Emotions

                if (actor.fashions.Exists(IsGuuIdentifiable))
                {
                    hasData = true;
                    StripByMatch(actor.fashions, newActor.fashions, IsGuuIdentifiable);
                }

                //# Strip Region Set && Position

                if (hasData)
                {
                    gameState.actors.Add(newActor);
                }
            }

            //& Strip Pedia
            //# Strip Unlocked IDs
            //# Strip Completed Tuts
            //# Strip Popup Queue

            //& Strip Achievements
            //# Strip Float Stats
            //# Strip Double Stats
            //# Strip Int Stats

            //# Strip ID Stats by Key
            foreach (KeyValuePair <AchievementsDirector.GameIdDictStat, Dictionary <Identifiable.Id, int> > idDictStat in original.achieve.gameIdDictStatDict.Where(pair => pair.Value.Count(pair2 => IsGuuIdentifiable(pair2.Key)) > 0))
            {
                gameState.achieve.gameIdDictStatDict[idDictStat.Key] = new Dictionary <Identifiable.Id, int>();
                StripByMatch(idDictStat.Value, gameState.achieve.gameIdDictStatDict[idDictStat.Key], IsGuuIdentifiable);
            }

            //& Strip Holidays
            StripByMatch(original.holiday.eventGordos, gameState.holiday.eventGordos, IsGuuID);
            StripByMatch(original.holiday.eventEchoNoteGordos, gameState.holiday.eventEchoNoteGordos, IsGuuID);

            //& Strip Appearances
            StripByMatch(original.appearances.unlocks, gameState.appearances.unlocks, IsGuuIdentifiable);
            //# Strip Unlocks based on Appearance Sets

            StripByMatch(original.appearances.selections, gameState.appearances.selections, IsGuuIdentifiable);
            //# Strip Selections based on Appearance Sets

            //& Strip Instruments
            //# Strip Unlocks
            //# Strip Selection

            // TODO: Strip content from the original
        }