public static void RunPatch(IPatcherState <ISkyrimMod, ISkyrimModGetter> state) { List <IngrCombination> combinations = new List <IngrCombination>(); IEnumerable <IIngredientGetter> ingredients = state.LoadOrder.PriorityOrder.OnlyEnabled().Ingredient().WinningOverrides(); ingredients = from ingrs in ingredients where !SkipPlugins.Contains(ingrs.FormKey.ModKey.Name.ToLower()) select ingrs; ingredients = from ingrs in ingredients where (!SkipIngrs.Intersect(ingrs.Name?.ToString()?.Split() !).Any() || SkipIngrs.Contains(ingrs.Name?.ToString())) select ingrs; ingredients = from ingrs in ingredients where !String.IsNullOrEmpty(ingrs.Name?.String) select ingrs; IEnumerator <IIngredientGetter> enumerator = ingredients.GetEnumerator(); int i = 0; int percent = (int)(ingredients.Count() * outputPercentage); while (enumerator.MoveNext()) { sw.Start(); if (i % percent == 0) { Console.WriteLine(i + " out of " + ingredients.Count() + " ingredients processed."); } List <IIngredientGetter> remainingingr = ingredients.Skip(i).ToList(); IIngredientGetter[] potionRecipeList = getIngredientsMatchingOneIngredient(enumerator.Current, remainingingr); if (String.IsNullOrEmpty(enumerator.Current.Name?.String)) { i++; continue; } foreach (IIngredientGetter ingr in potionRecipeList) { IEnumerable <IEffectGetter> ActiveEffects = ingr.Effects.Intersect(enumerator.Current.Effects).ToArray(); ActiveEffects = ActiveEffects.Distinct(); IEffectGetter[] ActiveEffectsA = ActiveEffects.ToArray(); if (ActiveEffectsA.Length < 1) { continue; } String potionString = "<font face='$HandwrittenFont'><font size='26'>"; potionString += "-<b>" + (enumerator.Current.Name + "<br><b>-<b>" + ingr.Name + "</b>"); List <String?> mgeflist = new List <String?>(); List <String?> mgeflists = new List <String?>(); foreach (IEffectGetter effect in ActiveEffectsA) { state.LinkCache.TryResolve <IMagicEffectGetter>(effect.BaseEffect.FormKey, out var mgeffect); mgeflist.Add(mgeffect?.Name?.String); mgeflists.AddRange(mgeffect?.Name?.String?.Split() !); } String prefix = "Potion"; int type = 0; if (!mgeflists.Intersect(potionWords.ToList()).Any() && mgeflists.Intersect(poisonWords.ToList()).Any()) { prefix = "Poison"; type = 1; if (mgeflist.Count() <= poisonSkipThreshold) { continue; } poisonRecipeCount++; } else if (mgeflists.Intersect(potionWords.ToList()).Any() && mgeflists.Intersect(poisonWords.ToList()).Any()) { prefix = "Impure Potion"; type = 2; if (mgeflist.Count() <= impureSkipThreshold) { continue; } impurepotionRecipeCount++; } else { if (mgeflist.Count() <= potionSkipThreshold) { continue; } potionRecipeCount++; } potionString += ("</font><font face='$HandwrittenFont'><font size='18'><br> to make " + prefix + " of "); String potionName = "Recipe: "; for (int k = 0; k < mgeflist.Count(); k++) { if (k > 0) { potionName += " and "; potionString += ("<br>"); } potionName += mgeflist[k]; potionString += (mgeflist[k]); } String sstring = ""; if (mgeflist.Count() > 1) { sstring = "s"; } potionString += ("<br></font><font size='14'> Contains " + mgeflist.Count() + " Effect" + sstring); potionString += "<\\font>"; IIngredientGetter[] ingrss = { enumerator.Current, ingr }; combinations.Add(new IngrCombination(potionName, ingrss, mgeflist?.ToArray() !, potionString, type)); } int j = i + 1; IEnumerator <IIngredientGetter> enumerator2 = remainingingr.GetEnumerator(); while (enumerator2.MoveNext()) { if (enumerator2.Current.Name?.Equals(enumerator.Current.Name) ?? true || String.IsNullOrEmpty(enumerator2.Current.Name?.String) || !enumerator.Current.Effects.Intersect(enumerator2.Current.Effects).Any()) { j++; continue; } List <IIngredientGetter> remainingingr2 = ingredients.Skip(j).ToList(); IIngredientGetter[] potionRecipeList2 = getIngredientsMatchingTwoIngredients(enumerator.Current, enumerator2.Current, remainingingr2); foreach (IIngredientGetter ingr in potionRecipeList2) { IEnumerable <IEffectGetter> ActiveEffects = ingr.Effects.Intersect(enumerator.Current.Effects); IEnumerable <IEffectGetter> ActiveEffects2 = ingr.Effects.Intersect(enumerator2.Current.Effects); IEnumerable <IEffectGetter> ActiveEffects3 = enumerator.Current.Effects.Intersect(enumerator2.Current.Effects); ActiveEffects.ToList().AddRange(ActiveEffects2); ActiveEffects.ToList().AddRange(ActiveEffects3); ActiveEffects = ActiveEffects.Distinct(); IEffectGetter[] ActiveEffectsA = ActiveEffects.ToArray(); if (ActiveEffectsA.Length < 1) { continue; } String potionString = "<font face='$HandwrittenFont'><font size='26'>"; potionString += "-<b>" + (enumerator.Current.Name + "<br></b>-<b>" + enumerator2.Current.Name + "<br></b>-<b>" + ingr.Name + "</b>"); List <String?> mgeflist = new List <String?>(); List <String?> mgeflists = new List <String?>(); foreach (IEffectGetter effect in ActiveEffects) { state.LinkCache.TryResolve <IMagicEffectGetter>(effect.BaseEffect.FormKey, out var mgeffect); mgeflist.Add(mgeffect?.Name?.String); mgeflists.AddRange(mgeffect?.Name?.String?.Split() !); } String prefix = "Potion"; int type = 0; if (!mgeflists.Intersect(potionWords.ToList()).Any() && mgeflists.Intersect(poisonWords.ToList()).Any()) { prefix = "Poison"; type = 1; if (mgeflist.Count() <= poisonSkipThreshold) { continue; } poisonRecipeCount++; } else if (mgeflist.Intersect(potionWords.ToList()).Any() && mgeflists.Intersect(poisonWords.ToList()).Any()) { prefix = "Impure Potion"; type = 2; if (mgeflists.Count() <= impureSkipThreshold) { continue; } impurepotionRecipeCount++; } else { if (mgeflist.Count() <= potionSkipThreshold) { continue; } potionRecipeCount++; } potionString += ("</font><font face='$HandwrittenFont'><font size='18'><br> to make " + prefix + " of: <br></font><font face='$HandwrittenFont'><font size='26'>"); String potionName = "Recipe: "; for (int k = 0; k < mgeflist.Count(); k++) { if (k > 0) { potionName += " and "; potionString += ("<br>"); } potionName += mgeflist[k]; potionString += (mgeflist[k]); } String sstring = ""; if (mgeflist.Count() > 1) { sstring = "s"; } potionString += ("<br></font><font size='14'> Contains " + mgeflist.Count() + " Effect" + sstring); potionString += "<\\font>"; IIngredientGetter[] ingrss = { enumerator.Current, enumerator2.Current, ingr }; combinations.Add(new IngrCombination(potionName, ingrss, mgeflist?.ToArray() !, potionString, type)); } j++; } i++; if (i % percent == 0) { sw.Stop(); Console.WriteLine("time elapsed: " + sw.Elapsed.TotalSeconds + " seconds"); sw.Reset(); } } Console.WriteLine("Creating Leveled lists..."); IEnumerable <IBookGetter> books = from book in state.LoadOrder.PriorityOrder.Book().WinningOverrides() where book.FormKey.Equals(new FormKey(new ModKey("Skyrim", ModType.Master), 0x0F5CB1)) select book; IBookGetter noteTemplate = books.ToList()[0]; Console.WriteLine("Creating " + combinations.Count() + " recipes."); percent = (int)(combinations.Count() * outputPercentage); i = 0; /* Main leveled list that gets added to recipe drop */ LeveledItem mainpotionRecipeLVLI = state.PatchMod.LeveledItems.AddNew(); LeveledItemEntry mainpotionRecipeLVLIentry = new LeveledItemEntry(); mainpotionRecipeLVLI.Entries = new Noggog.ExtendedList <LeveledItemEntry>(); LeveledItemEntryData mainpotionRecipeLVLIentrydata = new LeveledItemEntryData(); GlobalInt mainpotionGlobal = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); mainpotionGlobal.Data = new Random().Next(minChance, maxChance); state.PatchMod.Globals.Set(mainpotionGlobal); mainpotionRecipeLVLI.Global = mainpotionGlobal; mainpotionRecipeLVLI.EditorID = "mainpotionRecipeList"; /* Must split sub leveled lists because it can only hold 128 items */ uint potionRecipeListCount = (potionRecipeCount / 128) + 1; uint poisonRecipeListCount = (poisonRecipeCount / 128) + 1; uint impurepotionRecipeListCount = (impurepotionRecipeCount / 128) + 1; LeveledItem[] potionRecipeLVLIs = new LeveledItem[potionRecipeListCount]; uint masterpotionRecipeListCount = ((potionRecipeListCount + poisonRecipeListCount + impurepotionRecipeListCount) / 128) + 1; LeveledItem[] masterpotionRecipeLVLIs = new LeveledItem[masterpotionRecipeListCount]; LeveledItemEntry[] masterpotionRecipeLVLIentries = new LeveledItemEntry[masterpotionRecipeListCount]; LeveledItemEntryData[] masterpotionRecipeLVLIentriesdata = new LeveledItemEntryData[masterpotionRecipeListCount]; GlobalInt[] masterpotionGlobals = new GlobalInt[masterpotionRecipeListCount]; LeveledItemEntry[] potionRecipeLVLIentries = new LeveledItemEntry[potionRecipeListCount]; LeveledItemEntryData[] potionRecipeLVLIentriesdata = new LeveledItemEntryData[potionRecipeListCount]; GlobalInt[] potionGlobals = new GlobalInt[potionRecipeListCount]; for (int k = 0; k < masterpotionRecipeListCount; k++) { masterpotionRecipeLVLIentries[k] = new LeveledItemEntry(); masterpotionRecipeLVLIentriesdata[k] = new LeveledItemEntryData(); masterpotionRecipeLVLIs[k] = state.PatchMod.LeveledItems.AddNew(); masterpotionRecipeLVLIs[k].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); masterpotionGlobals[k] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); masterpotionGlobals[k].Data = new Random().Next(5, 25); state.PatchMod.Globals.Set(masterpotionGlobals[k]); masterpotionRecipeLVLIs[k].Global = masterpotionGlobals[k]; masterpotionRecipeLVLIs[k].EditorID = "masterpotionRecipeList" + k; masterpotionRecipeLVLIentriesdata[k].Reference = masterpotionRecipeLVLIs[k].FormKey; masterpotionRecipeLVLIentriesdata[k].Level = 1; masterpotionRecipeLVLIentriesdata[k].Count = 1; } for (int l = 0; l < potionRecipeListCount; l++) { potionRecipeLVLIentries[l] = new LeveledItemEntry(); potionRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); potionRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); potionRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); potionGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); potionGlobals[l].Data = new Random().Next(5, 25); state.PatchMod.Globals.Set(potionGlobals[l]); potionRecipeLVLIs[i].Global = potionGlobals[l]; potionRecipeLVLIs[l].EditorID = "potionRecipeList" + l; potionRecipeLVLIentriesdata[l].Reference = potionRecipeLVLIs[l].FormKey; potionRecipeLVLIentriesdata[l].Level = 1; potionRecipeLVLIentriesdata[l].Count = 1; } LeveledItem[] poisonRecipeLVLIs = new LeveledItem[poisonRecipeListCount]; LeveledItemEntry[] poisonRecipeLVLIentries = new LeveledItemEntry[poisonRecipeListCount]; LeveledItemEntryData[] poisonRecipeLVLIentriesdata = new LeveledItemEntryData[poisonRecipeListCount]; GlobalInt[] poisonGlobals = new GlobalInt[poisonRecipeListCount]; for (int l = 0; l < poisonRecipeListCount; l++) { poisonRecipeLVLIentries[l] = new LeveledItemEntry(); poisonRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); poisonRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); poisonRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); poisonGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); poisonGlobals[l].Data = new Random().Next(5, 25); state.PatchMod.Globals.Set(poisonGlobals[l]); poisonRecipeLVLIs[i].Global = poisonGlobals[l]; poisonRecipeLVLIs[l].EditorID = "poisonRecipeList" + l; poisonRecipeLVLIentriesdata[l].Reference = poisonRecipeLVLIs[l].FormKey; poisonRecipeLVLIentriesdata[l].Level = 1; poisonRecipeLVLIentriesdata[l].Count = 1; } LeveledItem[] impurepotionRecipeLVLIs = new LeveledItem[impurepotionRecipeListCount]; LeveledItemEntry[] impurepotionRecipeLVLIentries = new LeveledItemEntry[impurepotionRecipeListCount]; LeveledItemEntryData[] impurepotionRecipeLVLIentriesdata = new LeveledItemEntryData[impurepotionRecipeListCount]; GlobalInt[] impurepotionGlobals = new GlobalInt[impurepotionRecipeListCount]; for (int l = 0; l < impurepotionRecipeListCount; l++) { impurepotionRecipeLVLIentries[l] = new LeveledItemEntry(); impurepotionRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); impurepotionRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); impurepotionRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); impurepotionGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); impurepotionGlobals[l].Data = new Random().Next(5, 25); state.PatchMod.Globals.Set(impurepotionGlobals[l]); impurepotionRecipeLVLIs[i].Global = impurepotionGlobals[l]; impurepotionRecipeLVLIs[l].EditorID = "impurepotionRecipeList" + l; impurepotionRecipeLVLIentriesdata[l].Reference = impurepotionRecipeLVLIs[l].FormKey; impurepotionRecipeLVLIentriesdata[l].Level = 1; impurepotionRecipeLVLIentriesdata[l].Count = 1; } Console.WriteLine("Splitting potions into lists (" + potionRecipeListCount + " " + poisonRecipeListCount + " " + impurepotionRecipeListCount + ")"); uint potionIndex = 0, poisonIndex = 0, impurepotionIndex = 0; IEffectGetter[] effectCache = getAllEffects(ingredients).ToArray(); Dictionary <String, int> nameCache = new Dictionary <String, int>(); foreach (IngrCombination ic in combinations) { if (i % percent == 0) { Console.WriteLine(i + " out of " + combinations.Count() + " recipes created."); } IBook newRecipe = noteTemplate.DeepCopy(); newRecipe.FormKey = state.PatchMod.GetNextFormKey(); newRecipe.Description = ic.RecipeName; newRecipe.Name = ic.RecipeName; newRecipe.BookText = ic.PotionString; newRecipe.Weight = recipeWeight; String?name = "recipeof"; foreach (String?s in ic.MyEffects !) { name += s; } name = name.Replace(" ", String.Empty); int nameIndex = 0; if (nameCache.TryGetValue(name, out nameIndex)) { nameCache[name] = nameIndex + 1; name = name + nameCache[name]; } else { nameCache.Add(name, 0); name = name + "0"; } newRecipe.EditorID = name; state.PatchMod.Books.Set((Book)newRecipe); LeveledItemEntry lie = new LeveledItemEntry(); LeveledItemEntryData data = new LeveledItemEntryData(); data.Level = 1; data.Count = 1; data.Reference = new FormLink <IItemGetter>(newRecipe.FormKey); lie.Data = data; switch (ic.Type) { case 0: potionRecipeLVLIentriesdata[potionIndex / 128].Reference = potionRecipeLVLIs[potionIndex / 128].FormKey; potionRecipeLVLIentries[potionIndex / 128].Data = potionRecipeLVLIentriesdata[potionIndex / 128]; potionRecipeLVLIs[potionIndex / 128].Entries?.Add(lie); potionIndex++; break; case 1: poisonRecipeLVLIentriesdata[poisonIndex / 128].Reference = poisonRecipeLVLIs[poisonIndex / 128].FormKey; poisonRecipeLVLIentries[poisonIndex / 128].Data = poisonRecipeLVLIentriesdata[poisonIndex / 128]; poisonRecipeLVLIs[poisonIndex / 128].Entries?.Add(lie); poisonIndex++; break; case 2: impurepotionRecipeLVLIentriesdata[impurepotionIndex / 128].Reference = impurepotionRecipeLVLIs[impurepotionIndex / 128].FormKey; impurepotionRecipeLVLIentries[impurepotionIndex / 128].Data = impurepotionRecipeLVLIentriesdata[impurepotionIndex / 128]; impurepotionRecipeLVLIs[impurepotionIndex / 128].Entries?.Add(lie); impurepotionIndex++; break; } i++; } Console.WriteLine("Linking recipes to potion leveled list"); IEnumerable <ILeveledItemGetter> lvlilists = from list in state.LoadOrder.PriorityOrder.OnlyEnabled().LeveledItem().WinningOverrides() where list.EditorID?.Equals("LItemPotionAll") ?? true select list; ILeveledItemGetter allList = lvlilists.ToList()[0]; LeveledItem modifiedList = state.PatchMod.LeveledItems.GetOrAddAsOverride(allList); potionIndex = 0; poisonIndex = 0; impurepotionIndex = 0; for (int l = 0; l < masterpotionRecipeListCount; l++) { masterpotionRecipeLVLIentriesdata[l].Reference = masterpotionRecipeLVLIs[l].FormKey; masterpotionRecipeLVLIentries[l].Data = masterpotionRecipeLVLIentriesdata[l]; for (int k = 0; k < 128; k++) { if (potionIndex < potionRecipeLVLIentries.Count()) { masterpotionRecipeLVLIs[l].Entries?.Add(potionRecipeLVLIentries[potionIndex++]); } else if (poisonIndex < poisonRecipeLVLIentries.Count()) { masterpotionRecipeLVLIs[l].Entries?.Add(poisonRecipeLVLIentries[poisonIndex++]); } else if (impurepotionIndex < impurepotionRecipeLVLIentries.Count()) { masterpotionRecipeLVLIs[l].Entries?.Add(impurepotionRecipeLVLIentries[impurepotionIndex++]); } else { break; } } mainpotionRecipeLVLI.Entries?.Add(masterpotionRecipeLVLIentries[l]); } foreach (LeveledItem li in potionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in poisonRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in impurepotionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in masterpotionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } mainpotionRecipeLVLIentrydata.Reference = mainpotionRecipeLVLI.FormKey; mainpotionRecipeLVLIentry.Data = mainpotionRecipeLVLIentrydata; mainpotionRecipeLVLIentrydata.Count = 1; mainpotionRecipeLVLIentrydata.Level = 1; modifiedList.Entries?.Add(mainpotionRecipeLVLIentry); state.PatchMod.LeveledItems.Set(mainpotionRecipeLVLI); Console.WriteLine("Adding recipes to defined containers"); IEnumerable <IContainerGetter> chests = from list in state.LoadOrder.PriorityOrder.OnlyEnabled().Container().WinningOverrides() where containerEditorIDs?.ToList().Contains(list.EditorID !) ?? true select list; ContainerEntry potionListContainerEntry = new ContainerEntry(); ContainerItem potionListContainerItem = new ContainerItem(); potionListContainerItem.Item = mainpotionRecipeLVLI.FormKey; potionListContainerItem.Count = 1; potionListContainerEntry.Item = potionListContainerItem; foreach (IContainerGetter chest in chests) { Container rChest = state.PatchMod.Containers.GetOrAddAsOverride(chest); rChest.Items?.Add(potionListContainerEntry); } }
public static void RunPatch(IPatcherState <ISkyrimMod, ISkyrimModGetter> state) { badKeywordsF = (from keyword in state.LoadOrder.PriorityOrder.OnlyEnabled().Keyword().WinningOverrides() where badKeywords.Contains(keyword.EditorID) select(IFormLink <IKeyword>)(new FormLink <IKeyword>(keyword.FormKey))).ToList(); IEnumerable <IIngredientGetter> ingredients = state.LoadOrder.PriorityOrder.OnlyEnabled().Ingredient().WinningOverrides().Where(x => !SkipPlugins.Contains(x.FormKey.ModKey.Name.ToLower())).Where(x => (!SkipIngrs.Intersect(x.Name?.ToString()?.Split() !).Any() || SkipIngrs.Contains(x.Name?.ToString()))).Where(x => !String.IsNullOrEmpty(x.Name?.String)).ToList(); allIngredients = ingredients; percent = (int)(ingredients.Count() * outputPercentage); totalIngredientCount = ingredients.Count(); Thread[] threads = new Thread[workerThreadCount]; int partitionsize = (ingredients.Count() / workerThreadCount); /* Split ingredient list evenly across threads */ IEnumerable <IIngredientGetter>[] ingredientsL = ingredients.Partition(partitionsize).ToArray(); /* If there is a remainder add it to last thread */ if (ingredientsL.Length > workerThreadCount) { ingredientsL[ingredientsL.Length - 2] = ingredientsL[ingredientsL.Length - 2].Concat(ingredientsL[ingredientsL.Length - 1]); } sw.Start(); Console.WriteLine("Using " + workerThreadCount + " threads to handle " + partitionsize + " ingredients each."); int startindex = 0; for (int u = 0; u < workerThreadCount; u++) { ListProcessor lp = new ListProcessor(u, state, ingredientsL[u], startindex); threads[u] = new Thread(new ThreadStart(lp.run)); threads[u].Start(); startindex += partitionsize; } while (!finishedProcessing) { if (totalProcessedCount % percent == 0) { if (reportedCount != totalProcessedCount) { Console.WriteLine(totalProcessedCount + " out of " + ingredients.Count() + " ingredients processed."); sw.Stop(); Console.WriteLine("time elapsed: " + sw.Elapsed.TotalSeconds + " seconds"); sw.Reset(); sw.Start(); reportedCount = totalProcessedCount; } } Thread.Sleep(100); } ; Console.WriteLine("Terminating Threads."); for (int u = 0; u < workerThreadCount; u++) { threads[u].Join(); } Console.WriteLine("Creating Leveled lists..."); IEnumerable <IBookGetter> books = from book in state.LoadOrder.PriorityOrder.Book().WinningOverrides() where book.FormKey.Equals(new FormKey(new ModKey("Skyrim", ModType.Master), 0x0F5CB1)) select book; IBookGetter noteTemplate = books.ToList()[0]; Console.WriteLine("Creating " + combinations.Count + " recipes."); percent = (int)(combinations.Count * outputPercentage); int i = 0; /* Main leveled list that gets added to recipe drop */ LeveledItem mainpotionRecipeLVLI = state.PatchMod.LeveledItems.AddNew(); LeveledItemEntry mainpotionRecipeLVLIentry = new LeveledItemEntry(); mainpotionRecipeLVLI.Entries = new Noggog.ExtendedList <LeveledItemEntry>(); LeveledItemEntryData mainpotionRecipeLVLIentrydata = new LeveledItemEntryData(); GlobalInt mainpotionGlobal = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); mainpotionGlobal.Data = new Random().Next(minChance, maxChance); state.PatchMod.Globals.Set(mainpotionGlobal); mainpotionRecipeLVLI.Global = mainpotionGlobal; mainpotionRecipeLVLI.EditorID = "mainpotionRecipeList"; /* Must split sub leveled lists because it can only hold 128 items */ uint potionRecipeListCount = (potionRecipeCount / 128) + 1; uint poisonRecipeListCount = (poisonRecipeCount / 128) + 1; uint impurepotionRecipeListCount = (impurepotionRecipeCount / 128) + 1; LeveledItem[] potionRecipeLVLIs = new LeveledItem[potionRecipeListCount]; uint masterpotionRecipeListCount = ((potionRecipeListCount + poisonRecipeListCount + impurepotionRecipeListCount) / 128) + 1; LeveledItem[] masterpotionRecipeLVLIs = new LeveledItem[masterpotionRecipeListCount]; LeveledItemEntry[] masterpotionRecipeLVLIentries = new LeveledItemEntry[masterpotionRecipeListCount]; LeveledItemEntryData[] masterpotionRecipeLVLIentriesdata = new LeveledItemEntryData[masterpotionRecipeListCount]; GlobalInt[] masterpotionGlobals = new GlobalInt[masterpotionRecipeListCount]; LeveledItemEntry[] potionRecipeLVLIentries = new LeveledItemEntry[potionRecipeListCount]; LeveledItemEntryData[] potionRecipeLVLIentriesdata = new LeveledItemEntryData[potionRecipeListCount]; GlobalInt[] potionGlobals = new GlobalInt[potionRecipeListCount]; for (int k = 0; k < masterpotionRecipeListCount; k++) { masterpotionRecipeLVLIentries[k] = new LeveledItemEntry(); masterpotionRecipeLVLIentriesdata[k] = new LeveledItemEntryData(); masterpotionRecipeLVLIs[k] = state.PatchMod.LeveledItems.AddNew(); masterpotionRecipeLVLIs[k].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); masterpotionGlobals[k] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); masterpotionGlobals[k].Data = new Random().Next(5, 25);//Chance of picking a recipe from this list state.PatchMod.Globals.Set(masterpotionGlobals[k]); masterpotionRecipeLVLIs[k].Global = masterpotionGlobals[k]; masterpotionRecipeLVLIs[k].EditorID = "masterpotionRecipeList" + k; masterpotionRecipeLVLIentriesdata[k].Reference = masterpotionRecipeLVLIs[k].FormKey; masterpotionRecipeLVLIentriesdata[k].Level = 1; masterpotionRecipeLVLIentriesdata[k].Count = 1; } for (int l = 0; l < potionRecipeListCount; l++) { potionRecipeLVLIentries[l] = new LeveledItemEntry(); potionRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); potionRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); potionRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); potionGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); potionGlobals[l].Data = new Random().Next(5, 25);//Chance of picking a recipe from this list state.PatchMod.Globals.Set(potionGlobals[l]); potionRecipeLVLIs[i].Global = potionGlobals[l]; potionRecipeLVLIs[l].EditorID = "potionRecipeList" + l; potionRecipeLVLIentriesdata[l].Reference = potionRecipeLVLIs[l].FormKey; potionRecipeLVLIentriesdata[l].Level = 1; potionRecipeLVLIentriesdata[l].Count = 1; } LeveledItem[] poisonRecipeLVLIs = new LeveledItem[poisonRecipeListCount]; LeveledItemEntry[] poisonRecipeLVLIentries = new LeveledItemEntry[poisonRecipeListCount]; LeveledItemEntryData[] poisonRecipeLVLIentriesdata = new LeveledItemEntryData[poisonRecipeListCount]; GlobalInt[] poisonGlobals = new GlobalInt[poisonRecipeListCount]; for (int l = 0; l < poisonRecipeListCount; l++) { poisonRecipeLVLIentries[l] = new LeveledItemEntry(); poisonRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); poisonRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); poisonRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); poisonGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); poisonGlobals[l].Data = new Random().Next(5, 25);//Chance of picking a recipe from this list state.PatchMod.Globals.Set(poisonGlobals[l]); poisonRecipeLVLIs[i].Global = poisonGlobals[l]; poisonRecipeLVLIs[l].EditorID = "poisonRecipeList" + l; poisonRecipeLVLIentriesdata[l].Reference = poisonRecipeLVLIs[l].FormKey; poisonRecipeLVLIentriesdata[l].Level = 1; poisonRecipeLVLIentriesdata[l].Count = 1; } LeveledItem[] impurepotionRecipeLVLIs = new LeveledItem[impurepotionRecipeListCount]; LeveledItemEntry[] impurepotionRecipeLVLIentries = new LeveledItemEntry[impurepotionRecipeListCount]; LeveledItemEntryData[] impurepotionRecipeLVLIentriesdata = new LeveledItemEntryData[impurepotionRecipeListCount]; GlobalInt[] impurepotionGlobals = new GlobalInt[impurepotionRecipeListCount]; for (int l = 0; l < impurepotionRecipeListCount; l++) { impurepotionRecipeLVLIentries[l] = new LeveledItemEntry(); impurepotionRecipeLVLIentriesdata[l] = new LeveledItemEntryData(); impurepotionRecipeLVLIs[l] = state.PatchMod.LeveledItems.AddNew(); impurepotionRecipeLVLIs[l].Entries = new Noggog.ExtendedList <LeveledItemEntry>(); impurepotionGlobals[l] = new GlobalInt(state.PatchMod.GetNextFormKey(), SkyrimRelease.SkyrimSE); impurepotionGlobals[l].Data = new Random().Next(5, 25);//Chance of picking a recipe from this list state.PatchMod.Globals.Set(impurepotionGlobals[l]); impurepotionRecipeLVLIs[i].Global = impurepotionGlobals[l]; impurepotionRecipeLVLIs[l].EditorID = "impurepotionRecipeList" + l; impurepotionRecipeLVLIentriesdata[l].Reference = impurepotionRecipeLVLIs[l].FormKey; impurepotionRecipeLVLIentriesdata[l].Level = 1; impurepotionRecipeLVLIentriesdata[l].Count = 1; } Console.WriteLine("Splitting potions into lists (" + potionRecipeListCount + " " + poisonRecipeListCount + " " + impurepotionRecipeListCount + ")"); uint potionIndex = 0, poisonIndex = 0, impurepotionIndex = 0; Dictionary <String, int> nameCache = new Dictionary <String, int>(); foreach (IngrCombination ic in combinations) { if (i % percent == 0) { Console.WriteLine(i + " out of " + combinations.Count + " recipes created."); } IBook newRecipe = noteTemplate.DeepCopy(); newRecipe.FormKey = state.PatchMod.GetNextFormKey(); String prefix = "[Potion]"; if (ic.Type == 1) { prefix = "[Poison]"; } if (ic.Type == 2) { prefix = "[Impure Potion]"; } newRecipe.Description = prefix + ic.RecipeName; newRecipe.Name = ic.RecipeName; newRecipe.BookText = ic.PotionString; newRecipe.Weight = recipeWeight; newRecipe.Value = recipeValue; String?name = "recipeof"; foreach (String?s in ic.MyEffects !) { name += s; } name = name.Replace(" ", String.Empty); int nameIndex = 0; if (nameCache.TryGetValue(name, out nameIndex)) { nameCache[name] = nameIndex + 1; name = name + nameCache[name]; } else { nameCache.Add(name, 0); name = name + "0"; } newRecipe.EditorID = name; /* Add ingredients to CACO learning recipe script */ if (state.LoadOrder.ContainsKey(ModKey.FromNameAndExtension("Complete Alchemy & Cooking Overhaul.esp"))) { String[] s = (from scriptentry in newRecipe.VirtualMachineAdapter?.Scripts where scriptentry.Name.Equals("CACO_AlchemyRecipeScript") select scriptentry.Name).ToArray(); if (s.Length < 1 && learnEffectsFromRecipe)//For adding recipe to a brand new item (not a copy of a vanilla recipe) { ScriptEntry cacoscript = new ScriptEntry(); cacoscript.Name = "CACO_AlchemyRecipeScript"; newRecipe.VirtualMachineAdapter?.Scripts.Add(cacoscript); } if (newRecipe.VirtualMachineAdapter?.Scripts != null)//For modiying a copy of a vanilla recipe modified by CACO(default) { foreach (ScriptEntry se in newRecipe.VirtualMachineAdapter?.Scripts !) { if (se == null) { continue; } if (se.Name.Equals("CACO_AlchemyRecipeScript")) { if (!learnEffectsFromRecipe) { newRecipe.VirtualMachineAdapter?.Scripts?.Remove(se); continue; } int[,] ingrEffectIndex = new int[3, 4]; for (int j = 0; j < ingrEffectIndex.GetLength(0); j++) { for (int k = 0; k < ingrEffectIndex.GetLength(1); k++) { ingrEffectIndex[j, k] = -1; } } for (int j = 0; j < ic.MyIngrs.Length; j++) { int offset = 0; for (int k = 0; k < ic.MyIngrs[j].Effects.Count; k++) { foreach (String mgefname in ic.MyEffects) { state.LinkCache.TryResolve <IMagicEffectGetter>(ic.MyIngrs[j].Effects[k].BaseEffect.FormKey, out var mgeffect); if (mgeffect?.Name?.String?.Equals(mgefname) ?? true) { ingrEffectIndex[j, offset++] = k; } } } } bool[,] exists = new bool[3, 4]; bool[] rexists = new bool[3]; bool trexist = false, nvarexist = false, arrexist = false; foreach (ScriptProperty sp in se.Properties)//Scan CACO learning script properties { switch (sp.Name) { case "ThisRecipe": sp.Flags = ScriptProperty.Flag.Edited; ((ScriptObjectProperty)sp).Object = new FormLink <ISkyrimMajorRecordGetter>(newRecipe.FormKey); trexist = true; break; case "NoValueAfterRead": sp.Flags = ScriptProperty.Flag.Edited; ((ScriptBoolProperty)sp).Data = hasValueAfterRead; nvarexist = true; break; case "CACO_AlchemyRecipesRead": arrexist = true; break; } for (int j = 0; j < 3; j++) { if (sp.Name.Equals("Ingredient0" + (j + 1))) { if (ic.MyIngrs.Length > j) { sp.Flags = ScriptProperty.Flag.Edited; ((ScriptObjectProperty)sp).Object = new FormLink <ISkyrimMajorRecordGetter>(ic.MyIngrs[j].FormKey); rexists[j] = true; } } } for (int j = 0; j < 3; j++) { for (int k = 0; k < 4; k++) { if (sp.Name.Equals("Ingredient0" + (j + 1) + "Effect" + (k + 1))) { if (ingrEffectIndex[j, k] != -1) { ((ScriptIntProperty)sp).Data = ingrEffectIndex[j, k]; exists[j, k] = true; } } } } } for (int j = 0; j < rexists.Length; j++) { if (ic.MyIngrs.Length > j) { if (!rexists[j]) { ScriptObjectProperty sop = new ScriptObjectProperty(); sop.Object = new FormLink <ISkyrimMajorRecordGetter>(ic.MyIngrs[j].FormKey); sop.Name = "Ingredient0" + (j + 1); sop.Flags = ScriptProperty.Flag.Edited; se.Properties.Add(sop); } } } for (int j = 0; j < exists.GetLength(0); j++) { for (int k = 0; k < exists.GetLength(1); k++) { if (ic.MyIngrs.Length > j) { if (!exists[j, k] && ingrEffectIndex[j, k] != -1) { ScriptIntProperty sip = new ScriptIntProperty(); sip.Data = ingrEffectIndex[j, k]; sip.Name = "Ingredient0" + (j + 1) + "Effect" + (k + 1); sip.Flags = ScriptProperty.Flag.Edited; se.Properties.Add(sip); } } } } if (!trexist) { ScriptObjectProperty sop = new ScriptObjectProperty(); sop.Object = new FormLink <ISkyrimMajorRecordGetter>(newRecipe.FormKey); sop.Name = "ThisRecipe"; sop.Flags = ScriptProperty.Flag.Edited; se.Properties.Add(sop); } if (!nvarexist) { ScriptBoolProperty sbp = new ScriptBoolProperty(); sbp.Data = hasValueAfterRead; sbp.Name = "NoValueAfterRead"; sbp.Flags = ScriptProperty.Flag.Edited; se.Properties.Add(sbp); } if (arrexist) { FormList fl = new FormList(new FormKey(new ModKey("Complete Alchemy & Cooking Overhaul.esp", ModType.Plugin), 0xA2C667), SkyrimRelease.SkyrimSE); ScriptObjectProperty sop = new ScriptObjectProperty(); sop.Object = fl; sop.Name = "CACO_AlchemyRecipesRead"; sop.Flags = ScriptProperty.Flag.Edited; se.Properties.Add(sop); } } } } } state.PatchMod.Books.Set((Book)newRecipe); LeveledItemEntry lie = new LeveledItemEntry(); LeveledItemEntryData data = new LeveledItemEntryData(); data.Level = 1; data.Count = 1; data.Reference = new FormLink <IItemGetter>(newRecipe.FormKey); lie.Data = data; switch (ic.Type) { case 0: potionRecipeLVLIentriesdata[potionIndex / 128].Reference = potionRecipeLVLIs[potionIndex / 128].FormKey; potionRecipeLVLIentries[potionIndex / 128].Data = potionRecipeLVLIentriesdata[potionIndex / 128]; potionRecipeLVLIs[potionIndex / 128].Entries?.Add(lie); potionIndex++; break; case 1: poisonRecipeLVLIentriesdata[poisonIndex / 128].Reference = poisonRecipeLVLIs[poisonIndex / 128].FormKey; poisonRecipeLVLIentries[poisonIndex / 128].Data = poisonRecipeLVLIentriesdata[poisonIndex / 128]; poisonRecipeLVLIs[poisonIndex / 128].Entries?.Add(lie); poisonIndex++; break; case 2: impurepotionRecipeLVLIentriesdata[impurepotionIndex / 128].Reference = impurepotionRecipeLVLIs[impurepotionIndex / 128].FormKey; impurepotionRecipeLVLIentries[impurepotionIndex / 128].Data = impurepotionRecipeLVLIentriesdata[impurepotionIndex / 128]; impurepotionRecipeLVLIs[impurepotionIndex / 128].Entries?.Add(lie); impurepotionIndex++; break; } i++; } Console.WriteLine("Linking recipes to potion leveled list"); IEnumerable <ILeveledItemGetter> lvlilists = from list in state.LoadOrder.PriorityOrder.OnlyEnabled().LeveledItem().WinningOverrides() where list.EditorID?.Equals("LItemPotionAll") ?? true select list; ILeveledItemGetter allList = lvlilists.ToList()[0]; LeveledItem modifiedList = state.PatchMod.LeveledItems.GetOrAddAsOverride(allList); potionIndex = 0; poisonIndex = 0; impurepotionIndex = 0; for (int l = 0; l < masterpotionRecipeListCount; l++) { masterpotionRecipeLVLIentriesdata[l].Reference = masterpotionRecipeLVLIs[l].FormKey; masterpotionRecipeLVLIentries[l].Data = masterpotionRecipeLVLIentriesdata[l]; for (int k = 0; k < 128; k++) { if (potionIndex < potionRecipeLVLIentries.Length) { masterpotionRecipeLVLIs[l].Entries?.Add(potionRecipeLVLIentries[potionIndex++]); } else if (poisonIndex < poisonRecipeLVLIentries.Length) { masterpotionRecipeLVLIs[l].Entries?.Add(poisonRecipeLVLIentries[poisonIndex++]); } else if (impurepotionIndex < impurepotionRecipeLVLIentries.Length) { masterpotionRecipeLVLIs[l].Entries?.Add(impurepotionRecipeLVLIentries[impurepotionIndex++]); } else { break; } } mainpotionRecipeLVLI.Entries?.Add(masterpotionRecipeLVLIentries[l]); } foreach (LeveledItem li in potionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in poisonRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in impurepotionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } foreach (LeveledItem li in masterpotionRecipeLVLIs) { state.PatchMod.LeveledItems.Set(li); } mainpotionRecipeLVLIentrydata.Reference = mainpotionRecipeLVLI.FormKey; mainpotionRecipeLVLIentry.Data = mainpotionRecipeLVLIentrydata; mainpotionRecipeLVLIentrydata.Count = 1; mainpotionRecipeLVLIentrydata.Level = 1; modifiedList.Entries?.Add(mainpotionRecipeLVLIentry); state.PatchMod.LeveledItems.Set(mainpotionRecipeLVLI); Console.WriteLine("Adding recipes to defined containers"); IEnumerable <IContainerGetter> chests = from list in state.LoadOrder.PriorityOrder.OnlyEnabled().Container().WinningOverrides() where containerEditorIDs?.ToList().Contains(list.EditorID !) ?? true select list; ContainerEntry potionListContainerEntry = new ContainerEntry(); ContainerItem potionListContainerItem = new ContainerItem(); potionListContainerItem.Item = mainpotionRecipeLVLI.FormKey; potionListContainerItem.Count = 1; potionListContainerEntry.Item = potionListContainerItem; foreach (IContainerGetter chest in chests) { Container rChest = state.PatchMod.Containers.GetOrAddAsOverride(chest); rChest.Items?.Add(potionListContainerEntry); } }