Пример #1
0
        private IEnumerable <AnimalSkin> LoadSkins()
        {
            foreach (FileInfo file in new DirectoryInfo(Path.Combine(this.Helper.DirectoryPath, "assets", "skins")).EnumerateFiles())
            {
                // check extension
                string extension = Path.GetExtension(file.Name);
                if (!this.ValidExtensions.Contains(extension))
                {
                    this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid extension (must be one of {string.Join(", ", this.ValidExtensions)}).", LogLevel.Warn);
                    continue;
                }

                // parse name
                string[] parts = Path.GetFileNameWithoutExtension(file.Name).Split(new[] { '_' }, 2);
                if (!AnimalSkin.TryParseType(parts[0], out AnimalType type))
                {
                    this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid naming convention (can't parse '{parts[0]}' as an animal type, expected one of {string.Join(", ", Enum.GetNames(typeof(AnimalType)))}).", LogLevel.Warn);
                    continue;
                }
                int index = 0;
                if (parts.Length == 2 && !int.TryParse(parts[1], out index))
                {
                    this.Monitor.Log($"Ignored skin `assets/skins/{file.Name}` with invalid naming convention (can't parse '{parts[1]}' as a number).", LogLevel.Warn);
                    continue;
                }

                // yield
                string assetKey = this.Helper.Content.GetActualAssetKey(Path.Combine("assets", "skins", file.Name));
                yield return(new AnimalSkin(type, index, assetKey));
            }
        }
Пример #2
0
        /*********
        ** Public methods
        *********/
        public AdoptQuestion(AnimalSkin skin)
        {
            this.Skin = skin;

            this.Sprite = new AnimatedSprite(skin.AssetKey, 28, 32, 32)
            {
                loop = true
            };
        }
Пример #3
0
        /// <summary>Raised after the game state is updated (≈60 times per second).</summary>
        /// <param name="sender">The event sender.</param>
        /// <param name="e">The event arguments.</param>
        private void OnUpdateTicked(object sender, UpdateTickedEventArgs e)
        {
            if (!Context.IsPlayerFree)
            {
                return;
            }

            if (!SkinsReady)
            {
                this.LoadSkins();
            }

            // patch bus stop
            if (this.ReplaceBus && Game1.getLocationFromName("BusStop")?.map.Properties.ContainsKey("MA.Patched") == false)
            {
                MoreEvents.ActionTriggered += this.OnActionTriggered;
                this.Monitor.Log("Patching bus stop...", LogLevel.Trace);
                GameLocation bus = Game1.getLocationFromName("BusStop");
                bus.map.Properties.Add("MA.Patched", true);
                bus.map.AddTileSheet(new TileSheet("MorePetsTilesheet", bus.map, this.Helper.Content.GetActualAssetKey("assets/box.png"), new Size(2, 2), new Size(16, 16)));
                bus.SetTile(1, 2, "Front", 0, "MorePetsTilesheet");
                bus.SetTile(2, 2, "Front", 1, "MorePetsTilesheet");
                bus.SetTile(1, 3, "Buildings", 2, "MorePetsTilesheet");
                bus.SetTile(2, 3, "Buildings", 3, "MorePetsTilesheet");
                bus.SetTileProperty(1, 3, "Buildings", "Action", "MorePetsAdoption");
                bus.SetTileProperty(2, 3, "Buildings", "Action", "MorePetsAdoption");
            }

            // set pet skins
            foreach (Pet pet in GetAllPets())
            {
                if (pet.Manners > 0)
                {
                    AnimalSkin skin = this.GetSkin(pet);
                    if (skin != null && pet.Sprite.textureName.Value != skin.AssetKey)
                    {
                        pet.Sprite  = new AnimatedSprite(skin.AssetKey, 0, 32, 32);
                        pet.Manners = skin.ID;
                    }
                }
            }

            // set farm animal skins
            foreach (FarmAnimal animal in this.GetFarmAnimals())
            {
                AnimalSkin skin = this.GetSkin(animal);
                if (skin != null && animal.Sprite.textureName.Value != skin.AssetKey)
                {
                    animal.Sprite = new AnimatedSprite(skin.AssetKey, 0, animal.frontBackSourceRect.Width, animal.frontBackSourceRect.Height);
                    SkinMap[animal.myID.Value] = skin.ID;
                }
                else if (skin == null)
                {
                    SkinMap[animal.myID.Value] = 0;
                }
            }
        }
Пример #4
0
        /// <summary>Refreshes the texture of the creature's sprite if the texture it has is different from the one in the skin mapping</summary>
        internal static void UpdateSkin(Character creature)
        {
            if (!ModApi.IsInDatabase(creature) && !ModApi.IsStray(creature) && !ModApi.IsWildHorse(creature))
            {
                return;
            }

            AnimalSkin skin = GetSkin(creature);

            if (skin != null && creature.Sprite.textureName.Value != skin.AssetKey)
            {
                int[] spriteInfo = ModApi.GetSpriteInfo(creature);
                creature.Sprite = new AnimatedSprite(skin.AssetKey, spriteInfo[0], spriteInfo[1], spriteInfo[2]);
            }
        }
Пример #5
0
        private void GameEvents_UpdateTick(object s, EventArgs e)
        {
            if (!Context.IsWorldReady)
            {
                return;
            }

            // patch bus stop
            if (this.ReplaceBus && Game1.getLocationFromName("BusStop") != null)
            {
                this.Monitor.Log("Patching bus stop...", LogLevel.Trace);
                GameLocation bus = Game1.getLocationFromName("BusStop");
                bus.map.AddTileSheet(new TileSheet("MorePetsTilesheet", bus.map, this.Helper.Content.GetActualAssetKey("assets/box.png"), new Size(2, 2), new Size(16, 16)));
                bus.SetTile(1, 2, "Front", 0, "MorePetsTilesheet");
                bus.SetTile(2, 2, "Front", 1, "MorePetsTilesheet");
                bus.SetTile(1, 3, "Buildings", 2, "MorePetsTilesheet");
                bus.SetTile(2, 3, "Buildings", 3, "MorePetsTilesheet");
                bus.SetTileProperty(1, 3, "Buildings", "Action", "MorePetsAdoption");
                bus.SetTileProperty(2, 3, "Buildings", "Action", "MorePetsAdoption");
                this.ReplaceBus = false;
            }

            // set pet skins
            foreach (Pet pet in this.GetAllPets())
            {
                if (pet.Manners > 0 && !pet.updatedDialogueYet)
                {
                    AnimalSkin skin = this.GetSkin(pet);
                    if (skin != null)
                    {
                        pet.Sprite  = new AnimatedSprite(skin.AssetKey, 0, 32, 32);
                        pet.Manners = skin.ID;
                    }
                    pet.updatedDialogueYet = true;
                }
            }

            // set farm animal skins
            foreach (FarmAnimal animal in this.GetFarmAnimals())
            {
                AnimalSkin skin = this.GetSkin(animal);
                if (skin != null && animal.Sprite.textureName.Value != skin.AssetKey)
                {
                    animal.Sprite          = new AnimatedSprite(skin.AssetKey, 0, animal.frontBackSourceRect.Width, animal.frontBackSourceRect.Height);
                    animal.meatIndex.Value = skin.ID + 999;
                }
            }
        }
Пример #6
0
        /// <summary>Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations.</summary>
        /// <param name="sender">The event sender.</param>
        /// <param name="e">The event data.</param>
        private void OnGameLaunched(object sender, GameLaunchedEventArgs e)
        {
            // Prepare BabyDuck override
            try
            {
                string asset = this.Helper.Content.GetActualAssetKey(Path.Combine("assets", "skins", "BabyDuck.png"));
                Game1.content.Load <Texture2D>(asset);
                BabyDuck = new AnimalSkin("BabyDuck", 0, asset);
            }
            catch (Exception ex)
            {
                this.Monitor.Log("Unable to patch BabyDuck due to exception:", LogLevel.Error, ex);
            }

            // Register default supported animal types
            Api.RegisterAnimalType("Blue Chicken");
            Api.RegisterAnimalType("Brown Chicken");
            Api.RegisterAnimalType("Brown Cow");
            Api.RegisterAnimalType("Dinosaur", false);
            Api.RegisterAnimalType("Duck");
            Api.RegisterAnimalType("Goat");
            Api.RegisterAnimalType("Pig");
            Api.RegisterAnimalType("Rabbit");
            Api.RegisterAnimalType("Sheep", true, true);
            Api.RegisterAnimalType("Void Chicken");
            Api.RegisterAnimalType("White Chicken");
            Api.RegisterAnimalType("White Cow");

            if (Config.ExtraTypes != null && Config.ExtraTypes.Length > 0)
            {
                foreach (string type in Config.ExtraTypes)
                {
                    Api.RegisterAnimalType(type, false);
                }
            }

            // Register default supported pet types
            Api.RegisterPetType("cat", typeof(Cat));
            Api.RegisterPetType("dog", typeof(Dog));

            // Trigger setup
            this.DoSetup();
        }
Пример #7
0
        /// <summary>Refreshes the given animal, pet, or horse's skin texture with the one Adopt & Skin has saved for it.</summary>
        internal void UpdateSkin(Character creature)
        {
            switch (creature)
            {
            case Horse horse:
                if (Creator.HorseInfo != null && horse.Manners == WildHorse.WildID)
                {
                    horse.Sprite = new AnimatedSprite(GetSkinFromID(horse.GetType().Name, Creator.HorseInfo.SkinID).AssetKey, 0, 32, 32);
                    break;
                }
                AnimalSkin horseSkin = GetSkin(horse);
                if (horseSkin != null && horse.Sprite.textureName.Value != horseSkin.AssetKey)
                {
                    horse.Sprite = new AnimatedSprite(horseSkin.AssetKey, 7, 32, 32);
                }
                break;

            case Pet pet:
                if (Creator.StrayInfo != null && pet.Manners == Stray.StrayID)
                {
                    pet.Sprite = new AnimatedSprite(GetSkinFromID(pet.GetType().Name, Creator.StrayInfo.SkinID).AssetKey, 28, 32, 32);
                    break;
                }
                AnimalSkin petSkin = GetSkin(pet);
                if (petSkin != null && pet.Sprite.textureName.Value != petSkin.AssetKey)
                {
                    pet.Sprite = new AnimatedSprite(petSkin.AssetKey, 28, 32, 32);
                }
                break;

            case FarmAnimal animal:
                AnimalSkin animalSkin = GetSkin(animal);
                if (animalSkin != null && animal.Sprite.textureName.Value != animalSkin.AssetKey)
                {
                    animal.Sprite = new AnimatedSprite(animalSkin.AssetKey, 0, animal.frontBackSourceRect.Width, animal.frontBackSourceRect.Height);
                }
                break;

            default:
                break;
            }
        }
Пример #8
0
        /// <summary>Get the skin to apply for an animal.</summary>
        /// <param name="npc">The animal to check.</param>
        private AnimalSkin GetSkin(Character npc)
        {
            switch (npc)
            {
            case Pet pet:
                return(this.GetSkin(type: pet is Dog ? AnimalType.Dog : AnimalType.Cat, index: pet.Manners));

            case FarmAnimal animal:
            {
                // get type
                string typeStr = animal.type.Value;
                if (animal.age.Value < animal.ageWhenMature.Value)
                {
                    typeStr = $"Baby{animal.type.Value}";
                }
                else if (animal.showDifferentTextureWhenReadyForHarvest.Value && animal.currentProduce.Value <= 0)
                {
                    typeStr = $"Sheared{animal.type.Value}";
                }
                if (!AnimalSkin.TryParseType(typeStr, out AnimalType type))
                {
                    return(null);
                }

                // get index
                int index = animal.meatIndex.Value > 999
                            ? animal.meatIndex.Value - 999
                            : -1;

                // get skin
                return(this.GetSkin(type: type, index: index));
            }

            default:
                return(null);
            }
        }
Пример #9
0
        /// <summary>Get the skin to apply for an animal.</summary>
        /// <param name="type">The animal type.</param>
        /// <param name="index">The animal index.</param>
        private AnimalSkin GetSkin(string type, int index)
        {
            type = Sanitize(type);
            if (!ModEntry.Animals.TryGetValue(type, out List <AnimalSkin> skins) && !ModEntry.Pets.TryGetValue(type, out skins))
            {
                return(null);
            }
            // get assigned skin
            if (index >= 1)
            {
                AnimalSkin skin = skins.FirstOrDefault(p => p.ID == index);
                if (skin != null)
                {
                    return(skin);
                }

                this.Monitor.Log($"Found animal type {type} with index {index}, but there's no matching file. Reassigning a random skin to that animal.");
            }

            // get random skin
            int skinID = ModEntry.Animals.ContainsKey(type) ? this.SkinRandom.Next(skins.Count + 1) - 1 : this.SkinRandom.Next(skins.Count);

            return(skinID >= 0 ? skins[skinID] : null);
        }
Пример #10
0
        /*********
        ** Public methods
        *********/
        /// <summary>The mod entry point, called after the mod is first loaded.</summary>
        /// <param name="helper">Provides simplified APIs for writing mods.</param>
        public override void Entry(IModHelper helper)
        {
            // init
            ModEntry.Config   = helper.ReadConfig <ModConfig>();
            ModEntry.SHelper  = helper;
            ModEntry.SMonitor = this.Monitor;

            // Event listeners
            helper.Events.GameLoop.SaveLoaded += this.LoadSkinMap;
            helper.Events.GameLoop.Saving     += this.SaveSkinMap;
            helper.Events.GameLoop.Saved      += this.LoadSkinMap;

            // add commands
            helper.ConsoleCommands.Add("abandon_pet", "Remove a pet with the given name.", this.OnCommandReceived);
            helper.ConsoleCommands.Add("abandon_all_pets", "Remove all pets adopted using this mod, you monster.", this.OnCommandReceived);
            helper.ConsoleCommands.Add("list_animal_types", "Lists all animal types on your farm.", this.OnCommandReceived);
            helper.ConsoleCommands.Add("list_animal_skins", "Lists all animal skins used on your farm.", this.OnCommandReceived);
            helper.ConsoleCommands.Add("reset_animal_skins", "Lists all animal skins used on your farm.", this.OnCommandReceived);

            // Prepare BabyDuck override
            try
            {
                string asset = this.Helper.Content.GetActualAssetKey(Path.Combine("assets", "skins", "BabyDuck.png"));
                Game1.content.Load <Texture2D>(asset);
                BabyDuck = new AnimalSkin("BabyDuck", 0, asset);
            }
            catch (Exception e)
            {
                this.Monitor.Log("Unable to patch BabyDuck due to exception:", LogLevel.Error, e);
            }

            // Register default supported animal types
            Api.RegisterAnimalType("Blue Chicken");
            Api.RegisterAnimalType("Brown Chicken");
            Api.RegisterAnimalType("Brown Cow");
            Api.RegisterAnimalType("Dinosaur", false);
            Api.RegisterAnimalType("Duck");
            Api.RegisterAnimalType("Goat");
            Api.RegisterAnimalType("Pig");
            Api.RegisterAnimalType("Rabbit");
            Api.RegisterAnimalType("Sheep", true, true);
            Api.RegisterAnimalType("Void Chicken");
            Api.RegisterAnimalType("White Chicken");
            Api.RegisterAnimalType("White Cow");

            if (Config.ExtraTypes != null && Config.ExtraTypes.Length > 0)
            {
                foreach (string type in Config.ExtraTypes)
                {
                    Api.RegisterAnimalType(type, false);
                }
            }

            // Register default supported pet types
            Api.RegisterPetType("cat", typeof(Cat));
            Api.RegisterPetType("dog", typeof(Dog));

            // configure bus replacement
            if (ModEntry.Config.AnimalsOnly)
            {
                this.ReplaceBus = false;
            }
            if (this.ReplaceBus)
            {
                try
                {
                    string asset = this.Helper.Content.GetActualAssetKey(Path.Combine("assets", "box.png"));
                    Game1.content.Load <Texture2D>(asset);
                }
                catch (Exception e)
                {
                    this.ReplaceBus = false;
                    this.Monitor.Log("Unable to patch BusStop due to exception:", LogLevel.Error, e);
                }
            }

            // hook events
            helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked;
        }
Пример #11
0
        public static void Show()
        {
            Random     random = ModEntry.Random;
            string     type   = null;
            AnimalSkin skin   = null;

            if (ModEntry.Config.BalancedPetTypes)
            {
                double totalType = ModEntry.Pets.Count;
                Dictionary <string, double> types = ModEntry.Pets.Where(a => a.Value.Count > 0).ToDictionary(k => k.Key, v => totalType);
                foreach (Pet pet in ModEntry.GetAllPets().Where(p => ModEntry.PetTypesRev.ContainsKey(p.GetType()) && ModEntry.Pets[ModEntry.PetTypesRev[p.GetType()]].Count > 0))
                {
                    types[ModEntry.PetTypesRev[pet.GetType()]] *= 0.5;
                }
                types = types.ToDictionary(k => k.Key, v => v.Value / totalType);
                double   typeMax    = types.Values.OrderByDescending(a => a).First();
                double   typeChance = random.NextDouble() * typeMax;
                string[] validTypes = types.Where(a => a.Value >= typeChance).Select(a => a.Key).ToArray();
                if (validTypes.Length > 0)
                {
                    type = validTypes[random.Next(validTypes.Length)];
                }
            }
            if (string.IsNullOrEmpty(type))
            {
                string[] arr = ModEntry.Pets.Where(a => a.Value.Count > 0).Select(a => a.Key).ToArray();
                type = arr[random.Next(arr.Length)];
            }
            if (ModEntry.Config.BalancedPetSkins)
            {
                double totalSkin = ModEntry.Pets[type].Count;
                Dictionary <int, double> skins = ModEntry.Pets[type].ToDictionary(k => k.ID, v => totalSkin);
                foreach (Pet pet in ModEntry.GetAllPets().Where(pet => ModEntry.PetTypesRev.ContainsKey(pet.GetType()) && ModEntry.PetTypesRev[pet.GetType()].Equals(type) && skins.ContainsKey(pet.Manners)))
                {
                    skins[pet.Manners] *= 0.5;
                }
                skins = skins.ToDictionary(k => k.Key, v => v.Value / totalSkin);
                double skinMax = skins.Values.OrderByDescending(a => a).First();
                int[]  validSkins;
                if (ModEntry.Config.ForceUniqueSkins)
                {
                    validSkins = skins.Where(a => a.Value == skinMax).Select(a => a.Key).ToArray();
                }
                else
                {
                    double skinChance = Math.Min(random.NextDouble(), skinMax);
                    validSkins = skins.Where(a => a.Value >= skinChance).Select(a => a.Key).ToArray();
                }
                int id = 0;
                if (validSkins.Length > 0)
                {
                    id = validSkins[random.Next(validSkins.Length)];
                }
                skin = ModEntry.Pets[type].FirstOrDefault(a => a.ID == id);
            }
            if (skin == null)
            {
                skin = ModEntry.Pets[type][random.Next(ModEntry.Pets[type].Count)];
            }
            AdoptQuestion q = new AdoptQuestion(skin);

            ModEntry.SHelper.Events.Display.RenderedHud += q.Display;
            Game1.currentLocation.lastQuestionKey        = "AdoptPetQuestion";
            Game1.currentLocation.createQuestionDialogue(
                ModEntry.SHelper.Translation.Get("AdoptMessage", new { petType = type, adoptionPrice = ModEntry.Config.AdoptionPrice }),
                Game1.player.Money < ModEntry.Config.AdoptionPrice
                    ? new[]
            {
                new Response("n", ModEntry.SHelper.Translation.Get("AdoptNoGold", new { adoptionPrice = ModEntry.Config.AdoptionPrice }))
            }
                    : new[]
            {
                new Response("y", ModEntry.SHelper.Translation.Get("AdoptYes")),
                new Response("n", ModEntry.SHelper.Translation.Get("AdoptNo"))
            },
                q.Resolver);
        }