예제 #1
0
        private void BuildIconRow(ImGui gui, IReadOnlyList <FactorioObject> objects, int maxRows)
        {
            const int itemsPerRow = 9;
            var       count       = objects.Count;

            if (count == 0)
            {
                gui.BuildText("Nothing", color: SchemeColor.BackgroundTextFaint);
                return;
            }

            var arr = new List <FactorioObject>(count);

            arr.AddRange(objects);
            arr.Sort(DataUtils.DefaultOrdering);

            if (count <= maxRows)
            {
                for (var i = 0; i < count; i++)
                {
                    gui.BuildFactorioObjectButtonWithText(arr[i]);
                }
                return;
            }

            var index = 0;

            if (count - 1 < (maxRows - 1) * itemsPerRow)
            {
                gui.BuildFactorioObjectButtonWithText(arr[0]);
                index++;
            }

            var rows = Math.Min(((count - 1 - index) / itemsPerRow) + 1, maxRows);

            for (var i = 0; i < rows; i++)
            {
                using (gui.EnterRow())
                {
                    for (var j = 0; j < itemsPerRow; j++)
                    {
                        if (arr.Count <= index)
                        {
                            return;
                        }
                        gui.BuildFactorioObjectIcon(arr[index++]);
                    }
                }
            }

            if (rows * itemsPerRow < count)
            {
                gui.BuildText("... and " + (count - rows * itemsPerRow) + " more");
            }
        }
예제 #2
0
        private void DrawEntryList(ImGui gui, List <RecipeEntry> entries, bool production)
        {
            var            footerDrawn         = false;
            var            prevEntryStatus     = EntryStatus.Normal;
            FactorioObject prevLatestMilestone = null;

            foreach (var entry in entries)
            {
                var status = entry.entryStatus;

                if (status < showRecipesRange)
                {
                    DrawEntryFooter(gui, production);
                    footerDrawn = true;
                    gui.BuildText(entry.entryStatus == EntryStatus.Special ? "Show special recipes (barreling / voiding)" :
                                  entry.entryStatus == EntryStatus.NotAccessibleWithCurrentMilestones ? "There are more recipes, but they are locked based on current milestones" :
                                  "There are more recipes but they are inaccessible", wrap: true);
                    if (gui.BuildButton("Show more recipes"))
                    {
                        ChangeShowStatus(status);
                    }
                    break;
                }

                if (status < prevEntryStatus)
                {
                    prevEntryStatus = status;
                    using (gui.EnterRow())
                    {
                        gui.BuildText(status == EntryStatus.Special ? "Special recipes:" : status == EntryStatus.NotAccessibleWithCurrentMilestones ? "Locked recipes:" : "Inaccessible recipes:");
                        if (gui.BuildLink("hide"))
                        {
                            ChangeShowStatus(status + 1);
                        }
                    }
                }

                if (status == EntryStatus.NotAccessibleWithCurrentMilestones)
                {
                    var latest = Milestones.Instance.GetHighest(entry.recipe, false);
                    if (latest != prevLatestMilestone)
                    {
                        gui.BuildFactorioObjectButtonWithText(latest, size: 3f, display: MilestoneDisplay.None);
                        prevLatestMilestone = latest;
                    }
                }

                if (gui.ShouldBuildGroup(entry.recipe, out var group))
                {
                    DrawRecipeEntry(gui, entry, production);
                    group.Complete();
                }
            }
            if (!footerDrawn)
            {
                DrawEntryFooter(gui, production);
            }
            CheckChanging();
        }
예제 #3
0
 private void ChoiceObject <T>(ImGui gui, string text, T[] list, T current, Action <T> select) where T : FactorioObject
 {
     using (gui.EnterRow())
     {
         gui.BuildText(text, topOffset: 0.5f);
         if (gui.BuildFactorioObjectButtonWithText(current))
         {
             gui.BuildObjectSelectDropDown(list, DataUtils.DefaultOrdering, select, text);
         }
     }
 }
예제 #4
0
        public override void Build(ImGui gui)
        {
            BuildHeader(gui, "Module customisation");
            if (recipe.modules == null)
            {
                if (gui.BuildButton("Enable custom modules"))
                {
                    recipe.RecordUndo().modules = new CustomModules(recipe);
                }
            }
            else
            {
                gui.BuildText("Internal modules:", Font.subheader);
                gui.BuildText("Leave zero amount to fill the remainings slots");
                DrawRecipeModules(gui, null);
                gui.BuildText("Beacon modules:", Font.subheader);
                if (recipe.modules.beacon == null)
                {
                    gui.BuildText("Use default parameters");
                    if (gui.BuildButton("Override beacons as well"))
                    {
                        gui.ShowDropDown(SelectBeacon);
                    }
                }
                else
                {
                    if (gui.BuildFactorioObjectButtonWithText(recipe.modules.beacon))
                    {
                        gui.ShowDropDown(SelectBeacon);
                    }
                    gui.BuildText("Input the amount of modules, not the amount of beacons. Single beacon can hold " + recipe.modules.beacon.moduleSlots + " modules.", wrap: true);
                    DrawRecipeModules(gui, recipe.modules.beacon);
                }
            }

            gui.AllocateSpacing(3f);
            if (gui.BuildButton("Done"))
            {
                Close();
            }
        }
예제 #5
0
        private void BuildRecipe(RecipeOrTechnology recipe, ImGui gui)
        {
            BuildCommon(recipe, gui);
            using (gui.EnterGroup(contentPadding, RectAllocator.LeftRow))
            {
                gui.BuildIcon(Icon.Time, 2f, SchemeColor.BackgroundText);
                gui.BuildText(DataUtils.FormatAmount(recipe.time, UnitOfMeasure.Second));
            }

            using (gui.EnterGroup(contentPadding))
            {
                foreach (var ingredient in recipe.ingredients)
                {
                    BuildItem(gui, ingredient);
                }
                if (recipe is Recipe rec)
                {
                    var waste = rec.RecipeWaste();
                    if (waste > 0.01f)
                    {
                        var wasteAmount = MathUtils.Round(waste * 100f);
                        var wasteText   = ". (Wasting " + wasteAmount + "% of YAFC cost)";
                        var color       = wasteAmount < 90 ? SchemeColor.BackgroundText : SchemeColor.Error;
                        if (recipe.products.Length == 1)
                        {
                            gui.BuildText("YAFC analysis: There are better recipes to create " + recipe.products[0].goods.locName + wasteText, wrap: true, color: color);
                        }
                        else if (recipe.products.Length > 0)
                        {
                            gui.BuildText("YAFC analysis: There are better recipes to create each of the products" + wasteText, wrap: true, color: color);
                        }
                        else
                        {
                            gui.BuildText("YAFC analysis: This recipe wastes useful products. Don't do this recipe.", wrap: true, color: color);
                        }
                    }
                }
                if (recipe.flags.HasFlags(RecipeFlags.UsesFluidTemperature))
                {
                    gui.BuildText("Uses fluid temperature");
                }
                if (recipe.flags.HasFlags(RecipeFlags.UsesMiningProductivity))
                {
                    gui.BuildText("Uses mining productivity");
                }
                if (recipe.flags.HasFlags(RecipeFlags.ScaleProductionWithPower))
                {
                    gui.BuildText("Production scaled with power");
                }
            }

            if (recipe.products.Length > 0 && !(recipe.products.Length == 1 && recipe.products[0].IsSimple && recipe.products[0].goods is Item && recipe.products[0].amount == 1f))
            {
                BuildSubHeader(gui, "Products");
                using (gui.EnterGroup(contentPadding))
                    foreach (var product in recipe.products)
                    {
                        BuildItem(gui, product);
                    }
            }

            BuildSubHeader(gui, "Made in");
            using (gui.EnterGroup(contentPadding))
                BuildIconRow(gui, recipe.crafters, 2);

            if (recipe.modules.Length > 0)
            {
                BuildSubHeader(gui, "Allowed modules");
                using (gui.EnterGroup(contentPadding))
                    BuildIconRow(gui, recipe.modules, 1);
            }

            if (recipe is Recipe lockedRecipe && !lockedRecipe.enabled)
            {
                BuildSubHeader(gui, "Unlocked by");
                using (gui.EnterGroup(contentPadding))
                {
                    if (lockedRecipe.technologyUnlock.Count > 2)
                    {
                        BuildIconRow(gui, lockedRecipe.technologyUnlock, 1);
                    }
                    else
                    {
                        foreach (var technology in lockedRecipe.technologyUnlock)
                        {
                            var ingredient = TechnologyScienceAnalysis.Instance.GetMaxTechnologyIngredient(technology);
                            using (gui.EnterRow(allocator: RectAllocator.RightRow))
                            {
                                gui.spacing = 0f;
                                if (ingredient != null)
                                {
                                    gui.BuildFactorioObjectIcon(ingredient.goods);
                                    gui.BuildText(DataUtils.FormatAmount(ingredient.amount, UnitOfMeasure.None));
                                }

                                gui.allocator = RectAllocator.RemainigRow;
                                gui.BuildFactorioObjectButtonWithText(technology);
                            }
                        }
                    }
                }
            }
        }
예제 #6
0
        public override void Build(ImGui gui)
        {
            BuildHeader(gui, "Module customisation");
            if (recipe.modules == null)
            {
                if (gui.BuildButton("Enable custom modules"))
                {
                    recipe.RecordUndo().modules = new CustomModules(recipe);
                }
            }
            else
            {
                var effects = new ModuleEffects();
                if (recipe.entity?.moduleSlots > 0)
                {
                    gui.BuildText("Internal modules:", Font.subheader);
                    gui.BuildText("Leave zero amount to fill the remainings slots");
                    DrawRecipeModules(gui, null, ref effects);
                }
                else
                {
                    gui.BuildText("This building doesn't have module slots, but can be affected by beacons");
                }
                gui.BuildText("Beacon modules:", Font.subheader);
                if (recipe.modules.beacon == null)
                {
                    gui.BuildText("Use default parameters");
                    if (gui.BuildButton("Override beacons as well"))
                    {
                        SelectBeacon(gui);
                    }
                    var defaultFiller = recipe.GetModuleFiller();
                    if (defaultFiller != null && defaultFiller.beacon != null && defaultFiller.beaconModule != null)
                    {
                        effects.AddModules(defaultFiller.beaconModule.module, defaultFiller.beacon.beaconEfficiency * defaultFiller.beacon.moduleSlots * defaultFiller.beaconsPerBuilding);
                    }
                }
                else
                {
                    if (gui.BuildFactorioObjectButtonWithText(recipe.modules.beacon))
                    {
                        SelectBeacon(gui);
                    }
                    gui.BuildText("Input the amount of modules, not the amount of beacons. Single beacon can hold " + recipe.modules.beacon.moduleSlots + " modules.", wrap: true);
                    DrawRecipeModules(gui, recipe.modules.beacon, ref effects);
                }

                gui.BuildText("Current effects:", Font.subheader);
                gui.BuildText("Productivity bonus: " + DataUtils.FormatAmount(effects.productivity, UnitOfMeasure.Percent));
                gui.BuildText("Speed bonus: " + DataUtils.FormatAmount(effects.speedMod, UnitOfMeasure.Percent) + " (Crafting speed: " + DataUtils.FormatAmount((recipe.entity?.craftingSpeed ?? 1f) * (1f + effects.speedMod), UnitOfMeasure.None) + ")");
                var energyUsageLine = "Energy usage: " + DataUtils.FormatAmount(effects.energyUsageMod, UnitOfMeasure.Percent);
                if (!recipe.recipe.flags.HasFlagAny(RecipeFlags.UsesFluidTemperature | RecipeFlags.ScaleProductionWithPower) && recipe.entity != null)
                {
                    energyUsageLine += " (" + DataUtils.FormatAmount(effects.energyUsageMod * recipe.entity.power / recipe.entity.energy.effectivity, UnitOfMeasure.Megawatt) + " per building)";
                }
                gui.BuildText(energyUsageLine);
            }

            gui.AllocateSpacing(3f);
            using (gui.EnterRow(allocator: RectAllocator.RightRow))
            {
                if (gui.BuildButton("Done"))
                {
                    Close();
                }
                if (recipe.modules != null && gui.BuildButton("Copy settings", SchemeColor.Grey))
                {
                    if (copiedModuleSettings == null)
                    {
                        MessageBox.Show("Info", "Use ctrl+click on module slot to paste settings", "Ok");
                    }
                    copiedModuleSettings = JsonUtils.SaveToJson(recipe.modules);
                }
                gui.allocator = RectAllocator.LeftRow;
                if (recipe.modules != null && gui.BuildRedButton("Remove module customisation") == ImGuiUtils.Event.Click)
                {
                    recipe.RecordUndo().modules = null;
                    Close();
                }
            }
        }
예제 #7
0
        public override void Build(ImGui gui)
        {
            BuildHeader(gui, "Module autofill parameters");
            BuildSimple(gui, modules);
            if (gui.BuildCheckBox("Fill modules in miners", modules.fillMiners, out var newFill))
            {
                modules.RecordUndo().fillMiners = newFill;
            }
            gui.AllocateSpacing();
            gui.BuildText("Filler module:", Font.subheader);
            gui.BuildText("Use this module when aufofill doesn't add anything (for example when productivity modules doesn't fit)", wrap: true);
            if (gui.BuildFactorioObjectButtonWithText(modules.fillerModule))
            {
                SelectObjectPanel.Select(Database.allModules, "Select filler module", select => { modules.RecordUndo().fillerModule = select; }, true);
            }

            gui.AllocateSpacing();
            gui.BuildText("Beacons & beacon modules:", Font.subheader);
            if (gui.BuildFactorioObjectButtonWithText(modules.beacon))
            {
                SelectObjectPanel.Select(Database.allBeacons, "Select beacon", select =>
                {
                    modules.RecordUndo();
                    modules.beacon = select;
                    if (modules.beaconModule != null && (modules.beacon == null || !modules.beacon.CanAcceptModule(modules.beaconModule.module)))
                    {
                        modules.beaconModule = null;
                    }
                    gui.Rebuild();
                }, true);
            }

            if (gui.BuildFactorioObjectButtonWithText(modules.beaconModule))
            {
                SelectObjectPanel.Select(Database.allModules.Where(x => modules.beacon?.CanAcceptModule(x.module) ?? false), "Select module for beacon", select => { modules.RecordUndo().beaconModule = select; }, true);
            }

            using (gui.EnterRow())
            {
                gui.BuildText("Beacons per building: ");
                if (gui.BuildTextInput(modules.beaconsPerBuilding.ToString(), out var newText, null, Icon.None, true, new Padding(0.5f, 0f)) &&
                    int.TryParse(newText, out var newAmount) && newAmount > 0)
                {
                    modules.RecordUndo().beaconsPerBuilding = newAmount;
                }
            }
            gui.BuildText("Please note that beacons themself are not part of the calculation", wrap: true);

            using (gui.EnterRow())
            {
                gui.BuildText("Mining productivity bonus (project-wide setting): ");
                if (gui.BuildTextInput(DataUtils.FormatAmount(Project.current.settings.miningProductivity, UnitOfMeasure.Percent), out var newText, null, Icon.None, true, new Padding(0.5f, 0f)) &&
                    DataUtils.TryParseAmount(newText, out var newAmount, UnitOfMeasure.Percent))
                {
                    Project.current.settings.RecordUndo().miningProductivity = newAmount;
                }
            }

            if (gui.BuildButton("Done"))
            {
                Close();
            }
        }