private void BuildRecipeEntity(ImGui gui, RecipeRow recipe) { if (recipe.isOverviewMode) { return; } if (gui.BuildFactorioObjectWithAmount(recipe.entity, (float)(recipe.recipesPerSecond * recipe.parameters.recipeTime), UnitOfMeasure.None) && recipe.recipe.crafters.Count > 0) { gui.ShowDropDown(((ImGui dropGui, ref bool closed) => { closed = dropGui.BuildInlineObejctListAndButton(recipe.recipe.crafters, DataUtils.FavouriteCrafter, sel => { DataUtils.FavouriteCrafter.AddToFavourite(sel); if (recipe.entity == sel) { return; } recipe.RecordUndo().entity = sel; if (!sel.energy.fuels.Contains(recipe.fuel)) { recipe.fuel = recipe.entity.energy.fuels.AutoSelect(DataUtils.FavouriteFuel); } }, "Select crafting entity"); })); } gui.AllocateSpacing(0.5f); BuildGoodsIcon(gui, recipe.fuel, (float)(recipe.parameters.fuelUsagePerSecondPerRecipe * recipe.recipesPerSecond), ProductDropdownType.Fuel, recipe, recipe.linkRoot); }
private void BuildRecipeModules(ImGui gui, RecipeRow recipe) { if (recipe.isOverviewMode) { return; } if (recipe.entity != null && recipe.entity.moduleSlots > 0 && gui.BuildFactorioObjectWithAmount(recipe.parameters.modules.module, recipe.parameters.modules.count, UnitOfMeasure.None)) { gui.ShowDropDown((ImGui dropGui, ref bool closed) => { dropGui.BuildText("Selecting a fixed module will override auto-module filler!", wrap: true); closed = dropGui.BuildInlineObejctListAndButton(recipe.recipe.modules, DataUtils.FavouriteModule, sel => { DataUtils.FavouriteModule.AddToFavourite(sel); if (recipe.module == sel) { return; } recipe.RecordUndo().module = sel; }, "Select fixed module", allowNone: recipe.parameters.modules.module != null); }); } if (recipe.parameters.modules.beacon != null) { gui.BuildFactorioObjectWithAmount(recipe.parameters.modules.beacon, recipe.parameters.modules.beaconCount, UnitOfMeasure.None); } }
private void AddRecipe(ProductionTable table, Recipe recipe) { var recipeRow = new RecipeRow(table, recipe); table.RecordUndo().recipes.Add(recipeRow); recipeRow.entity = recipe.crafters.AutoSelect(DataUtils.FavouriteCrafter); recipeRow.fuel = recipeRow.entity.energy.fuels.AutoSelect(DataUtils.FavouriteFuel); }
private void ShowEntityDropPown(ImGui imgui, RecipeRow recipe) { imgui.ShowDropDown((ImGui gui, ref bool closed) => { closed = gui.BuildInlineObejctListAndButton(recipe.recipe.crafters, DataUtils.FavouriteCrafter, sel => { if (recipe.entity == sel) { return; } recipe.RecordUndo().entity = sel; if (!sel.energy.fuels.Contains(recipe.fuel)) { recipe.fuel = recipe.entity.energy.fuels.AutoSelect(DataUtils.FavouriteFuel); } }, "Select crafting entity", extra: x => DataUtils.FormatAmount(x.craftingSpeed, UnitOfMeasure.Percent)); if (recipe.fixedBuildings > 0f) { if (gui.BuildButton("Clear fixed building count") && (closed = true)) { recipe.RecordUndo().fixedBuildings = 0f; } } else { if (gui.BuildButton("Set fixed building count") && (closed = true)) { recipe.RecordUndo().fixedBuildings = recipe.buildingCount <= 0f ? 1f : recipe.buildingCount; } } if (recipe.entity != null && gui.BuildButton("Create single building blueprint") && (closed = true)) { var entity = new BlueprintEntity { index = 1, name = recipe.entity.name }; if (!(recipe.recipe is Mechanics)) { entity.recipe = recipe.recipe.name; } var modules = recipe.parameters.modules.modules; if (modules != null) { entity.items = new Dictionary <string, int>(); foreach (var(module, count) in recipe.parameters.modules.modules) { entity.items[module.name] = count; } } var bp = new BlueprintString { blueprint = { label = recipe.recipe.locName, entities = { entity } } }; SDL.SDL_SetClipboardText(bp.ToBpString()); } }); }
private void BuildSolarPanelAccumulatorView(ImGui gui, RecipeRow recipe) { var accumulator = recipe.GetVariant(Database.allAccumulators); var requiredMj = recipe.entity.craftingSpeed * recipe.buildingCount * (70 / 0.7f); // 70 seconds of charge time to last through the night var requiredAccumulators = requiredMj / accumulator.accumulatorCapacity; if (gui.BuildFactorioObjectWithAmount(accumulator, requiredAccumulators, UnitOfMeasure.None)) { ShowAccumulatorDropdown(gui, recipe, accumulator); } }
void AddRow(ItemType inputA, ItemType inputB, ItemType output) { GameObject go = Instantiate(recipeRowTemplatePrefab, transform.position, Quaternion.identity); go.transform.SetParent(transform); RecipeRow recipeRow = go.GetComponent <RecipeRow>(); recipeRow.SetItems(inputA, inputB, output); recipeRow.transform.localScale = Vector3.one; }
private void ShowAccumulatorDropdown(ImGui gui, RecipeRow recipe, Entity accumulator) { gui.ShowDropDown((ImGui imGui, ref bool closed) => { if (imGui.BuildInlineObejctListAndButton <EntityAccumulator>(Database.allAccumulators, DataUtils.DefaultOrdering, accum => recipe.RecordUndo().ChangeVariant(accumulator, accum), "Select accumulator", extra: x => DataUtils.FormatAmount(x.accumulatorCapacity, UnitOfMeasure.Megajoule))) { closed = true; } }); }
private List <RecipeRow> GetRecipesRecursive(RecipeRow recipeRoot) { var list = new List <RecipeRow> { recipeRoot }; if (recipeRoot.subgroup != null) { FillRecipeList(recipeRoot.subgroup, list); } return(list); }
private void BuildRecipePad(ImGui gui, RecipeRow row) { gui.allocator = RectAllocator.Center; gui.spacing = 0f; if (row.subgroup != null) { if (gui.BuildButton(row.subgroup.expanded ? Icon.ShevronDown : Icon.ShevronRight)) { row.subgroup.RecordUndo(true).expanded = !row.subgroup.expanded; flatHierarchyBuilder.SetData(model); } } if (row.parameters.warningFlags != 0) { var isError = row.parameters.warningFlags >= WarningFlags.EntityNotSpecified; bool hover; if (isError) { hover = gui.BuildRedButton(Icon.Error) == ImGuiUtils.Event.MouseOver; } else { using (gui.EnterGroup(ImGuiUtils.DefaultIconPadding)) gui.BuildIcon(Icon.Help); hover = gui.BuildButton(gui.lastRect, SchemeColor.None, SchemeColor.Grey) == ImGuiUtils.Event.MouseOver; } if (hover) { gui.ShowTooltip(g => { if (isError) { g.boxColor = SchemeColor.Error; g.textColor = SchemeColor.ErrorText; } foreach (var(flag, text) in WarningsMeaning) { if ((row.parameters.warningFlags & flag) != 0) { g.BuildText(text, wrap: true); } } }); } } else { //gui.BuildText((index+1).ToString()); TODO } }
public static Recipe ToRecipe(this RecipeRow row, IReferenceBookService referenceBook) { if (row == null) { throw new ArgumentNullException(nameof(row)); } if (referenceBook == null) { throw new ArgumentNullException(nameof(referenceBook)); } var recipe = row.Recipe.ToRecipe(referenceBook); recipe.Id = row.Id; return(recipe); }
private void AddRecipe(ProductionTable table, Recipe recipe) { var recipeRow = new RecipeRow(table, recipe); table.RecordUndo().recipes.Add(recipeRow); recipeRow.entity = recipe.crafters.AutoSelect(DataUtils.FavouriteCrafter); recipeRow.fuel = recipeRow.entity.energy.fuels.AutoSelect(DataUtils.FavouriteFuel); foreach (var ingr in recipeRow.recipe.ingredients) { if (ingr.variants != null) { recipeRow.variants.Add(ingr.variants.AutoSelect(DefaultVariantOrdering)); } } }
/// <summary> /// Add the recipe in the define row /// </summary> /// <param name="recipeRow"></param> /// <param name="recipe"></param> private void AddRecipe(RecipeRow recipeRow, Recipe recipe) { switch (recipeRow) { case RecipeRow.cheaper: CheaperRecipeStackPanel.Children.Add(GetButton(recipe)); break; case RecipeRow.rated: BestRatedStackPanel.Children.Add(GetButton(recipe)); break; case RecipeRow.trending: TrendingStackPanel.Children.Add(GetButton(recipe)); break; } }
private void BuildRecipeProducts(ImGui gui, RecipeRow recipe) { var grid = gui.EnterInlineGrid(3f, 1f); if (recipe.isOverviewMode) { BuildTableProducts(gui, recipe.subgroup, recipe.owner, ref grid); } else { foreach (var product in recipe.recipe.products) { grid.Next(); BuildGoodsIcon(gui, product.goods, (float)(product.amount * recipe.recipesPerSecond * recipe.parameters.productionMultiplier), ProductDropdownType.Product, recipe, recipe.linkRoot); } } grid.Dispose(); }
public Recipe FindRecipe(int id) { if (_isDisposed) { throw new ObjectDisposedException(nameof(RecipePersistenceService)); } if (id <= 0) { throw new ArgumentOutOfRangeException(nameof(id)); } RecipeRow row = null; using (_connection.Lock()) { row = _connection.Get <RecipeRow>(x => x.Id == id); } return(row?.ToRecipe(_referenceBook)); }
private void BuildRecipeIngredients(ImGui gui, RecipeRow recipe) { var grid = gui.EnterInlineGrid(3f, 1f); if (recipe.isOverviewMode) { BuildTableIngredients(gui, recipe.subgroup, recipe.owner, ref grid); } else { foreach (var ingredient in recipe.recipe.ingredients) { grid.Next(); BuildGoodsIcon(gui, ingredient.goods, (float)(ingredient.amount * recipe.recipesPerSecond), ProductDropdownType.Ingredient, recipe, recipe.linkRoot); } } grid.Dispose(); }
private void BuildRecipeName(ImGui gui, RecipeRow recipe) { gui.spacing = 0.5f; if (gui.BuildFactorioObjectButton(recipe.recipe, 3f)) { gui.ShowDropDown(delegate(ImGui imgui, ref bool closed) { if (recipe.subgroup == null && imgui.BuildButton("Create nested table")) { recipe.RecordUndo().subgroup = new ProductionTable(recipe); closed = true; } if (recipe.subgroup != null && imgui.BuildButton("Unpack nested table")) { var evacuate = recipe.subgroup.recipes; recipe.subgroup.RecordUndo(); recipe.RecordUndo().subgroup = null; var index = recipe.owner.recipes.IndexOf(recipe); foreach (var evacRecipe in evacuate) { evacRecipe.SetOwner(recipe.owner); } recipe.owner.RecordUndo().recipes.InsertRange(index + 1, evacuate); closed = true; } if (recipe.subgroup != null && imgui.BuildRedButton("Remove nested table") == ImGuiUtils.Event.Click) { recipe.owner.RecordUndo().recipes.Remove(recipe); closed = true; } if (recipe.subgroup == null && imgui.BuildRedButton("Delete recipe") == ImGuiUtils.Event.Click) { recipe.owner.RecordUndo().recipes.Remove(recipe); closed = true; } }); } gui.BuildText(recipe.recipe.locName, wrap: true); }
private void BuildRecipeProducts(ImGui gui, RecipeRow recipe) { var grid = gui.EnterInlineGrid(3f, 1f); if (recipe.isOverviewMode) { BuildTableProducts(gui, recipe.subgroup, recipe.owner, ref grid); } else { for (var i = 0; i < recipe.recipe.products.Length; i++) { var product = recipe.recipe.products[i]; grid.Next(); BuildGoodsIcon(gui, product.goods, recipe.links.products[i], (float)(recipe.recipesPerSecond * product.GetAmount(recipe.parameters.productivity)), ProductDropdownType.Product, recipe, recipe.linkRoot); } } grid.Dispose(); }
private void BuildRecipeEntity(ImGui gui, RecipeRow recipe) { if (recipe.isOverviewMode) { return; } bool clicked; if (recipe.fixedBuildings > 0) { var evt = gui.BuildFactorioObjectWithEditableAmount(recipe.entity, recipe.fixedBuildings, UnitOfMeasure.None, out var newAmount); if (evt == GoodsWithAmountEvent.TextEditing) { recipe.RecordUndo().fixedBuildings = newAmount; } clicked = evt == GoodsWithAmountEvent.ButtonClick; } else { clicked = gui.BuildFactorioObjectWithAmount(recipe.entity, recipe.buildingCount, UnitOfMeasure.None) && recipe.recipe.crafters.Count > 0; } if (clicked) { ShowEntityDropPown(gui, recipe); } gui.AllocateSpacing(0.5f); if (recipe.fuel != Database.voidEnergy) { BuildGoodsIcon(gui, recipe.fuel, recipe.links.fuel, (float)(recipe.parameters.fuelUsagePerSecondPerRecipe * recipe.recipesPerSecond), ProductDropdownType.Fuel, recipe, recipe.linkRoot); } else { if (recipe.recipe == Database.electricityGeneration && recipe.entity.factorioType == "solar-panel") { BuildSolarPanelAccumulatorView(gui, recipe); } } }
private void BuildRecipeModules(ImGui gui, RecipeRow recipe) { if (recipe.isOverviewMode) { return; } using (var grid = gui.EnterInlineGrid(3f)) { if (recipe.entity != null && recipe.entity.allowedEffects != AllowedEffects.None) { if (recipe.parameters.modules.modules == null || recipe.parameters.modules.modules.Length == 0) { grid.Next(); if (gui.BuildFactorioObjectWithAmount(null, 0, UnitOfMeasure.None)) { ShowModuleDropDown(gui, recipe); } } else { foreach (var(module, count) in recipe.parameters.modules.modules) { grid.Next(); if (gui.BuildFactorioObjectWithAmount(module, count, UnitOfMeasure.None)) { ShowModuleDropDown(gui, recipe); } } } } if (recipe.parameters.modules.beacon != null) { grid.Next(); if (gui.BuildFactorioObjectWithAmount(recipe.parameters.modules.beacon, recipe.parameters.modules.beaconCount, UnitOfMeasure.None)) { ModuleCustomisationScreen.Show(recipe); } } } }
private void BuildRecipeIngredients(ImGui gui, RecipeRow recipe) { var grid = gui.EnterInlineGrid(3f, 1f); if (recipe.isOverviewMode) { BuildTableIngredients(gui, recipe.subgroup, recipe.owner, ref grid); } else { for (var i = 0; i < recipe.recipe.ingredients.Length; i++) { var ingredient = recipe.recipe.ingredients[i]; var link = recipe.links.ingredients[i]; var goods = recipe.links.ingredientGoods[i]; grid.Next(); BuildGoodsIcon(gui, goods, link, (float)(ingredient.amount * recipe.recipesPerSecond), ProductDropdownType.Ingredient, recipe, recipe.linkRoot, ingredient.variants); } } grid.Dispose(); }
private void BuildRecipePad(ImGui gui, RecipeRow row) { gui.allocator = RectAllocator.Center; gui.spacing = 0f; if (row.subgroup != null) { if (gui.BuildButton(row.subgroup.expanded ? Icon.ShevronDown : Icon.ShevronRight)) { row.subgroup.RecordUndo(true).expanded = !row.subgroup.expanded; flatHierarchyBuilder.SetData(model); } } if (row.parameters.warningFlags != 0) { if (gui.BuildRedButton(Icon.Error) == ImGuiUtils.Event.MouseOver) { gui.ShowTooltip(g => { g.boxColor = SchemeColor.Error; g.textColor = SchemeColor.ErrorText; foreach (var(flag, text) in WarningsMeaning) { if ((row.parameters.warningFlags & flag) != 0) { g.BuildText(text, wrap: true); } } }); } } else { //gui.BuildText((index+1).ToString()); TODO } }
private void BuildShoppngList(RecipeRow recipeRoot) { var shopList = new Dictionary <FactorioObject, int>(); var recipes = recipeRoot == null?GetRecipesRecursive() : GetRecipesRecursive(recipeRoot); foreach (var recipe in recipes) { if (recipe.entity != null) { shopList.TryGetValue(recipe.entity, out var prev); var count = MathUtils.Ceil(recipe.buildingCount); shopList[recipe.entity] = prev + count; if (recipe.parameters.modules.modules != null) { foreach (var module in recipe.parameters.modules.modules) { shopList.TryGetValue(module.module, out prev); shopList[module.module] = prev + count * module.count; } } } } ShoppingListScreen.Show(shopList); }
private void ShowModuleDropDown(ImGui gui, RecipeRow recipe) { if (InputSystem.Instance.control) { if (recipe.entity != null && ModuleCustomisationScreen.copiedModuleSettings != null) { var result = JsonUtils.LoadFromJson(ModuleCustomisationScreen.copiedModuleSettings, recipe, recipe.modules); foreach (var module in result.list) { if (!recipe.recipe.modules.Contains(module.module) && recipe.entity.CanAcceptModule(module.module.module)) { MessageBox.Show("Module mismatch", "This module cannot be used: " + module.module.locName, "OK"); return; } } recipe.RecordUndo().modules = JsonUtils.LoadFromJson(ModuleCustomisationScreen.copiedModuleSettings, recipe, recipe.modules); } } else if (recipe.entity?.moduleSlots == 0 || recipe.modules != null && (recipe.modules.list.Count > 1 || recipe.modules.beacon != null)) { ModuleCustomisationScreen.Show(recipe); } else { var modules = recipe.recipe.modules.Where(x => recipe.entity?.CanAcceptModule(x.module) ?? false).ToArray(); gui.ShowDropDown((ImGui dropGui, ref bool closed) => { dropGui.BuildText("Selecting a fixed module will override auto-module filler!", wrap: true); closed = dropGui.BuildInlineObejctListAndButton(modules, DataUtils.FavouriteModule, recipe.SetFixedModule, "Select fixed module", allowNone: recipe.modules != null); if (dropGui.BuildButton("Customize modules") && (closed = true)) { ModuleCustomisationScreen.Show(recipe); } }); } }
private void DrawRecipeTagSelect(ImGui gui, RecipeRow recipe) { using (gui.EnterRow()) { for (var i = 0; i < tagIcons.Length; i++) { var(icon, color) = tagIcons[i]; var selected = i == recipe.tag; gui.BuildIcon(icon, color: selected ? SchemeColor.Background : color); if (selected) { gui.DrawRectangle(gui.lastRect, color); } else { var evt = gui.BuildButton(gui.lastRect, SchemeColor.None, SchemeColor.BackgroundAlt, SchemeColor.BackgroundAlt); if (evt == ImGuiUtils.Event.Click) { recipe.RecordUndo(true).tag = i; } } } } }
public static void Show(RecipeRow recipe) { Instance.recipe = recipe; MainScreen.Instance.ShowPseudoScreen(Instance); }
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); } }
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; } } } }
private void BuildRecipeName(ImGui gui, RecipeRow recipe) { gui.spacing = 0.5f; if (gui.BuildFactorioObjectButton(recipe.recipe, 3f)) { gui.ShowDropDown(delegate(ImGui imgui, ref bool closed) { DrawRecipeTagSelect(imgui, recipe); if (recipe.subgroup == null && imgui.BuildButton("Create nested table")) { recipe.RecordUndo().subgroup = new ProductionTable(recipe); closed = true; } if (recipe.subgroup != null && imgui.BuildButton("Add nested desired product")) { AddDesiredProductAtLevel(recipe.subgroup); closed = true; } if (recipe.subgroup != null && imgui.BuildButton("Add raw recipe")) { SelectObjectPanel.Select(Database.recipes.all, "Select raw recipe", r => AddRecipe(recipe.subgroup, r)); closed = true; } if (recipe.subgroup != null && imgui.BuildButton("Unpack nested table")) { var evacuate = recipe.subgroup.recipes; recipe.subgroup.RecordUndo(); recipe.RecordUndo().subgroup = null; var index = recipe.owner.recipes.IndexOf(recipe); foreach (var evacRecipe in evacuate) { evacRecipe.SetOwner(recipe.owner); } recipe.owner.RecordUndo().recipes.InsertRange(index + 1, evacuate); closed = true; } if (recipe.subgroup != null && imgui.BuildButton("ShoppingList")) { BuildShoppngList(recipe); closed = true; } if (imgui.BuildCheckBox("Enabled", recipe.enabled, out var newEnabled)) { recipe.RecordUndo().enabled = newEnabled; } if (recipe.subgroup != null && imgui.BuildRedButton("Delete nested table") == ImGuiUtils.Event.Click) { recipe.owner.RecordUndo().recipes.Remove(recipe); closed = true; } if (recipe.subgroup == null && imgui.BuildRedButton("Delete recipe") == ImGuiUtils.Event.Click) { recipe.owner.RecordUndo().recipes.Remove(recipe); closed = true; } }); } gui.textColor = recipe.hierarchyEnabled ? SchemeColor.BackgroundText : SchemeColor.BackgroundTextFaint; gui.BuildText(recipe.recipe.locName, wrap: true); }
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); } } }
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); } }