public void Analyze(List <FFXIVAetheryte> iAetherytes, List <FFXIVGatheringNode> iNodes, ref Dictionary <string, double> dictionaryClosestAetherytes) { Status = "Unknown"; IsValid = false; try { string contentGrid = File.ReadAllText(GridFile.FullName); if (contentGrid == "") { Status = "Empty Grid"; return; } ParseFromLine(contentGrid); //Finding item gathering nodes bool noGatheringNodeMode = false; List <FFXIVGatheringNode> correspondingNodes = new List <FFXIVGatheringNode>(); foreach (FFXIVGatheringNode node in iNodes) { if (null == node) { continue; } string foundItemName = node.NodeItems.Find(x => x != null && x.ToLower().Trim() == ItemName.ToLower().Trim()); if (foundItemName != null && foundItemName != "") { correspondingNodes.Add(node); } } if (correspondingNodes.Count <= 0 && ItemName != "") { List <FFXIVSearchItem> resultGarlandTools = GarlandTool.Search(ItemName, null, FFXIVItem.TypeItem.Gathered); if (resultGarlandTools.Count > 0) { List <FFXIVGatheringNode> correspondingNodesFromGarland = GarlandTool.GetGatheringNodesFromItem(resultGarlandTools[0].ID); foreach (FFXIVGatheringNode garlandNode in correspondingNodesFromGarland) { string foundItemName = garlandNode.NodeItems.Find(x => x != null && x.ToLower().Trim() == ItemName.ToLower().Trim()); if (foundItemName != null && foundItemName != "") { correspondingNodes.Add(garlandNode); } /* * FFXIVGatheringNode bestNode = null; * double maxCorrespondance = -1; * foreach (FFXIVGatheringNode node in iNodes) * { * if(node.Zone.ToLower().Trim() != garlandNode.Zone.ToLower().Trim()) * { * continue; * } * * double nbSameItem = 0; * double nbTotalItem = node.NodeItems.Count; * * foreach(string itemName in node.NodeItems) * { * if (null != garlandNode.NodeItems.Find(x => x != null && x.ToLower().Trim() == itemName.ToLower().Trim())) * { * nbSameItem += 1.0; * } * } * double correspondance = 100.0 * nbSameItem / nbTotalItem; * if(maxCorrespondance < correspondance) * { * maxCorrespondance = correspondance; * bestNode = node; * } * } * if (maxCorrespondance < 0) continue; * if (null == bestNode) continue; * correspondingNodes.Add(bestNode); */ } } noGatheringNodeMode = correspondingNodes.Count > 0; } AllNodes = correspondingNodes; //Finding closest node double minDistance = -1; if (!noGatheringNodeMode) { foreach (FFXIVGatheringNode node in correspondingNodes) { if (null == node) { continue; } double nodeDistance = -1; foreach (FFXIVPosition point in Points) { double distance = node.Position.PlanarDistanceTo(point); if (minDistance < 0 || distance < minDistance) { minDistance = distance; ClosestNode = node; ClosestNodeDistance = minDistance; } if (nodeDistance < 0 || distance < nodeDistance) { nodeDistance = distance; } } AllNodesDistance.Add(nodeDistance); } if (minDistance > 50) { Status = "Too far from closest gathering node."; return; } if (null == ClosestNode) { Status = "No gathering node."; return; } } else { if (AllNodes.Count == 1) { ClosestNode = AllNodes[0]; } foreach (FFXIVGatheringNode node in correspondingNodes) { AllNodesDistance.Add(-1); } } string statusPrefix = ""; if (noGatheringNodeMode) { statusPrefix = "[No-Node] "; } //Finding zone aetherytes List <FFXIVAetheryte> listZoneAetherytes = new List <FFXIVAetheryte>(); foreach (FFXIVAetheryte aetherythe in iAetherytes) { if (noGatheringNodeMode) { foreach (FFXIVGatheringNode node in correspondingNodes) { if (aetherythe.Zone == node.Zone) { listZoneAetherytes.Add(aetherythe); } } } else { if (aetherythe.Zone == ClosestNode.Zone) { listZoneAetherytes.Add(aetherythe); } } } //Finding closest aetheryte double minDistanceAetheryte = -1; List <FFXIVPosition> listAetheryteClosePoints = new List <FFXIVPosition>(); foreach (FFXIVAetheryte aetherythe in listZoneAetherytes) { if (null == aetherythe) { continue; } double distanceAetheryte = -1; foreach (FFXIVPosition point in Points) { double distance = aetherythe.Position.PlanarDistanceTo(point); if (minDistanceAetheryte < 0 || distance < minDistanceAetheryte) { minDistanceAetheryte = distance; ClosestAetheryte = aetherythe; ClosestAetheryteDistance = minDistanceAetheryte; } if (distanceAetheryte < 0 || distance < distanceAetheryte) { distanceAetheryte = distance; } if (distance < 50) { listAetheryteClosePoints.Add(point); } } ZoneAetherytes.Add(aetherythe); ZoneAetherytesDistance.Add(distanceAetheryte); } if (minDistanceAetheryte > 40) { Status = statusPrefix + "Too far from closest aetheryte."; return; } if (null == ClosestAetheryte) { Status = statusPrefix + "No Aetheryte."; return; } if (listAetheryteClosePoints.Count < 1) { Status = statusPrefix + "Not enough close points."; return; } ListAetheryteClosePoints = listAetheryteClosePoints; if (dictionaryClosestAetherytes.ContainsKey(ItemName)) { double distance = dictionaryClosestAetherytes[ItemName]; if (distance < minDistanceAetheryte) { Status = statusPrefix + "Other grid is closer to grid points."; return; } } dictionaryClosestAetherytes[ItemName] = minDistanceAetheryte; Status = statusPrefix + "OK"; IsValid = true; } catch (Exception e) { Status = e.Message; } }
public static string GenerateScenario(List <FFXIVItem> iItemToGenerate, MiqobotScenarioOption iOptions, System.Windows.Forms.TextBox iLogBox, out string fullScenario) { fullScenario = ""; if (null == iOptions) { Service_Misc.LogText(iLogBox, "Whoooops wrong options selected..."); return(null); } Service_Misc.LogText(iLogBox, "Let's whisper to miqobot ears..."); MiqoCraftOptions options = new MiqoCraftOptions(); options.Load(OptionLocation.UserOption); //Login to miqobot forums CookieCollection logMiqobotCookies = Miqobot.LogInForum(); if (null != logMiqobotCookies) { Service_Misc.LogText(iLogBox, "I'm logged into miqobot forum !"); } else { Service_Misc.LogText(iLogBox, "Failed to log into miqobot forum... well you'll have to manually gather stuff, sorry !"); } //Listing items List <FFXIVItem> allItems = new List <FFXIVItem>(); List <int> allItemsQuantity = new List <int>(); string scenarioName = ""; foreach (FFXIVItem iItem in iItemToGenerate) { if (null == iItem) { continue; } if (scenarioName != "") { scenarioName += ","; } scenarioName += iItem.Name; RecFindItems(iItem, iOptions.Quantity, ref allItems, ref allItemsQuantity, iOptions.CustomQuantities); } if (iItemToGenerate.Count > 5) { scenarioName = iItemToGenerate.Count + " Items"; } fullScenario = ""; string allGrids = ""; string allRotations = ""; string allPreset = ""; List <string> catalysts = GetCatalysts(); if (!iOptions.IgnoreCatalysts) { catalysts.Clear(); } //Creating rotations allRotations += "gatherrotation.Collect Gathering +15%" + Environment.NewLine; allRotations += "[31,9,22,26,25,[34,[35,29,36,26]],25,[34,[35,29,36,26]],23,1,32]" + Environment.NewLine; allRotations += "gatherrotation.Collect Gathering +5%" + Environment.NewLine; allRotations += "[31,9,22,26,25,[34,[35,29,36,26]],25,[34,[35,29,36,26]],23,0]" + Environment.NewLine; allRotations += "gatherrotation.Gathering +15%/HQ +10%" + Environment.NewLine; allRotations += "[31,1,3]" + Environment.NewLine; allRotations += "gatherrotation.HQ +10%" + Environment.NewLine; allRotations += "[31,3]" + Environment.NewLine; allRotations += "gatherrotation.Gathering +5%/HQ +10%" + Environment.NewLine; allRotations += "[31,0,3]" + Environment.NewLine; allRotations += MiqoCraftCore.GetCacheRotations() + Environment.NewLine;; //Creating default preset allPreset += "solverpreset.recommended" + Environment.NewLine; allPreset += "{\"cpchunk\":4,\"skillinnovation\":true,\"skillmanipulation\":false,\"skillwastenot1\":false,\"skillwastenot2\":false,\"skillwhistle\":false,\"progresssolver\":true,\"enforcebb100\":true,\"enforcepbp100\":true,\"ignorequality\":false,\"reclaimhqon\":false,\"reclaimhqvalue\":85,\"reclaimqualityon\":false,\"reclaimqualityvalue\":4000}" + Environment.NewLine; allPreset += MiqoCraftCore.GetCacheSolverPresets() + Environment.NewLine;; //Header Service_Misc.LogText(iLogBox, "Creating scenario header..."); fullScenario += "\""; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "// " + scenarioName + Environment.NewLine; fullScenario += "// Script Generated by MiqoCrafter" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "// Copyright 2019 - Shishio Valentine" + Environment.NewLine; fullScenario += "// [email protected]" + Environment.NewLine; fullScenario += "// http://patreon.com/miqocrafter" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; //Prerequisite fullScenario += Environment.NewLine; fullScenario += Environment.NewLine; fullScenario += "// Prerequisite" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "//" + Environment.NewLine; if (iOptions.IgnoreCatalysts) { fullScenario += "// You will need to buy or obtain those items using external means, cause Miqocrafter can't automate it [Yet], or they are ignored catalysts" + Environment.NewLine; } else { fullScenario += "// You will need to buy or obtain those items using external means, cause Miqocrafter can't automate it [Yet]" + Environment.NewLine; } for (int i = 0; i < allItems.Count && i < allItemsQuantity.Count; i++) { FFXIVItem iItem = allItems[i]; if (null == iItem) { continue; } int quantity = allItemsQuantity[i]; FFXIVCraftingOptions itemOptions = options.GetOption(iItem); if (iItem.Type == FFXIVItem.TypeItem.NPC || iItem.Type == FFXIVItem.TypeItem.Unkwown || null != catalysts.Find(x => x != null && x.ToLower() == iItem.Name.ToLower()) || (null != itemOptions && itemOptions.IgnoreItem)) { fullScenario += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; } } //Reduced fullScenario += Environment.NewLine; fullScenario += Environment.NewLine; fullScenario += "// Reduced Items" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "//" + Environment.NewLine; fullScenario += "// You will need to manually reduce those items, cause Miqocrafter can't automate it [Yet]" + Environment.NewLine; fullScenario += "// However Miqocrafter will try to gather/craft/retrieve the items that need to be reduced." + Environment.NewLine; for (int i = 0; i < allItems.Count && i < allItemsQuantity.Count; i++) { FFXIVItem iItem = allItems[i]; if (null == iItem) { continue; } int quantity = allItemsQuantity[i]; FFXIVReducedItem reducedItem = null; if (iItem is FFXIVReducedItem) { reducedItem = iItem as FFXIVReducedItem; } if (null != reducedItem) { if (null != reducedItem.ReducedFrom) { fullScenario += "// - " + iItem.Name + " (Reduced from " + reducedItem.ReducedFrom + " - " + iItem.UrlGarland + ")" + Environment.NewLine; } else { fullScenario += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; } } } //Errors fullScenario += "ERRORS_ITEMS_DUMMY"; fullScenario += "\","; //Getting miqo preset content string miqoPresetContent = ""; if (null != iOptions.MiqoPresetPath && "" != iOptions.MiqoPresetPath) { FileInfo presetFile = new FileInfo(Path.Combine(iOptions.MiqoPresetPath, "presets.miqo")); if (presetFile.Exists) { miqoPresetContent = File.ReadAllText(presetFile.FullName); } } if (miqoPresetContent == "" && null != options.MiqoPresetPath && "" != options.MiqoPresetPath) { FileInfo presetFile = new FileInfo(Path.Combine(options.MiqoPresetPath, "presets.miqo")); if (presetFile.Exists) { miqoPresetContent = File.ReadAllText(presetFile.FullName); } } //Gathering stuff string lastTeleport = ""; string errorContent = ""; Service_Misc.LogText(iLogBox, "Creating gathering grids..."); fullScenario += "\""; fullScenario += Environment.NewLine; fullScenario += Environment.NewLine; fullScenario += "// Gathered Items" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "//" + Environment.NewLine; fullScenario += "// Miqocrafter will use the gathering scenario from https://miqobot.com/forum/forums/topic/index-gathering-grids/ to retrieve those." + Environment.NewLine; for (int i = 0; i < allItems.Count && i < allItemsQuantity.Count; i++) { FFXIVItem iItem = allItems[i]; if (null == iItem) { continue; } int quantity = allItemsQuantity[i] / iOptions.NbPerNode + 1; if (!(iItem is FFXIVGatheredItem)) { continue; } FFXIVGatheredItem gatheredItem = iItem as FFXIVGatheredItem; if (null != catalysts.Find(x => x != null && x.ToLower() == iItem.Name.ToLower())) { continue; } FFXIVCraftingOptions itemOptions = options.GetOption(iItem); if (null != itemOptions && itemOptions.IgnoreItem) { continue; } if (null != gatheredItem) { Service_Misc.LogText(iLogBox, "Searching for item grid : " + iItem + ""); if (gatheredItem.Slot.Count <= 0) { errorContent += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; fullScenario += "// Failed to retrieve item gathering slot from FGarlandTool, can't gather this item " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; continue; } if (null != logMiqobotCookies) { List <MiqoItemPage> listItemPage = Miqobot.GetURLItem(iItem.Name, logMiqobotCookies, null); if (listItemPage.Count <= 0) { errorContent += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; fullScenario += "// Failed to retrieve item gathering scenario from miqobot forums, can't gather this item " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; } else { string initName = ""; string grid = null; for (int j = 0; j < listItemPage.Count && null == grid; j++) { grid = Miqobot.GetLastGrid(iItem.Name, logMiqobotCookies, listItemPage[j], out initName); } if (null != grid) { //Finding right zone string zone = ""; string type = ""; string slot = ""; string time = ""; string gatheringType = ""; if (gatheredItem.Slot.Count == 1) { //No ambiguity zone = gatheredItem.Zones[0]; type = gatheredItem.Types[0]; slot = gatheredItem.Slot[0]; time = gatheredItem.Times[0]; gatheringType = gatheredItem.GatheringTypes[0]; } else { if (zone == "") { foreach (string zoneName in gatheredItem.Zones) { string initNameCorrected = initName.Replace(" ", "").ToLower(); string gridDataCorrected = grid.Replace(" ", "").ToLower(); string zoneNameCorrected = zoneName.ToLower().Replace("the ", "").Replace(" ", "").Trim(); if (initNameCorrected.Contains(zoneNameCorrected)) { int index = gatheredItem.Zones.IndexOf(zoneName); zone = gatheredItem.Zones[index]; type = gatheredItem.Types[index]; slot = gatheredItem.Slot[index]; time = gatheredItem.Times[index]; gatheringType = gatheredItem.GatheringTypes[index]; break; } if (gridDataCorrected.Contains(zoneNameCorrected)) { int index = gatheredItem.Zones.IndexOf(zoneName); zone = gatheredItem.Zones[index]; type = gatheredItem.Types[index]; slot = gatheredItem.Slot[index]; time = gatheredItem.Times[index]; gatheringType = gatheredItem.GatheringTypes[index]; break; } } } } if (zone == "") { errorContent += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; fullScenario += "// Failed to retrieve item gathering zone from miqobot grid, can't gather this item " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; continue; } //Find teleport item string teleportTo = GarlandTool.GetTeleportName(zone, grid, gatheredItem); //Compute grid name from miqo presets, to avoid duplicates string gridName = iItem.Name + " Grid"; int indexGrid = 1; while (miqoPresetContent.Contains("grid." + gridName + Environment.NewLine)) { string oldGridName = gridName; gridName = iItem.Name + " Grid" + indexGrid; grid = grid.Replace("grid." + oldGridName + Environment.NewLine, "grid." + gridName + Environment.NewLine); indexGrid++; } //Embed grid allGrids += grid + Environment.NewLine; //Get preset string preset = MiqoCraftCore.GetCraftingPreset(gatheringType, slot, gatheredItem, iOptions.GatheringRotation, gridName, time); //Compute preset name from miqo presets, to avoid duplicates string presetName = iItem.Name + " preset"; int indexpreset = 1; while (miqoPresetContent.Contains("gatherpreset." + presetName + Environment.NewLine)) { string oldpresetName = presetName; presetName = iItem.Name + " preset" + indexpreset; preset = preset.Replace("gatherpreset." + oldpresetName + Environment.NewLine, "gatherpreset." + presetName + Environment.NewLine); indexpreset++; } //Embed a new preset allPreset += preset; //Add gathering rotation to scenario //Add gathering rotation to scenario //teleportIf(Black Brush Station)\r\nunstealth()\r\nchangeJob(Miner)\r\nselectGrid(Min5-Copper Ore)\r\nselectGatherPreset(Metal Worm Jar- Copper Ore)\r\nstartGathering(4) //teleportIfNotThere fullScenario += "// Gathering " + iItem.Name + Environment.NewLine; if (lastTeleport == "" || lastTeleport == teleportTo) { fullScenario += "teleport(" + teleportTo + ")" + Environment.NewLine; } else { fullScenario += "teleportIfNotThere(" + teleportTo + ")" + Environment.NewLine; } lastTeleport = teleportTo; //Adding custom scenario after teleport DirectoryInfo customDirectory = new DirectoryInfo(Path.Combine(Service_Misc.GetExecutionPath(), "CustomTeleport")); if (!customDirectory.Exists) { customDirectory.Create(); } FileInfo customTeleportScenarioFile = new FileInfo(Path.Combine(customDirectory.FullName, teleportTo + " Scenario.txt")); if (customTeleportScenarioFile.Exists) { fullScenario += File.ReadAllText(customTeleportScenarioFile.FullName) + Environment.NewLine; } FileInfo customTeleportGridFile = new FileInfo(Path.Combine(customDirectory.FullName, teleportTo + " Grid.txt")); if (customTeleportGridFile.Exists) { allGrids += File.ReadAllText(customTeleportGridFile.FullName) + Environment.NewLine; } //fullScenario += "unstealth()" + Environment.NewLine; fullScenario += "changeJob(" + GarlandTool.GetGatheringJobName(gatheringType, iItem) + ")" + Environment.NewLine; fullScenario += "selectGrid(" + gridName + ")" + Environment.NewLine; fullScenario += "selectGatherPreset(" + presetName + ")" + Environment.NewLine; if (null != gatheredItem && gatheredItem.AsCollectable) { fullScenario += "rotationIfGP(470 Collect 5% Gathering)" + Environment.NewLine; fullScenario += "rotationIfGP(470 Collect 15% Gathering)" + Environment.NewLine; } else { fullScenario += "rotationIfGP(" + iOptions.GatheringRotation + ")" + Environment.NewLine; } fullScenario += "startGathering(" + quantity + ")" + Environment.NewLine; fullScenario += Environment.NewLine; } else { errorContent += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; fullScenario += "// Failed to retrieve the grid from miqobot forums, can't gather this item " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; } } } else { errorContent += "// - " + quantity + "x " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; fullScenario += "// Failed to log into miqobot forums, can't gather this item " + iItem.Name + " (see " + iItem.UrlGarland + ")" + Environment.NewLine; } } } fullScenario += "\","; //Crafting stuff Service_Misc.LogText(iLogBox, "Generating craft scenario..."); fullScenario += "\""; fullScenario += Environment.NewLine; fullScenario += Environment.NewLine; fullScenario += "// Crafted Items" + Environment.NewLine; fullScenario += "//--------------------------------------------------------------" + Environment.NewLine; fullScenario += "//" + Environment.NewLine; fullScenario += "solverPreset(" + iOptions.CraftPreset + ")" + Environment.NewLine; fullScenario += "nqhq(" + iOptions.NQHQPreset + ")" + Environment.NewLine; fullScenario += "reclaimOff()" + Environment.NewLine; string teleportCraft = iOptions.CustomTeleport; if (teleportCraft != "") { fullScenario += "teleport(" + teleportCraft + ")" + Environment.NewLine; } List <FFXIVCraftedItem> listAllCraftedItems = new List <FFXIVCraftedItem>(); for (int i = 0; i < allItems.Count && i < allItemsQuantity.Count; i++) { FFXIVItem iItem = allItems[i]; if (null == iItem) { continue; } int quantity = allItemsQuantity[i]; FFXIVCraftedItem craftedItem = null; if (iItem is FFXIVCraftedItem) { craftedItem = iItem as FFXIVCraftedItem; } if (null != craftedItem) { listAllCraftedItems.Add(craftedItem); } } for (int i = 0; i < allItems.Count && i < allItemsQuantity.Count; i++) { FFXIVItem iItem = allItems[i]; if (null == iItem) { continue; } int quantity = allItemsQuantity[i]; FFXIVCraftedItem craftedItem = null; if (iItem is FFXIVCraftedItem) { craftedItem = iItem as FFXIVCraftedItem; } FFXIVCraftingOptions itemOptions = options.GetOption(iItem); if (null != itemOptions && itemOptions.IgnoreItem) { continue; } if (null != craftedItem) { fullScenario += "// " + craftedItem + Environment.NewLine; int indexCraftedItem = listAllCraftedItems.IndexOf(craftedItem); if (listAllCraftedItems.IndexOf(craftedItem) >= listAllCraftedItems.Count - 1 && iOptions.Collectable) { fullScenario += "setCraftCollect(on)" + Environment.NewLine; } else { fullScenario += "setCraftCollect(off)" + Environment.NewLine; } fullScenario += "job(" + craftedItem.Class + ")" + Environment.NewLine; fullScenario += "recipe(" + craftedItem.Name + ")" + Environment.NewLine; if (null != itemOptions && itemOptions.CustomCraftingMacro != "") { fullScenario += "selectCraftMacro(" + itemOptions.CustomCraftingMacro + ")" + Environment.NewLine; } fullScenario += "craft(" + quantity + ")" + Environment.NewLine; if (listAllCraftedItems.IndexOf(craftedItem) >= listAllCraftedItems.Count - 1 && iOptions.Collectable) { fullScenario += "setCraftCollect(off)" + Environment.NewLine; } if (null != itemOptions && itemOptions.CustomCraftingMacro != "") { fullScenario += "solverPreset(" + iOptions.CraftPreset + ")" + Environment.NewLine; } fullScenario += Environment.NewLine; } } fullScenario += "\""; if (errorContent == "") { fullScenario = fullScenario.Replace("ERRORS_ITEMS_DUMMY", ""); } else { string scenarioError = ""; scenarioError += Environment.NewLine; scenarioError += Environment.NewLine; scenarioError += "// Items without grid / Miqocrafter couldn't automate" + Environment.NewLine; scenarioError += "//--------------------------------------------------------------" + Environment.NewLine; scenarioError += "//" + Environment.NewLine; scenarioError += "// You will need to buy or obtain those items using external means, cause Miqocrafter can't automate it [Yet]" + Environment.NewLine; scenarioError += errorContent; scenarioError += Environment.NewLine; fullScenario = fullScenario.Replace("ERRORS_ITEMS_DUMMY", scenarioError); } string textFileContent = "scenario.Craft " + scenarioName + Environment.NewLine; textFileContent += "{ \"chapters\":["; textFileContent += fullScenario.Replace(Environment.NewLine, "\\r\\n").Replace("/", "\\/"); textFileContent += "]}" + Environment.NewLine; textFileContent += allRotations + Environment.NewLine; textFileContent += allGrids + Environment.NewLine; textFileContent += allPreset + Environment.NewLine; while (textFileContent.Contains(Environment.NewLine + Environment.NewLine)) { textFileContent = textFileContent.Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine); } return(textFileContent); }