Haruchai

oredig

Jan 26th, 2015
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.     Do whatever you want with the script, but give credit to people who wrote it and keep this license. Simple, right?
  3.     Writers:
  4.     access_denied
  5. ]]
  6.  
  7. --[[
  8.     OreDig version 1.4.1
  9. ]]
  10.  
  11. --[[
  12.     CONSTANTS
  13. ]]
  14. BEDROCK_LEVEL = 2 --Level at which the bedrock is
  15. PERSISTANCE_FILE_PATH = "digpersist"
  16. MOVEMENT_DELAY = 0.0
  17. ROTATION_DELAY = 0.0
  18. TRY_LIMIT = 10
  19. STARTUP_SCRIPT_STRING = [[shell.run("%s", "resume")]]
  20.  
  21. DIRS = { --Directions are numbers for easy manipulation.
  22.     NORTH = 0,
  23.     EAST = 1,
  24.     SOUTH = 2,
  25.     WEST = 3,
  26. }
  27.  
  28. TASKS = { --Different task descriptions
  29.     SHAFT =  "digging shaft",
  30.     MOVING_TO_DOCK = "moving to dock",
  31.     MOVING_TO_SHAFT = "moving to shaft",
  32.     REFUELING = "refueling",
  33.     DUMPING = "dumping all items",
  34.     WAITING_FOR_FUEL = "waiting for fuel",
  35.     FINISHED = "finished"
  36. }
  37.  
  38. STARTUP_SCRIPT_INSTALL_STATUS = {
  39.     NOT_INSTALLED = 1,
  40.     DIFFERENT = 2,
  41.     INSTALLED = 0
  42. }
  43. --[[
  44.     Code from http://wiki.interfaceware.com/112.html
  45.     Allows me to serialize tables.
  46. ]]
  47. function SaveTable(Table)
  48.    local savedTables = {} -- used to record tables that have been saved, so that we do not go into an infinite recursion
  49.    local outFuncs = {
  50.       ['string']  = function(value) return string.format("%q",value) end;
  51.       ['boolean'] = function(value) if (value) then return 'true' else return 'false' end end;
  52.       ['number']  = function(value) return string.format('%f',value) end;
  53.    }
  54.    local outFuncsMeta = {
  55.       __index = function(t,k) error('Invalid Type For SaveTable: '..k) end      
  56.    }
  57.    setmetatable(outFuncs,outFuncsMeta)
  58.    local tableOut = function(value)
  59.       if (savedTables[value]) then
  60.          error('There is a cyclical reference (table value referencing another table value) in this set.');
  61.       end
  62.       local outValue = function(value) return outFuncs[type(value)](value) end
  63.       local out = '{'
  64.       for i,v in pairs(value) do out = out..'['..outValue(i)..']='..outValue(v)..';' end
  65.       savedTables[value] = true; --record that it has already been saved
  66.       return out..'}'
  67.    end
  68.    outFuncs['table'] = tableOut;
  69.    return tableOut(Table);
  70. end
  71.  
  72. function LoadTable(Input)
  73.    -- note that this does not enforce anything, for simplicity
  74.    return assert(loadstring('return '..Input))()
  75. end
  76.  
  77. --[[
  78.     Now my stuff
  79. ]]
  80.  
  81. data = { --Just a table that I have created for convenience. It will be written to a file every move. Keeps track of many different variables.
  82.     lenx = 4, --Width of quarry
  83.     lenz = 4, --Depth of quarry
  84.     height = 6, --Height of quarry
  85.     shaftsDone = 0, --How many shafts are already done
  86.     shaftsToDo = 0, --How many shafts left
  87.     dir = DIRS.NORTH, --Relative direction in which the turtle is currently facing. North will always be the direction in which the turtle was facing when it was started.
  88.     reservedSlots = 2, --How many slots are reserved for items that aren't to be mined and fuel items.
  89.     fuelPerItem = 80, --How much fuel is given per fuel item
  90.     currentlyDoing = TASKS.WAITING_FOR_FUEL, --What task is currently being done
  91.     currentShaftProgress = 0, --How many blocks are done in the current shaft
  92.     coords = {}, --Current coordinates relative to the dock
  93.     shafts = {}, --Array of shaft coordinates left to do
  94.     fuelItemsRequired = 0,
  95.     fuelItemsUsed = 0,
  96.     debug = 0,
  97.     shaftsGenerated = false
  98. }
  99. data.coords = {x = 0, y = data.height, z = 0} --We start at the dock.
  100. --[[
  101.     Helper methods
  102. ]]
  103. function xor(a, b) return (a~=b) and (a or b) end --Fake XOR snipplet
  104. function cleanup()
  105.     term.clear()
  106.     term.setCursorPos(1, 1)
  107. end
  108. --[[
  109.     Persistance
  110. ]]
  111. function dumpToFile() --Dump the state to file
  112.     local file = io.open(PERSISTANCE_FILE_PATH, "w")
  113.     file:write(SaveTable(data))
  114.     file:close()
  115. end
  116.  
  117. function readFromFile() --Read the state from file
  118.     local file = io.open(PERSISTANCE_FILE_PATH, "r")
  119.     if file then
  120.         local tableStr = file:read("*a")
  121.         data = LoadTable(tableStr) 
  122.         file:close()
  123.     end
  124. end
  125.  
  126. function periodicSave()
  127.     while 1 do
  128.         dumpToFile()
  129.         sleep(0.5)
  130.     end
  131. end
  132. --[[
  133.     Mining methods
  134. ]]
  135. do
  136.     function setStatus(status)
  137.         data.currentlyDoing = status
  138.     end
  139.     local function getRequiredFuelToGoBack(x, y, z) --Not tested, but should return the fuel required to go back to dock
  140.         return data.height - y + x + z + 2
  141.     end
  142.     local function getRequiredFuelToProcessShaft(x, z) --Calculates how much fuel is required to go to the shaft, process it and come back.
  143.         return (data.height - BEDROCK_LEVEL + x + z + 2) * 2
  144.     end
  145.     local function hasRequiredFuelToGoBack(x, y, z)
  146.         return getRequiredFuelToGoBack(x, y, z) <= turtle.getFuelLevel()
  147.     end
  148.     local function hasRequiredFuelToProcessShaft(x, z)
  149.         return getRequiredFuelToProcessShaft(x, z) <= turtle.getFuelLevel()
  150.     end
  151.     local function hasRequiredFuelAndSpace(x, y, z)
  152.         return hasRequiredFuelToGoBack(x, y, z) and turtle.getItemCount(16) == 0 -- We need enough fuel to go up after going down and return to the dock. We also need space to put the items into.
  153.     end
  154.     function setDir(todir) --Turn to the required direction optimaly
  155.         if(data.dir == todir) then return end --No need to turn!
  156.         local way = math.abs(data.dir-todir) <= (math.min(data.dir, todir) + 4 - math.max(data.dir,todir)) -- true if we don't need to go "out of bounds", e.g. <-0 or 3->
  157.         local rotdir = (xor(way, (todir > data.dir))) and -1 or 1 --Direction in which we will spin
  158.         while data.dir ~= todir do
  159.             data.dir = (data.dir + rotdir) % 4 --Enforce 0<=dir<=3
  160.             dumpToFile() --Each turn, we have to dump to file, otherwise we might have a problem with sync of virtual state and real state of the turtle.
  161.             turtle[rotdir > 0 and "turnRight" or "turnLeft"]()
  162.         end
  163.         sleep(ROTATION_DELAY)
  164.     end
  165.     function dump() --Dump all mined materials
  166.         setStatus(TASKS.DUMPING)
  167.         for i = data.reservedSlots + 2, 16 do --Dump all mined materials
  168.             if turtle.getItemCount(i)~=0 then --DAMN, I NEED MY CONTINUE!!! Well, we don't want to waste time on empty slots...
  169.                 turtle.select(i)
  170.                 turtle.drop(turtle.getItemCount(i))
  171.             end
  172.         end
  173.     end
  174.     function refuelAndDump(x, z) --Refuel and dump
  175.         setDir(DIRS.SOUTH)
  176.         setStatus(TASKS.REFUELING)
  177.         turtle.select(1)
  178.         if not hasRequiredFuelToProcessShaft(x, z) and turtle.getItemCount(1)>1 then --Use coal that we've mined
  179.             turtle.refuel(math.min(turtle.getItemCount(1)-1, math.ceil((getRequiredFuelToProcessShaft(x, z)-turtle.getFuelLevel()) / data.fuelPerItem)))
  180.         end
  181.         while not hasRequiredFuelToProcessShaft(x, z) do
  182.             turtle.select(1)
  183.             data.fuelItemsRequired = math.ceil((getRequiredFuelToProcessShaft(x, z) - turtle.getFuelLevel()) / data.fuelPerItem) --We require this much fuel items
  184.             data.debug = getRequiredFuelToProcessShaft(x, z).." "..turtle.getFuelLevel()
  185.             turtle.suckUp()
  186.             local willConsume = math.min(turtle.getItemCount(1)-1, data.fuelItemsRequired)
  187.             if willConsume > 0 and turtle.refuel(willConsume) then --Successfully consumed
  188.                 setStatus(TASKS.REFUELING)
  189.                 data.fuelItemsUsed = data.fuelItemsUsed + willConsume
  190.             else --Could not consume
  191.                 setStatus(TASKS.WAITING_FOR_FUEL)
  192.                 sleep(5)
  193.             end
  194.         end
  195.         data.fuelItemsRequired = 0
  196.         if turtle.getItemCount(1)>1 then turtle.dropUp(turtle.getItemCount(1)-1) end --Drop off the fuel we didn't use
  197.         dump()
  198.     end
  199.     local function tryEmptyChest(postfix)
  200.         while (turtle.select(1) or true) and turtle["suck"..postfix]() do
  201.             checkShaftStep()
  202.         end
  203.     end
  204.     local function move(forward, postfix, add, remove, dir)
  205.         local tryCount = 0
  206.         while turtle["detect"..postfix]() do
  207.             tryEmptyChest(postfix)
  208.             if not turtle["dig"..postfix]() then tryCount = tryCount + 1 end
  209.             if tryCount>TRY_LIMIT then return false end
  210.             sleep(0.2)
  211.         end
  212.         while (add(dir) or true) and not turtle[forward]() do
  213.             remove(dir)
  214.             if not turtle["attack"..postfix]() then tryCount = tryCount + 1 end
  215.             if tryCount>TRY_LIMIT then return false end
  216.             sleep(0.2)
  217.         end
  218.         return true
  219.     end
  220.     function moveX(dir) --X+ = E, X- = W
  221.         setDir(DIRS.WEST - (dir + 1)) --Direction arithmetic magic :D
  222.         local add = function (dir)
  223.             data.coords.x = data.coords.x + dir
  224.             dumpToFile()
  225.             return true
  226.         end
  227.         local remove = function (dir)
  228.             data.coords.x = data.coords.x - dir
  229.             dumpToFile()
  230.             return true
  231.         end
  232.         if not move("forward", "", add, remove, dir) then return false end
  233.         sleep(MOVEMENT_DELAY)
  234.         return true
  235.     end
  236.     function moveY(dir) --Y+ = U, Y- = D
  237.         local add = function (dir)
  238.             data.coords.y = data.coords.y + dir
  239.             dumpToFile()
  240.             return true
  241.         end
  242.         local remove = function (dir)
  243.             data.coords.y = data.coords.y - dir
  244.             dumpToFile()
  245.             return true
  246.         end
  247.         if not move(dir > 0 and "up" or "down", dir > 0 and "Up" or "Down", add, remove, dir) then return false end
  248.         dumpToFile()
  249.         sleep(MOVEMENT_DELAY)
  250.         return true
  251.     end
  252.     function moveZ(dir) --Z+ = N, Z- = S
  253.         setDir(DIRS.NORTH - (dir - 1)) --Direction arithmetic magic :D
  254.         local add = function (dir)
  255.             data.coords.z = data.coords.z + dir
  256.             dumpToFile()
  257.             return true
  258.         end
  259.         local remove = function (dir)
  260.             data.coords.z = data.coords.z - dir
  261.             dumpToFile()
  262.             return true
  263.         end
  264.         if not move("forward", "", add, remove, dir) then return false end
  265.         dumpToFile()
  266.         sleep(MOVEMENT_DELAY)
  267.         return true
  268.     end
  269.     function dock(x, z) --Go back to dock
  270.         setStatus(TASKS.MOVING_TO_DOCK)
  271.         moveVerticalTo(data.height)
  272.         moveHorizontalTo(0, 0)
  273.         refuelAndDump(x, z)
  274.     end
  275.     function moveHorizontalTo(x, z)
  276.         while data.coords.x ~= x do while not moveX(x-data.coords.x>0 and 1 or -1) do sleep(0.2) end end
  277.         while data.coords.z ~= z do while not moveZ(z-data.coords.z>0 and 1 or -1) do sleep(0.2) end end
  278.     end
  279.     function moveVerticalTo(y)
  280.         while data.coords.y ~= y do while not moveY(y-data.coords.y>0 and 1 or -1) do end end
  281.     end
  282.     function processBlockInFront() --Determine if we are interested in the block in front. If we are, then mine it.
  283.         local flag = true
  284.         for i = 2, data.reservedSlots + 1 do
  285.             turtle.select(i)
  286.             flag = flag and not turtle.compare(i)
  287.         end
  288.         turtle.select(1)
  289.         if flag then
  290.             tryEmptyChest("")
  291.             turtle.dig()
  292.         end
  293.     end
  294.     function checkShaftStep()
  295.         --The next if should never happen, but whatever, let it live, might come in useful later on.
  296.         if not hasRequiredFuelToGoBack(data.coords.x, data.coords.y, data.coords.z) and turtle.getItemCount(1)>1 then --Use coal that we've mined to refuel to cut down on docking time
  297.             setStatus(TASKS.REFUELING)
  298.             turtle.select(1)
  299.             local consumeItems = math.ceil((getRequiredFuelToGoBack(data.coords.x, data.coords.y, data.coords.z) - turtle.getFuelLevel()) / data.fuelPerItem)
  300.             turtle.refuel(math.min(turtle.getItemCount(1)-1, consumeItems))
  301.         end
  302.         if not hasRequiredFuelAndSpace(data.coords.x, data.coords.y, data.coords.z) then --If we don't have enough coal to refuel or we don't have enough space, we need to dock and come back to the spot
  303.             local backupDir = data.dir
  304.             local backupX = data.coords.x
  305.             local backupY = data.coords.y
  306.             local backupZ = data.coords.z
  307.             dock(data.coords.x, data.coords.z)
  308.             setStatus(TASKS.MOVING_TO_SHAFT)
  309.             moveHorizontalTo(backupX, backupZ)
  310.             moveVerticalTo(backupY)
  311.             setDir(backupDir)
  312.         end
  313.     end
  314.     function processShaft(x, z)
  315.         dock(x, z)
  316.         setStatus(TASKS.MOVING_TO_SHAFT)
  317.         moveHorizontalTo(x, z)
  318.         data.currentShaftProgress = 0
  319.         while data.coords.y > BEDROCK_LEVEL + 1 do
  320.             --Digging the shaft
  321.             setStatus(TASKS.SHAFT)
  322.             checkShaftStep()
  323.             turtle.select(1)
  324.             if not moveY(-1) then return end --We hit bedrock, nothing to do here...
  325.             for i = 0, 3 do
  326.                 checkShaftStep()
  327.                 turtle.select(1)
  328.                 processBlockInFront()
  329.                 setDir((data.dir + (i~=3 and 1 or 0)) % 4)
  330.             end
  331.             data.currentShaftProgress = data.currentShaftProgress + 1
  332.         end
  333.         data.shaftsDone = data.shaftsDone + 1
  334.     end
  335.     function excavate()
  336.         if not data.shaftsGenerated then
  337.             for x = 0, data.lenx - 1 do
  338.                 for z = 0, data.lenz - 1 do
  339.                     if (z-(x*2))%5==0 then table.insert(data.shafts, {x = x, z = z + 1}) end
  340.                 end
  341.             end
  342.             data.shaftsToDo = #data.shafts
  343.             data.shaftsGenerated = true
  344.         end
  345.         while #data.shafts > 0 do
  346.             local shaft = data.shafts[1]
  347.             processShaft(shaft.x, shaft.z)
  348.             table.remove(data.shafts, 1)
  349.         end
  350.         moveVerticalTo(data.height)
  351.         moveHorizontalTo(0, 0)
  352.         dump()
  353.         setDir(DIRS.NORTH)
  354.         setStatus(TASKS.FINISHED)
  355.         fs.delete(PERSISTANCE_FILE_PATH)
  356.     end
  357. end
  358. --[[
  359.     Check if the startup script is right
  360. ]]
  361. function getStartupScriptStatus()
  362.     if not fs.exists("startup") then return STARTUP_SCRIPT_INSTALL_STATUS.NOT_INSTALLED end
  363.     local file = io.open("startup", "r")
  364.     if not file then return STARTUP_SCRIPT_INSTALL_STATUS.NOT_INSTALLED end
  365.     local str = file:read("*a")
  366.     file:close()
  367.     return str == string.format(STARTUP_SCRIPT_STRING, shell.getRunningProgram()) and STARTUP_SCRIPT_INSTALL_STATUS.INSTALLED or STARTUP_SCRIPT_INSTALL_STATUS.DIFFERENT
  368. end
  369.  
  370. function installStartupScript()
  371.     fs.delete("startup")
  372.     local file = io.open("startup", "w")
  373.     file:write(string.format(STARTUP_SCRIPT_STRING, shell.getRunningProgram()))
  374.     file:close()
  375. end
  376.  
  377. --[[
  378.     GUI
  379. ]]
  380.  
  381. function splitIntoLines(str)
  382.     local w, h = term.getSize()
  383.     local lines = {}
  384.     for line in str:gmatch("[^\r\n]+") do  
  385.         local currentLine = ""
  386.         for token in line:gmatch("[^%s]+") do
  387.             if #(currentLine .. token) > w-3 then
  388.                 table.insert(lines, currentLine)
  389.                 currentLine = token
  390.             else
  391.                 currentLine = (currentLine~="" and currentLine .. " " or "") .. token
  392.             end
  393.         end
  394.         if currentLine~="" then table.insert(lines, currentLine) end
  395.     end
  396.     return lines
  397. end
  398.  
  399. function showProgress(finished) --Progress
  400.     local progressBarSpinChars = {"/", "-", "\\", "|"}
  401.     local curChar = 0
  402.     local cur = 1
  403.     local w, h = term.getSize()
  404.     local exit = false
  405.     local running = true
  406.     local function cycleProgressBar()
  407.         curChar = (curChar + 1) % 4 --Cycle through the progress bar chars for an animation effect
  408.     end
  409.  
  410.     local function clear()
  411.         term.clear()
  412.         cur = 0
  413.     end
  414.  
  415.     local function allocateLine()
  416.         cur = cur + 1
  417.     end
  418.  
  419.     local function renderProgressBar(fraction)
  420.         allocateLine()
  421.         term.setCursorPos(1, cur)
  422.         local numOfDone = math.floor((w-3)*fraction)
  423.         local numOfLeft = math.ceil((w-3)*(1-fraction))
  424.         term.write("[")
  425.         if numOfDone>0 then term.write(string.rep("=", numOfDone)) end
  426.         term.write(fraction == 1 and "=" or progressBarSpinChars[curChar + 1])
  427.         if numOfLeft>0 then term.write(string.rep(" ", numOfLeft)) end
  428.         term.write("]")
  429.     end
  430.  
  431.     local function writeLine(desc, value)
  432.         if type(value) ~= "string" then value = tostring(value) end
  433.         allocateLine()
  434.         term.setCursorPos(1, cur)
  435.         term.write(desc .. (value~="" and ":" or ""))
  436.         term.setCursorPos(w - #value + 1, cur)
  437.         term.write(value)
  438.     end
  439.  
  440.     local function normalProgressRenderer()
  441.         writeLine("Current task", data.currentlyDoing)
  442.         writeLine("Shafts done", data.shaftsDone)
  443.         writeLine("Total shafts", data.shaftsToDo)
  444.         local localProgress = data.currentShaftProgress / (data.height - BEDROCK_LEVEL - 1)
  445.         if localProgress==0/0 then localProgress = 0 end
  446.         writeLine("Current shaft progress", math.floor(localProgress*100).."%")
  447.         renderProgressBar(localProgress)
  448.         local totalProgress = (data.shaftsDone + localProgress % 1)/data.shaftsToDo
  449.         if totalProgress==0/0 then totalProgress = 0 end
  450.         writeLine("Whole progress", math.floor(totalProgress*100).."%")
  451.         renderProgressBar(totalProgress)
  452.         writeLine("Coordinates", data.coords.x..", "..data.coords.y..", "..data.coords.z)
  453.         writeLine("Fuel used so far", data.fuelItemsUsed)
  454.         if data.currentlyDoing == TASKS.WAITING_FOR_FUEL then writeLine("Fuel items needed", data.fuelItemsRequired)
  455.         else writeLine("Sufficient fuel for now.", "") cycleProgressBar() end
  456.         term.setCursorPos(1, h) term.write("Press Enter to exit...")
  457.     end
  458.  
  459.     local function finishedProgressRenderer()
  460.         writeLine("Finished.", "")
  461.         writeLine("Shafts done", data.shaftsDone)
  462.         writeLine("Fuel used", data.fuelItemsUsed)
  463.         term.setCursorPos(1, 4)
  464.     end
  465.  
  466.     local function renderProgress()
  467.         clear()
  468.         if finished then
  469.             finishedProgressRenderer()
  470.         else
  471.             normalProgressRenderer()
  472.         end
  473.     end
  474.  
  475.     local function displayProgress()
  476.         while data.currentlyDoing~=TASKS.FINISHED and running do
  477.             --Update information
  478.             renderProgress(false)      
  479.             sleep(0.1)
  480.         end
  481.         running = false
  482.     end
  483.  
  484.     local function waitForKey()
  485.         while running do
  486.             local sEvent, param = os.pullEvent("key")
  487.             if sEvent == "key" then
  488.                 if param == 28 then
  489.                 exit = true
  490.                 running = false
  491.                 dumpToFile()
  492.                 end
  493.             end
  494.         end
  495.     end
  496.     if finished then renderProgress() else parallel.waitForAny(function() parallel.waitForAll(displayProgress, waitForKey) end, excavate, periodicSave) cleanup() end
  497.     return exit
  498. end
  499. function showConfig() --Config
  500.     local currentlySelected = 1
  501.     local running = true
  502.     local exit = false
  503.     local configOptions = setmetatable({
  504.         {key = "Width", keyBlank = "Width (required!)", value = "8", varType = "number", transferName = "lenx"},
  505.         {key = "Length", keyBlank = "Length (required!)", value = "8", varType = "number", transferName = "lenz"},
  506.         {key = "Height", keyBlank = "Height (required!)", value = "8", varType = "number", transferName = "height"},
  507.         {key = "Number of excluded blocks", keyBlank = "Number of excluded blocks (required!)", value = "2", varType = "number", transferName = "reservedSlots"},
  508.         {key = "Fuel units per item", keyBlank = "Fuel units per item (required!)", value = "80", varType = "number", transferName = "fuelPerItem"}--[[, TODO
  509.         {key = "Save config to", keyBlank = "Save config to (optional)", value = "", varType = "string", transferName = nil}    ]]
  510.     },
  511.     {
  512.         __concat = function(t, s)
  513.             t[currentlySelected].value = t[currentlySelected].value .. (t[currentlySelected].varType=="number" and (tonumber(s)~=nil and s or "") or s)
  514.         end,
  515.         __sub = function(t, s)
  516.             t[currentlySelected].value = t[currentlySelected].value:sub(1, #t[currentlySelected].value - 1)
  517.         end,
  518.         __index = function(t, key)
  519.             if tonumber(key)~=nil then
  520.                 return t[key]
  521.             else
  522.                 for i = 1, #t do
  523.                     if t[i].transferName == key then return t[i] end
  524.                 end
  525.             end
  526.             return nil
  527.         end
  528.     }
  529.     )
  530.    
  531.     local function renderConfig()
  532.         term.clear()
  533.         local w, h = term.getSize()
  534.         for i = 1, #configOptions do
  535.             term.setCursorPos(1, i)
  536.             term.write(#configOptions[i].value>0 and configOptions[i].key or configOptions[i].keyBlank)
  537.             term.setCursorPos(w-1-#configOptions[i].value, i)
  538.             term.write(i==currentlySelected and "[" or " ")
  539.             term.write(configOptions[i].value)
  540.             term.write(i==currentlySelected and "]" or " ")
  541.         end
  542.         term.setCursorPos(1, h-1)
  543.         term.write((currentlySelected == (#configOptions + 1)) and "[Next]" or " Next ")
  544.         term.setCursorPos(w-5, h-1)
  545.         term.write((currentlySelected == (#configOptions + 2)) and "[Exit]" or " Exit ")
  546.         term.setCursorPos(w-2, currentlySelected)
  547.     end
  548.  
  549.     local function showConfig()
  550.         while running do renderConfig() sleep(0.2) end
  551.     end
  552.  
  553.     local function transferValues()
  554.         for i = 1, #configOptions do if configOptions[i].transferName ~= nil then
  555.             data[configOptions[i].transferName] = (configOptions[i].varType=="number" and tonumber or function(a) return a end)(configOptions[i].value)
  556.         end end
  557.         data.coords = {x = 0, y = data.height, z = 0} --We start at the dock.
  558.     end
  559.     local function handleInputForConfig()
  560.         while running do
  561.             local event, param = os.pullEvent()
  562.             if event == "key" then
  563.                 if param == 200 then
  564.                     currentlySelected = math.max(1, currentlySelected - 1)
  565.                     renderConfig()
  566.                 elseif param == 208 then
  567.                     currentlySelected = math.min(#configOptions + 2, currentlySelected + 1)
  568.                     renderConfig()
  569.                 elseif param == 14 then
  570.                     local t = configOptions - nil
  571.                     renderConfig()
  572.                 elseif param == 28 then
  573.                     if currentlySelected == #configOptions + 2 then
  574.                         exit = true
  575.                         running = false
  576.                     elseif currentlySelected == #configOptions + 1 then
  577.                         transferValues()
  578.                         running = false
  579.                         term.clear()
  580.                     end
  581.                 end
  582.             elseif event == "char" then
  583.                 local t = configOptions .. param
  584.                 renderConfig()
  585.             end
  586.         end
  587.     end
  588.     parallel.waitForAll(handleInputForConfig, showConfig)
  589.     cleanup()
  590.     return exit
  591. end
  592. function showDialog(dialogStr, buttons, centre) --Load from old config or not
  593.     local currentlySelected = 1
  594.     local running = true
  595.     local result = false
  596.     --local dialogStr = "Persistance file from previous run found. Would you like to continue from where you left off?"
  597.     local lines = {}
  598.     local w, h = term.getSize()
  599.     for line in dialogStr:gmatch("[^\r\n]+") do
  600.         local currentLine = ""
  601.         for token in line:gmatch("[^%s]+") do
  602.             if #(currentLine .. token) > w-3 then
  603.                 table.insert(lines, currentLine)
  604.                 currentLine = token
  605.             else
  606.                 currentLine = (currentLine~="" and currentLine .. " " or "") .. token
  607.             end
  608.         end
  609.         if currentLine~="" then table.insert(lines, currentLine) end
  610.     end
  611.     local function renderDialog()
  612.         term.clear()       
  613.         for i = 1, #lines do       
  614.             term.setCursorPos(centre and ((w - #lines[i]) / 2 + 1) or 1, i + 1)
  615.             term.write(lines[i])
  616.         end
  617.         for i = 1, #buttons do
  618.             term.setCursorPos((w / (#buttons + 1)) * i - #buttons[i]/2, h - 1)
  619.             term.write((currentlySelected == i) and ("[" .. buttons[i] .. "]") or (" " .. buttons[i] .. " "))
  620.         end
  621.     end
  622.  
  623.     local function showDialog()
  624.         while running do renderDialog() sleep(0.2) end
  625.     end
  626.  
  627.     local function handleInputForDialog()
  628.         while running do
  629.             local event, param = os.pullEvent()
  630.             if event == "key" then
  631.                 if param == 200 then
  632.                     currentlySelected = math.max(1, currentlySelected - 1)
  633.                     renderDialog()
  634.                 elseif param == 208 then
  635.                     currentlySelected = math.min(#buttons, currentlySelected + 1)
  636.                     renderDialog()
  637.                 elseif param == 28 then
  638.                     running = false
  639.                 end
  640.             end
  641.         end
  642.     end
  643.     parallel.waitForAll(handleInputForDialog, showDialog)
  644.     cleanup()
  645.     return currentlySelected
  646. end
  647.  
  648. function showResumeWarning()
  649.    
  650.     local running = true
  651.     local exit = false
  652.     local function displayWarning()
  653.         for i = 10, 0, -1 do
  654.             term.clear()
  655.             local lines = splitIntoLines(string.format(
  656. [[The turtle will continue to dig shafts in %i seconds.
  657. Press Enter to exit to shell.]], i))
  658.             for i = 1, #lines do
  659.                 term.setCursorPos(1, i)
  660.                 term.write(lines[i])
  661.             end
  662.             sleep(1)
  663.             if not running then return end
  664.         end
  665.         running = false
  666.     end
  667.     local function waitForKey()
  668.         while running do
  669.             local sEvent, param = os.pullEvent("key")
  670.             if sEvent == "key" then
  671.                 if param == 28 then
  672.                 exit = true
  673.                 running = false
  674.                 dumpToFile()
  675.                 end
  676.             end
  677.         end
  678.     end
  679.     parallel.waitForAny(waitForKey, displayWarning)
  680.     return exit
  681. end
  682. --[[
  683.     Entry
  684. ]]
  685. args={...}
  686.  
  687. if args[1] == "resume" then
  688.     if fs.exists(PERSISTANCE_FILE_PATH) then
  689.         readFromFile()
  690.         --[[print("The turtle will automatically resume in 10 seconds.")
  691.         print("Press Enter to abort.")
  692.         parallel.waitForAny(function() sleep(10) running = false end,
  693.         function()
  694.             while running do
  695.                 local sEvent, param = os.pullEvent("key")
  696.                 if sEvent == "key" then
  697.                     if param == 28 then
  698.                     exit = true
  699.                     running = false
  700.                     end
  701.                 end
  702.             end
  703.         end)]]
  704.         if showResumeWarning() then
  705.             cleanup()
  706.             return
  707.         end
  708.         if showProgress(false) then
  709.             cleanup()
  710.             return
  711.         end
  712.         showProgress(true)
  713.     end
  714.     cleanup()
  715.     return
  716. end
  717. local startupStatus = getStartupScriptStatus()
  718. if startupStatus ~= STARTUP_SCRIPT_INSTALL_STATUS.INSTALLED then
  719.     local variations =  {"not installed", "different from what this program suggests/needs"}
  720.     local dialogString = string.format(
  721. [[The startup script is %s.
  722. This means that the turtle will not automatically resume when it boots up (e.g. chunk loads).
  723. Would you like to install the recommended startup script?]], variations[startupStatus])
  724.     local startupDialogResult = showDialog(dialogString, {"Yes", "No"}, true)
  725.     if startupDialogResult == 1 then
  726.         installStartupScript()
  727.     end
  728. end
  729. local loadFromFile = false
  730. if fs.exists(PERSISTANCE_FILE_PATH) then
  731.     loadFromFile = showDialog("Persistance file from previous run found. Would you like to continue from where you left off?", {"Yes", "No"}, true) == 1
  732. end
  733. if loadFromFile then
  734.     readFromFile()
  735.     local dirNames = {"north", "east", "south", "west"}
  736.     local dialogString = string.format(
  737. [[Persistance file loaded.
  738. The turtle thinks it is located at:
  739. Y=%i; relative X,Z (to dock)=%i,%i; facing %s
  740. Options are:
  741. 1. The turtle is facing and is located as stated above.
  742. 2. The turtle is located at the dock, facing away from the output chest.
  743.  
  744. ]],
  745.     data.coords.y, data.coords.x, data.coords.z, dirNames[data.dir + 1])
  746.     local posDialogResult = showDialog(dialogString, {"1", "2", "Exit"}, false)
  747.     if posDialogResult == 2 then
  748.         data.coords = {x = 0, y = data.height, z = 0}
  749.         data.dir = DIRS.NORTH
  750.     elseif posDialogResult == 3 then
  751.         cleanup()
  752.         return
  753.     end
  754. else
  755.     if showConfig() then
  756.         cleanup()
  757.         return
  758.     end
  759. end
  760. local warningStr = string.format("Before continuing, please make sure that the first slot is occupied by the fuel item, and the next %i slots are occupied by the blocks that shouldn't be mined.", data.reservedSlots)
  761. if showDialog(warningStr, {"Continue", "Exit"}, true) == 2 then
  762.     cleanup()
  763.     return
  764. end
  765. if showProgress(false) then
  766.     cleanup()
  767.     return
  768. end
  769. showProgress(true)
Add Comment
Please, Sign In to add comment