예제 #1
0
        private void AddGenericModConfigMenu()
        {
            IGenericModConfigMenuAPI modconfigAPI = this.Helper.ModRegistry.GetApi <IGenericModConfigMenuAPI>("spacechase0.GenericModConfigMenu");

            if (modconfigAPI != null)
            {
                modconfigAPI.RegisterModConfig(
                    mod: this.ModManifest,
                    revertToDefault: () => ModEntry.Config = new Config(),
                    saveToFile: () => this.Helper.WriteConfig(ModEntry.Config));
                modconfigAPI.SetDefaultIngameOptinValue(
                    mod: this.ModManifest,
                    optedIn: true);
                System.Reflection.PropertyInfo[] properties = ModEntry.Config
                                                              .GetType()
                                                              .GetProperties()
                                                              .Where(p => p.PropertyType == typeof(bool))
                                                              .ToArray();
                foreach (System.Reflection.PropertyInfo property in properties)
                {
                    string key         = property.Name.ToLower();
                    string description = Translations.GetTranslation($"config.{key}.description", defaultToNull: true);
                    modconfigAPI.RegisterSimpleOption(
                        mod: this.ModManifest,
                        optionName: Translations.GetTranslation($"config.{key}.name"),
                        optionDesc: string.IsNullOrWhiteSpace(description) ? null : description,
                        optionGet: () => (bool)property.GetValue(ModEntry.Config),
                        optionSet: (bool value) => property.SetValue(ModEntry.Config, value: value));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Return the display name for an item definition in the <see cref="Translations.ItemTranslations"/> dictionary.
        /// </summary>
        /// <param name="data">Item definition entry.</param>
        public static string GetNameTranslation(ItemDefinition data)
        {
            string pack = data.ContentPack.Manifest.UniqueID;
            string item = data.LocalName;

            foreach (LocalizedContentManager.LanguageCode lc in Translations.LanguageCodesToTry)
            {
                Dictionary <string, Dictionary <string, string> > packs;
                Dictionary <string, string> items;
                string translation;

                if (Translations.ItemTranslations.TryGetValue(lc.ToString(), out packs) && packs != null &&
                    packs.TryGetValue(pack, out items) && items != null &&
                    items.TryGetValue(item, out translation) && !string.IsNullOrWhiteSpace(translation))
                {
                    return(Translations.GetTranslation("item.name.variant", tokens: new[] { translation ?? data.LocalName }));
                }
            }
            return(data.LocalName);
        }
예제 #3
0
        public NewRecipeMenu(List <string> variantKeys)
            : base(x: 0, y: 0, width: 0, height: 0)
        {
            Log.T($"Opened end of night menu: {this.GetType().FullName}");

            Game1.player.team.endOfNightStatus.UpdateState(ModEntry.EndOfNightState);
            this.VariantKeys = variantKeys;
            this.width       = (int)Dimensions.X;
            this.height      = ((int)Dimensions.Y / 2) + (this.VariantKeys.Count * Game1.smallestTileSize * 3 / 2 * Game1.pixelZoom);
            this.OkButton    = new ClickableTextureComponent(
                bounds: Rectangle.Empty,
                texture: Game1.mouseCursors,
                sourceRect: Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 46),
                scale: 1f)
            {
                myID = NewRecipeMenu.OkButtonId
            };

            this._isActive         = true;
            this._timerBeforeStart = 250;
            Game1.player.completelyStopAnimatingOrDoingAction();
            Game1.player.freezePause = 100;
            this.gameWindowSizeChanged(Rectangle.Empty, Rectangle.Empty);
            this.populateClickableComponentList();

            string craftingString = Game1.content.LoadString("Strings\\UI:LearnedRecipe_crafting");

            this._titleString = Translations.GetTranslation("menu.title.new");
            this._itemStrings =
                this.VariantKeys
                .ToDictionary(
                    vk => vk,
                    vk => Game1.content.LoadString("Strings\\UI:LevelUp_NewRecipe",
                                                   craftingString,
                                                   OutdoorPot.GetDisplayNameFromVariantKey(variantKey: vk)));
            this._itemSprites =
                this.VariantKeys
                .ToDictionary(
                    vk => vk,
                    vk => OutdoorPot.GetSpriteFromVariantKey(variantKey: vk));
        }
예제 #4
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;
            }
        }