public bool FillModules(RecipeParameters recipeParams, Recipe recipe, Entity entity, Goods fuel, out ModuleEffects effects, out RecipeParameters.UsedModule used) { effects = new ModuleEffects(); var beaconedModules = 0; var nonBeaconedModules = 0; Item nonBeacon = null; foreach (var module in list) { float multiplier; if (module.inBeacon) { if (beacon != null) { beaconedModules += module.fixedCount; multiplier = beacon.beaconEfficiency * module.fixedCount; } else { multiplier = 0f; } } else { var count = module.fixedCount > 0 ? module.fixedCount : Math.Max(0, entity.moduleSlots - nonBeaconedModules); multiplier = count; nonBeaconedModules += count; if (nonBeacon == null) { nonBeacon = module.module; } } effects.AddModules(module.module.module, multiplier); } used = new RecipeParameters.UsedModule { module = nonBeacon, count = nonBeaconedModules }; if (beaconedModules > 0 && beacon != null) { used.beacon = beacon; used.beaconCount = ((beaconedModules - 1) / beacon.moduleSlots + 1); } return(list.Count > 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(); } } }
private void DrawRecipeModules(ImGui gui, EntityBeacon beacon, ref ModuleEffects effects) { var remainingModules = recipe.entity?.moduleSlots ?? 0; using (var grid = gui.EnterInlineGrid(3f, 1f)) { var list = beacon != null ? recipe.modules.beaconList : recipe.modules.list; foreach (var module in list) { grid.Next(); var evt = gui.BuildFactorioObjectWithEditableAmount(module.module, module.fixedCount, UnitOfMeasure.None, out var newAmount); if (evt == GoodsWithAmountEvent.ButtonClick) { SelectObjectPanel.Select(GetModules(beacon), "Select module", sel => { if (sel == null) { recipe.modules.RecordUndo().list.Remove(module); } else { module.RecordUndo().module = sel; } gui.Rebuild(); }, DataUtils.FavouriteModule, true); } else if (evt == GoodsWithAmountEvent.TextEditing) { var amountInt = MathUtils.Floor(newAmount); if (amountInt < 0) { amountInt = 0; } module.RecordUndo().fixedCount = amountInt; } if (beacon == null) { var count = Math.Min(remainingModules, module.fixedCount > 0 ? module.fixedCount : int.MaxValue); if (count > 0) { effects.AddModules(module.module.module, count); remainingModules -= count; } } else { effects.AddModules(module.module.module, module.fixedCount * beacon.beaconEfficiency); } } grid.Next(); if (gui.BuildButton(Icon.Plus, SchemeColor.Primary, SchemeColor.PrimalyAlt, size: 2.5f)) { gui.BuildObjectSelectDropDown(GetModules(beacon), DataUtils.FavouriteModule, sel => { recipe.modules.RecordUndo(); list.Add(new RecipeRowCustomModule(recipe.modules, sel)); gui.Rebuild(); }, "Select module"); } } }