happydude11209

cbuild2

Mar 24th, 2013
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.69 KB | None | 0 0
  1. -- Circular structure builder
  2. -- Copyright (C) 2012 Timothy Goddard
  3. -- modified by Marco Nicoletti (Happydude11209)
  4. --
  5. -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. -- this software and associated documentation files (the "Software"), to deal in
  7. -- the Software without restriction, including without limitation the rights to
  8. -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. -- the Software, and to permit persons to whom the Software is furnished to do so,
  10. -- subject to the following conditions:
  11. --
  12. -- The above copyright notice and this permission notice shall be included in all
  13. -- copies or substantial portions of the Software.
  14. --
  15. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. --
  22. -- usage: cbuild <buildType> <radius> [height] [-c]
  23. -- buildType should be dome, bowl, sphere, or cylinder
  24. -- radius is distance from centre - total width is actually 2 * radius + 1
  25. -- the structure will be built with its lowest point on the level the turtle is at
  26. -- the block the turtle starts on will be the horizontal centre
  27. -- if -c is passed, will only calculate number of blocks required and not build
  28.  
  29. local arg = { ... }
  30.  
  31. buildType = arg[1]
  32. radius = tonumber(arg[2])
  33. height = tonumber(arg[3])
  34.  
  35. cost_calc = false
  36. resume = false
  37. blocks = 0
  38.  
  39. if arg[1] == "-r" then
  40.     resume = true
  41.     if fs.exists("cbuildsave") then
  42.         saveFile = fs.open("cbuildsave", "r")
  43.         currentFile = saveFile.readAll()
  44.         for key, value in string.gmatch(currentFile, "(%S+)=(%S+)") do
  45.             write(key .. " = ")
  46.             print(value)
  47.             if key == "x" then
  48.                 resumeX = tonumber(value)
  49.             elseif key == "y" then
  50.                 resumeY = tonumber(value)
  51.             elseif key == "z" then
  52.                 resumeZ = tonumber(value)
  53.             elseif key == "radius" then
  54.                 radius = tonumber(value)
  55.             elseif key == "type" then
  56.                 buildType = value
  57.             elseif key == "height" then
  58.                 resumeHeight = tonumber(value)
  59.             elseif key == "precount" then
  60.                 resumePrecount = tonumber(value)
  61.             elseif key == "blocks" then
  62.                 resumeBlocks = tonumber(value)
  63.             elseif key == "facing" then
  64.                 resumeFacing = tonumber(value)
  65.             elseif key == "side" then
  66.                 resumeSide = tonumber(value)
  67.             end
  68.         end
  69.     saveFile.close()
  70.     else
  71.         resume = false
  72.         print("No save file exists, sorry.")
  73.         return
  74.     end
  75. end
  76.  
  77. if not resume then
  78.     if arg[3] == "-c"   or arg[4] == "-c" then
  79.         cost_calc = true
  80.     end
  81. end
  82.  
  83. needsFuel = false
  84. if pcall(turtle.select, 16) then
  85.     needsFuel = true
  86. else
  87.     needsFuel = false
  88. end
  89.  
  90. -- Navigation features
  91. -- allow the turtle to move while tracking its position
  92. -- this allows us to just give a destination point and have it go there
  93. if resume then
  94.     positionx = resumeX
  95.     positiony = resumeY
  96.     facing = resumeFacing
  97. else
  98.     positionx = radius
  99.     positiony = radius
  100.     facing = 0
  101. end
  102.  
  103. function updateSaveFile(currentX, currentY, currentZ, currentRadius, currentHeight, currentType, currentPrecount, currentBlocks, currentFacing, currentSide)
  104.     saveFile = fs.open("cbuildsave", "w")
  105.     saveFile.writeLine("x=" .. currentX)
  106.     saveFile.writeLine("y=" .. currentY)
  107.     saveFile.writeLine("z=" .. currentZ)
  108.     saveFile.writeLine("radius=" .. currentRadius)
  109.     saveFile.writeLine("height=" .. currentHeight)
  110.     saveFile.writeLine("type=" .. currentType)
  111.     saveFile.writeLine("precount=" .. currentPrecount)
  112.     saveFile.writeLine("blocks=" .. currentBlocks)
  113.     saveFile.writeLine("facing=" .. currentFacing)
  114.     saveFile.writeLine("side=" .. currentSide)
  115.     saveFile.close()
  116. end
  117.  
  118. function turnRightTrack()
  119.     turtle.turnRight()
  120.     facing = facing + 1
  121.     if facing >= 4 then
  122.         facing = 0
  123.     end
  124.     updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  125. end
  126.  
  127. function turnLeftTrack()
  128.     turtle.turnLeft()
  129.     facing = facing - 1
  130.     if facing < 0 then
  131.         facing = 3
  132.     end
  133.     updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  134. end
  135.  
  136. function safeForward()
  137.     success = false
  138.     while not success do
  139.         success = turtle.forward()
  140.         if not success then
  141.             print("Blocked attempting to move forward.")
  142.             print("Please clear and press enter to continue.")
  143.             io.read()
  144.         end
  145.     end
  146. end
  147.  
  148. function safeBack()
  149.     success = false
  150.     while not success do
  151.         success = turtle.back()
  152.         if not success then
  153.             print("Blocked attempting to move back.")
  154.             print("Please clear and press enter to continue.")
  155.             io.read()
  156.         end
  157.     end
  158. end
  159.  
  160. function safeUp()
  161.     success = false
  162.     while not success do
  163.         success = turtle.up()
  164.         if not success then
  165.             print("Blocked attempting to move up.")
  166.             print("Please clear and press enter to continue.")
  167.             io.read()
  168.         end
  169.     end
  170. end
  171.  
  172. function moveY(targety)
  173.     if targety == positiony then
  174.         updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  175.         return
  176.     end
  177.    
  178.     if (facing ~= 0 and facing ~= 2) then -- check axis
  179.         turnRightTrack()
  180.     end
  181.    
  182.     while targety > positiony do
  183.         if facing == 0 then
  184.             safeForward()
  185.         else
  186.             safeBack()
  187.         end
  188.         positiony = positiony + 1
  189.     end
  190.    
  191.     while targety < positiony do
  192.         if facing == 2 then
  193.             safeForward()
  194.         else
  195.             safeBack()
  196.         end
  197.         positiony = positiony - 1
  198.     end
  199.     updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  200. end
  201.  
  202. function moveX(targetx)
  203.     if targetx == positionx then
  204.         return
  205.     end
  206.    
  207.     if (facing ~= 1 and facing ~= 3) then -- check axis
  208.         turnRightTrack()
  209.     end
  210.    
  211.     while targetx > positionx do
  212.         if facing == 1 then
  213.             safeForward()
  214.         else
  215.             safeBack()
  216.         end
  217.         positionx = positionx + 1
  218.     end
  219.    
  220.     while targetx < positionx do
  221.         if facing == 3 then
  222.             safeForward()
  223.         else
  224.             safeBack()
  225.         end
  226.         positionx = positionx - 1
  227.     end
  228.     updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  229. end
  230.  
  231. function navigateTo(targetx, targety)
  232.     -- Cost calculation mode - don't move
  233.     if cost_only then
  234.         return
  235.     end
  236.    
  237.     if needsFuel then
  238.         while turtle.getFuelLevel() < 10 do
  239.             cslot = 10
  240.             turtle.select(cslot)
  241.             while not turtle.refuel(1) do
  242.                 fueled = false
  243.                 for i = cslot, 16 do
  244.                     turtle.select(i)
  245.                     if turtle.refuel(1) then
  246.                         fueled = true
  247.                         i = 17
  248.                     end
  249.                 end
  250.                 if not fueled then
  251.                     print("Out of fuel, or not fuel items. Please refill (10-16) and press enter.")
  252.                 end
  253.             end
  254.         end
  255.     end
  256.    
  257.     if facing == 0 or facing == 2 then -- Y axis
  258.         moveY(targety)
  259.         moveX(targetx)
  260.     else
  261.         moveX(targetx)
  262.         moveY(targety)
  263.     end
  264. end
  265.  
  266. function round(num, idp)
  267.     local mult = 10^(idp or 0)
  268.     return math.floor(num * mult + 0.5) / mult
  269. end
  270.  
  271. function progresBar(current, final, displayPercent)
  272.     local termWidth, termHeight = term.getSize()
  273.     local numPossibleEqualsSigns = termWidth - 2
  274.    
  275.     progres = (current / final) * 100
  276.     equalsSigns = math.floor(numPossibleEqualsSigns * (current / final))
  277.     x = 1
  278.     if displayPercent then
  279.         term.clear()
  280.     end
  281.     term.setCursorPos(x, 1)
  282.     write("|")
  283.     x = x + 1
  284.     for signs = 1, equalsSigns do
  285.         term.setCursorPos(x, 1)
  286.         write("=")
  287.         x = x + 1
  288.     end
  289.     term.setCursorPos(termWidth - 1, 1)
  290.     write("|")
  291.     if displayPercent then
  292.         term.setCursorPos(1, 2)
  293.         write(round(progres, 2) .. "%")
  294.     end
  295. end
  296.  
  297. cslot = 1
  298.  
  299. function placeBlock()
  300.     -- Cost calculation mode - don't move
  301.     blocks = blocks + 1
  302.     if cost_only then
  303.         return
  304.     end
  305.    
  306.     if turtle.getItemCount(cslot) == 0 then
  307.         foundSlot = false
  308.         while not foundSlot do
  309.             for i = 1,9 do
  310.                 if turtle.getItemCount(i) > 0 then
  311.                     foundSlot = i
  312.                     break
  313.                 end
  314.             end
  315.             if not foundSlot then
  316.                 -- No resources
  317.                 print("Out of building materials. Please refill (1-9) and press enter to continue.")
  318.                 io.read()
  319.             end
  320.         end
  321.         cslot = foundSlot
  322.         turtle.select(foundSlot)
  323.     end
  324.    
  325.     turtle.placeDown()
  326.     updateSaveFile(positionx,positiony,z,radius,height,buildType,preCount,blocks,facing, side)
  327. end
  328.  
  329. -- Main building functions
  330.  
  331. preCount = 0
  332. progres = 0
  333. width = radius * 2 + 1
  334. sqrt3 = 3 ^ 0.5
  335. boundary_radius = radius + 1.0
  336. boundary2 = boundary_radius ^ 2
  337.  
  338. function buildCylinder(calculateCost, zstart, zend)
  339.     if calculateCost then
  340.         cost_only = true
  341.     else
  342.         cost_only = false
  343.     end
  344.     if resume then
  345.         zstart = resumeZ
  346.         zend = resumeHeight
  347.     end
  348.    
  349.     -- This loop is for each vertical layer through the cylinder
  350.         for z = zstart,zend do
  351.         if not cost_only then
  352.             safeUp()
  353.         end
  354.         if cost_only then
  355.             progresBar(z, zend, false)
  356.             print("Calculating...")
  357.             -- print("Layer " .. z)
  358.         end
  359.         -- cz2 = (radius - z) ^ 2
  360.        
  361.         -- limit_offset_y = (boundary2 - cz2) ^ 0.5
  362.         limit_offset_y = boundary_radius
  363.         max_offset_y = math.ceil(limit_offset_y)
  364.        
  365.         -- We do first the +x side, then the -x side to make movement efficient
  366.         for side = 0,1 do
  367.             if resume then
  368.                 side = resumeSide
  369.             end
  370.             -- On the right we go from small y to large y, on the left reversed
  371.             -- This makes us travel clockwise around each layer
  372.             if (side == 0) then
  373.                 if resume then
  374.                     ystart = resumeY
  375.                 else
  376.                     ystart = radius - max_offset_y
  377.                 end
  378.                 yend = radius + max_offset_y
  379.                 ystep = 1
  380.             else
  381.                 ystart = radius + max_offset_y
  382.                 yend = radius - max_offset_y
  383.                 ystep = -1
  384.             end
  385.            
  386.             for y = ystart,yend,ystep do
  387.                 cy2 = (radius - y) ^ 2
  388.                
  389.                 -- remainder2 = (boundary2 - cz2 - cy2)
  390.                 remainder2 = (boundary2 - cy2)
  391.                
  392.                
  393.                 if remainder2 >= 0 then
  394.                     -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
  395.                     -- max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
  396.                     max_offset_x = math.ceil((boundary2 - cy2) ^ 0.5)
  397.                    
  398.                     -- Only do either the +x or -x side
  399.                     if (side == 0) then
  400.                         -- +x side
  401.                         xstart = radius
  402.                         xend = radius + max_offset_x
  403.                     else
  404.                         -- -x side
  405.                         xstart = radius - max_offset_x
  406.                         xend = radius - 1
  407.                     end
  408.                    
  409.                     -- Reverse direction we traverse xs when in -y side
  410.                     if y > radius then
  411.                         temp = xstart
  412.                         xstart = xend
  413.                         xend = temp
  414.                         xstep = -1
  415.                     else
  416.                         xstep = 1
  417.                     end
  418.                    
  419.                     for x = xstart,xend,xstep do
  420.                         cx2 = (radius - x) ^ 2
  421.                         -- distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
  422.                         distance_to_centre = (cx2 + cy2) ^ 0.5
  423.                         -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
  424.                         if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
  425.                             offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
  426.                             for i=1,6 do
  427.                                 offset = offsets[i]
  428.                                 dx = offset[1]
  429.                                 dy = offset[2]
  430.                                 -- dz = offset[3]
  431.                                 -- if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
  432.                                 if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2) ^ 0.5 >= boundary_radius then
  433.                                     -- This is a point to use
  434.                                     navigateTo(x, y)
  435.                                     placeBlock()
  436.                                     if not cost_only then
  437.                                         progresBar(blocks, preCount, true)
  438.                                         write(", Layer " .. z .. "/" .. zend)
  439.                                     end
  440.                                     break
  441.                                 end
  442.                             end
  443.                         end
  444.                     end
  445.                 end
  446.             end
  447.         end
  448.     end
  449.     if cost_only then
  450.         preCount = blocks
  451.         blocks = 0
  452.     end
  453. end
  454.  
  455. function buildOther(calculateCost, zstart, zend)
  456.     if calculateCost then
  457.         cost_only = true
  458.     else
  459.         cost_only = false
  460.     end
  461.    
  462.     -- This loop is for each vertical layer through the sphere or dome.
  463.     for z = zstart,zend do
  464.         if not cost_only then
  465.             safeUp()
  466.         end
  467.         if cost_only then
  468.             progresBar(z, zend, false)
  469.             print("Calculating...")
  470.             -- print("Layer " .. z)
  471.         end
  472.        
  473.         cz2 = (radius - z) ^ 2
  474.        
  475.         limit_offset_y = (boundary2 - cz2) ^ 0.5
  476.         max_offset_y = math.ceil(limit_offset_y)
  477.        
  478.         -- We do first the +x side, then the -x side to make movement efficient
  479.         for side = 0,1 do
  480.             -- On the right we go from small y to large y, on the left reversed
  481.             -- This makes us travel clockwise around each layer
  482.             if (side == 0) then
  483.                 ystart = radius - max_offset_y
  484.                 yend = radius + max_offset_y
  485.                 ystep = 1
  486.             else
  487.                 ystart = radius + max_offset_y
  488.                 yend = radius - max_offset_y
  489.                 ystep = -1
  490.             end
  491.            
  492.             for y = ystart,yend,ystep do
  493.                 cy2 = (radius - y) ^ 2
  494.                
  495.                 remainder2 = (boundary2 - cz2 - cy2)
  496.                
  497.                
  498.                 if remainder2 >= 0 then
  499.                     -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
  500.                     max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
  501.                    
  502.                     -- Only do either the +x or -x side
  503.                     if (side == 0) then
  504.                         -- +x side
  505.                         xstart = radius
  506.                         xend = radius + max_offset_x
  507.                     else
  508.                         -- -x side
  509.                         xstart = radius - max_offset_x
  510.                         xend = radius - 1
  511.                     end
  512.                    
  513.                     -- Reverse direction we traverse xs when in -y side
  514.                     if y > radius then
  515.                         temp = xstart
  516.                         xstart = xend
  517.                         xend = temp
  518.                         xstep = -1
  519.                     else
  520.                         xstep = 1
  521.                     end
  522.                    
  523.                     for x = xstart,xend,xstep do
  524.                         cx2 = (radius - x) ^ 2
  525.                         distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
  526.                         -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
  527.                         if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
  528.                             offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
  529.                             for i=1,6 do
  530.                                 offset = offsets[i]
  531.                                 dx = offset[1]
  532.                                 dy = offset[2]
  533.                                 dz = offset[3]
  534.                                 if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
  535.                                     -- This is a point to use
  536.                                     navigateTo(x, y)
  537.                                     placeBlock()
  538.                                     if not cost_only then
  539.                                         progresBar(blocks, preCount, true)
  540.                                         write(", Layer " .. z .. "/" .. zend)
  541.                                     end
  542.                                     break
  543.                                 end
  544.                             end
  545.                         end
  546.                     end
  547.                 end
  548.             end
  549.         end
  550.     end
  551.     if cost_only then
  552.         preCount = blocks
  553.         blocks = 0
  554.     end
  555. end
  556.  
  557. cost_only = true
  558.  
  559. if buildType == "cylinder" then
  560.     buildCylinder(true, 1, height)
  561.     if not cost_calc then
  562.         cost_only = false
  563.         buildCylinder(false, 1, height)
  564.     end
  565. elseif buildType == "sphere" then
  566.     buildOther(true, 0, width - 1)
  567.     if not cost_calc then
  568.         cost_only = false
  569.         buildOther(false, 0, width - 1)
  570.     end
  571. elseif buildType == "dome" then
  572.     buildOther(true, radius, width - 1)
  573.     if not cost_calc then
  574.         cost_only = false
  575.         buildOther(false, radius, width - 1)
  576.     end
  577. elseif buildType == "bowl" then
  578.     buildOther(true, 0, radius)
  579.     if not cost_calc then
  580.         cost_only = false
  581.         buildOther(false, 0, radius)
  582.     end
  583. else
  584.     print("Unknown type")
  585.     print("Usage: cbuild <type> <radius> [height] [-c] [-r]")
  586.     print("Acceptable types: sphere, dome, bowl, and cylinder")
  587.     print("pass -c to calculate needed blocks")
  588.     -- print("pass -r to resume from reload")
  589.     return
  590. end
  591.  
  592. -- Return to where we started in x,y place and turn to face original direction
  593. -- Don't change vertical place though - should be solid under us!
  594. navigateTo(radius, radius)
  595. term.clear()
  596. term.setCursorPos(1,1)
  597. while (facing > 0) do
  598.     turnLeftTrack()
  599. end
  600.  
  601. if cost_calc then
  602.     blocks = preCount
  603. end
  604. if buildType == "cylinder" then
  605.     print("Blocks used: " .. blocks)
  606.     print("While building a cylinder of radius " .. radius .. " and height " .. height)
  607. else
  608.     print("Blocks used: " .. blocks)
  609.     print("While building a " .. buildType .. " of radius " .. radius)
  610. end
  611. fs.delete("cbuildsave")
Advertisement
Add Comment
Please, Sign In to add comment