Advertisement
Anonomit

Rabbit

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