internal void PetNamer(string petName)
        {
            Pet pet = PetInfo.CreatePet(petName);

            Earth.AddCreature(pet, PetInfo.SkinID);
            pet.warpToFarmHouse(Game1.player);

            // Disable adoption again for today
            CanAdopt = false;

            // Exit the naming menu
            Game1.drawObjectDialogue($"Adopted {petName}.");
        }
        /// <summary>Refreshes creature information based on how much information the save file contains</summary>
        internal static void LoadCreatureSkins()
        {
            foreach (FarmAnimal animal in ModApi.GetAnimals())
            {
                if (!ModEntry.AnimalLongToShortIDs.ContainsKey(ModEntry.GetLongID(animal)))
                {
                    Entry.AddCreature(animal);
                }
                else
                {
                    ModEntry.UpdateSkin(animal);
                }
            }


            foreach (Pet pet in ModApi.GetPets())
            {
                // Remove extra Strays left on the map
                if (ModApi.IsStray(pet))
                {
                    Game1.removeThisCharacterFromAllLocations(pet);
                }
                else if (ModEntry.GetLongID(pet) == 0)
                {
                    Entry.AddCreature(pet);
                }
                else
                {
                    ModEntry.UpdateSkin(pet);
                }
            }

            foreach (Horse horse in ModApi.GetHorses())
            {
                // Remove extra WildHorses left on the map
                if (ModApi.IsWildHorse(horse))
                {
                    Game1.removeThisCharacterFromAllLocations(horse);
                }
                else if (ModApi.IsNotATractor(horse) && ModEntry.GetLongID(horse) == 0)
                {
                    Entry.AddCreature(horse);
                }
                else if (ModApi.IsNotATractor(horse))
                {
                    ModEntry.UpdateSkin(horse);
                }
            }
        }
        /// <summary>Refreshes creature information based on how much information the save file contains</summary>
        internal static void LoadCreatureSkins()
        {
            foreach (FarmAnimal animal in ModApi.GetAnimals())
            {
                if (!ModEntry.AnimalLongToShortIDs.ContainsKey(ModEntry.GetLongID(animal)))
                {
                    Entry.AddCreature(animal);
                }
                else
                {
                    ModEntry.UpdateSkin(animal);
                }
            }


            foreach (Pet pet in ModApi.GetPets())
            {
                if (ModEntry.GetLongID(pet) == 0)
                {
                    Entry.AddCreature(pet);
                }
                else
                {
                    ModEntry.UpdateSkin(pet);
                }
            }

            foreach (Horse horse in ModApi.GetHorses())
            {
                if (ModEntry.GetLongID(horse) == 0)
                {
                    Entry.AddCreature(horse);
                }
                else
                {
                    ModEntry.UpdateSkin(horse);
                }
            }
        }
Example #4
0
        /// <summary>Adopts and names the stray being interacted with. Called in the CheckStray event handler.</summary>
        internal void PetNamer(string petName)
        {
            // Name Pet and add to Adopt & Skin database
            StrayInfo.PetInstance.Name        = petName;
            StrayInfo.PetInstance.displayName = petName;
            Earth.AddCreature(StrayInfo.PetInstance, StrayInfo.SkinID);

            // Warp the new Pet to the farmhouse
            StrayInfo.PetInstance.warpToFarmHouse(Game1.player);

            // Set walk-through pet configuration
            if (!ModEntry.Config.WalkThroughPets)
            {
                StrayInfo.PetInstance.farmerPassesThrough = false;
            }

            // Pet is no longer a Stray to keep track of
            StrayInfo = null;

            // Exit the naming menu
            Game1.drawObjectDialogue($"{petName} was brought home.");
        }
Example #5
0
        /*****************************
        ** Console Command Handlers
        ******************************/

        /// <summary>Handles commands for the SMAPI console</summary>
        internal void OnCommandReceived(string command, string[] args)
        {
            switch (command)
            {
            case "debug_asreset":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                ModEntry.SkinMap              = new Dictionary <long, int>();
                ModEntry.IDToCategory         = new Dictionary <long, ModEntry.CreatureCategory>();
                ModEntry.AnimalLongToShortIDs = new Dictionary <long, int>();
                ModEntry.AnimalShortToLongIDs = new Dictionary <int, long>();
                foreach (Pet pet in ModApi.GetPets())
                {
                    pet.Manners = 0;
                }
                foreach (Horse horse in ModApi.GetHorses())
                {
                    horse.Manners = 0;
                }

                // Re-add all creatures
                foreach (Pet pet in ModApi.GetPets())
                {
                    Earth.AddCreature(pet);
                }
                foreach (Horse horse in ModApi.GetHorses())
                {
                    Earth.AddCreature(horse, 0, Game1.MasterPlayer);
                }
                foreach (FarmAnimal animal in ModApi.GetAnimals())
                {
                    Earth.AddCreature(animal);
                }
                ModEntry.SMonitor.Log("All creatures have be readded into the A&S system. This has randomized all skins. Strays and wild horses have been unaffected.", LogLevel.Info);
                return;


            case "debug_idmaps":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                ModEntry.SMonitor.Log($"Animals Long to Short:\n{string.Join("\n", ModEntry.AnimalLongToShortIDs)}", LogLevel.Info);
                ModEntry.SMonitor.Log($"Animals Short to Long equal length: {ModEntry.AnimalLongToShortIDs.Count == ModEntry.AnimalShortToLongIDs.Count}", LogLevel.Info);
                return;


            case "debug_skinmaps":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                ModEntry.SMonitor.Log($"{string.Join("\n", ModEntry.SkinMap)}", LogLevel.Info);
                return;


            case "debug_pets":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                foreach (Pet pet in ModApi.GetAllPets())
                {
                    int petSkin = 0;
                    if (ModApi.IsStray(pet))
                    {
                        petSkin = ModEntry.Creator.StrayInfo.SkinID;
                    }
                    else if (ModApi.IsInDatabase(pet))
                    {
                        petSkin = ModEntry.SkinMap[pet.Manners];
                    }

                    ModEntry.SMonitor.Log($"[{pet.Name}] | Manners: {pet.Manners} | Skin: {petSkin} | Stray: {pet.Manners == Stray.StrayID}", LogLevel.Info);
                }
                return;


            case "debug_horses":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                foreach (Horse horse in ModApi.GetAllHorses())
                {
                    int horseSkin = 0;
                    if (ModApi.IsWildHorse(horse))
                    {
                        horseSkin = ModEntry.Creator.HorseInfo.SkinID;
                    }
                    else if (ModApi.IsInDatabase(horse))
                    {
                        horseSkin = ModEntry.SkinMap[horse.Manners];
                    }

                    ModEntry.SMonitor.Log($"[{horse.Name}] | Manners: {horse.Manners} | Skin: {horseSkin} | Wild: {horse.Manners == WildHorse.WildID}", LogLevel.Info);
                }
                return;


            case "summon_stray":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                // Get rid of any previous stray still on the map
                if (ModEntry.Creator.StrayInfo != null)
                {
                    ModEntry.Creator.StrayInfo.RemoveFromWorld();
                }
                // Create a gosh darn new stray
                ModEntry.Creator.StrayInfo = new Stray();
                return;


            case "summon_horse":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                // Get rid of any previous horse still on the map
                if (ModEntry.Creator.HorseInfo != null)
                {
                    ModEntry.Creator.HorseInfo.RemoveFromWorld();
                }
                // Create a gosh darn new horse
                ModEntry.Creator.HorseInfo = new WildHorse();
                return;


            case "debug_clearunowned":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                ModApi.ClearUnownedPets();
                return;


            // Expected arguments: <creature ID>
            case "debug_find":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 1) ||
                    !EnforceArgTypeInt(args[0], 1))
                {
                    return;
                }

                Character creatureToFind = ModEntry.GetCreatureFromShortID(int.Parse(args[0]));
                if (creatureToFind != null)
                {
                    ModEntry.SMonitor.Log($"{creatureToFind.Name} located at: {creatureToFind.currentLocation} | {creatureToFind.getTileX()}, {creatureToFind.getTileY()}", LogLevel.Info);
                }
                else
                {
                    ModEntry.SMonitor.Log($"No creature exists with the given ID: {args[0]}", LogLevel.Error);
                }
                return;


            case "horse_whistle":
                if (args.ToList().Count == 1)
                {
                    // Enforce argument constraints
                    if (!EnforceArgTypeInt(args[0], 1))
                    {
                        return;
                    }

                    int callID = int.Parse(args[0]);
                    if (ModEntry.CallHorse(callID))
                    {
                        return;
                    }
                    // Horse with given ID wasn't found
                    ModEntry.SMonitor.Log($"No horse exists with the given ID: {callID}", LogLevel.Error);
                }
                else
                {
                    // Enforce argument constraints
                    if (!EnforceArgCount(args, 0))
                    {
                        return;
                    }

                    // Call the first horse found
                    ModEntry.CallHorse();
                }
                return;


            case "corral_horses":
                ModEntry.CorralHorses();
                return;


            case "sell":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 1) ||
                    !EnforceArgTypeInt(args[0], 1))
                {
                    return;
                }

                Character sellCreature = ModEntry.GetCreatureFromShortID(int.Parse(args[0]));
                if (sellCreature == null)
                {
                    ModEntry.SMonitor.Log($"No creature exists with the given ID: {args[0]}", LogLevel.Error);
                    return;
                }
                else if ((sellCreature is Pet || sellCreature is Horse) && !ModApi.IsStray(sellCreature) && !ModApi.IsWildHorse(sellCreature))
                {
                    Game1.activeClickableMenu = new ConfirmationDialog($"Are you sure you want to sell your {ModApi.GetInternalType(sellCreature)}, {sellCreature.Name}?", (who) =>
                    {
                        if (Game1.activeClickableMenu is StardewValley.Menus.ConfirmationDialog cd)
                        {
                            cd.cancel();
                        }

                        Earth.RemoveCreature(ModEntry.GetLongID(sellCreature));
                        Game1.removeThisCharacterFromAllLocations((NPC)sellCreature);
                        return;
                    });
                }
                else
                {
                    ModEntry.SMonitor.Log("You may only sell pets and horses via the A&S console. The ID given is for a farm animal or an unknown type of creature.", LogLevel.Error);
                }

                return;


            // Expected arguments: <creature ID> <string name>
            case "rename":
                if (!EnforceArgCount(args, 2) ||
                    !EnforceArgTypeInt(args[0], 1))
                {
                    return;
                }

                int       idToName       = int.Parse(args[0]);
                Character creatureToName = EnforceIdAndGetCreature(idToName);

                if (creatureToName == null)
                {
                    return;
                }

                string oldName = creatureToName.Name;
                creatureToName.Name        = args[1];
                creatureToName.displayName = args[1];
                // Rename the horseName field if the original horse is being renamed.
                if (creatureToName is Horse horseToName && oldName == Game1.player.horseName.ToString())
                {
                    Game1.player.horseName.Set(args[1]);
                }
                ModEntry.SMonitor.Log($"{oldName} (ID {idToName}) has been renamed to {args[1]}", LogLevel.Info);

                return;


            // Expected arguments: <creature type/category/group>
            case "list_creatures":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 1) ||
                    !EnforceArgTypeGroup(args[0]))
                {
                    return;
                }

                PrintRequestedCreatures(ModEntry.Sanitize(args[0]));
                return;


            // Expected arguments: None.
            case "randomize_all_skins":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                // Randomize all skins
                foreach (Pet pet in ModApi.GetPets())
                {
                    ModEntry.RandomizeSkin(pet);
                }
                foreach (Horse horse in ModApi.GetHorses())
                {
                    ModEntry.RandomizeSkin(horse);
                }
                foreach (FarmAnimal animal in ModApi.GetAnimals())
                {
                    ModEntry.RandomizeSkin(animal);
                }

                ModEntry.SMonitor.Log("All animal, pet, and horse skins have been randomized.", LogLevel.Info);
                return;


            // Expected arguments: <creature group or creature ID>
            case "randomize_skin":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 1))
                {
                    return;
                }

                string call = ModEntry.Sanitize(args[0]);
                if (CreatureGroups.Contains(call) || ModApi.GetHandledAllTypes().Contains(call))
                {
                    List <Character> group = GetCreaturesFromGroup(call);
                    foreach (Character creature in group)
                    {
                        ModEntry.RandomizeSkin(creature);
                    }

                    ModEntry.SMonitor.Log($"All creatures in group `{call}` have been randomized.", LogLevel.Info);
                }
                else if (EnforceArgTypeInt(args[0], 1))
                {
                    // Find associated creature instance
                    int       creatureID = int.Parse(args[0]);
                    Character creature   = EnforceIdAndGetCreature(creatureID);

                    if (creature == null)
                    {
                        return;
                    }

                    // A creature was able to be located with the given category and ID
                    if (ModApi.IsInDatabase(creature))
                    {
                        if (ModEntry.RandomizeSkin(creature) == 0)
                        {
                            ModEntry.SMonitor.Log($"No skins are located in `/assets/skins` for {creature.Name}'s type: {ModEntry.Sanitize(creature.GetType().Name)}", LogLevel.Error);
                        }
                        else
                        {
                            ModEntry.SMonitor.Log($"{creature.Name}'s skin has been randomized.", LogLevel.Info);
                        }
                    }
                }
                return;


            // Expected arguments: <skin ID>, <creature ID>
            case "set_skin":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 2) ||
                    !EnforceArgTypeInt(args[0], 1) ||
                    !EnforceArgTypeInt(args[1], 2))
                {
                    return;
                }

                int       skinID         = int.Parse(args[0]);
                int       shortID        = int.Parse(args[1]);
                Character creatureToSkin = EnforceIdAndGetCreature(shortID);

                if (creatureToSkin == null)
                {
                    return;
                }

                // Enforce argument range to the range of the available skins for this creature's type
                if (!ModEntry.Assets[ModApi.GetInternalType(creatureToSkin)].ContainsKey(skinID))
                {
                    ModEntry.SMonitor.Log($"{creatureToSkin.Name}'s type ({ModApi.GetInternalType(creatureToSkin)}) has no skin with ID {skinID}", LogLevel.Error);
                    return;
                }

                // Successfully found given creature to set skin for
                ModEntry.SetSkin(creatureToSkin, skinID);
                ModEntry.SMonitor.Log($"{creatureToSkin.Name}'s skin has been set to skin {skinID}", LogLevel.Info);
                return;


            default:
                return;
            }
        }
        /// <summary>Adds creatures into the system based on the data from older versions' save files or for files new to A&S.</summary>
        internal static void LoadSkinsOldVersion()
        {
            Dictionary <Character, int> creaturesToAdd = new Dictionary <Character, int>();

            // Load pet information stored from older version formats
            Dictionary <long, int> petSkinMap = SHelper.Data.ReadSaveData <Dictionary <long, int> >("pet-skin-map") ?? new Dictionary <long, int>();

            foreach (Pet pet in ModApi.GetPets())
            {
                if (ModApi.IsStray(pet))
                {
                    Game1.removeThisCharacterFromAllLocations(pet);
                    continue;
                }

                long longID = ModEntry.GetLongID(pet);
                // Pet unregistered
                if (longID == 0)
                {
                    creaturesToAdd.Add(pet, 0);
                }
                // Pet registered in previous system
                else if (petSkinMap.ContainsKey(longID))
                {
                    creaturesToAdd.Add(pet, petSkinMap[longID]);
                }
                // Reset any previous known ShortID
                pet.Manners = 0;
            }

            // Load horse information stored from older version formats
            Dictionary <long, int> horseSkinMap = SHelper.Data.ReadSaveData <Dictionary <long, int> >("horse-skin-map") ?? new Dictionary <long, int>();

            foreach (Horse horse in ModApi.GetHorses())
            {
                if (ModApi.IsWildHorse(horse))
                {
                    Game1.removeThisCharacterFromAllLocations(horse);
                    continue;
                }
                else if (!ModApi.IsNotATractor(horse))
                {
                    continue;
                }

                long longID = ModEntry.GetLongID(horse);
                // Horse unregistered
                if (longID == 0)
                {
                    creaturesToAdd.Add(horse, 0);
                }
                // Horse registered in previous system
                else if (horseSkinMap.ContainsKey(longID))
                {
                    creaturesToAdd.Add(horse, horseSkinMap[longID]);
                }
                // Reset any previous known ShortID
                horse.Manners = 0;
            }

            // Load animal information stored from older version formats
            Dictionary <long, int> animalSkinMap = SHelper.Data.ReadSaveData <Dictionary <long, int> >("animal-skin-map") ?? new Dictionary <long, int>();

            ModEntry.AnimalLongToShortIDs = new Dictionary <long, int>();
            ModEntry.AnimalShortToLongIDs = new Dictionary <int, long>();
            foreach (FarmAnimal animal in ModApi.GetAnimals())
            {
                long longID = ModEntry.GetLongID(animal);
                // Animal registered in previous system
                if (animalSkinMap.ContainsKey(longID))
                {
                    creaturesToAdd.Add(animal, animalSkinMap[longID]);
                }
                // Animal unregistered
                else
                {
                    creaturesToAdd.Add(animal, 0);
                }
            }

            // Add in all creatures from older systems
            foreach (KeyValuePair <Character, int> creatureInfo in creaturesToAdd)
            {
                Entry.AddCreature(creatureInfo.Key, creatureInfo.Value);
            }
        }
Example #7
0
        /*****************************
        ** Console Command Handlers
        ******************************/

        /// <summary>Handles commands for the SMAPI console</summary>
        internal void OnCommandReceived(string command, string[] args)
        {
            switch (command)
            {
            case "debug_reset":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                ModEntry.SkinMap              = new Dictionary <long, int>();
                ModEntry.IDToCategory         = new Dictionary <long, ModEntry.CreatureCategory>();
                ModEntry.AnimalLongToShortIDs = new Dictionary <long, int>();
                ModEntry.AnimalShortToLongIDs = new Dictionary <int, long>();
                foreach (Pet pet in ModApi.GetPets())
                {
                    if (!ModApi.IsStray(pet))
                    {
                        pet.Manners = 0;
                    }
                }
                foreach (Horse horse in ModApi.GetHorses())
                {
                    if (!ModApi.IsWildHorse(horse) && ModApi.IsNotATractor(horse))
                    {
                        horse.Manners = 0;
                    }
                }

                // Re-add all creatures
                foreach (Pet pet in ModApi.GetPets())
                {
                    if (!ModApi.IsStray(pet))
                    {
                        Earth.AddCreature(pet);
                    }
                }
                foreach (Horse horse in ModApi.GetHorses())
                {
                    if (!ModApi.IsWildHorse(horse) && ModApi.IsNotATractor(horse))
                    {
                        Earth.AddCreature(horse);
                    }
                }
                foreach (FarmAnimal animal in ModApi.GetAnimals())
                {
                    Earth.AddCreature(animal);
                }
                return;


            case "debug_idmaps":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                ModEntry.SMonitor.Log($"Animals Long to Short:\n{string.Join("\n", ModEntry.AnimalLongToShortIDs)}", LogLevel.Info);
                ModEntry.SMonitor.Log($"Animals Short to Long equal length: {ModEntry.AnimalLongToShortIDs.Count == ModEntry.AnimalShortToLongIDs.Count}", LogLevel.Alert);
                return;


            case "debug_skinmaps":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                ModEntry.SMonitor.Log($"{string.Join("\n", ModEntry.SkinMap)}", LogLevel.Info);
                return;


            case "debug_pets":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }
                foreach (Pet pet in ModApi.GetPets())
                {
                    int petSkin = 0;
                    if (ModApi.IsStray(pet))
                    {
                        petSkin = ModEntry.Creator.StrayInfo.SkinID;
                    }
                    else if (ModApi.IsInDatabase(pet))
                    {
                        petSkin = ModEntry.SkinMap[pet.Manners];
                    }

                    ModEntry.SMonitor.Log($"[{pet.Name}] | Manners: {pet.Manners} | Skin: {petSkin} | Stray: {pet.Manners == Stray.StrayID}", LogLevel.Info);
                }
                return;


            case "debug_horses":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                foreach (Horse horse in ModApi.GetHorses())
                {
                    int horseSkin = 0;
                    if (ModApi.IsWildHorse(horse))
                    {
                        horseSkin = ModEntry.Creator.HorseInfo.SkinID;
                    }
                    else if (ModApi.IsInDatabase(horse))
                    {
                        horseSkin = ModEntry.SkinMap[horse.Manners];
                    }

                    ModEntry.SMonitor.Log($"[{horse.Name}] | Manners: {horse.Manners} | Skin: {horseSkin} | Wild: {horse.Manners == WildHorse.WildID}", LogLevel.Info);
                }
                return;


            case "summon_stray":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                // Get rid of any previous stray still on the map
                if (ModEntry.Creator.StrayInfo != null)
                {
                    ModEntry.Creator.StrayInfo.RemoveFromWorld();
                }
                // Create a gosh darn new stray
                ModEntry.Creator.StrayInfo = new Stray();
                return;


            case "summon_horse":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                // Get rid of any previous horse still on the map
                if (ModEntry.Creator.HorseInfo != null)
                {
                    ModEntry.Creator.HorseInfo.RemoveFromWorld();
                }
                // Create a gosh darn new horse
                ModEntry.Creator.HorseInfo = new WildHorse();
                return;


            case "debug_clearunowned":
                if (!EnforceArgCount(args, 0))
                {
                    return;
                }

                foreach (NPC npc in Utility.getAllCharacters())
                {
                    if (npc is Horse horse && ModApi.IsWildHorse(horse))
                    {
                        Game1.removeThisCharacterFromAllLocations(horse);
                    }
Example #8
0
        /*****************************
        ** Console Command Handlers
        ******************************/

        /// <summary>Handles commands for the SMAPI console</summary>
        internal void OnCommandReceived(string command, string[] args)
        {
            switch (command)
            {
            case "debug_reset":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                ModEntry.AnimalSkinMap = new Dictionary <long, int>();
                ModEntry.PetSkinMap    = new Dictionary <long, int>();
                ModEntry.HorseSkinMap  = new Dictionary <long, int>();

                ModEntry.AnimalLongToShortIDs = new Dictionary <long, int>();
                ModEntry.AnimalShortToLongIDs = new Dictionary <int, long>();

                foreach (Horse horse in ModEntry.GetHorses())
                {
                    if (horse.Manners != WildHorse.WildID)
                    {
                        horse.Manners = 0;
                    }
                }
                foreach (Pet pet in ModEntry.GetPets())
                {
                    if (pet.Manners != Stray.StrayID)
                    {
                        pet.Manners = 0;
                    }
                }

                foreach (Horse horse in ModEntry.GetHorses())
                {
                    if (horse.Manners != WildHorse.WildID)
                    {
                        Earth.AddCreature(horse);
                    }
                }
                foreach (Pet pet in ModEntry.GetPets())
                {
                    if (pet.Manners != Stray.StrayID)
                    {
                        Earth.AddCreature(pet);
                    }
                }
                foreach (FarmAnimal animal in ModEntry.GetAnimals())
                {
                    Earth.AddCreature(animal);
                }


                break;


            case "debug_idmaps":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                ModEntry.SMonitor.Log($"Animals Long to Short:\n{string.Join("\n", ModEntry.AnimalLongToShortIDs)}", LogLevel.Info);
                ModEntry.SMonitor.Log($"Animals Short to Long equal length: {ModEntry.AnimalLongToShortIDs.Count == ModEntry.AnimalShortToLongIDs.Count}", LogLevel.Alert);
                break;


            case "debug_skinmaps":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                ModEntry.SMonitor.Log($"Animals:\n{string.Join("\n", ModEntry.AnimalSkinMap)}", LogLevel.Info);
                ModEntry.SMonitor.Log($"Pets:\n{string.Join("\n", ModEntry.PetSkinMap)}", LogLevel.Alert);
                ModEntry.SMonitor.Log($"Horses:\n{string.Join("\n", ModEntry.HorseSkinMap)}", LogLevel.Info);
                break;


            case "debug_pets":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                foreach (NPC npc in Utility.getAllCharacters())
                {
                    if (npc is Pet pet)
                    {
                        int petSkin = 0;
                        if (pet.Manners == Stray.StrayID)
                        {
                            petSkin = ModEntry.Creator.StrayInfo.SkinID;
                        }
                        else if (ModEntry.HorseSkinMap.ContainsKey(pet.Manners))
                        {
                            petSkin = ModEntry.HorseSkinMap[pet.Manners];
                        }

                        ModEntry.SMonitor.Log($"[{pet.Name}] | Manners: {pet.Manners} | Skin: {petSkin} | Stray: {pet.Manners == Stray.StrayID}", LogLevel.Info);
                    }
                }
                break;


            case "debug_horses":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                foreach (NPC npc in Utility.getAllCharacters())
                {
                    if (npc is Horse horse)
                    {
                        int horseSkin = 0;
                        if (horse.Manners == WildHorse.WildID)
                        {
                            horseSkin = ModEntry.Creator.HorseInfo.SkinID;
                        }
                        else if (ModEntry.HorseSkinMap.ContainsKey(horse.Manners))
                        {
                            horseSkin = ModEntry.HorseSkinMap[horse.Manners];
                        }

                        ModEntry.SMonitor.Log($"[{horse.Name}] | Manners: {horse.Manners} | Skin: {horseSkin} | Wild: {horse.Manners == WildHorse.WildID}", LogLevel.Info);
                    }
                }
                break;


            case "summon_stray":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                // Get rid of any previous stray still on the map
                if (ModEntry.Creator.StrayInfo != null)
                {
                    ModEntry.Creator.StrayInfo.RemoveFromWorld();
                }
                // Create a gosh darn new stray
                ModEntry.Creator.StrayInfo = new Stray();
                break;


            case "summon_horse":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                // Get rid of any previous horse still on the map
                if (ModEntry.Creator.HorseInfo != null)
                {
                    ModEntry.Creator.HorseInfo.RemoveFromWorld();
                }
                // Create a gosh darn new horse
                ModEntry.Creator.HorseInfo = new WildHorse();
                break;


            case "debug_clearunowned":
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                foreach (NPC npc in Utility.getAllCharacters())
                {
                    if (npc is Horse horse && horse.Manners == WildHorse.WildID)
                    {
                        Game1.removeThisCharacterFromAllLocations(horse);
                    }
                    if (npc is Pet pet && pet.Manners == Stray.StrayID)
                    {
                        Game1.removeThisCharacterFromAllLocations(pet);
                    }
                }
                break;


            // Expected arguments: <horse ID>
            case "debug_find":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 2) ||
                    !EnforceArgTypeCategory(args[0], 1) ||
                    !EnforceArgTypeInt(args[1], 2))
                {
                    break;
                }

                string cat = ModEntry.Sanitize(args[0]);
                int    id  = int.Parse(args[1]);

                switch (cat)
                {
                case "horse":
                    foreach (Horse horse in ModEntry.GetHorses())
                    {
                        if (horse.Manners == id)
                        {
                            ModEntry.SMonitor.Log($"{horse.Name} located at: {horse.currentLocation} | {horse.getTileX()}, {horse.getTileY()}", LogLevel.Alert);
                        }
                    }
                    break;

                case "pet":
                    foreach (Pet pet in ModEntry.GetPets())
                    {
                        if (pet.Manners == id)
                        {
                            ModEntry.SMonitor.Log($"{pet.Name} located at: {pet.currentLocation} | {pet.getTileX()}, {pet.getTileY()}", LogLevel.Alert);
                        }
                    }
                    break;

                case "animal":
                    foreach (FarmAnimal animal in ModEntry.GetAnimals())
                    {
                        if (ModEntry.AnimalLongToShortIDs[animal.myID.Value] == id)
                        {
                            ModEntry.SMonitor.Log($"{animal.Name} located at: {animal.currentLocation} | {animal.getTileX()}, {animal.getTileY()}", LogLevel.Alert);
                        }
                    }
                    break;

                default:
                    break;
                }

                break;


            case "horse_whistle":
                if (args.ToList().Count == 1)
                {
                    // Enforce argument constraints
                    if (!EnforceArgTypeInt(args[0], 1))
                    {
                        break;
                    }

                    int callID = int.Parse(args[0]);
                    foreach (Horse horse in ModEntry.GetHorses())
                    {
                        if (horse.Manners == callID)
                        {
                            Game1.warpCharacter(horse, Game1.player.currentLocation, Game1.player.getTileLocation());
                            return;
                        }
                    }
                    // Horse with given ID wasn't found
                    ModEntry.SMonitor.Log($"No horse exists with the given ID: {callID}", LogLevel.Error);
                }
                else
                {
                    // Enforce argument constraints
                    if (!EnforceArgCount(args, 0))
                    {
                        break;
                    }

                    // Call the first horse found
                    ModEntry.CallHorse();
                }
                break;


            case "corral_horses":
                ModEntry.CorralHorses();
                break;


            case "sell":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 2))
                {
                    break;
                }
                if (!EnforceArgTypeCategory(args[0], 1))
                {
                    break;
                }
                if (!EnforceArgTypeInt(args[1], 2))
                {
                    break;
                }


                string type   = ModEntry.Sanitize(args[0]);
                int    sellID = int.Parse(args[1]);
                ModEntry.CreatureCategory sellCategory = ModEntry.CreatureCategory.Animal;
                if (type == "horse")
                {
                    if (!ModEntry.HorseSkinMap.ContainsKey(sellID))
                    {
                        ModEntry.SMonitor.Log($"Horse with the given ID does not exist: {sellID}", LogLevel.Error);
                        return;
                    }
                    sellCategory = ModEntry.CreatureCategory.Horse;
                }
                else if (type == "pet")
                {
                    if (!ModEntry.PetSkinMap.ContainsKey(sellID))
                    {
                        ModEntry.SMonitor.Log($"Pet with the given ID does not exist: {sellID}", LogLevel.Error);
                        return;
                    }
                    sellCategory = ModEntry.CreatureCategory.Pet;
                }
                else
                {
                    ModEntry.SMonitor.Log("Go sell that somewhere else.", LogLevel.Error);
                    return;
                }

                if (sellCategory != ModEntry.CreatureCategory.Animal)
                {
                    Character sellCreature = ModEntry.GetCreature(sellCategory, sellID);
                    Game1.activeClickableMenu = new ConfirmationDialog($"Are you sure you want to sell your {ModEntry.Sanitize(sellCreature.GetType().Name)}, {sellCreature.Name}?", (who) =>
                    {
                        if (Game1.activeClickableMenu is StardewValley.Menus.ConfirmationDialog cd)
                        {
                            cd.cancel();
                        }

                        Earth.RemoveCreature(sellCategory, sellID);
                        Game1.removeThisCharacterFromAllLocations((NPC)sellCreature);
                    });
                }

                break;


            // Expected arguments: <creature type/category/group>
            case "list_creatures":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 1) ||
                    !EnforceArgTypeGroup(args[0]))
                {
                    break;
                }

                PrintRequestedCreatures(ModEntry.Sanitize(args[0]));
                break;


            // Expected arguments: None.
            case "randomize_all_skins":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 0))
                {
                    break;
                }

                // Randomize all skins
                foreach (Horse horse in ModEntry.GetHorses())
                {
                    Earth.SetRandomSkin(horse);
                }
                foreach (Pet pet in ModEntry.GetPets())
                {
                    Earth.SetRandomSkin(pet);
                }
                foreach (FarmAnimal animal in ModEntry.GetAnimals())
                {
                    Earth.SetRandomSkin(animal);
                }

                ModEntry.SMonitor.Log("All animal, pet, and horse skins have been randomized.", LogLevel.Alert);
                break;


            // Expected arguments: <creature category>, <creature ID>
            case "randomize_skin":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 2))
                {
                    break;
                }
                if (!EnforceArgTypeCategory(args[0], 1) || !EnforceArgTypeInt(args[1], 2))
                {
                    break;
                }

                string    category   = ModEntry.Sanitize(args[0]);
                int       creatureID = int.Parse(args[1]);
                Character creature   = null;

                // Find associated creature instance
                if (category == "horse" && ModEntry.HorseSkinMap.ContainsKey(creatureID))
                {
                    creature = ModEntry.GetCreature(ModEntry.CreatureCategory.Horse, creatureID);
                }
                else if (category == "pet" && ModEntry.PetSkinMap.ContainsKey(creatureID))
                {
                    creature = ModEntry.GetCreature(ModEntry.CreatureCategory.Pet, creatureID);
                }
                else if (category == "animal" && ModEntry.AnimalShortToLongIDs.ContainsKey(creatureID))
                {
                    creature = ModEntry.GetCreature(ModEntry.CreatureCategory.Animal, ModEntry.AnimalShortToLongIDs[creatureID]);
                }


                // A creature was able to be located with the given category and ID
                if (creature != null)
                {
                    int newSkin = Earth.SetRandomSkin(creature);
                    if (newSkin == 0)
                    {
                        ModEntry.SMonitor.Log($"No skins are located in `/assets/skins` for {creature.Name}'s type: {ModEntry.Sanitize(creature.GetType().Name)}", LogLevel.Error);
                    }
                    else
                    {
                        ModEntry.SMonitor.Log($"{creature.Name}'s skin has been randomized.", LogLevel.Alert);
                    }
                }
                else
                {
                    ModEntry.SMonitor.Log($"Creature category `{category}` with given ID does not exist: {creatureID}", LogLevel.Error);
                }


                break;


            // Expected arguments: <skin ID>, <creature category>, <creature ID>
            case "set_skin":
                // Enforce argument constraints
                if (!EnforceArgCount(args, 3))
                {
                    break;
                }
                if (!EnforceArgTypeInt(args[0], 1) || !EnforceArgTypeCategory(args[1], 2) || !EnforceArgTypeInt(args[2], 3))
                {
                    break;
                }

                int       skinID         = int.Parse(args[0]);
                string    creatureCat    = ModEntry.Sanitize(args[1]);
                int       shortID        = int.Parse(args[2]);
                Character creatureToSkin = null;

                if (creatureCat == "horse" && ModEntry.HorseSkinMap.ContainsKey(shortID))
                {
                    creatureToSkin = ModEntry.GetCreature(ModEntry.CreatureCategory.Horse, shortID);

                    // Ensure that the skin ID given exists in Adopt & Skin
                    if (!EnforceArgRange(skinID, ModEntry.HorseAssets[ModEntry.Sanitize(creatureToSkin.GetType().Name)].Count, 1))
                    {
                        break;
                    }

                    // Set skin
                    ModEntry.HorseSkinMap[shortID] = skinID;
                }
                else if (creatureCat == "pet" && ModEntry.PetSkinMap.ContainsKey(shortID))
                {
                    creatureToSkin = ModEntry.GetCreature(ModEntry.CreatureCategory.Pet, shortID);

                    // Ensure that the skin ID given exists in Adopt & Skin
                    if (!EnforceArgRange(skinID, ModEntry.PetAssets[ModEntry.Sanitize(creatureToSkin.GetType().Name)].Count, 1))
                    {
                        break;
                    }

                    // Set skin
                    ModEntry.PetSkinMap[shortID] = skinID;
                }
                else if (creatureCat == "animal" && ModEntry.AnimalShortToLongIDs.ContainsKey(shortID))
                {
                    FarmAnimal animal = ModEntry.GetCreature(ModEntry.CreatureCategory.Animal, ModEntry.AnimalShortToLongIDs[shortID]) as FarmAnimal;
                    creatureToSkin = animal;

                    // Ensure that the skin ID given exists in Adopt & Skin
                    if (!EnforceArgRange(skinID, ModEntry.AnimalAssets[ModEntry.Sanitize(animal.type.Value)].Count, 1))
                    {
                        break;
                    }

                    // Set skin
                    ModEntry.AnimalSkinMap[ModEntry.AnimalShortToLongIDs[shortID]] = skinID;
                }


                // Successfully found given creature to set skin for. Run a skin update.
                if (creatureToSkin != null)
                {
                    Earth.UpdateSkin(creatureToSkin);
                    ModEntry.SMonitor.Log($"{creatureToSkin.Name}'s skin has been set to skin {skinID}", LogLevel.Alert);
                }
                else
                {
                    ModEntry.SMonitor.Log($"Skin setting error. Creature category {creatureCat} ID {shortID} could not be given skin {skinID}", LogLevel.Error);
                }

                break;


            default:
                break;
            }
        }
 /// <summary>Refreshes creature information based on how much information the save file contains</summary>
 internal static void LoadCreatureSkins()
 {
     // File is new to A&S. Add all creatures into the system
     if (ModEntry.AnimalSkinMap.Count == 0 && ModEntry.PetSkinMap.Count == 0 && ModEntry.HorseSkinMap.Count == 0)
     {
         foreach (FarmAnimal animal in ModEntry.GetAnimals())
         {
             Entry.AddCreature(animal);
         }
         foreach (Pet pet in ModEntry.GetPets())
         {
             Entry.AddCreature(pet);
         }
         foreach (Horse horse in ModEntry.GetHorses())
         {
             Entry.AddCreature(horse);
         }
     }
     // Refresh skins on creatures + add creatures to system if the save is an older version
     else
     {
         foreach (FarmAnimal animal in ModEntry.GetAnimals())
         {
             if (!ModEntry.AnimalLongToShortIDs.ContainsKey(animal.myID.Value))
             {
                 Entry.AddCreature(animal);
             }
             else
             {
                 Entry.UpdateSkin(animal);
             }
         }
         foreach (Pet pet in ModEntry.GetPets())
         {
             if (pet.Manners == 0)
             {
                 Entry.AddCreature(pet);
             }
             // Remove extra Strays left on map
             else if (pet.Manners == Stray.StrayID && (ModEntry.Creator.StrayInfo == null || ModEntry.Creator.StrayInfo.PetInstance != pet))
             {
                 Game1.removeThisCharacterFromAllLocations(pet);
             }
             else
             {
                 Entry.UpdateSkin(pet);
             }
         }
         foreach (Horse horse in ModEntry.GetHorses())
         {
             // Don't add tractors to the system
             if (horse.Manners == 0 && !horse.Name.StartsWith("tractor/"))
             {
                 Entry.AddCreature(horse);
             }
             // Remove extra WildHorses left on the map
             else if (horse.Manners == WildHorse.WildID && (ModEntry.Creator.HorseInfo == null || ModEntry.Creator.HorseInfo.HorseInstance != horse))
             {
                 Game1.removeThisCharacterFromAllLocations(horse);
             }
             else if (!horse.Name.StartsWith("tractor/"))
             {
                 Entry.UpdateSkin(horse);
             }
         }
     }
 }