diff --git a/Yafc.Model/Model/ProductionTable.cs b/Yafc.Model/Model/ProductionTable.cs index dbaede73..8e7eb5bb 100644 --- a/Yafc.Model/Model/ProductionTable.cs +++ b/Yafc.Model/Model/ProductionTable.cs @@ -291,6 +291,7 @@ public void AddRecipe(IObjectWithQuality recipe, IComparer? selectedFuel) => diff --git a/Yafc.Model/Model/ProductionTableContent.cs b/Yafc.Model/Model/ProductionTableContent.cs index 006ca3eb..57a40dd7 100644 --- a/Yafc.Model/Model/ProductionTableContent.cs +++ b/Yafc.Model/Model/ProductionTableContent.cs @@ -808,6 +808,65 @@ public void AutoApplyModuleTemplate(List moduleTemplates) } } + /// + /// Apply a default module when this row uses a single-category module building and no template was selected. + /// The chosen module is based upon the unlock order and what milestones are currently unlocked. No secondary sort on prod/speed to keep the code simpler + /// + public void AutoApplySingleCategoryModule() { + //Don't change anything if existing modules are set + if (modules != null) { + return; + } + + //Basic safety checks + if (recipe is null || entity is null || entity.target.moduleSlots <= 0) { + return; + } + + if (recipe.target is not Recipe targetRecipe) { + return; + } + + if (entity.target.allowedModuleCategories is not [string moduleCategory]) { + return; + } + + IObjectWithQuality? bestModule = null; + Bits bestUnlockOrder = default; + + //Loop over all modules finding the one that is usable, unlocked, and unlocks latest according to milestones + foreach (Module module in Database.allModules) { + //Check module is in the building's allowed category + if (module.moduleSpecification.category != moduleCategory) { + continue; + } + + //Check the recipe allows this module + if (!entity.target.CanAcceptModule(module.moduleSpecification) || !recipe.target.CanAcceptModule(module)) { + continue; + } + + //Check if this module is currently available with the active milestones + if (!module.IsAccessibleWithCurrentMilestones()) { + continue; + } + + //Update if this module is better (milestone order) + Bits moduleMilestoneOrder = Milestones.Instance.GetMilestoneResult(module.id); + if (bestModule == null || moduleMilestoneOrder > bestUnlockOrder) { + bestModule = module.With(Quality.MaxAccessible); + bestUnlockOrder = moduleMilestoneOrder; + } + } + + //We have a working module, fill all the module slots + if (bestModule != null) { + modules = new ModuleTemplateBuilder { + list = [(bestModule, 0)] + }.Build(this); + } + } + public float DetermineFlow(IObjectWithQuality goods) { if (recipe is null) { throw new InvalidOperationException("Cannot determine flow when no recipe is selected."); diff --git a/changelog.txt b/changelog.txt index e69f7668..221be1fd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -23,6 +23,7 @@ Version: Date: Features: - Improve early-startup error logging + - Automatically apply single use modules to recipes. e.g. Autoamtically fill PyAL buildings with appropriate module for the current milestone Fixes: ---------------------------------------------------------------------------------------------------------------------- Version: 2.18.1