Advertisement
YK7942

Potion Turtle v1.3

Apr 30th, 2014
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 32.22 KB | None | 0 0
  1. --[[TODO LIST
  2. 01. DONE make prompts blink/countdown to make them stand out to the user
  3. 02. DONE modify FindHome() to prevent turtle from running away
  4. 03. DONE modify RunMenu() so that the printing code is more compact
  5. 04. DONE modify menu routine to have +duration/+effect/splash sub menus for each of the primary potions
  6. 05. DONE allow for 'n' dispensers to be used
  7. 06. DONE modify menu to indicate what potions were selected for inactive shelves
  8. 07. DONE make the apothecary double sided for increased capacity
  9. 08. DONE allow for choosing of build position above/in/below ground
  10. 09. DONE break up Main() into simpler functions ie select, build, brew
  11. 10. DONE turtle identifies a fully stocked apothecary and sleeps longer
  12. 11. DONE make the 'are you sure?' feature remember what you were unsure about
  13. 12. TODO write more comprehensive instructions (i.e. write a manual)
  14. 13. DONE update potions list to include latest update
  15. ]]
  16.  
  17. function Main() --Control center for the program DONE
  18.     local potionList, ApothecarySize = GetPotionList()
  19.     Build(ApothecarySize)
  20.     Brew(potionList, ApothecarySize)
  21. end
  22.  
  23.  
  24. function GetPotionList() --acquires the potion list from file or from user DONE
  25.     local size, potionList
  26.     if DoesOldSaveExist() then
  27.         if IsNewSetWanted() then
  28.             size = GetSize()
  29.             potionList = RunMenu(size,{},{})
  30.             SaveFile(potionList)
  31.         else
  32.             potionList = LoadFile()
  33.             size = #potionList
  34.         end
  35.     else
  36.         size = GetSize()
  37.         potionList = RunMenu(size,{},{})
  38.         SaveFile(potionList)
  39.     end
  40.     return potionList, size
  41. end
  42.  
  43.  
  44. function Build(size) --constructs the apothecary if required DONE
  45.     if IsBuilderWanted() then
  46.         local orientation = SelectBuildOrientation()
  47.         WaitForInventory(size)
  48.         SurveySite(size,orientation)
  49.         AutoBuilder(size)
  50.     end
  51. end
  52.  
  53.  
  54. function Brew(potionList, ApothecarySize) --brews the potions DONE
  55.     local inventory, reservedSlots = DefineInventory(potionList)
  56.     FindHome(ApothecarySize)
  57.     CleanUp(reservedSlots)
  58.     local shelfNo = 1
  59.     while true do
  60.         local fullyStocked = true
  61.         if IsShelfFull(shelfNo, reservedSlots) then
  62.             fullyStocked = false
  63.         else
  64.             if IsEnoughIngredients(potionList[shelfNo], inventory) then
  65.                 FillBottles(reservedSlots)
  66.                 BrewPotion(potionList[shelfNo],inventory)
  67.                 RestockShelf(shelfNo)
  68.             else
  69.                 RestockTurtle(reservedSlots)
  70.             end
  71.         end
  72.        
  73.         shelfNo = LoopVariable(shelfNo, ApothecarySize, "+")
  74.         if shelfNo == 1 and fullyStocked then
  75.             Rest(300,"sleep","Fully stocked.")
  76.         elseif shelfNo == 1 then
  77.             Rest(60,"sleep","Cycle complete.")
  78.         end
  79.     end
  80.  
  81. end
  82.  
  83. --GetPotionList---------------------------------------------------------------------------------------------------------------
  84.  
  85. function DoesOldSaveExist() --Is there an old save file existing? DONE
  86.     print("Searching for existing save file..")
  87.     local fileName = os.getComputerID()..".potions" --computer ID with the extension .potions
  88.     local file = io.open(fileName,"r")
  89.     if file == nil then
  90.         return false
  91.     else
  92.         file:close()
  93.         return true
  94.     end
  95. end
  96.  
  97.  
  98. function IsNewSetWanted() --do you need to choose a new potion set? DONE
  99.     local timeLeft = 20
  100.     local timeInterval = 1 --in seconds
  101.     while timeLeft > 0 do
  102.         local timer = os.startTimer(timeInterval)
  103.         term.clear() term.setCursorPos(1,1)
  104.         print("Would you like to select a new set of potions??  (Y/N) \nProgram will continue in "..timeLeft.." seconds")
  105.         timeLeft = timeLeft - timeInterval
  106.         local event, result = os.pullEvent()
  107.         if event == "key" then
  108.             if result == keys.enter or result == keys.y then return true
  109.             elseif result == keys.n then return false              
  110.             end
  111.         end
  112.     end
  113.     return false
  114. end
  115.  
  116.  
  117. function GetSize() --ask user what size the apothecary should be DONE
  118.     term.clear() term.setCursorPos(1,1)
  119.     local maximum = 12 --maximum due to building materials is 17
  120.     local minimum = 4
  121.     local default = minimum
  122.     while true do
  123.         print("How many different types of potion do you wish to have in stock?")
  124.         print("NOTE: this will change the size of the apothecary")
  125.         print("Max = "..maximum..". Min = "..minimum..". Default = "..default)
  126.         local userInput = string.lower(read())
  127.         if tonumber(userInput) ~= nil then
  128.             if tonumber(userInput) >= minimum and tonumber(userInput) <= maximum then
  129.                 return tonumber(userInput)
  130.             else
  131.                 term.clear() term.setCursorPos(1,1)
  132.                 print("Outside of limits.  Try again")
  133.             end
  134.         else
  135.             term.clear() term.setCursorPos(1,1)
  136.             print("Not an integer.  Try again")
  137.         end
  138.     end
  139. end
  140.  
  141.  
  142. function RunMenu(size,potIDforShelfNo,recipeOfShelfNo) --choose a potion class and then tailor it --DONE
  143.     local potionType = {} --2D array of basic potion types {name, base ingr, [second ingr,] maxLVL, maxDUR}
  144.     local XlocOfPotionNo = {} --vector of x locations for each potion
  145.     local YlocOfPotionNo = {} --vector of y locations for each potion
  146.     local currShelfID = 1       --starting choice
  147.     local topRow = 5 --indicates the length of the headings before potions can be printed
  148.     potionType[01] = {"Water Breathing","puff.fish",1,009}
  149.     potionType[02] = {"Fire Resistance","mag.cream",1,009}
  150.     potionType[03] = {"Swiftness",      "sugar    ",009,009}
  151.     potionType[04] = {"Slowness",       "sugar    ","fm.sp.eye",009,009}
  152.     potionType[05] = {"Instant Healing","gls.melon",009,1}
  153.     potionType[06] = {"Instant Harming","spiderEye","fm.sp.eye",009,1}
  154.     potionType[07] = {"Regeneration",   "ghastTear",009,009}
  155.     potionType[08] = {"Poison",         "spiderEye",009,009}
  156.     potionType[09] = {"Night Vision",   "gldCarrot",1,009}
  157.     potionType[10] = {"Invisibility",   "gldCarrot","fm.sp.eye",1,009}
  158.     potionType[11] = {"Strength",       "blzPowder",009,009}
  159.     potionType[12] = {"Weakness",       "blzPowder","fm.sp.eye",009,009}
  160.     local itemsPP = math.ceil(#potionType/2)        --number of potions that can fit in a column
  161.    
  162.     for potionID = 1,#potionType do
  163.         local colIndex = math.ceil(potionID/itemsPP)-1
  164.         local rowIndex = potionID - colIndex*itemsPP
  165.         XlocOfPotionNo[potionID] = colIndex*20 + 1
  166.         YlocOfPotionNo[potionID] = rowIndex + topRow
  167.     end
  168.     if #potIDforShelfNo ~= size or #recipeOfShelfNo ~= size then --set selection to the default
  169.         potIDforShelfNo = {}
  170.         recipeOfShelfNo = {}
  171.         for i = 1,size do
  172.             potIDforShelfNo[i] = i
  173.             if #potionType[i] == 4 then
  174.                 recipeOfShelfNo[i] = {potionType[i][1], potionType[i][2]}
  175.             else
  176.                 recipeOfShelfNo[i] = {potionType[i][1], potionType[i][2], potionType[i][3]}
  177.             end
  178.         end
  179.     end
  180.  
  181.     local currShelfID = 1
  182.     repeat
  183.         term.clear() term.setCursorPos(1,1)
  184.         --Print the headings
  185.         print("Select your potions: (UDLR Enter)\nPress TAB to customise")
  186.         print("          <<< Shelf "..currShelfID.." of "..#potIDforShelfNo.." >>>")
  187.         PrintCentered(recipeOfShelfNo[currShelfID][1])
  188.        
  189.         --Print the potions
  190.         for potionID = 1,#potionType do
  191.             term.setCursorPos(XlocOfPotionNo[potionID], YlocOfPotionNo[potionID])
  192.             print("   "..potionType[potionID][1])
  193.         end
  194.                
  195.         --Print the indicators
  196.         term.setCursorPos(XlocOfPotionNo[potIDforShelfNo[currShelfID]], YlocOfPotionNo[potIDforShelfNo[currShelfID]])
  197.         print(">>>")
  198.        
  199.         --Print the numbers
  200.         for i = 1,#potIDforShelfNo do
  201.             term.setCursorPos(XlocOfPotionNo[potIDforShelfNo[i]], YlocOfPotionNo[potIDforShelfNo[i]])
  202.             print(i)
  203.         end
  204.        
  205.         --Receive and process keyboard input
  206.         local eventtype, key = os.pullEvent()  --get keyboard input
  207.         if key == 200 then --up key
  208.             local currPotID = potIDforShelfNo[currShelfID]
  209.             currPotID = LoopVariable(currPotID, #potionType, "-")
  210.             --copy and overwrite the ingredients to the recipe matrix
  211.             recipeOfShelfNo[currShelfID] = {}
  212.             for i = 1,#potionType[currPotID] -2 do
  213.                 recipeOfShelfNo[currShelfID][i] = potionType[currPotID][i]
  214.             end
  215.             potIDforShelfNo[currShelfID] = currPotID
  216.         elseif key == 208 then --down key
  217.             local currPotID = potIDforShelfNo[currShelfID]
  218.             currPotID = LoopVariable(currPotID, #potionType, "+")
  219.             --copy and overwrite the ingredients to the recipe matrix
  220.             recipeOfShelfNo[currShelfID] = {}
  221.             for i = 1,#potionType[currPotID] -2 do
  222.                 recipeOfShelfNo[currShelfID][i] = potionType[currPotID][i]
  223.             end
  224.             potIDforShelfNo[currShelfID] = currPotID
  225.         elseif key == 205 then --right key
  226.             currShelfID = LoopVariable(currShelfID, size, "+")
  227.         elseif key == 203 then --left key
  228.             currShelfID = LoopVariable(currShelfID, size, "-")
  229.         elseif key == 15 then --tab key
  230.             local currPotID = potIDforShelfNo[currShelfID]
  231.             --copy and overwrite the ingredients to the recipe matrix
  232.             recipeOfShelfNo[currShelfID] = {}
  233.             for i = 1,#potionType[currPotID] -2 do
  234.                 recipeOfShelfNo[currShelfID][i] = potionType[currPotID][i]
  235.             end
  236.             potIDforShelfNo[currShelfID] = currPotID
  237.             local x = XlocOfPotionNo[currPotID]
  238.             local y = YlocOfPotionNo[currPotID]
  239.             local maxLVL = potionType[currPotID][#potionType[currPotID]-1]
  240.             local maxDUR = potionType[currPotID][#potionType[currPotID]]
  241.             recipeOfShelfNo[currShelfID] = TailorPotion(x, y, maxLVL, maxDUR, recipeOfShelfNo[currShelfID])
  242.         end
  243.     until key == 28
  244.        
  245.     --print the user selection
  246.     term.clear() term.setCursorPos(1,1)
  247.     local lowestLine = 1 --used in finding where to print the "are you sure"
  248.     print("You have selected:")
  249.     for i = 1,#potIDforShelfNo do
  250.         if YlocOfPotionNo[i]-3 > lowestLine then lowestLine = YlocOfPotionNo[i]-3 end
  251.         term.setCursorPos(XlocOfPotionNo[i], YlocOfPotionNo[i]-3)
  252.         if size > 6 then --shorten the printouts to fit 2 columns to a page
  253.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Water Breathing","WtrBrea")
  254.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Fire Resistance","FireRes")
  255.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Swiftness"      ,"Speed")
  256.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Slowness"       ,"Slowness")
  257.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Instant Healing","InstHeal")
  258.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Instant Harming","InstHarm")
  259.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Regeneration"   ,"Regen.")
  260.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Poison"         ,"Poison")
  261.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Night Vision"   ,"NightVis")
  262.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Invisibility"   ,"Invis.")
  263.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Strength"       ,"Strength")
  264.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Weakness"       ,"Weakness")
  265.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Duration "      ,"Dur")
  266.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"Level "         ,"lvl")
  267.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1]," (splash)"      ,"s")
  268.             recipeOfShelfNo[i][1] = string.gsub(recipeOfShelfNo[i][1],"(splash)"       ,"s")
  269.             print(" "..NumToString(i, 2)..":"..string.sub(recipeOfShelfNo[i][1],1,15))
  270.         else
  271.             print(" "..NumToString(i, 2)..":"..recipeOfShelfNo[i][1])
  272.         end
  273.     end
  274.     term.setCursorPos(1,lowestLine)
  275.     print("\nAre you happy with this selection?(Y/N)")
  276.     input = string.upper(read())
  277.     term.clear() term.setCursorPos(1,1)
  278.     if input == "Y" then
  279.         return recipeOfShelfNo
  280.     else
  281.         return RunMenu(size,potIDforShelfNo,recipeOfShelfNo)
  282.     end
  283. end
  284.  
  285.  
  286. function TailorPotion(curX, curY, maxLevel, maxDuration, baseRecipe) --allows customization of level, duration & splash --DONE
  287.     local category = 1 --1=level, 2=duration, 3=splash
  288.     local level = 1
  289.     local duration = 1
  290.     local splash = false
  291.    
  292.     --find where to print the menu
  293.     local maxX, maxY = term.getSize()
  294.     local menuX, menuY
  295.     local sizeX, sizeY = 17, 5
  296.     local spaceX, spaceY = maxX-curX, maxY-curY
  297.     if spaceX > sizeX then
  298.         menuX = curX
  299.     else
  300.         menuX = curX - sizeX + spaceX
  301.     end
  302.     if spaceY > sizeY then
  303.         menuY = curY + 1
  304.     else
  305.         menuY = curY - sizeY
  306.     end
  307.        
  308.     repeat --until keypress = enter or tab
  309.         --print the menu
  310.         if splash == true then splashString = "[x]" else splashString = "[ ]" end
  311.         term.setCursorPos(menuX, menuY)
  312.         print("#=(UDLR Enter)==#")
  313.         term.setCursorPos(menuX, menuY+1)
  314.         print("| Level:"..NumToString(level,1).."       |")
  315.         term.setCursorPos(menuX, menuY+2)
  316.         print("| Duration:"..NumToString(duration,1).."    |")
  317.         term.setCursorPos(menuX, menuY+3)
  318.         print("| Splash:"..splashString.."    |")
  319.         term.setCursorPos(menuX, menuY+4)
  320.         print("#===============#")
  321.         if category == 1 then term.setCursorPos(menuX +1,menuY +1) end
  322.         if category == 2 then term.setCursorPos(menuX +1,menuY +2) end
  323.         if category == 3 then term.setCursorPos(menuX +1,menuY +3) end
  324.         print(">")
  325.        
  326.         --Recieve and process keyboard input
  327.         local eventtype, key = os.pullEvent()  --get keyboard input
  328.         if key == 203 then --left key changes category
  329.             if category == 1 then level = LoopVariable(level, maxLevel, "-") duration = 1
  330.             elseif category == 2 then duration = LoopVariable(duration, maxDuration, "-") level = 1
  331.             elseif category == 3 then splash = not splash
  332.             end
  333.         elseif key == 205 then --right key changes category
  334.             if category == 1 then level = LoopVariable(level, maxLevel, "+") duration = 1
  335.             elseif category == 2 then duration = LoopVariable(duration, maxDuration, "+") level = 1
  336.             elseif category == 3 then splash = not splash
  337.             end
  338.         elseif key == 208 then --down key changes number
  339.             category = LoopVariable(category, 3, "+")
  340.         elseif key == 200 then --up key changes number
  341.             category = LoopVariable(category, 3, "-")
  342.         end
  343.     until key == 28 or key == 15  --if keypress = 'enter' or 'tab'
  344.    
  345.     --tailor the name of the potion
  346.     local suffix = ""
  347.     if duration > 1 then suffix = "Duration "..duration.." " end
  348.     if level > 1 then suffix = "Level "..level.." " end
  349.     if splash == true then suffix = suffix.."(splash)" end
  350.     baseRecipe[1] = baseRecipe[1].." "..suffix
  351.    
  352.     --adjust the recipe based on the users input
  353.     for i = 1,level-1,1 do baseRecipe[#baseRecipe+1] = "glowstone" end
  354.     for i = 1,duration-1,1 do baseRecipe[#baseRecipe+1] = "redstone " end
  355.     if splash then baseRecipe[#baseRecipe+1] = "gunpowder" end
  356.     return baseRecipe
  357. end
  358.  
  359.  
  360. function SaveFile(potionShortList) --saves the potion list as an 8 bit number in a file DONE
  361.     print("Saving potion set to file..")
  362.     local fileName = os.getComputerID()..".potions" --computer ID with the extension .potions
  363.     local file = fs.open(fileName,"w")
  364.     for potionNo = 1,#potionShortList do
  365.         local potionString = ""
  366.         for potionItem = 1,#potionShortList[potionNo],1 do
  367.             potionString = potionString..potionShortList[potionNo][potionItem]
  368.         end
  369.         file.writeLine(potionString)
  370.     end
  371.     file:close()
  372. end
  373.  
  374.  
  375. function LoadFile() --loads the data from file and returns the potion list DONE
  376.     print("Loading potions set from existing file..")
  377.     local fileName = os.getComputerID()..".potions" --computer ID with the extension .potions
  378.     local file = fs.open(fileName,"r")
  379.     local potionShortList = {}
  380.     local dataString = file.readLine()
  381.     local potionNumber = 0
  382.    
  383.     while dataString ~= null do
  384.         potionNumber = potionNumber + 1
  385.         potionShortList[potionNumber] = {}
  386.         potionShortList[potionNumber][1] = dataString:sub(1,10) --record the potion name
  387.         for potionItem = 1,(dataString:len()-10)/9 do
  388.             local startChar = potionItem*9 + 1 + 1
  389.             local endChar =   potionItem*9 + 1 + 9
  390.             potionShortList[potionNumber][potionItem+1] = dataString:sub(startChar,endChar)
  391.         end
  392.         dataString = file.readLine()
  393.     end    
  394.    
  395.     file:close()
  396.     return potionShortList
  397. end
  398.  
  399. --Build-----------------------------------------------------------------------------------------------------------------------
  400.  
  401. function IsBuilderWanted() --Ask the user if they require instructions DONE
  402.     local timeLeft = 20
  403.     local timeInterval = 1 --in seconds
  404.     while timeLeft > 0 do
  405.         local timer = os.startTimer(timeInterval)
  406.         term.clear() term.setCursorPos(1,1)
  407.         print("Would you like to use the builder program??  (Y/N) \nProgram will continue in "..timeLeft.." seconds")
  408.         timeLeft = timeLeft - timeInterval
  409.         local event, result = os.pullEvent()
  410.         if event == "key" then
  411.             if result == keys.enter or result == keys.y then return true
  412.             elseif result == keys.n then return false              
  413.             end
  414.         end
  415.     end
  416.     return false
  417. end
  418.  
  419.  
  420. function SelectBuildOrientation() --Asks the user how the apothecary will lie in the ground DONE
  421.     local depth
  422.     term.clear() term.setCursorPos(1,1)
  423.     while true do
  424.         print("How would you like the apothecary to be built? 0|1|2")
  425.         print[[
  426. [0] ABOVE GROUND       [][][][][]
  427.                    ____[][][][][]____
  428.                
  429. [1] IN GROUND      ____[][][][][]____
  430.                        [][][][][]
  431.              
  432. [2] BELOW GROUND   ____          ____
  433.                        [][][][][]
  434.                        [][][][][] ]]
  435.         depth = read()
  436.         if tonumber(depth) == nil or 0 > tonumber(depth) or tonumber(depth) > 2 then
  437.             term.clear() term.setCursorPos(1,1)
  438.             print("INVALID INPUT. \""..depth.."\" TRY AGAIN.")
  439.         else
  440.             return tonumber(depth)
  441.         end
  442.     end
  443. end
  444.  
  445.  
  446. function WaitForInventory(size) --Waits for the required building materials DONE
  447.     local reqBM
  448.     if size < 10 then
  449.         reqBM = 11+3*size
  450.     else
  451.         reqBM = 29 - size
  452.     end
  453.     repeat
  454.         term.clear() term.setCursorPos(1,1)
  455.         local inventory = "good"
  456.         turtle.select(1)  --building material
  457.         if turtle.getItemCount(1) ~= reqBM then
  458.             print(" - Put exactly "..(11+3*size).." blocks of a building material in slot 1")
  459.             inventory = "bad"
  460.         end
  461.         turtle.select(2)  --dispensers
  462.         if turtle.getItemCount(2) ~= size then
  463.             print(" - Put exactly "..size.." dispensers or droppers in slot 2")
  464.             inventory = "bad"
  465.         end
  466.         turtle.select(3)  --chest
  467.         if turtle.getItemCount(3) ~= 2 then
  468.             print(" - Put exactly 2 chests in slot 3")
  469.             inventory = "bad"
  470.         end
  471.         turtle.select(4)  --brewing stand
  472.         if turtle.getItemCount(4) ~= 1 then
  473.             print(" - Put exactly one brewing stand in slot 4")
  474.             inventory = "bad"
  475.         end
  476.         turtle.select(5)  --fuel
  477.         turtle.refuel()
  478.         if turtle.getFuelLevel() < 90 then
  479.             print(" - Put at least 2 coal worth of fuel in slot 5")
  480.             inventory = "bad"
  481.         end
  482.         if inventory == "bad" then sleep(3) end
  483.     until inventory == "good"
  484. end
  485.  
  486.  
  487. function SurveySite(size,depth) --starting at brewing stand end DONE
  488.     if size > 9 then size = 9 end
  489.     term.clear() term.setCursorPos(1,1)
  490.     print("Surveying site.  Clear the blocks I indicate.")
  491.     --moving to account for depth selection
  492.     for i = 1,depth do
  493.         while turtle.detectDown() == true do
  494.             term.clear() term.setCursorPos(1,1)
  495.             print("Remove the block below. TimeStamp = " ..os.clock())
  496.             sleep(2)
  497.         end
  498.         turtle.down()
  499.     end
  500.     --survey the main volume
  501.     for layer = 1,2 do
  502.         for i = 1,size+1 do
  503.             while turtle.detect() == true do
  504.                 term.clear() term.setCursorPos(1,1)
  505.                 print("Remove this block. TimeStamp = " ..os.clock())
  506.                 sleep(2)
  507.             end
  508.             turtle.turnLeft()
  509.             while turtle.detect() == true do
  510.                 term.clear() term.setCursorPos(1,1)
  511.                 print("Remove this block. TimeStamp = " ..os.clock())
  512.                 sleep(2)
  513.             end
  514.             TurnAround()
  515.             while turtle.detect() == true do
  516.                 term.clear() term.setCursorPos(1,1)
  517.                 print("Remove this block. TimeStamp = " ..os.clock())
  518.                 sleep(2)
  519.             end
  520.             turtle.turnLeft()
  521.             turtle.forward()
  522.         end
  523.         turtle.forward()
  524.         turtle.turnLeft()
  525.         while turtle.detect() == true do
  526.             term.clear() term.setCursorPos(1,1)
  527.             print("Remove this block. TimeStamp = " ..os.clock())
  528.             sleep(2)
  529.         end
  530.         TurnAround()
  531.         while turtle.detect() == true do
  532.             term.clear() term.setCursorPos(1,1)
  533.             print("Remove this block. TimeStamp = " ..os.clock())
  534.             sleep(2)
  535.         end
  536.         turtle.turnLeft()
  537.        
  538.         if layer == 1 then
  539.             while turtle.detectUp() == true do
  540.                 term.clear() term.setCursorPos(1,1)
  541.                 print("Remove the block above. TimeStamp = " ..os.clock())
  542.                 sleep(2)
  543.             end
  544.             turtle.up()
  545.             TurnAround()
  546.         end
  547.     end
  548.     turtle.down()
  549.     TurnAround()
  550.    
  551.     --survey the water well
  552.     turtle.forward() turtle.forward()
  553.     while turtle.detectDown() == true do
  554.         term.clear() term.setCursorPos(1,1)
  555.         print("Remove the block below and fill it with water. TimeStamp = " ..os.clock())
  556.         sleep(2)
  557.     end
  558.     turtle.back() turtle.back()
  559. end
  560.  
  561.  
  562. function AutoBuilder(noDispensers) --starting at brewing stand end DONE
  563.     local BM = 1 DISP = 2 CH = 3 BS = 4 --remember which slot has what
  564.     local size
  565.     if noDispensers > 9 then size = 9 else size = noDispensers end
  566.     print("Laying bottom layer")
  567.     turtle.select(BM)
  568.     turtle.turnLeft() --build brewing end
  569.     turtle.place()
  570.     TurnAround()
  571.     turtle.place()
  572.     turtle.turnRight()
  573.     turtle.back()
  574.     turtle.place()
  575.     turtle.turnRight()
  576.     turtle.place()
  577.     TurnAround()
  578.     turtle.place()
  579.     turtle.turnRight()
  580.     turtle.back()
  581.     turtle.select(BS)
  582.     turtle.place()
  583.     turtle.select(BM)
  584.     turtle.turnRight()
  585.     turtle.place()
  586.     TurnAround()
  587.     turtle.place()
  588.     turtle.turnLeft()
  589.     for i = 1,size-1 do
  590.         turtle.forward()
  591.         turtle.turnLeft()
  592.         turtle.place()
  593.         TurnAround()
  594.         turtle.place()
  595.         turtle.turnLeft()
  596.     end
  597.     print("Laying top layer layer")
  598.     turtle.up()
  599.     turtle.placeDown()
  600.     turtle.turnLeft()
  601.     turtle.place()
  602.     TurnAround()
  603.     turtle.place()
  604.     turtle.turnLeft()
  605.     turtle.back()
  606.     turtle.select(CH)
  607.     turtle.place()
  608.     turtle.placeDown()
  609.     TurnAround()
  610.     for i = 1,size do
  611.         turtle.turnLeft()
  612.         turtle.select(DISP)
  613.         turtle.place()
  614.         TurnAround()
  615.         if i >= size*2-noDispensers then --dispenser or BM?
  616.             turtle.select(BM)
  617.         end
  618.         turtle.place()
  619.         turtle.turnLeft()
  620.         turtle.forward()
  621.     end
  622.     turtle.turnLeft()
  623.     turtle.place()
  624.     TurnAround()
  625.     turtle.place()
  626.     turtle.turnLeft()
  627.     turtle.back()
  628.     turtle.place()
  629. end
  630.  
  631. --Brew-----------------------------------------------------------------------------------------------------------------------
  632.  
  633. function DefineInventory(potionShortList) --gives instruction on inventory layout and returns the inventory array DONE
  634.     local inventory = {"bottles  ","neth.wart"} --establish the inventory
  635.     for potID = 1,#potionShortList do --loop through all potions
  636.         for ingredient = 2,#potionShortList[potID] do --loop through all the ingredients
  637.             local listed = false  --assume the current ingredient not in the inventory array
  638.             for slot = 1,#inventory do
  639.                 if inventory[slot] == potionShortList[potID][ingredient] then
  640.                     listed = true
  641.                 end
  642.             end
  643.             if listed == false then
  644.                 inventory[#inventory+1] = potionShortList[potID][ingredient] --append the array
  645.             end
  646.         end
  647.     end
  648.     local resSlotNum = #inventory --calculates the number of reserved slots
  649.     for slot = resSlotNum+1,16 do inventory[slot] = "[empty]  " end --mark the empty slots
  650.  
  651.     --prints the inventory and scans the inventory ensuring it is at least minimally stocked
  652.     local stocked
  653.     repeat
  654.         stocked = true
  655.         for slot = 1,resSlotNum do
  656.             turtle.select(slot)
  657.             if turtle.getItemCount(slot) == 0 then
  658.                 stocked = false
  659.                 term.clear() term.setCursorPos(1,1)
  660.                 print("Stock the inventory to continue.\n\n")
  661.                 for x = 0,3 do
  662.                     print(inventory[x*4+1].." "..inventory[x*4+2].." "..inventory[x*4+3].." "..inventory[x*4+4].."")
  663.                 end
  664.                 sleep(1)
  665.             end
  666.         end
  667.     until stocked
  668.     term.clear() term.setCursorPos(1,1)
  669.    
  670.     return inventory, resSlotNum
  671. end
  672.  
  673.  
  674. function FindHome(size) --Navigates to home base DONE
  675.     print("\nGetting my bearings...")
  676.     --turtle will find the position above the water and then move to be above the brewing stand
  677.     --orient turtle in the axis of the apothecary
  678.     local turnCount = 4
  679.     while turtle.detect() == true do
  680.         turtle.turnLeft()
  681.         turnCount = turnCount - 1
  682.         if turnCount == 0 then error("NAVIGATION ERROR\nTurtle is lost\nForcing quit\n") end
  683.     end
  684.     --check if it on the top layer or bottom layer based on the length
  685.     for i = 1,size do turtle.forward() end --go to end
  686.     TurnAround()
  687.     for i = 1,size-3 do turtle.forward() end
  688.     if turtle.detect() == false then --the turtle is on the top layer
  689.         turtle.down()
  690.         turtle.forward()
  691.     end
  692.     if turtle.detectDown() == true then --if it is at the far end
  693.         TurnAround()
  694.         for i = 1,size-3 do turtle.forward() end
  695.     end
  696.     if turtle.detectDown() == true then error("NAVIGATION ERROR\nTurtle is lost!\nForcing quit\n") end
  697.     turtle.up()
  698.     turtle.forward()
  699. end
  700.  
  701.  
  702. function CleanUp(reservedSlotCount) --Clears away any leftovers from the previous run DONE
  703.     print("Cleaning up from last time")
  704.     turtle.suckDown()
  705.     turtle.back()
  706.     turtle.down()
  707.     for i = 1,3 do turtle.suck() end
  708.     TurnAround()
  709.     GoToEnd(9)
  710.     for slot = reservedSlotCount+1,16 do
  711.         turtle.select(slot)
  712.         turtle.drop(64)
  713.     end
  714.     TurnAround()
  715.     turtle.up()
  716.     GoToEnd(9)
  717.     term.clear() term.setCursorPos(1,1)
  718. end
  719.  
  720.  
  721. function IsShelfFull(shelfID,reservedSlotCount) --counts the contents of a shelf and returns true or false DONE
  722.     print("Inspecting shelf #"..shelfID.."..")
  723.     --calculate distance to shelf and which side it is on
  724.     local distance local turnLeft
  725.     if shelfID > 9 then
  726.         distance = shelfID - 9
  727.         turnLeft = false
  728.     else
  729.         distance = shelfID
  730.         turnLeft = true
  731.     end
  732.     --move into position and face the shelf
  733.     while distance > 1 do
  734.         turtle.back()
  735.         distance = distance - 1
  736.     end
  737.     if turnLeft then
  738.         turtle.turnLeft()
  739.     else
  740.         turtle.turnRight()
  741.     end
  742.     --attempt to withdraw as many potions as possible
  743.     turtle.select(reservedSlotCount+1)
  744.     for slot = reservedSlotCount+1,16 do
  745.         turtle.suck()
  746.     end
  747.     --count the potions and put them back
  748.     local potionCount = 0
  749.     for slot = reservedSlotCount+1,16 do
  750.         turtle.select(slot)
  751.         if turtle.getItemCount(slot) == 1 then --if there's a potion
  752.             potionCount = potionCount + 1
  753.         elseif turtle.getItemCount(slot) == 0 then --if there's nothing
  754.             break
  755.         else
  756.             print("ERROR: Detected non-potion item.  Proceeding regardless")
  757.         end
  758.         turtle.drop()
  759.     end
  760.     --go home
  761.     if turnLeft == false then
  762.         turtle.turnLeft()
  763.     else
  764.         turtle.turnRight()
  765.     end
  766.     GoToEnd(9)
  767.     --return a result
  768.     local emptySlotCount = 16-reservedSlotCount
  769.     if potionCount < emptySlotCount then --if less than maximum count
  770.         if potionCount > 6 then --if no room for more potions (max:9)
  771.             print("Shelf is full.")
  772.             return true
  773.         else
  774.             print("Shelf is NOT full.")
  775.             return false
  776.         end
  777.     else
  778.         print("Shelf is full.")
  779.         return true
  780.     end
  781. end
  782.  
  783.  
  784. function IsEnoughIngredients(potionRecipe, inventoryList) --ensures enough supply of raw materials for brewing DONE
  785.     print("Checking internal storage..")
  786.     turtle.select(1) --contains bottles
  787.     if turtle.getItemCount(1) <= 3 then return false end
  788.     turtle.select(2)
  789.     if turtle.getItemCount(2) <= 1 then return false end
  790.     for slot = 3,16 do
  791.         turtle.select(slot)
  792.         if turtle.getItemCount(slot) <= 1 then --check item count first.  more likely to be false.  saves time
  793.             for ingredient = 2,#potionRecipe do
  794.                 if inventoryList[slot] == potionRecipe[ingredient] then
  795.                     print("Insufficient internal storage.")
  796.                     return false
  797.                 end
  798.             end
  799.         end
  800.     end
  801.     if turtle.getFuelLevel() < 200 then return false end
  802.     print("Internal storage is sufficient.")
  803.     return true
  804. end
  805.  
  806.  
  807. function FillBottles(reservedSlotCount) --DONE
  808.     print("Filling bottles..")
  809.     turtle.back()
  810.     turtle.down()
  811.     for i = 1,3 do
  812.         turtle.select(1) --slot 1 contains empty bottles
  813.         turtle.placeDown()
  814.         turtle.select(reservedSlotCount + 1)
  815.         turtle.drop()
  816.     end
  817.     turtle.up()
  818.     turtle.forward()
  819. end
  820.  
  821.  
  822. function BrewPotion(potionRecipe, inventoryList) --brews the potion corresponding to the shelfID DONE
  823.     local potionSize = #potionRecipe
  824.     --find the next ingredient in the recipe in the inventory and put it in the stand
  825.     for ingredient = 1,#potionRecipe do --for each ingredient in the potion
  826.         for slot = 2,16 do --for each slot in the inventory
  827.             if inventoryList[slot] == potionRecipe[ingredient] then --compare the recipe step to the inventory slot
  828.                 turtle.select(slot)
  829.                 turtle.dropDown(1)
  830.                 sleep(1) --this is just a buffer in case it takes longer than 20s to brew a step
  831.                 term.clear() term.setCursorPos(1,1)
  832.                 Rest(20,"brew","Brewing step "..ingredient.." of "..#potionRecipe.." for "..potionRecipe[1])
  833.             end
  834.         end
  835.     end
  836. end
  837.  
  838.  
  839. function RestockShelf(shelfID)  --puts freshly brewed potions on the shelf DONE
  840.     print("Restocking Shelves...")
  841.     --calculate distance to shelf and which side it is on
  842.     local distance local turnLeft
  843.     if shelfID > 9 then
  844.         distance = shelfID - 9
  845.         turnLeft = false
  846.     else
  847.         distance = shelfID
  848.         turnLeft = true
  849.     end
  850.     --move to the brewing stand
  851.     turtle.back()
  852.     turtle.down()
  853.     --extract potions
  854.     for i = 1,3 do
  855.         turtle.suck()
  856.     end
  857.     --move to home
  858.     turtle.up()
  859.     turtle.forward()
  860.     --move into position and face the shelf
  861.     while distance > 1 do
  862.         turtle.back()
  863.         distance = distance - 1
  864.     end
  865.     if turnLeft then
  866.         turtle.turnLeft()
  867.     else
  868.         turtle.turnRight()
  869.     end
  870.     --identify which slots the potions are stored in
  871.     local slot = 16
  872.     turtle.select(slot)
  873.     while turtle.getItemCount(slot) == 0 do
  874.         slot = slot - 1
  875.         turtle.select(slot)
  876.     end
  877.     --put the potions away
  878.     for i = 1,3 do
  879.         turtle.drop()
  880.         slot = slot - 1
  881.         turtle.select(slot)
  882.     end
  883.     --move to home
  884.     if turnLeft == false then
  885.         turtle.turnLeft()
  886.     else
  887.         turtle.turnRight()
  888.     end
  889.     GoToEnd(9)
  890. end
  891.  
  892.  
  893. function RestockTurtle(reservedSlotCount) --restocks the turtle from the storage chests DONE
  894.     print("Restocking turtle...")
  895.     TurnAround()
  896.     GoToEnd(9)
  897.    
  898.     turtle.select(reservedSlotCount+1)
  899.     while turtle.suck() == true do --get a stack of items
  900.         for slot = 1,reservedSlotCount do turtle.transferTo(slot,64) end  --shove it in the working inventory
  901.         turtle.refuel()   --attempt to refuel with the item
  902.         turtle.dropDown()  --dump the item in the temp chest
  903.     end
  904.     while turtle.suckDown() == true do  --move items from temp to perm chest
  905.       turtle.drop()
  906.     end
  907.    
  908.     TurnAround()
  909.     GoToEnd(9)
  910.     if turtle.getFuelLevel() < 100 then
  911.         Rest(300,"sleep","Low on fuel.  Slowing down work rate..")
  912.     elseif turtle.getFuelLevel() < 200 then
  913.         Rest(100,"sleep","Low on fuel.  Slowing down work rate..")
  914.     end
  915. end
  916.  
  917. --Utilities------------------------------------------------------------------------------------------------------------------
  918.  
  919. function Rest(restTime, restType, heading) --makes the turtle sleep for a time with animations DONE
  920.     term.clear() term.setCursorPos(1,1)
  921.     print(heading)
  922.     local restStep
  923.     while restTime > 0 do
  924.         term.setCursorPos(1,2)
  925.         if restType == "brew" then
  926.             restStep = 1 --must be an odd number
  927.             print("Brewing for "..restTime.."s  \n")
  928.             if math.fmod(restTime,2) == 0 then
  929.                 print[[
  930.                   \      
  931.                  } \   {
  932.                 |O  \o  |
  933.                 |  o \  |
  934.                  \_____/
  935.                 ]]
  936.             else
  937.                 print[[
  938.                       /  
  939.                  }   / {
  940.                 | o / O |
  941.                 |  / o  |
  942.                  \_____/
  943.                 ]]
  944.             end
  945.         elseif restType == "sleep" then
  946.             restStep = 1 --must be an odd number
  947.             print("Sleeping for "..restTime.."s   \n")
  948.             if math.fmod(restTime,2) == 0 then
  949.                 print[[
  950.                 ==== ====          
  951.                   //   // ===  ===  
  952.                  //   //   //   //  
  953.                 ==== ====  ===  ===
  954.                 ]]
  955.             else
  956.                 print[[
  957.                 ==== ====  ===  ===
  958.                   //   //   //   //
  959.                  //   //    ===  ===
  960.                 ==== ====          
  961.                 ]]
  962.             end
  963.         end
  964.         restTime = restTime - restStep
  965.         sleep(restStep)
  966.     end
  967.     term.clear() term.setCursorPos(1,1)
  968. end
  969.  
  970.  
  971. function LoopVariable(i, maximum, direction) --loops variable from 1->maximum->1 DONE
  972.     if direction == "+" and i >= maximum then return 1   end
  973.     if direction == "+" and i  < maximum then return i+1 end
  974.     if direction == "-" and i <= 1 then return maximum end
  975.     if direction == "-" and i  > 1 then return i-1     end
  976. end
  977.  
  978.  
  979. function NumToString(x,sigFig) --converts int to string showing significant figures
  980.     local zeros = tostring(x)
  981.     local numberSize = math.ceil(math.log10(x+1))
  982.     for i = numberSize,sigFig-1,1 do
  983.         zeros = "0"..zeros
  984.     end
  985.     return zeros
  986. end
  987.  
  988.  
  989. function PrintCentered(text)
  990.     local textLength = string.len(tostring(text))
  991.     local pageWidth,pageLength = term.getSize()
  992.     if textLength > pageWidth then error("Error in PrintCentered(). Cannot fit text to screen") end
  993.     local spacerLength = math.ceil(0.5*(pageWidth-textLength))
  994.     local cursorX, cursorY = term.getCursorPos()
  995.     term.setCursorPos(cursorX + spacerLength, cursorY)
  996.     print(text)
  997. end
  998.  
  999.  
  1000. function TurnAround()  --turtle performs a 180 leftwise turn DONE
  1001.     turtle.turnLeft() turtle.turnLeft()
  1002. end
  1003.  
  1004.  
  1005. function GoToEnd(runCount) --turtle moves until it hits something (break after 8 paces)
  1006.     if runCount == nil then print("ERROR in func:GoToEnd()\nDist not specified") runCount = 8 end
  1007.     while turtle.forward() == true do
  1008.         turtle.forward()
  1009.         runCount = runCount - 1
  1010.         if runCount == 0 then
  1011.             error("\nTurtle is lost!\nForcing quit\n")
  1012.         end
  1013.     end
  1014. end
  1015.  
  1016. term.clear() term.setCursorPos(1,1)
  1017. print("Starting program 'Potion Robot v1.3' by YardKing42 aka YK7942\n")
  1018. Main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement