Example #1
0
        private void BuildGoodsIcon(ImGui gui, Goods goods, float amount, ProductDropdownType dropdownType, RecipeRow recipe, ProductionTable context)
        {
            var hasLink       = context.FindLink(goods, out var link);
            var linkIsError   = hasLink && ((link.flags & (ProductionLink.Flags.HasProductionAndConsumption | ProductionLink.Flags.LinkRecursiveNotMatched)) != ProductionLink.Flags.HasProductionAndConsumption);
            var linkIsForeign = hasLink && link.owner != context;

            if (gui.BuildFactorioObjectWithAmount(goods, amount, goods?.flowUnitOfMeasure ?? UnitOfMeasure.None, hasLink ? linkIsError ? SchemeColor.Error : linkIsForeign?SchemeColor.Secondary : SchemeColor.Primary: SchemeColor.None) && goods != Database.voidEnergy)
            {
                OpenProductDropdown(gui, gui.lastRect, goods, dropdownType, recipe, context);
            }
        }
Example #2
0
        private void OpenProductDropdown(ImGui targetGui, Rect rect, Goods goods, ProductDropdownType type, RecipeRow recipe, ProductionTable context)
        {
            context.FindLink(goods, out var link);
            var comparer   = DataUtils.GetRecipeComparerFor(goods);
            var allRecipes = new HashSet <Recipe>(context.recipes.Select(x => x.recipe));
            Predicate <Recipe> recipeExists = rec => allRecipes.Contains(rec);
            Action <Recipe>    addRecipe    = rec =>
            {
                CreateLink(context, goods);
                if (!allRecipes.Contains(rec))
                {
                    AddRecipe(context, rec);
                }
            };
            var selectFuel = type != ProductDropdownType.Fuel ? null : (Action <Goods>)(fuel =>
            {
                recipe.RecordUndo().fuel = fuel;
                DataUtils.FavouriteFuel.AddToFavourite(fuel);
            });

            targetGui.ShowDropDown(rect, DropDownContent, new Padding(1f));

            void DropDownContent(ImGui gui, ref bool close)
            {
                if (type == ProductDropdownType.Fuel && (recipe.entity.energy.fuels.Count > 0))
                {
                    close |= gui.BuildInlineObejctListAndButton(recipe.entity.energy.fuels, DataUtils.FavouriteFuel, selectFuel, "Select fuel");
                }

                if (link != null)
                {
                    if (link.goods.fluid != null)
                    {
                        gui.BuildText("Fluid temperature: " + DataUtils.FormatAmount(link.resultTemperature, UnitOfMeasure.None) + "°");
                    }
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasProduction))
                    {
                        gui.BuildText("This link has no production (Link ignored)", wrap: true, color: SchemeColor.Error);
                    }
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasConsumption))
                    {
                        gui.BuildText("This link has no consumption (Link ignored)", wrap: true, color: SchemeColor.Error);
                    }
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasProductionAndConsumption) && link.owner.owner is RecipeRow recipeRow && recipeRow.FindLink(link.goods, out _))
                    {
                        gui.BuildText("Nested tables have their own set of links that DON'T connect to parent links. To connect this product to the outside, remove this link", wrap: true, color: SchemeColor.Error);
                    }
                    if (link.flags.HasFlags(ProductionLink.Flags.LinkRecursiveNotMatched))
                    {
                        if (link.notMatchedFlow <= 0f)
                        {
                            gui.BuildText("YAFC was unable to satisfy this link (Negative feedback loop). This doesn't mean that this link is the problem, but it is part of the loop.", wrap: true, color: SchemeColor.Error);
                        }
                        else
                        {
                            gui.BuildText("YAFC was unable to satisfy this link (Overproduction). You can allow overproduction for this link to solve the error.", wrap: true, color: SchemeColor.Error);
                        }
                    }
                }

                if (type != ProductDropdownType.Product && goods != null && goods.production.Length > 0)
                {
                    close |= gui.BuildInlineObejctListAndButton(goods.production, comparer, addRecipe, "Add production recipe", 6, true, recipeExists);
                }

                if (type != ProductDropdownType.Fuel && goods != null && type != ProductDropdownType.Ingredient && goods.usages.Length > 0)
                {
                    close |= gui.BuildInlineObejctListAndButton(goods.usages, DataUtils.DefaultRecipeOrdering, addRecipe, "Add consumption recipe", type == ProductDropdownType.Product ? 6 : 3, true, recipeExists);
                }

                if (link != null && gui.BuildCheckBox("Allow overproduction", link.algorithm == LinkAlgorithm.AllowOverProduction, out var newValue))
                {
                    link.RecordUndo().algorithm = newValue ? LinkAlgorithm.AllowOverProduction : LinkAlgorithm.Match;
                }

                if (link != null && link.owner == context)
                {
                    if (link.amount != 0)
                    {
                        gui.BuildText(goods.locName + " is a desired product and cannot be unlinked.", wrap: true);
                    }
                    else
                    {
                        gui.BuildText(goods.locName + " production is currently linked. This means that YAFC will try to match production with consumption.", wrap: true);
                    }
                    if (type == ProductDropdownType.DesiredProduct)
                    {
                        if (gui.BuildButton("Remove desired product"))
                        {
                            link.RecordUndo().amount = 0;
                            close = true;
                        }

                        if (gui.BuildButton("Remove and unlink"))
                        {
                            DestroyLink(context, goods);
                            close = true;
                        }
                    }
                    else if (link.amount == 0 && gui.BuildButton("Unlink"))
                    {
                        DestroyLink(context, goods);
                        close = true;
                    }
                }
                else if (goods != null)
                {
                    if (link != null)
                    {
                        gui.BuildText(goods.locName + " production is currently linked, but the link is outside this nested table. Nested tables can have its own separate set of links", wrap: true);
                    }
                    else
                    {
                        gui.BuildText(goods.locName + " production is currently NOT linked. This means that YAFC will make no attempt to match production with consumption.", wrap: true);
                    }
                    if (gui.BuildButton("Create link"))
                    {
                        CreateLink(context, goods);
                        close = true;
                    }
                }
            }
        }
Example #3
0
        private void OpenProductDropdown(ImGui targetGui, Rect rect, Goods goods, float amount, ProductionLink link, ProductDropdownType type, RecipeRow recipe, ProductionTable context, Goods[] variants = null)
        {
            if (InputSystem.Instance.control)
            {
                Project.current.preferences.SetSourceResource(goods, !goods.IsSourceResource());
                targetGui.Rebuild();
                return;
            }

            var comparer   = DataUtils.GetRecipeComparerFor(goods);
            var allRecipes = new HashSet <Recipe>(context.recipes.Select(x => x.recipe));
            Predicate <Recipe> recipeExists = rec => allRecipes.Contains(rec);
            Action <Recipe>    addRecipe    = async rec =>
            {
                if (variants == null)
                {
                    CreateLink(context, goods);
                }
                else
                {
                    foreach (var variant in variants)
                    {
                        if (rec.GetProduction(variant) > 0f)
                        {
                            CreateLink(context, variant);
                            if (variant != goods)
                            {
                                recipe.RecordUndo().ChangeVariant(goods, variant);
                            }
                            break;
                        }
                    }
                }
                if (!allRecipes.Contains(rec) || (await MessageBox.Show("Recipe already exists", "Add a second copy?", "Add a copy", "Cancel")).choice)
                {
                    AddRecipe(context, rec);
                }
            };
            var selectFuel = type != ProductDropdownType.Fuel ? null : (Action <Goods>)(fuel =>
            {
                recipe.RecordUndo().fuel = fuel;
            });
            var allProduction = goods == null?Array.Empty <Recipe>() : variants == null ? goods.production : variants.SelectMany(x => x.production).Distinct().ToArray();

            var fuelDisplayFunc = recipe?.entity?.energy.type == EntityEnergyType.FluidHeat
                ? (Func <Goods, string>)(g => DataUtils.FormatAmount(g.fluid?.heatValue ?? 0, UnitOfMeasure.Megajoule))
                : g => DataUtils.FormatAmount(g.fuelValue, UnitOfMeasure.Megajoule);

            targetGui.ShowDropDown(rect, DropDownContent, new Padding(1f), 25f);

            void DropDownContent(ImGui gui, ref bool close)
            {
                if (type == ProductDropdownType.Fuel && recipe?.entity != null && recipe.entity.energy.fuels.Count > 1)
                {
                    close |= gui.BuildInlineObejctListAndButton(recipe.entity.energy.fuels, DataUtils.FavouriteFuel, selectFuel, "Select fuel", extra: fuelDisplayFunc);
                }

                if (variants != null)
                {
                    gui.BuildText("Accepted fluid variants:");
                    using (var grid = gui.EnterInlineGrid(3f))
                    {
                        foreach (var variant in variants)
                        {
                            grid.Next();
                            if (gui.BuildFactorioObjectButton(variant, 3f, MilestoneDisplay.Contained, variant == goods ? SchemeColor.Primary : SchemeColor.None) &&
                                variant != goods)
                            {
                                recipe.RecordUndo().ChangeVariant(goods, variant);
                                close = true;
                            }
                        }
                    }

                    gui.allocator = RectAllocator.Stretch;
                }

                if (link != null)
                {
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasProduction))
                    {
                        gui.BuildText("This link has no production (Link ignored)", wrap: true, color: SchemeColor.Error);
                    }
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasConsumption))
                    {
                        gui.BuildText("This link has no consumption (Link ignored)", wrap: true, color: SchemeColor.Error);
                    }
                    if (link.flags.HasFlags(ProductionLink.Flags.ChildNotMatched))
                    {
                        gui.BuildText("Nested table link have unmatched production/consumption. These unmatched products are not captured by this link.", wrap: true, color: SchemeColor.Error);
                    }
                    if (!link.flags.HasFlags(ProductionLink.Flags.HasProductionAndConsumption) && link.owner.owner is RecipeRow recipeRow && recipeRow.FindLink(link.goods, out _))
                    {
                        gui.BuildText("Nested tables have their own set of links that DON'T connect to parent links. To connect this product to the outside, remove this link", wrap: true, color: SchemeColor.Error);
                    }
                    if (link.flags.HasFlags(ProductionLink.Flags.LinkRecursiveNotMatched))
                    {
                        if (link.notMatchedFlow <= 0f)
                        {
                            gui.BuildText("YAFC was unable to satisfy this link (Negative feedback loop). This doesn't mean that this link is the problem, but it is part of the loop.", wrap: true, color: SchemeColor.Error);
                        }
                        else
                        {
                            gui.BuildText("YAFC was unable to satisfy this link (Overproduction). You can allow overproduction for this link to solve the error.", wrap: true, color: SchemeColor.Error);
                        }
                    }
                }

                if (type != ProductDropdownType.Product && goods != null && allProduction.Length > 0)
                {
                    close |= gui.BuildInlineObejctListAndButton(allProduction, comparer, addRecipe, "Add production recipe", 6, true, recipeExists);
                }

                if (type != ProductDropdownType.Fuel && goods != null && type != ProductDropdownType.Ingredient && goods.usages.Length > 0)
                {
                    close |= gui.BuildInlineObejctListAndButton(goods.usages, DataUtils.DefaultRecipeOrdering, addRecipe, "Add consumption recipe", type == ProductDropdownType.Product ? 6 : 3, true, recipeExists);
                }

                if (type == ProductDropdownType.Product && goods != null && allProduction.Length > 0)
                {
                    close |= gui.BuildInlineObejctListAndButton(allProduction, comparer, addRecipe, "Add production recipe", 1, true, recipeExists);
                }

                if (link != null && gui.BuildCheckBox("Allow overproduction", link.algorithm == LinkAlgorithm.AllowOverProduction, out var newValue))
                {
                    link.RecordUndo().algorithm = newValue ? LinkAlgorithm.AllowOverProduction : LinkAlgorithm.Match;
                }

                if (link != null && gui.BuildButton("View link summary") && (close = true))
                {
                    ProductionLinkSummaryScreen.Show(link);
                }

                if (link != null && link.owner == context)
                {
                    if (link.amount != 0)
                    {
                        gui.BuildText(goods.locName + " is a desired product and cannot be unlinked.", wrap: true);
                    }
                    else
                    {
                        gui.BuildText(goods.locName + " production is currently linked. This means that YAFC will try to match production with consumption.", wrap: true);
                    }
                    if (type == ProductDropdownType.DesiredProduct)
                    {
                        if (gui.BuildButton("Remove desired product"))
                        {
                            link.RecordUndo().amount = 0;
                            close = true;
                        }

                        if (gui.BuildButton("Remove and unlink"))
                        {
                            DestroyLink(link);
                            close = true;
                        }
                    }
                    else if (link.amount == 0 && gui.BuildButton("Unlink"))
                    {
                        DestroyLink(link);
                        close = true;
                    }
                }
                else if (goods != null)
                {
                    if (link != null)
                    {
                        gui.BuildText(goods.locName + " production is currently linked, but the link is outside this nested table. Nested tables can have its own separate set of links", wrap: true);
                    }
                    else
                    {
                        gui.BuildText(goods.locName + " production is currently NOT linked. This means that YAFC will make no attempt to match production with consumption.", wrap: true);
                    }
                    if (gui.BuildButton("Create link"))
                    {
                        CreateLink(context, goods);
                        close = true;
                    }
                }

                if (goods is Item)
                {
                    BuildBeltInserterInfo(gui, amount, recipe?.buildingCount ?? 0, ref close);
                }
            }
        }
Example #4
0
        private void BuildGoodsIcon(ImGui gui, Goods goods, ProductionLink link, float amount, ProductDropdownType dropdownType, RecipeRow recipe, ProductionTable context, Goods[] variants = null)
        {
            var linkIsError   = link != null && ((link.flags & (ProductionLink.Flags.HasProductionAndConsumption | ProductionLink.Flags.LinkRecursiveNotMatched | ProductionLink.Flags.ChildNotMatched)) != ProductionLink.Flags.HasProductionAndConsumption);
            var linkIsForeign = link != null && link.owner != context;

            if (gui.BuildFactorioObjectWithAmount(goods, amount, goods?.flowUnitOfMeasure ?? UnitOfMeasure.None, link != null ? linkIsError ? SchemeColor.Error : linkIsForeign?SchemeColor.Secondary : SchemeColor.Primary: goods.IsSourceResource() ? SchemeColor.Green : SchemeColor.None) && goods != Database.voidEnergy)
            {
                OpenProductDropdown(gui, gui.lastRect, goods, amount, link, dropdownType, recipe, context, variants);
            }
        }