Esempio n. 1
0
        public static List <string> AddNewAvailableRecipes()
        {
            List <string> newVariants = new List <string>();

            for (int i = 0; i < ModEntry.ItemDefinitions.Count; ++i)
            {
                string variantKey = ModEntry.ItemDefinitions.Keys.ElementAt(i);
                string itemName   = OutdoorPot.GetNameFromVariantKey(variantKey);

                if (Game1.player.craftingRecipes.ContainsKey(itemName) ||
                    string.IsNullOrEmpty(ModEntry.ItemDefinitions[variantKey].RecipeConditions) ||
                    !Game1.player.eventsSeen.Contains(ModEntry.EventRootId))
                {
                    continue;
                }

                int    eventID      = ModEntry.EventRootId + i;
                string eventKey     = $"{eventID.ToString()}/{ModEntry.ItemDefinitions[variantKey].RecipeConditions}";
                int    precondition = Game1.getFarm().checkEventPrecondition(eventKey);
                if (precondition != -1)
                {
                    newVariants.Add(variantKey);
                    Game1.player.craftingRecipes.Add(itemName, 0);
                }
            }
            return(newVariants);
        }
Esempio n. 2
0
        public static void AddDefaultRecipes()
        {
            List <string> recipesToAdd = new List <string>();

            int[]  eventsSeen            = Game1.player.eventsSeen.ToArray();
            string precondition          = $"{ModEntry.EventRootId}/{ModEntry.EventData[0]["Conditions"]}";
            int    rootEventReady        = Game1.getFarm().checkEventPrecondition(precondition);
            bool   hasOrWillSeeRootEvent = eventsSeen.Contains(ModEntry.EventRootId) || rootEventReady != -1;

            for (int i = 0; i < ModEntry.ItemDefinitions.Count; ++i)
            {
                string variantKey           = ModEntry.ItemDefinitions.Keys.ElementAt(i);
                string craftingRecipeName   = OutdoorPot.GetNameFromVariantKey(variantKey: variantKey);
                bool   isAlreadyKnown       = Game1.player.craftingRecipes.ContainsKey(craftingRecipeName);
                bool   isDefaultRecipe      = ModEntry.ItemDefinitions[variantKey].RecipeIsDefault;
                bool   isInitialEventRecipe = string.IsNullOrEmpty(ModEntry.ItemDefinitions[variantKey].RecipeConditions);
                bool   shouldAdd            = ModEntry.Config.RecipesAlwaysAvailable || isDefaultRecipe || (hasOrWillSeeRootEvent && isInitialEventRecipe);

                if (!isAlreadyKnown && shouldAdd)
                {
                    recipesToAdd.Add(craftingRecipeName);
                }
            }
            if (recipesToAdd.Count > 0)
            {
                Log.T($"Adding {recipesToAdd.Count} default recipes:{recipesToAdd.Aggregate(string.Empty, (str, s) => $"{str}{Environment.NewLine}{s}")}");

                for (int i = 0; i < recipesToAdd.Count; ++i)
                {
                    Game1.player.craftingRecipes.Add(recipesToAdd[i], 0);
                }
            }
        }
Esempio n. 3
0
        public void Edit <T>(IAssetData asset)
        {
            /*********
            *  Local data
            *********/

            if (asset.AssetNameEquals(GameContentEventDataPath))
            {
                var events = ((Newtonsoft.Json.Linq.JArray)asset
                              .AsDictionary <string, object>()
                              .Data["Events"])
                             .ToObject <List <Dictionary <string, string> > >();

                // Events are populated with preset tokens and script dialogues depending on game locale.

                // Root event tokenisation
                for (int i = 0; i < events.Count; ++i)
                {
                    // Format event script with event NPC name, as well as their dialogue strings
                    string[] args = new string[] { events[i]["Who"] }
                    .Concat(new int[] { 1, 2, 3, 4 }
                            .Select(j => Translations.GetTranslation($"event.{i}.dialogue.{j}")))
                    .ToArray();
                    events[i]["Script"] = string.Format(
                        format: events[i]["Script"],
                        args: args);
                    events[i]["Conditions"] = string.Format(
                        format: events[i]["Conditions"],
                        events[i]["Who"]);
                }

                Log.T($"Loaded {events.Count} event(s).{Environment.NewLine}Root event: {events[0]["Where"]}/{events[0]["Conditions"]}");

                ModEntry.EventData = events;

                return;
            }

            /********
            *  Game data
            ********/

            int id = OutdoorPot.BaseParentSheetIndex;

            if (asset.AssetNameEquals(Path.Combine("Data", "BigCraftablesInformation")))
            {
                if (ModEntry.ItemDefinitions == null)
                {
                    return;
                }

                string[] fields;
                var      data = asset.AsDictionary <int, string>().Data;

                // Set or reset the item ID for the generic object to some first best available index
                id = OutdoorPot.BaseParentSheetIndex = data.Keys.Max() + 2;

                string name, description;

                // Patch generic object entry into bigcraftables file, including display name and description from localisations file
                name        = Translations.GetTranslation("item.name");
                description = Translations.GetTranslation("item.description.default");
                fields      = data.First().Value.Split('/');            // Use existing data as a template; most fields are common or unused
                fields[0]   = OutdoorPot.GenericName;
                fields[4]   = description;
                fields[8]   = name;
                data[id]    = string.Join("/", fields);

                // Patch in dummy object entries after generic object entry
                for (int i = 1; i < ModEntry.ItemDefinitions.Count; ++i)
                {
                    ItemDefinition d = ModEntry.ItemDefinitions[ModEntry.ItemDefinitions.Keys.ElementAt(i)];
                    name         = Translations.GetNameTranslation(data: d);
                    fields       = data[id].Split('/');
                    fields[4]    = description;
                    fields[8]    = name;
                    data[id + i] = string.Join("/", fields);
                }

                // Don't remove the generic craftable from data lookup, since it's used later for crafting recipes and defaults

                return;
            }
            if (asset.AssetNameEquals(Path.Combine("Data", "CraftingRecipes")))
            {
                if (ModEntry.ItemDefinitions == null || id < 0)
                {
                    return;
                }

                // As above for the craftables dictionary, the recipes dictionary needs to have
                // our varieties patched in to have them appear.
                // Since all objects share a single ParentSheetIndex, each crafting recipe will normally
                // only produce a generic/wooden object.
                // This is handled in HarmonyPatches.CraftingPage_ClickCraftingRecipe_Prefix, which
                // is also needed to produce an OutdoorPot instance rather than a StardewValley.Object.

                // Add crafting recipes for all object variants
                var data = asset.AsDictionary <string, string>().Data;
                foreach (KeyValuePair <string, ItemDefinition> idAndFields in ModEntry.ItemDefinitions)
                {
                    string[] newFields = new string[]
                    {                           // Crafting ingredients:
                        ItemDefinition.ParseRecipeIngredients(data: idAndFields.Value),
                        // Unused field:
                        "blue berry",
                        // Crafted item ID and quantity:
                        $"{OutdoorPot.BaseParentSheetIndex} {idAndFields.Value.RecipeCraftedCount}",
                        // Recipe is bigCraftable:
                        "true",
                        // Recipe conditions (we ignore these):
                        "blue berry",
                        // Recipe display name:
                        Translations.GetNameTranslation(data: idAndFields.Value)
                    };
                    data[OutdoorPot.GetNameFromVariantKey(idAndFields.Key)] = string.Join("/", newFields);
                }

                return;
            }
            if (asset.AssetName.StartsWith(Path.Combine("Data", "Events")) &&
                Path.GetFileNameWithoutExtension(asset.AssetName) is string where)
            {
                // Patch our event data into whatever location happens to match the one specified.
                // Event tokenisation is handled in the Edit block for GameContentEventDataPath.

                if (ModEntry.EventData != null &&
                    ModEntry.EventData.FirstOrDefault(e => e["Where"] == where) is Dictionary <string, string> eventData)
                {
                    string key = $"{ModEntry.EventRootId}{ModEntry.EventData.IndexOf(eventData)}/{eventData["Conditions"]}";
                    asset.AsDictionary <string, string>().Data[key] = eventData["Script"];
                }

                return;
            }
        }