Advertisement
JereTheJuggler

potions_v2.lua

Nov 14th, 2021 (edited)
704
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 50.60 KB | None | 0 0
  1. Filenames = {}
  2. Filenames.configFolder = "config"
  3. Filenames.tankContents = Filenames.configFolder.."/tank_contents.json"
  4. Filenames.potionTypes = Filenames.configFolder.."/potion_types.json"
  5. Filenames.fuelItems = Filenames.configFolder.."/blaze_fuels.txt"
  6.  
  7. ItemNames = {
  8.     redstone = "minecraft:redstone",
  9.     glowstone = "minecraft:glowstone_dust",
  10.     gunpowder = "minecraft:gunpowder",
  11.     dragonBreath = "minecraft:dragon_breath",
  12.     netherwart = "minecraft:nether_wart",
  13.     bottle = "minecraft:glass_bottle"
  14. }
  15.  
  16. term.clear()
  17. term.setCursorPos(1,1)
  18. term.setTextColor(colors.white)
  19. if not fs.exists(Filenames.potionTypes) then
  20.     print("Downloading potion types config...")
  21.     shell.run("pastebin","get","YBSC0sGp",Filenames.potionTypes)
  22. end
  23.  
  24. UNKNOWN = "unknown"
  25.  
  26. string.startsWith = function(self,str)
  27.     return self:find("^"..str)
  28. end
  29. string.split = function(self,sep)
  30.     if sep == nil then
  31.         sep = "%s"
  32.     end
  33.     local t = {}
  34.     for str in self:gmatch("([^"..sep.."]+)") do
  35.         table.insert(t,str)
  36.     end
  37.     return t
  38. end
  39. table.contains = function(self,value)
  40.     for _, v in ipairs(self) do
  41.         if v == value then
  42.             return true
  43.         end
  44.     end
  45.     return false
  46. end
  47.  
  48. PotionTypes = {
  49.     definitions=nil,
  50.     aliases={},
  51.     initialize=function()
  52.         print("Initializing potion definitions...")
  53.         PotionTypes.definitions = {}
  54.         PotionTypes.aliases = {}
  55.         local potionTypes = {}
  56.         if not pcall(function()
  57.             local h = fs.open(Filenames.potionTypes,"r")
  58.             local data = h.readAll()
  59.             h.close()
  60.             potionTypes = textutils.unserializeJSON(data)
  61.         end) then
  62.             --failed to decode file and load potion types
  63.             clearTerm()
  64.             printError("An error occurred while reading potion types config")
  65.             return false
  66.         end
  67.         for typeName,typeData in pairs(potionTypes) do
  68.             PotionTypes.addDefinition(typeName,PotionDefinition:new(typeData))
  69.         end
  70.         return true
  71.     end,
  72.     addDefinition=function(name,definition)
  73.         PotionTypes.definitions[name] = definition
  74.         for _,displayName in ipairs(definition.names) do
  75.             PotionTypes.aliases[string.lower(displayName)] = name
  76.         end
  77.     end,
  78.     getInternalName=function(name)
  79.         if name == nil then return nil end
  80.         name = string.lower(name)
  81.         if PotionTypes.definitions[name] ~= nil then return name end
  82.         if PotionTypes.aliases[name] ~= nil then return PotionTypes.aliases[name] end
  83.     end,
  84.     getDefinition=function(name)
  85.         local internalName = PotionTypes.getInternalName(name)
  86.         if internalName == nil then return nil end
  87.         return PotionTypes.definitions[internalName]
  88.     end
  89. }
  90. PotionModifiers = {
  91.     normal="Normal",
  92.     extended="Extended",
  93.     levelTwo="Level II",
  94.     getList=function()
  95.         return {
  96.             PotionModifiers.normal,
  97.             PotionModifiers.extended,
  98.             PotionModifiers.levelTwo
  99.         }
  100.     end,
  101.     isValid=function(value)
  102.         return PotionModifiers.getModifier(value) ~= nil
  103.     end,
  104.     getModifier=function(value)
  105.         if type(value) == "number" then return PotionModifiers.getList()[value] end
  106.         value = string.lower(value)
  107.         if value == string.lower(PotionModifiers.normal) then return PotionModifiers.normal end
  108.         if value == string.lower(PotionModifiers.extended) then return PotionModifiers.extended end
  109.         if value == string.lower(PotionModifiers.levelTwo) then return PotionModifiers.levelTwo end
  110.         if value == "l2" then return PotionModifiers.levelTwo end
  111.         if value == "level ii" then return PotionModifiers.levelTwo end
  112.         if value == "ext" then return PotionModifiers.extended end
  113.         return nil
  114.     end,
  115.     getItem=function(modifier)
  116.         if modifier == PotionModifiers.extended then
  117.             return ItemNames.redstone
  118.         elseif modifier == PotionModifiers.levelTwo then
  119.             return ItemNames.glowstone
  120.         end
  121.         return nil
  122.     end
  123. }
  124. PotionStyles = {
  125.     normal="Normal",
  126.     splash="Splash",
  127.     lingering="Lingering",
  128.     getList=function()
  129.         return {
  130.             PotionStyles.normal,
  131.             PotionStyles.splash,
  132.             PotionStyles.lingering
  133.         }
  134.     end,
  135.     isValid=function(value)
  136.         return PotionStyles.getStyle(value) ~= nil
  137.     end,
  138.     getStyle=function(value)
  139.         if type(value) == "number" then return PotionStyles.getList()[value] end
  140.         value = string.lower(value)
  141.         if value == string.lower(PotionStyles.normal) then return PotionStyles.normal end
  142.         if value == string.lower(PotionStyles.splash) then return PotionStyles.splash end
  143.         if value == string.lower(PotionStyles.lingering) then return PotionStyles.lingering end
  144.         return nil
  145.     end,
  146.     getItem=function(style)
  147.         if style == PotionStyles.splash then
  148.             return ItemNames.gunpowder
  149.         elseif style == PotionStyles.lingering then
  150.             return ItemNames.dragonBreath
  151.         end
  152.         return nil
  153.     end
  154. }
  155. PotionDefinition = {
  156.     new=function(self,data)
  157.         local o = {}
  158.         setmetatable(o,self)
  159.         self.__index = self
  160.  
  161.         o.names = List:new(data.names)
  162.         o.recipes = RecipeList:new()
  163.         for _,recipeData in ipairs(data.recipes) do
  164.             o.recipes:addRecipe(Recipe:new(recipeData))
  165.         end
  166.         return o
  167.     end
  168. }
  169. RecipeList = {
  170.     new=function(self)
  171.         local o = {}
  172.         setmetatable(o,self)
  173.         self.__index = self
  174.         return o
  175.     end,
  176.     addRecipe=function(self,recipe)
  177.         self:insert(recipe)
  178.     end,
  179.     --- Gets a list of recipes and the number of times each should be crafted
  180.     --
  181.     -- first return is a bool for whether or not the desired qty can be satisfied
  182.     --
  183.     -- second return is the list of recipes and quantities
  184.     getCraftPlan=function(self,qty)
  185.         local plan = List:new()
  186.         for _,recipe in ipairs(self) do
  187.             local maxCrafts = recipe:getMaxCrafts(qty)
  188.             if maxCrafts > 0 then
  189.                 qty = qty - maxCrafts
  190.                 plan:insert({maxCrafts,recipe})
  191.                 if qty == 0 then
  192.                     break
  193.                 end
  194.             end
  195.         end
  196.         return qty == 0, plan
  197.     end,
  198.     insert=table.insert,
  199.     remove=table.remove,
  200.     contains=table.contains
  201. }
  202. Recipe = {
  203.     new=function(self,items)
  204.         local o = {}
  205.         o.items = List:new(items)
  206.         setmetatable(o,self)
  207.         self.__index = self
  208.         return o
  209.     end,
  210.     getMaxCrafts=function(self,targetQty)
  211.         local maxCrafts = targetQty
  212.         for _,itemName in ipairs(self.items) do
  213.             local available = Inventories.getItemCount(itemName)
  214.             if available == 0 then return 0 end
  215.             if maxCrafts == nil or available < maxCrafts then maxCrafts = available end
  216.         end
  217.         return maxCrafts
  218.     end,
  219.     checkMissingItems=function(self,qty,missingItems)
  220.         for _,itemName in ipairs(self.items) do
  221.             Inventories.checkMissingItem(itemName,qty,missingItems)
  222.         end
  223.     end
  224. }
  225. Potion = {
  226.     new=function(self,type,modifier,style)
  227.         local contents = {}
  228.         contents.type = type
  229.         contents.modifier = modifier or PotionStyles.normal
  230.         contents.style = style or PotionStyles.normal
  231.         setmetatable(contents,self)
  232.         self.__index = self
  233.         return contents
  234.     end,
  235.     matches=function(self,def)
  236.         if def == nil then return false end
  237.         if self.type ~= def.type then return false end
  238.         if self.type == UNKNOWN then return true end
  239.         return self.modifier == def.modifier and self.style == def.style
  240.     end,
  241.     canCreate=function(self,def)
  242.         if def == nil or self.type == UNKNOWN then return false end
  243.         if self.type ~= def.type then return false end
  244.         if self.modifier ~= def.modifier then
  245.             if def.modifier == PotionModifiers.normal then return false end
  246.             if self.modifier ~= PotionModifiers.normal then return false end
  247.         end
  248.         if self.style ~= def.style then
  249.             if def.style == PotionModifiers.normal then return false end
  250.             if self.modifier ~= PotionModifiers.normal then return false end
  251.         end
  252.         return true
  253.     end,
  254.     isUnknown=function(self)
  255.         return self.type == UNKNOWN
  256.     end,
  257.     getDisplayName=function(self)
  258.         local fullPotionName = "Potion of "..PotionTypes.getDefinition(self.type).names[1]
  259.         if self.style ~= PotionStyles.normal then
  260.             fullPotionName = self.style.." "..fullPotionName
  261.         end
  262.         if self.modifier == PotionModifiers.extended then
  263.             fullPotionName = PotionModifiers.extended.." "..fullPotionName
  264.         elseif self.modifier == PotionModifiers.levelTwo then
  265.             fullPotionName = fullPotionName.." II"
  266.         end
  267.         return fullPotionName
  268.     end,
  269.     getSaveObject=function(self)
  270.         return {
  271.             type=self.type,
  272.             modifier=self.modifier,
  273.             style=self.style
  274.         }
  275.     end
  276. }
  277.  
  278. List = {
  279.     new=function(self,t)
  280.         local list = t or {}
  281.         setmetatable(list,self)
  282.         self.__index = self
  283.         return list
  284.     end,
  285.     insert=table.insert,
  286.     remove=table.remove,
  287.     contains=table.contains
  288. }
  289.  
  290. StorageTanks = {
  291.     list={},
  292.     findStorage=function(potion)
  293.         local matchingTanks = List:new()
  294.         local unknownTanks = List:new()
  295.         local emptyTanks = List:new()
  296.         for tankName,tank in pairs(StorageTanks.list) do
  297.             if tank:hasContents() then
  298.                 if tank:contentsMatch(potion) then
  299.                     matchingTanks:insert(tank)
  300.                 elseif tank:isUnknown() then
  301.                     unknownTanks:insert(tank)
  302.                 end
  303.             else
  304.                 emptyTanks:insert(tank)
  305.             end
  306.         end
  307.         return matchingTanks, unknownTanks, emptyTanks
  308.     end,
  309.     writeTankContents=function()
  310.         local saveData = {}
  311.         for name,tank in pairs(StorageTanks.list) do
  312.             if tank:hasContents(true) and not tank:isUnknown(true) then
  313.                 saveData[name] = tank.contents:getSaveObject()
  314.             end
  315.         end
  316.         saveData = textutils.serializeJSON(saveData)
  317.         local h = fs.open(Filenames.tankContents,"w")
  318.         h.write(saveData)
  319.         h.close()
  320.         return true
  321.     end,
  322.     initializeTankContents=function()
  323.         print("Initializing tank contents...")
  324.         if fs.exists(Filenames.tankContents) then
  325.             local h = fs.open(Filenames.tankContents,"r")
  326.             local saveData = h.readAll()
  327.             h.close()
  328.             saveData = textutils.unserializeJSON(saveData)
  329.             for name,tank in pairs(StorageTanks.list) do
  330.                 if tank:hasContents(true) then
  331.                     if saveData[name] ~= nil then
  332.                         tank:setContents(Potion:new(saveData[name].type,saveData[name].modifier,saveData[name].style),true)
  333.                     else
  334.                         tank:setContents(Potion:new(UNKNOWN),true)
  335.                     end
  336.                 else
  337.                     tank:setContents(nil,true)
  338.                 end
  339.             end
  340.         else
  341.             for _,tank in pairs(StorageTanks.list) do
  342.                 if tank:hasContents(true) then
  343.                     tank:setContents(Potion:new(UNKNOWN),true)
  344.                 else
  345.                     tank:setContents(nil,true)
  346.                 end
  347.             end
  348.         end
  349.     end,
  350.     storePotion=function(potion)
  351.         while true do
  352.             local matchingTanks, unknownTanks, emptyTanks = StorageTanks.findStorage(potion)
  353.             local basin = Peripherals.basin
  354.             if #matchingTanks > 0 then
  355.                 for _,t in ipairs(matchingTanks) do
  356.                     if t.pullFluid(basin.name) > 0 then
  357.                         if not basin:hasFluid() then
  358.                             return true
  359.                         end
  360.                     end
  361.                 end
  362.             end
  363.             if #unknownTanks > 0 then
  364.                 for _,t in ipairs(unknownTanks) do
  365.                     if t.pullFluid(basin.name) > 0 then
  366.                         t:setContents(potion)
  367.                         if not basin:hasFluid() then
  368.                             return true
  369.                         end
  370.                     end
  371.                 end
  372.             end
  373.             if #emptyTanks > 0 then
  374.                 for _,t in ipairs(emptyTanks) do
  375.                     if t.pullFluid(basin.name) > 0 then
  376.                         t:setContents(potion)
  377.                         if not basin:hasFluid() then
  378.                             return true
  379.                         end
  380.                     end
  381.                 end
  382.             end
  383.             if not Issues.cannotStorePotion() then return false end
  384.         end
  385.     end,
  386.     outputPotion=function(potion,qty,outputtingInfinite)
  387.         if outputtingInfinite == nil then outputtingInfinite = false end
  388.         qty = qty * 1000
  389.         local qtyOutput = 0
  390.         while qtyOutput < qty do
  391.             local tank = StorageTanks.findTank(potion)
  392.             if tank ~= nil then
  393.                 local amountPushed = tank.pushFluid(Peripherals.workbench.name,qty)
  394.                 if amountPushed == 0 then
  395.                     if not Issues.cannotOutputPotion() then
  396.                         return false
  397.                     end
  398.                 else
  399.                     qtyOutput = qtyOutput + amountPushed
  400.                     tank:hasContents()
  401.                 end
  402.             else
  403.                 if not Crafting.craft(potion,1) then
  404.                     return false
  405.                 end
  406.             end
  407.         end
  408.         return true
  409.     end,
  410.     outputInfinitePotion=function(potion)
  411.         local infiniteOutputCancelled = false
  412.         parallel.waitForAll(function()
  413.             parallel.waitForAny(function()
  414.                 while not infiniteOutputCancelled do
  415.                     local _,key = waitForKey()
  416.                     if key == keys.backspace then
  417.                         infiniteOutputCancelled = true
  418.                         print("Cancelling infinite output...")
  419.                     end
  420.                 end
  421.             end,function()
  422.                 while not infiniteOutputCancelled do
  423.                     sleep(5)
  424.                 end
  425.             end)
  426.         end,function()
  427.             while not infiniteOutputCancelled do
  428.                 if not StorageTanks.outputPotion(potion,1,true) then
  429.                     infiniteOutputCancelled = true
  430.                     print("Cancelling infinite output...")
  431.                     break
  432.                 end
  433.             end
  434.         end)
  435.     end,
  436.     findTank=function(potion)
  437.         for name,tank in pairs(StorageTanks.list) do
  438.             if tank:contentsMatch(potion) then
  439.                 return tank
  440.             end
  441.         end
  442.         return nil
  443.     end
  444. }
  445. StorageTank = {
  446.     new=function(self,peripheralName)
  447.         perip = peripheral.wrap(peripheralName)
  448.         perip.name = peripheralName
  449.         perip.contents=nil
  450.         setmetatable(perip,self)
  451.         self.__index = self
  452.         return perip
  453.     end,
  454.     hasContents=function(self,preventWrite)
  455.         if preventWrite == nil then preventWrite = false end
  456.         if #self.tanks() == 0 then
  457.             if self.contents ~= nil then
  458.                 self:setContents(nil,preventWrite)
  459.             end
  460.             return false
  461.         else
  462.             if self.contents == nil then
  463.                 self:setContents(Potion:new(UNKNOWN),preventWrite)
  464.             end
  465.             return true
  466.         end
  467.     end,
  468.     isUnknown=function(self,preventWrite)
  469.         if preventWrite == nil then preventWrite = false end
  470.         if self.contents == nil then
  471.             if #self.tanks() ~= 0 then
  472.                 self:setContents(Potion:new(UNKNOWN),preventWrite)
  473.                 return true
  474.             end
  475.             return false
  476.         else
  477.             if #self.tanks() == 0 then
  478.                 self.contents = nil
  479.                 self:setContents(nil,preventWrite)
  480.                 return false
  481.             end
  482.             return self.contents:isUnknown()
  483.         end
  484.     end,
  485.     contentsMatch=function(self,potionDef)
  486.         if self.contents == nil then
  487.             return potionDef == nil
  488.         elseif potionDef == nil then
  489.             return false
  490.         end
  491.         return self.contents:matches(potionDef)
  492.     end,
  493.     setContents=function(self,potionDef,preventWrite)
  494.         if preventWrite == nil then preventWrite = false end
  495.         self.contents = potionDef
  496.         if not preventWrite then
  497.             StorageTanks:writeTankContents()
  498.         end
  499.     end,
  500.     getContentsName=function(self)
  501.         if self.contents == nil then return "Empty" end
  502.         if self.contents.type == UNKNOWN then return "Unknown contents" end
  503.         return self.contents:getDisplayName()
  504.     end
  505. }
  506.  
  507. Inventories = {
  508.     list=List:new(),
  509.     indexedItems={},
  510.     indexInventories=function()
  511.         local totalSlots = 0
  512.         for _,inv in ipairs(Inventories.list) do
  513.             totalSlots = totalSlots + inv.size()
  514.         end
  515.         Inventories.indexedItems = {}
  516.         local currentSlot = 1
  517.         clearTerm()
  518.         for _,inv in ipairs(Inventories.list) do
  519.             local inventorySize = inv.size()
  520.             for slot=1, inventorySize do
  521.                 term.setCursorPos(1,1)
  522.                 term.write("Indexing Inventories... Slot "..currentSlot.." of "..totalSlots)
  523.                 local itemDetail = inv.getItemDetail(slot)
  524.                 if itemDetail ~= nil then
  525.                     if not Inventories.hasItem(itemDetail.name) then
  526.                         Inventories.indexedItems[itemDetail.name] = IndexedItem:new(itemDetail.name)
  527.                     end
  528.                     Inventories.indexedItems[itemDetail.name]:addLocation(ItemLocation:new(inv,slot,itemDetail.count))
  529.                 end
  530.                 currentSlot = currentSlot + 1
  531.             end
  532.         end
  533.         clearTerm()
  534.     end,
  535.     hasItem=function(itemName)
  536.         return Inventories.indexedItems[itemName] ~= nil
  537.     end,
  538.     getItemCount=function(itemName)
  539.         if Inventories.indexedItems[itemName] == nil then return 0 end
  540.         return Inventories.indexedItems[itemName].total
  541.     end,
  542.     getItemLocations=function(itemName)
  543.         if not Inventories.hasItem(itemName) then return nil end
  544.         return Inventories.indexedItems[itemName].locations
  545.     end,
  546.     checkMissingItem=function(itemName,qty,missingItems)
  547.         local count = Inventories.getItemCount(itemName)
  548.         if count < qty then
  549.             missingItems:insert({itemName,qty - count})
  550.         end
  551.     end,
  552.     --- Returns true if the operation was successful
  553.     --
  554.     -- Can trigger issue if item is not found, after which user can add more items or cancel the operation
  555.     take=function(itemName,toInventory,qty)
  556.         if Inventories.getItemCount(itemName) < qty then
  557.             if not Issues.itemMissingInInventory(itemName,qty) then
  558.                 return false
  559.             end
  560.         end
  561.         while qty > 0 do
  562.             local satisfied, remainingQty = Inventories.indexedItems[itemName]:take(toInventory,qty)
  563.             if not satisfied then
  564.                 qty = remainingQty
  565.                 if not Issues.itemMissingInInventory(itemName,qty) then
  566.                     return false
  567.                 end
  568.             else
  569.                 qty = 0
  570.             end
  571.         end
  572.         return true
  573.     end
  574. }
  575. IndexedItem={
  576.     new=function(self,name)
  577.         local o = {}
  578.         o.name = name
  579.         o.total = 0
  580.         o.locations = List:new()
  581.         setmetatable(o,self)
  582.         self.__index = self
  583.         return o
  584.     end,
  585.     addLocation=function(self,location)
  586.         self.locations:insert(location)
  587.         self.total = self.total + location.stackSize
  588.     end,
  589.     --- Takes an item from the index
  590.     --
  591.     -- first return is true if the qty was satisfied, otherwise false
  592.     --
  593.     -- second return is the remaining qty that was not satisfied
  594.     take=function(self,toInventory,qty)
  595.         qty = qty or 1
  596.         if self.total == 0 or #self.locations == 0 then return false end
  597.         if qty > self.total then return false end
  598.         while qty > 0 and self.total > 0 do
  599.             local moveCount = toInventory.pullItems(self.locations[1].inventory.name,self.locations[1].slot,qty)
  600.             if moveCount > 0 then
  601.                 qty = qty - moveCount
  602.                 self.locations[1].stackSize = self.locations[1].stackSize - moveCount
  603.                 self.total = self.total - moveCount
  604.                 self:validateFirstLocation()
  605.             else
  606.                 if self:validateFirstLocation() then
  607.                     --stored location is still valid
  608.                     --destination must have an issue
  609.                     break
  610.                 end
  611.             end
  612.         end
  613.         return qty == 0, qty
  614.     end,
  615.     --- returns true if location still exists after being validated, else false
  616.     validateFirstLocation=function(self)
  617.         local count, difference = self.locations[1]:validateCount(self.name)
  618.         if difference ~= 0 then
  619.             self.total = self.total + difference
  620.         end
  621.         if count == 0 then
  622.             self.locations:remove(1)
  623.             return false
  624.         end
  625.         return true
  626.     end
  627. }
  628. ItemLocation={
  629.     new=function(self,inventory,slot,stackSize)
  630.         local o = {}
  631.         o.inventory = inventory
  632.         o.slot = slot
  633.         o.stackSize = stackSize
  634.         setmetatable(o,self)
  635.         self.__index = self
  636.         return o
  637.     end,
  638.     --- checks the location to validate that the expected item still exists, and updates the stored qty if it differs
  639.     --
  640.     -- first return is the count of the item that exists in the stack
  641.     --
  642.     -- second return is the difference between the actual and the stored value
  643.     validateCount=function(self,itemName)
  644.         local detail = self.inventory.getItemDetail(self.slot)
  645.         if detail == nil then return 0, -1 * self.stackSize end
  646.         if detail.name ~= itemName then return 0, -1 * self.stackSize end
  647.         local diff = detail.count - self.stackSize
  648.         if diff ~= 0 then self.stackSize = detail.count end
  649.         return detail.count, diff
  650.     end
  651. }
  652.  
  653. Peripherals={
  654.     waterTank=nil,
  655.     basin=nil,
  656.     spout=nil,
  657.     depot=nil,
  658.     workbench=nil,
  659.     deployer=nil,
  660.     wrapPeripherals=function()
  661.         while true do
  662.             Peripherals.waterTank = nil
  663.             StorageTanks.list = {}
  664.             Peripherals.basin = nil
  665.             Inventories.list = List:new()
  666.             Monitors.list = List:new()
  667.             Peripherals.spout = nil
  668.             Peripherals.depot = nil
  669.             Peripherals.workbench = nil
  670.             local foundTanks = false
  671.             local sideNames = List:new({"top","front","left","right","back","bottom"})
  672.             for _,name in ipairs(peripheral.getNames()) do
  673.                 if not sideNames:contains(name) then
  674.                     local ptype = peripheral.getType(name)
  675.                     local perip = peripheral.wrap(name)
  676.                     perip.name = name
  677.                     if ptype == "create:fluid_tank" or ptype == "thermal:fluid_cell" then
  678.                         local tanks = perip.tanks()
  679.                         if #tanks > 0 and tanks[1].name == "minecraft:water" then
  680.                             Peripherals.waterTank = perip
  681.                         else
  682.                             perip = StorageTank:new(name)
  683.                             StorageTanks.list[name] = perip
  684.                             foundTanks = true
  685.                         end
  686.                     elseif ptype == "thermal:tinker_bench" then
  687.                         Peripherals.workbench = perip
  688.                     elseif ptype == "create:basin" then
  689.                         Peripherals.basin = Basin:new(name)
  690.                     elseif ptype == "monitor" then
  691.                         Monitors.list:insert(perip)
  692.                     elseif ptype == "create:spout" then
  693.                         Peripherals.spout = perip
  694.                     elseif ptype == "create:depot" then
  695.                         Peripherals.depot = perip
  696.                     elseif ptype == "create:deployer" then
  697.                         Peripherals.deployer = perip
  698.                     else
  699.                         if perip.pullItems ~= nil then
  700.                             Inventories.list:insert(perip)
  701.                         end
  702.                     end
  703.                 end
  704.             end
  705.             local messages = List:new()
  706.             if Peripherals.waterTank == nil then
  707.                 messages:insert("No water tank found")
  708.             end
  709.             if not foundTanks then
  710.                 messages:insert("No storage tanks found")
  711.             end
  712.             if Peripherals.basin == nil then
  713.                 messages:insert("No Basin found")
  714.             end
  715.             if #Inventories.list == 0 then
  716.                 messages:insert("No item inventories found")
  717.             end
  718.             if #messages > 0 then
  719.                 Monitors.error("Could not find necessary peripherals")
  720.                 clearTerm()
  721.                 printError("Could not find necessary peripherals")
  722.                 for _,msg in ipairs(messages) do
  723.                     printError("- "..msg)
  724.                 end
  725.                 printLine()
  726.                 print("Press X to quit. Press any other key to retry.")
  727.                 local _, key = waitForKey()
  728.                 if key == keys.x then
  729.                     return false
  730.                 end
  731.             else
  732.                 return true
  733.             end
  734.         end
  735.     end
  736. }
  737. Basin={
  738.     new=function(self,peripheralName)
  739.         local basin = peripheral.wrap(peripheralName)
  740.         basin.name = peripheralName
  741.         setmetatable(basin,self)
  742.         self.__index = self
  743.         return basin
  744.     end,
  745.     hasWater=function(self)
  746.         if not self:hasFluid() then return false end
  747.         if #self.tanks() > 0 then
  748.             return self.tanks()[1].name == "minecraft:water"
  749.         end
  750.         return self.tanks()[3].name == "minecraft:water"
  751.     end,
  752.     hasFluid=function(self)
  753.         if #self.tanks() > 0 then
  754.             return true
  755.         end
  756.         if self.tanks()[3] ~= nil then
  757.             return true
  758.         end
  759.         return false
  760.     end,
  761.     hasItem=function(self)
  762.         return self.getItemDetail(1) ~= nil
  763.     end,
  764.     insertItem=function(self,itemName)
  765.         if self:hasItem() then
  766.             if not Issues.itemStuckInBasin() then
  767.                 return false
  768.             end
  769.         end
  770.         if not Inventories.take(itemName,self,1) then
  771.             return false
  772.         end
  773.         return true
  774.     end
  775. }
  776.  
  777. Monitors = {
  778.     lineNum=1,
  779.     list=List:new(),
  780.     setLineNum=function(lineNum)
  781.         if #Monitors.list > 0 then
  782.             for _,v in ipairs(Monitors.list) do
  783.                 v.setCursorPos(1,lineNum)
  784.             end
  785.             Monitors.lineNum=lineNum
  786.         end
  787.     end,
  788.     clear=function()
  789.         if #Monitors.list > 0 then
  790.             for _,v in ipairs(Monitors.list) do
  791.                 v.clear()
  792.                 v.setCursorPos(1,1)
  793.             end
  794.             Monitors.lineNum=1
  795.         end
  796.     end,
  797.     clearLine=function(line)
  798.         line = line or Monitors.lineNum
  799.         if #Monitors.list > 0 then
  800.             for _,v in ipairs(Monitors.list) do
  801.                 v.setCursorPos(1,line)
  802.                 v.clearLine()
  803.             end
  804.             Monitors.lineNum=line
  805.         end
  806.     end,
  807.     write=function(text,line)
  808.         if #Monitors.list > 0 then
  809.             for _,v in ipairs(Monitors.list) do
  810.                 if line ~= nil then
  811.                     v.setCursorPos(1,line)
  812.                 else
  813.                     v.setCursorPos(1,Monitors.lineNum)
  814.                 end
  815.                 v.clearLine()
  816.                 v.write(text)
  817.             end
  818.             if line == nil then
  819.                 Monitors.lineNum = Monitors.lineNum+1
  820.             end
  821.         end
  822.     end,
  823.     error=function(text)
  824.         if #Monitors.list > 0 then
  825.             for _,v in ipairs(Monitors.list) do
  826.                 v.setTextColor(colors.red)
  827.                 v.setCursorPos(1,Monitors.lineNum)
  828.                 v.write(text)
  829.                 v.setTextColor(colors.white)
  830.             end
  831.             Monitors.lineNum = Monitors.lineNum+1
  832.         end
  833.     end,
  834.     back=function()
  835.         if #Monitors.list > 0 then
  836.             if Monitors.lineNum > 1 then
  837.                 Monitors.lineNum = Monitors.lineNum-1
  838.             end
  839.             for _,mon in ipairs(Monitors.list) do
  840.                 mon.setCursorPos(1,Monitors.lineNum)
  841.             end
  842.         end
  843.     end
  844. }
  845.  
  846. function clearTerm()
  847.     term.clear()
  848.     term.setCursorPos(1,1)
  849. end
  850. function printError(text)
  851.     term.setTextColor(colors.red)
  852.     print(text)
  853.     term.setTextColor(colors.white)
  854. end
  855. function printInstruction(text)
  856.     term.setTextColor(colors.lightBlue)
  857.     print(text)
  858.     term.setTextColor(colors.white)
  859. end
  860. function printLine()
  861.     print()
  862. end
  863. function waitForKey()
  864.     local event, key = os.pullEvent("key")
  865.     sleep(.5)
  866.     return event, key
  867. end
  868.  
  869. Crafting = {
  870.     fuels=nil,
  871.     craft=function(potion,qty,craftingInfinite)
  872.         local cancelled = false
  873.  
  874.         if craftingInfinite == nil then craftingInfinite = false end
  875.         local craftPlan = nil
  876.         while true do
  877.             local result, missing, recipes = Crafting.canCraftPotion(potion,qty)
  878.             if not result then
  879.                 if not Issues.multipleItemsMissing(missing) then
  880.                     return false
  881.                 end
  882.             else
  883.                 craftPlan = recipes
  884.                 break
  885.             end
  886.         end
  887.  
  888.         clearTerm()
  889.  
  890.         local remainingQty = qty
  891.         local fullPotionName = potion:getDisplayName()
  892.  
  893.         Crafting.setRedstone(true)
  894.         for _,recipePlan in ipairs(craftPlan) do
  895.             local recipeCount = recipePlan[1]
  896.             local recipe = recipePlan[2]
  897.             for i=1, recipeCount do
  898.                 Monitors.clear()
  899.                 clearTerm()
  900.                 if craftingInfinite then
  901.                     Monitors.write("Crafting infinite")
  902.                     print("Crafting infinite "..fullPotionName)
  903.                     printInstruction("Press backspace to stop crafting")
  904.                 else
  905.                     Monitors.write("Crafting "..(qty-remainingQty+1).." of "..qty)
  906.                     print("Crafting "..(qty-remainingQty+1).." of "..qty)
  907.                     print(fullPotionName)
  908.                 end
  909.                 Monitors.write(fullPotionName)
  910.                 if not Crafting.refillWater() then
  911.                     cancelled = true
  912.                     break
  913.                 end
  914.                 if not Crafting.mix(ItemNames.netherwart) then
  915.                     cancelled = true
  916.                     break
  917.                 end
  918.                 for _,itemName in ipairs(recipe.items) do
  919.                     if not Crafting.mix(itemName) then
  920.                         cancelled = true
  921.                         break
  922.                     end
  923.                 end
  924.                 local modItem = PotionModifiers.getItem(potion.modifier)
  925.                 if modItem ~= nil then
  926.                     if not Crafting.mix(modItem) then
  927.                         cancelled = true
  928.                         break
  929.                     end
  930.                 end
  931.                 local styleItem = PotionStyles.getItem(potion.style)
  932.                 if styleItem ~= nil then
  933.                     if not Crafting.mix(styleItem) then
  934.                         cancelled = true
  935.                         break
  936.                     end
  937.                 end
  938.                 if not StorageTanks.storePotion(potion) then
  939.                     cancelled = true
  940.                     break
  941.                 end
  942.                 remainingQty = remainingQty - 1
  943.             end
  944.             if cancelled then break end
  945.         end
  946.         Monitors.clear()
  947.         clearTerm()
  948.         Crafting.setRedstone(false)
  949.         return not cancelled
  950.     end,
  951.     craftInfinite=function(potion)
  952.         local infiniteCraftingCancelled = false
  953.         parallel.waitForAll(function()
  954.             parallel.waitForAny(function()
  955.                 while not infiniteCraftingCancelled do
  956.                     local _,key = waitForKey()
  957.                     if key == keys.backspace then
  958.                         infiniteCraftingCancelled = true
  959.                         print("Cancelling infinite crafting...")
  960.                     end
  961.                 end
  962.             end,function()
  963.                 while not infiniteCraftingCancelled do
  964.                     sleep(5)
  965.                 end
  966.             end)
  967.         end,function()
  968.             while not infiniteCraftingCancelled do
  969.                 if not Crafting.craft(potion,1,true) then
  970.                     infiniteCraftingCancelled = true
  971.                     print("Cancelling infinite crafting...")
  972.                     break
  973.                 end
  974.             end
  975.         end)
  976.     end,
  977.     canCraftPotion=function(potion,qty)
  978.         local potionDef = PotionTypes.getDefinition(potion.type)
  979.         if potionDef == nil then
  980.             printError(potion.type)
  981.         end
  982.         local missingItems = List:new()
  983.  
  984.         Inventories.checkMissingItem(ItemNames.netherwart,qty,missingItems)
  985.         local modItem = PotionModifiers.getItem(potion.modifier)
  986.         if modItem ~= nil then
  987.             Inventories.checkMissingItem(modItem,qty,missingItems)
  988.         end
  989.         local styleItem = PotionStyles.getItem(potion.style)
  990.         if styleItem ~= nil then
  991.             Inventories.checkMissingItem(styleItem,qty,missingItems)
  992.         end
  993.  
  994.         local canCraft, craftPlan = potionDef.recipes:getCraftPlan(qty)
  995.         if not canCraft then
  996.             potionDef.recipes[1]:checkMissingItems(qty,missingItems)
  997.         end
  998.  
  999.         if #missingItems > 0 then
  1000.             return false, missingItems, nil
  1001.         end
  1002.         return true, nil, craftPlan
  1003.     end,
  1004.     refillWater=function()
  1005.         local basin = Peripherals.basin
  1006.         if basin:hasFluid() then
  1007.             if basin:hasWater() then return true end
  1008.             Issues.fluidStuckInBasin()
  1009.         end
  1010.         basin.pullFluid(Peripherals.waterTank.name)
  1011.         return true
  1012.     end,
  1013.     mix=function(itemName)
  1014.         if Peripherals.basin:hasItem() then
  1015.             Issues.itemStuckInBasin()
  1016.         end
  1017.         if Peripherals.basin:insertItem(itemName) then
  1018.             while true do
  1019.                 sleep(1)
  1020.                 if not Peripherals.basin:hasItem() then
  1021.                     break
  1022.                 end
  1023.             end
  1024.         else
  1025.             return false
  1026.         end
  1027.         return true
  1028.     end,
  1029.     setRedstone=function(on)
  1030.         for _,side in ipairs(redstone.getSides()) do
  1031.             redstone.setOutput(side,on)
  1032.         end
  1033.     end,
  1034.     getRedstone=function()
  1035.         return redstone.getOutput(redstone.getSides()[1])
  1036.     end,
  1037.     initializeFuels=function()
  1038.         print("Initializing fuel types")
  1039.         Crafting.fuels = List:new()
  1040.         local h = nil
  1041.         if not pcall(function()
  1042.             if fs.exists(Filenames.fuelItems) then
  1043.                 h = fs.open(Filenames.fuelItems,"r")
  1044.                 local l = h.readLine()
  1045.                 while l ~= nil do
  1046.                     Crafting.fuels:insert(l)
  1047.                     l = h.readLine()
  1048.                 end
  1049.                 h.close()
  1050.                 h = nil
  1051.             end
  1052.         end) then
  1053.             if h ~= nil then h.close() end
  1054.         end
  1055.         if #Crafting.fuels == 0 then
  1056.             Crafting.fuels = List:new({
  1057.                 "minecraft:charcoal",
  1058.                 "minecraft:charcoal_block",
  1059.                 "minecraft:coal",
  1060.                 "minecraft:coal_block",
  1061.                 "create:blaze_cake"
  1062.             })
  1063.             h = fs.open(Filenames.fuelItems,"w")
  1064.             for _,itemName in ipairs(Crafting.fuels) do
  1065.                 h.writeLine(itemName)
  1066.             end
  1067.             h.close()
  1068.         end
  1069.     end
  1070. }
  1071.  
  1072. Issues = {
  1073.     itemStuckInBasin=function()
  1074.         Monitors.error("Item stuck in Basin!")
  1075.         printError("An item is stuck in the basin")
  1076.         while true do
  1077.             sleep(10)
  1078.             if not Peripherals.basin:hasItem() then
  1079.                 Monitors.back()
  1080.                 Monitors.clearLine()
  1081.                 clearTerm()
  1082.                 return
  1083.             end
  1084.         end
  1085.     end,
  1086.     fluidStuckInBasin=function()
  1087.         Monitors.error("Fluid stuck in Basin!")
  1088.         printError("Fluid is stuck in the basin")
  1089.         while true do
  1090.             sleep(10)
  1091.             if not Peripherals.basin:hasFluid() then
  1092.                 Monitors.back()
  1093.                 Monitors.clearLine()
  1094.                 clearTerm()
  1095.                 return true
  1096.             end
  1097.         end
  1098.     end,
  1099.     missingBlazeFuel=function()
  1100.         Monitors.error("Could not find fuel for blaze!")
  1101.         while true do
  1102.             clearTerm()
  1103.             printError("Could not find fuel for blaze!")
  1104.             printInstruction("Press X to cancel")
  1105.             printInstruction("Press any other key after adding fuel")
  1106.             local _,key = waitForKey()
  1107.             if key == keys.x then
  1108.                 clearTerm()
  1109.                 Monitors.clear()
  1110.                 return false
  1111.             end
  1112.             Inventories.indexInventories()
  1113.             for _,name in ipairs(Crafting.fuels) do
  1114.                 if Inventories.hasItem(name) then
  1115.                     clearTerm()
  1116.                     Monitors.clear()
  1117.                     return true
  1118.                 end
  1119.             end
  1120.         end
  1121.     end,
  1122.     itemMissingInInventory=function(itemName,qty)
  1123.         Monitors.error("Item could not be found in inventory!")
  1124.         while true do
  1125.             clearTerm()
  1126.             printError("Item could not be found in inventory!")
  1127.             print("Item: "..itemName)
  1128.             print("Needed quantity: "..qty)
  1129.             printInstruction("Press X to cancel")
  1130.             printInstruction("Press any other key after adding item")
  1131.             local _,key = waitForKey()
  1132.             if key == keys.x then
  1133.                 clearTerm()
  1134.                 Monitors.clear()
  1135.                 return false
  1136.             end
  1137.             Inventories.indexInventories()
  1138.             if Inventories.getItemCount(itemName) > 0 then
  1139.                 clearTerm()
  1140.                 Monitors.back()
  1141.                 Monitors.clearLine()
  1142.                 return true
  1143.             end
  1144.         end
  1145.     end,
  1146.     multipleItemsMissing=function(missingItems)
  1147.         Monitors.error("Insufficient items in inventory!")
  1148.         clearTerm()
  1149.         printError("The following items could not be found:")
  1150.         for _,itemData in ipairs(missingItems) do
  1151.             print(" "..itemData[2].."x "..itemData[1])
  1152.         end
  1153.         printInstruction("Press x to cancel")
  1154.         printInstruction("Press any other key after adding items")
  1155.         local _,key = waitForKey()
  1156.         if key == keys.x then
  1157.             clearTerm()
  1158.             Monitors.clear()
  1159.             return false
  1160.         end
  1161.         Monitors.back()
  1162.         Monitors.clearLine()
  1163.         clearTerm()
  1164.         Inventories.indexInventories()
  1165.         return true
  1166.     end,
  1167.     cannotStorePotion=function()
  1168.         Monitors.error("Potion in Basin could not be stored!")
  1169.         clearTerm()
  1170.         printError("Potion in the Basin could not be stored")
  1171.         printInstruction("Please empty an existing storage tank")
  1172.         print("Adding additional storage tanks during runtime")
  1173.         print("is not currently supported.")
  1174.         printLine()
  1175.         printInstruction("Press x to cancel")
  1176.         printInstruction("Press any other key to try again")
  1177.         local _,key = waitForKey()
  1178.         if key == keys.x then
  1179.             Monitors.clear()
  1180.             clearTerm()
  1181.             return false
  1182.         end
  1183.         Monitors.back()
  1184.         Monitors.clearLine()
  1185.         term.clear()
  1186.         return true
  1187.     end,
  1188.     cannotOutputPotion=function()
  1189.         Monitors.error("Potion could not be put in Tinker's Bench!")
  1190.         clearTerm()
  1191.         printError("Potion could not be output to Tinker's Bench")
  1192.         printInstruction("Please empty bench or ensure it does not contain")
  1193.         printInstruction("an incompatible fluid")
  1194.         printLine()
  1195.         printInstruction("Press x to cancel")
  1196.         printInstruction("Press any other key to try again")
  1197.         local bench = Peripherals.workbench
  1198.         local startingAmount = bench.tanks()[1].amount
  1199.         local cancelled = false
  1200.         parallel.waitForAny(function()
  1201.             while true do
  1202.                 local t = bench.tanks()[1]
  1203.                 if t == nil then
  1204.                     break
  1205.                 elseif t.amount < startingAmount then
  1206.                     break
  1207.                 end
  1208.                 sleep(2)
  1209.             end
  1210.         end,function()
  1211.             local _,key = waitForKey()
  1212.             if key == keys.x then
  1213.                 Monitors.clear()
  1214.                 clearTerm()
  1215.                 cancelled = true
  1216.             end
  1217.         end)
  1218.         Monitors.back()
  1219.         Monitors.clearLine()
  1220.         term.clear()
  1221.         return not cancelled
  1222.     end
  1223. }
  1224.  
  1225. CommandLine = {
  1226.     commands={
  1227.         craft={
  1228.             desc="Crafts the specified potion",
  1229.             usage="craft,<potionType>,<modifier>,<style>,<qty>"
  1230.         },
  1231.         help={
  1232.             desc="Displays this screen",
  1233.             usage="help"
  1234.         },
  1235.         list={
  1236.             desc={
  1237.                 "Prints a list of the connected storage",
  1238.                 "tanks along with their current contents"
  1239.             },
  1240.             usage="list"
  1241.         },
  1242.         exit={
  1243.             desc="Quits the program",
  1244.             usage="exit"
  1245.         }
  1246.     },
  1247.     read=function()
  1248.         while true do
  1249.             Monitors.clear()
  1250.             Monitors.write("Waiting for input...")
  1251.             clearTerm()
  1252.             printInstruction("Please enter command (use help for more info)")
  1253.             local com = tostring(read()):split(",")
  1254.             Monitors.clear()
  1255.             if #com > 0 then
  1256.                 if com[1] == "craft" then
  1257.                     CommandLine.craft(com[2],com[3],com[4],com[5])
  1258.                 elseif com[1] == "output" then
  1259.                     CommandLine.output(com[2],com[3],com[4],com[5])
  1260.                 elseif com[1] == "bottle" then
  1261.                    
  1262.                 elseif com[1] == "list" then
  1263.                     CommandLine.list()
  1264.                 elseif com[1] == "help" then
  1265.                     CommandLine.help()
  1266.                 elseif com[1] == "index" then
  1267.                     Inventories.indexInventories()
  1268.                 elseif com[1] == "exit" then
  1269.                     return
  1270.                 end
  1271.             end
  1272.         end
  1273.     end,
  1274.     craft=function(potionName,modifier,style,qty)
  1275.         local potionType = CommandLine.validatePotionType(potionName)
  1276.         if potionType == nil then return end
  1277.         modifier = CommandLine.validateModifier(modifier)
  1278.         if modifier == nil then return end
  1279.         style = CommandLine.validateStyle(style)
  1280.         if style == nil then return end
  1281.         qty = CommandLine.validateQty(qty,"buckets")
  1282.         if qty == nil then return end
  1283.         if type(qty) == "string" and qty == "infinite" then
  1284.             Crafting.craftInfinite(Potion:new(potionType,modifier,style))
  1285.         else
  1286.             if not Crafting.craft(Potion:new(potionType,modifier,style),qty) then
  1287.                 print("Crafting aborted")
  1288.                 sleep(3)
  1289.             end
  1290.         end
  1291.     end,
  1292.     output=function(potionName,modifier,style,qty)
  1293.         if Peripherals.workbench == nil then
  1294.             printError("Tinker's Workbench not found")
  1295.             waitForKey()
  1296.             return
  1297.         end
  1298.         local potionType = CommandLine.validatePotionType(potionName)
  1299.         if potionType == nil then return end
  1300.         modifier = CommandLine.validateModifier(modifier)
  1301.         if modifier == nil then return end
  1302.         style = CommandLine.validateStyle(style)
  1303.         if style == nil then return end
  1304.         qty = CommandLine.validateQty(qty,"buckets")
  1305.         if qty == nil then return end
  1306.         if type(qty) == "string" and qty == "infinite" then
  1307.             StorageTanks.outputInfinitePotion(Potion:new(potionType,modifier,style))
  1308.         else
  1309.             if not StorageTanks.outputPotion(Potion:new(potionType,modifier,style),qty) then
  1310.                 print("Outputting potion aborted")
  1311.                 sleep(3)
  1312.             end
  1313.         end
  1314.     end,
  1315.     list=function()
  1316.         clearTerm()
  1317.         local i = 1
  1318.         for _,tank in pairs(StorageTanks.list) do
  1319.             print("Tank "..i..": "..tank:getContentsName())
  1320.             i = i + 1
  1321.         end
  1322.         printInstruction("Press any key to continue")
  1323.         waitForKey()
  1324.     end,
  1325.     help=function()
  1326.         clearTerm()
  1327.         for commandName,data in pairs(CommandLine.commands) do
  1328.             term.setTextColor(colors.lightBlue)
  1329.             term.write(commandName)
  1330.             term.setTextColor(colors.white)
  1331.             if type(data.desc) == "string" then
  1332.                 print(data.desc)
  1333.             else
  1334.                 for _,line in ipairs(data.desc) do
  1335.                     print(line)
  1336.                 end
  1337.             end
  1338.             print("Usage: "..data.usage)
  1339.         end
  1340.         printInstruction("Press any key to continue")
  1341.         waitForKey()
  1342.     end,
  1343.     validatePotionType=function(potionName)
  1344.         local potionType = nil
  1345.         if potionName ~= nil then
  1346.             potionType = PotionTypes.getInternalName(potionName)
  1347.             if potionType == nil then
  1348.                 printError("Invalid potion name provided")
  1349.                 printInstruction("Press any key to continue")
  1350.                 waitForKey()
  1351.             end
  1352.         else
  1353.             potionType = CommandLine.promptPotionType()
  1354.         end
  1355.         return potionType
  1356.     end,
  1357.     promptPotionType=function()
  1358.         clearTerm()
  1359.         local names = List:new()
  1360.         for internalName,_ in pairs(PotionTypes.definitions) do
  1361.             names:insert(internalName)
  1362.         end
  1363.         while true do
  1364.             printInstruction("Which potion type do you want?")
  1365.             for i,internalName in ipairs(names) do
  1366.                 print(" "..i..") "..PotionTypes.definitions[internalName].names[1])
  1367.             end
  1368.             printError(" "..(#names+1)..") Cancel")
  1369.  
  1370.             local i = tonumber(read())
  1371.             if i < 1 or i > #names+1 then
  1372.                 printError("Invalid value provided")
  1373.             elseif i == #names+1 then
  1374.                 return nil
  1375.             else
  1376.                 return names[i]
  1377.             end
  1378.         end
  1379.     end,
  1380.     validateModifier=function(modifier)
  1381.         if modifier ~= nil then
  1382.             modifier = PotionModifiers.getModifier(modifier)
  1383.             if modifier == nil then
  1384.                 printError("Invalid value provided for potion modifier")
  1385.                 printInstruction("Press any key to continue")
  1386.                 waitForKey()
  1387.                 return nil
  1388.             end
  1389.             return modifier
  1390.         end
  1391.         return CommandLine.promptModifier()
  1392.     end,
  1393.     promptModifier=function()
  1394.         clearTerm()
  1395.         local mods = PotionModifiers.getList()
  1396.         while true do
  1397.             printInstruction("Which modifier do you want?")
  1398.             for m=1, #mods do
  1399.                 print(" "..m..") "..mods[m])
  1400.             end
  1401.             printError(" "..(#mods+1)..") Cancel")
  1402.             local i = tonumber(read())
  1403.             if i == nil or i < 1 or i > #mods+1 then
  1404.                 printError("Invalid value provided")
  1405.             elseif i == #mods+1 then
  1406.                 return nil
  1407.             else
  1408.                 return mods[i]
  1409.             end
  1410.         end
  1411.     end,
  1412.     validateStyle=function(style)
  1413.         if style ~= nil then
  1414.             style = PotionStyles.getStyle(style)
  1415.             if style == nil then
  1416.                 printError("Invalid value provided for potion style")
  1417.                 printInstruction("Press any key to continue")
  1418.                 waitForKey()
  1419.                 return nil
  1420.             end
  1421.             return style
  1422.         end
  1423.         return CommandLine.promptStyle()
  1424.     end,
  1425.     promptStyle=function()
  1426.         clearTerm()
  1427.         local mods = PotionStyles.getList()
  1428.         while true do
  1429.             printInstruction("Which style do you want?")
  1430.             for m=1, #mods do
  1431.                 print(" "..m..") "..mods[m])
  1432.             end
  1433.             printError(" "..(#mods+1)..") Cancel")
  1434.             local i = tonumber(read())
  1435.             if i == nil or i < 1 or i > #mods+1 then
  1436.                 printError("Invalid value provided")
  1437.             elseif i == #mods+1 then
  1438.                 return nil
  1439.             else
  1440.                 return mods[i]
  1441.             end
  1442.         end
  1443.     end,
  1444.     validateQty=function(qty,type)
  1445.         if qty ~= nil then
  1446.             if qty == "infinite" then
  1447.                 return qty
  1448.             end
  1449.             qty = tonumber(qty)
  1450.             if qty == nil or qty < 1 then
  1451.                 printError("Invalid value provided for number of "..type)
  1452.                 printInstruction("Press any key to continue")
  1453.                 waitForKey()
  1454.             end
  1455.             return qty
  1456.         end
  1457.         return CommandLine.promptQty(type)
  1458.     end,
  1459.     promptQty=function(qtyType)
  1460.         clearTerm()
  1461.         while true do
  1462.             printInstruction("How many "..qtyType.." do you want?")
  1463.             printInstruction("Enter \"infinite\" to keep producing forever")
  1464.             printError("Enter \"cancel\" to quit")
  1465.             local i = read()
  1466.             if i == "cancel" then
  1467.                 return nil
  1468.             elseif i == "infinite" then
  1469.                 return -1
  1470.             else
  1471.                 i = tonumber(i)
  1472.                 if i == nil or i <= 0 then
  1473.                     printError("Invalid value provided")
  1474.                 else
  1475.                     return i
  1476.                 end
  1477.             end
  1478.         end
  1479.     end
  1480. }
  1481.  
  1482. function run()
  1483.     if not Peripherals.wrapPeripherals() then
  1484.         return
  1485.     end
  1486.     Monitors.clear()
  1487.     clearTerm()
  1488.  
  1489.     --if Peripherals.deployer ~= nil then
  1490.     --    Crafting.initializeFuels()
  1491.     --end
  1492.  
  1493.     StorageTanks.initializeTankContents()
  1494.     if not PotionTypes.initialize() then
  1495.         return
  1496.     end
  1497.  
  1498.     Inventories.indexInventories()
  1499.  
  1500.     CommandLine.read()
  1501. end
  1502.  
  1503. run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement