happydude11209

cbuild

Mar 24th, 2013
947
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.80 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. end
  42.  
  43. if arg[3] == "-c"   or arg[4] == "-c" then
  44.     cost_calc = true
  45. end
  46.  
  47. needsFuel = false
  48. if pcall(turtle.select, 16) then
  49.     needsFuel = true
  50. else
  51.     needsFuel = false
  52. end
  53.  
  54. -- Navigation features
  55. -- allow the turtle to move while tracking its position
  56. -- this allows us to just give a destination point and have it go there
  57.  
  58. positionx = radius
  59. positiony = radius
  60. facing = 0
  61.  
  62. function turnRightTrack()
  63.     turtle.turnRight()
  64.     facing = facing + 1
  65.     if facing >= 4 then
  66.         facing = 0
  67.     end
  68. end
  69.  
  70. function turnLeftTrack()
  71.     turtle.turnLeft()
  72.     facing = facing - 1
  73.     if facing < 0 then
  74.         facing = 3
  75.     end
  76. end
  77.  
  78. function safeForward()
  79.     success = false
  80.     while not success do
  81.         success = turtle.forward()
  82.         if not success then
  83.             print("Blocked attempting to move forward.")
  84.             print("Please clear and press enter to continue.")
  85.             io.read()
  86.         end
  87.     end
  88. end
  89.  
  90. function safeBack()
  91.     success = false
  92.     while not success do
  93.         success = turtle.back()
  94.         if not success then
  95.             print("Blocked attempting to move back.")
  96.             print("Please clear and press enter to continue.")
  97.             io.read()
  98.         end
  99.     end
  100. end
  101.  
  102. function safeUp()
  103.     success = false
  104.     while not success do
  105.         success = turtle.up()
  106.         if not success then
  107.             print("Blocked attempting to move up.")
  108.             print("Please clear and press enter to continue.")
  109.             io.read()
  110.         end
  111.     end
  112. end
  113.  
  114. function moveY(targety)
  115.     if targety == positiony then
  116.         return
  117.     end
  118.    
  119.     if (facing ~= 0 and facing ~= 2) then -- check axis
  120.         turnRightTrack()
  121.     end
  122.    
  123.     while targety > positiony do
  124.         if facing == 0 then
  125.             safeForward()
  126.         else
  127.             safeBack()
  128.         end
  129.         positiony = positiony + 1
  130.     end
  131.    
  132.     while targety < positiony do
  133.         if facing == 2 then
  134.             safeForward()
  135.         else
  136.             safeBack()
  137.         end
  138.         positiony = positiony - 1
  139.     end
  140. end
  141.  
  142. function moveX(targetx)
  143.     if targetx == positionx then
  144.         return
  145.     end
  146.    
  147.     if (facing ~= 1 and facing ~= 3) then -- check axis
  148.         turnRightTrack()
  149.     end
  150.    
  151.     while targetx > positionx do
  152.         if facing == 1 then
  153.             safeForward()
  154.         else
  155.             safeBack()
  156.         end
  157.         positionx = positionx + 1
  158.     end
  159.    
  160.     while targetx < positionx do
  161.         if facing == 3 then
  162.             safeForward()
  163.         else
  164.             safeBack()
  165.         end
  166.         positionx = positionx - 1
  167.     end
  168. end
  169.  
  170. function navigateTo(targetx, targety)
  171.     -- Cost calculation mode - don't move
  172.     if cost_only then
  173.         return
  174.     end
  175.    
  176.     if facing == 0 or facing == 2 then -- Y axis
  177.         moveY(targety)
  178.         moveX(targetx)
  179.     else
  180.         moveX(targetx)
  181.         moveY(targety)
  182.     end
  183. end
  184.  
  185. function round(num, idp)
  186.     local mult = 10^(idp or 0)
  187.     return math.floor(num * mult + 0.5) / mult
  188. end
  189.  
  190. function progresBar(current, final, displayPercent)
  191.     local termWidth, termHeight = term.getSize()
  192.     local numPossibleEqualsSigns = termWidth - 2
  193.    
  194.     progres = (current / final) * 100
  195.     equalsSigns = math.floor(numPossibleEqualsSigns * (current / final))
  196.     x = 1
  197.     if displayPercent then
  198.         term.clear()
  199.     end
  200.     term.setCursorPos(x, 1)
  201.     write("|")
  202.     x = x + 1
  203.     for signs = 1, equalsSigns do
  204.         term.setCursorPos(x, 1)
  205.         write("=")
  206.         x = x + 1
  207.     end
  208.     term.setCursorPos(termWidth - 1, 1)
  209.     write("|")
  210.     if displayPercent then
  211.         term.setCursorPos(1, 2)
  212.         write(round(progres, 2) .. "%")
  213.     end
  214. end
  215.  
  216. cslot = 1
  217.  
  218. function placeBlock()
  219.     -- Cost calculation mode - don't move
  220.     blocks = blocks + 1
  221.     if cost_only then
  222.         return
  223.     end
  224.    
  225.     if turtle.getItemCount(cslot) == 0 then
  226.         foundSlot = false
  227.         while not foundSlot do
  228.             for i = 1,9 do
  229.                 if turtle.getItemCount(i) > 0 then
  230.                     foundSlot = i
  231.                     break
  232.                 end
  233.             end
  234.             if not foundSlot then
  235.                 -- No resources
  236.                 print("Out of building materials. Please refill and press enter to continue.")
  237.                 io.read()
  238.             end
  239.         end
  240.         cslot = foundSlot
  241.         turtle.select(foundSlot)
  242.     end
  243.    
  244.     turtle.placeDown()
  245. end
  246.  
  247. -- Main building functions
  248.  
  249. preCount = 0
  250. progres = 0
  251. width = radius * 2 + 1
  252. sqrt3 = 3 ^ 0.5
  253. boundary_radius = radius + 1.0
  254. boundary2 = boundary_radius ^ 2
  255.  
  256. function buildCylinder(calculateCost, zstart, zend)
  257.     if calculateCost then
  258.         cost_only = true
  259.     else
  260.         cost_only = false
  261.     end
  262.    
  263.     -- This loop is for each vertical layer through the cylinder
  264.         for z = zstart,zend do
  265.         if not cost_only then
  266.             safeUp()
  267.         end
  268.         if cost_only then
  269.             progresBar(z, zend, false)
  270.             print("Calculating...")
  271.             -- print("Layer " .. z)
  272.         end
  273.         -- cz2 = (radius - z) ^ 2
  274.        
  275.         -- limit_offset_y = (boundary2 - cz2) ^ 0.5
  276.         limit_offset_y = boundary_radius
  277.         max_offset_y = math.ceil(limit_offset_y)
  278.        
  279.         -- We do first the +x side, then the -x side to make movement efficient
  280.         for side = 0,1 do
  281.             -- On the right we go from small y to large y, on the left reversed
  282.             -- This makes us travel clockwise around each layer
  283.             if (side == 0) then
  284.                 ystart = radius - max_offset_y
  285.                 yend = radius + max_offset_y
  286.                 ystep = 1
  287.             else
  288.                 ystart = radius + max_offset_y
  289.                 yend = radius - max_offset_y
  290.                 ystep = -1
  291.             end
  292.            
  293.             for y = ystart,yend,ystep do
  294.                 cy2 = (radius - y) ^ 2
  295.                
  296.                 -- remainder2 = (boundary2 - cz2 - cy2)
  297.                 remainder2 = (boundary2 - cy2)
  298.                
  299.                
  300.                 if remainder2 >= 0 then
  301.                     -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
  302.                     -- max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
  303.                     max_offset_x = math.ceil((boundary2 - cy2) ^ 0.5)
  304.                    
  305.                     -- Only do either the +x or -x side
  306.                     if (side == 0) then
  307.                         -- +x side
  308.                         xstart = radius
  309.                         xend = radius + max_offset_x
  310.                     else
  311.                         -- -x side
  312.                         xstart = radius - max_offset_x
  313.                         xend = radius - 1
  314.                     end
  315.                    
  316.                     -- Reverse direction we traverse xs when in -y side
  317.                     if y > radius then
  318.                         temp = xstart
  319.                         xstart = xend
  320.                         xend = temp
  321.                         xstep = -1
  322.                     else
  323.                         xstep = 1
  324.                     end
  325.                    
  326.                     for x = xstart,xend,xstep do
  327.                         cx2 = (radius - x) ^ 2
  328.                         -- distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
  329.                         distance_to_centre = (cx2 + cy2) ^ 0.5
  330.                         -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
  331.                         if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
  332.                             offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
  333.                             for i=1,6 do
  334.                                 offset = offsets[i]
  335.                                 dx = offset[1]
  336.                                 dy = offset[2]
  337.                                 -- dz = offset[3]
  338.                                 -- if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
  339.                                 if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2) ^ 0.5 >= boundary_radius then
  340.                                     -- This is a point to use
  341.                                     navigateTo(x, y)
  342.                                     placeBlock()
  343.                                     if not cost_only then
  344.                                         progresBar(blocks, preCount, true)
  345.                                         write(", Layer " .. z .. "/" .. zend)
  346.                                     end
  347.                                     break
  348.                                 end
  349.                             end
  350.                         end
  351.                     end
  352.                 end
  353.             end
  354.         end
  355.     end
  356.     if cost_only then
  357.         preCount = blocks
  358.         blocks = 0
  359.     end
  360. end
  361.  
  362. function buildOther(calculateCost, zstart, zend)
  363.     if calculateCost then
  364.         cost_only = true
  365.     else
  366.         cost_only = false
  367.     end
  368.    
  369.     -- This loop is for each vertical layer through the sphere or dome.
  370.     for z = zstart,zend do
  371.         if not cost_only then
  372.             safeUp()
  373.         end
  374.         if cost_only then
  375.             progresBar(z, zend, false)
  376.             print("Calculating...")
  377.             -- print("Layer " .. z)
  378.         end
  379.        
  380.         cz2 = (radius - z) ^ 2
  381.        
  382.         limit_offset_y = (boundary2 - cz2) ^ 0.5
  383.         max_offset_y = math.ceil(limit_offset_y)
  384.        
  385.         -- We do first the +x side, then the -x side to make movement efficient
  386.         for side = 0,1 do
  387.             -- On the right we go from small y to large y, on the left reversed
  388.             -- This makes us travel clockwise around each layer
  389.             if (side == 0) then
  390.                 ystart = radius - max_offset_y
  391.                 yend = radius + max_offset_y
  392.                 ystep = 1
  393.             else
  394.                 ystart = radius + max_offset_y
  395.                 yend = radius - max_offset_y
  396.                 ystep = -1
  397.             end
  398.            
  399.             for y = ystart,yend,ystep do
  400.                 cy2 = (radius - y) ^ 2
  401.                
  402.                 remainder2 = (boundary2 - cz2 - cy2)
  403.                
  404.                
  405.                 if remainder2 >= 0 then
  406.                     -- This is the maximum difference in x from the centre we can be without definitely being outside the radius
  407.                     max_offset_x = math.ceil((boundary2 - cz2 - cy2) ^ 0.5)
  408.                    
  409.                     -- Only do either the +x or -x side
  410.                     if (side == 0) then
  411.                         -- +x side
  412.                         xstart = radius
  413.                         xend = radius + max_offset_x
  414.                     else
  415.                         -- -x side
  416.                         xstart = radius - max_offset_x
  417.                         xend = radius - 1
  418.                     end
  419.                    
  420.                     -- Reverse direction we traverse xs when in -y side
  421.                     if y > radius then
  422.                         temp = xstart
  423.                         xstart = xend
  424.                         xend = temp
  425.                         xstep = -1
  426.                     else
  427.                         xstep = 1
  428.                     end
  429.                    
  430.                     for x = xstart,xend,xstep do
  431.                         cx2 = (radius - x) ^ 2
  432.                         distance_to_centre = (cx2 + cy2 + cz2) ^ 0.5
  433.                         -- Only blocks within the radius but still within 1 3d-diagonal block of the edge are eligible
  434.                         if distance_to_centre < boundary_radius and distance_to_centre + sqrt3 >= boundary_radius then
  435.                             offsets = {{0, 1, 0}, {0, -1, 0}, {1, 0, 0}, {-1, 0, 0}, {0, 0, 1}, {0, 0, -1}}
  436.                             for i=1,6 do
  437.                                 offset = offsets[i]
  438.                                 dx = offset[1]
  439.                                 dy = offset[2]
  440.                                 dz = offset[3]
  441.                                 if ((radius - (x + dx)) ^ 2 + (radius - (y + dy)) ^ 2 + (radius - (z + dz)) ^ 2) ^ 0.5 >= boundary_radius then
  442.                                     -- This is a point to use
  443.                                     navigateTo(x, y)
  444.                                     placeBlock()
  445.                                     if not cost_only then
  446.                                         progresBar(blocks, preCount, true)
  447.                                         write(", Layer " .. z .. "/" .. zend)
  448.                                     end
  449.                                     break
  450.                                 end
  451.                             end
  452.                         end
  453.                     end
  454.                 end
  455.             end
  456.         end
  457.     end
  458.     if cost_only then
  459.         preCount = blocks
  460.         blocks = 0
  461.     end
  462. end
  463.  
  464. cost_only = true
  465.  
  466. if buildType == "cylinder" then
  467.     buildCylinder(true, 1, height)
  468.     if not cost_calc then
  469.         cost_only = false
  470.         buildCylinder(false, 1, height)
  471.     end
  472. elseif buildType == "sphere" then
  473.     buildOther(true, 0, width - 1)
  474.     if not cost_calc then
  475.         cost_only = false
  476.         buildOther(false, 0, width - 1)
  477.     end
  478. elseif buildType == "dome" then
  479.     buildOther(true, radius, width - 1)
  480.     if not cost_calc then
  481.         cost_only = false
  482.         buildOther(false, radius, width - 1)
  483.     end
  484. elseif buildType == "bowl" then
  485.     buildOther(true, 0, radius)
  486.     if not cost_calc then
  487.         cost_only = false
  488.         buildOther(false, 0, radius)
  489.     end
  490. else
  491.     print("Unknown type")
  492.     print("Usage: cbuild <type> <radius> [height] [-c] [-r]")
  493.     print("Acceptable types: sphere, dome, bowl, and cylinder")
  494.     print("pass -c to calculate needed blocks")
  495.     -- print("pass -r to resume from reload")
  496.     return
  497. end
  498.  
  499. -- Return to where we started in x,y place and turn to face original direction
  500. -- Don't change vertical place though - should be solid under us!
  501. navigateTo(radius, radius)
  502. term.clear()
  503. term.setCursorPos(1,1)
  504. while (facing > 0) do
  505.     turnLeftTrack()
  506. end
  507.  
  508. if cost_calc then
  509.     blocks = preCount
  510. end
  511. if buildType == "cylinder" then
  512.     print("Blocks used: " .. blocks)
  513.     print("While building a cylinder of radius " .. radius .. " and height " .. height)
  514. else
  515.     print("Blocks used: " .. blocks)
  516.     print("While building a " .. buildType .. " of radius " .. radius)
  517. end
Advertisement
Add Comment
Please, Sign In to add comment