Advertisement
civilwargeeky

TreeFeller

Dec 31st, 2013
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.82 KB | None | 0 0
  1. --Single Tree-Cutter
  2. --Version 1.0.0
  3. --Made by Civilwargeeky, at the request of Mr. Hohenheim
  4. --Idea, if mod that lets see inv, then check if things are bonemeal/saplings
  5. --[[
  6. More ideas:
  7.   If wanting to save progress, you need these:
  8.     slotTypes
  9.     facing
  10.     atHome
  11.   On startup, if not at home, go down until you are level, then back one
  12.   Also on startup, turnTo 0
  13.  
  14.   MAKE IT SO ON ITEM RESTOCK, MATCHING ITEMS AND MATCHING ITEMS ONLY ARE PROPERLY MARKED
  15.   ]]
  16.  
  17.  
  18.  insistOnStock = false --Whether or not it will force a certain amount of things to be in inventory
  19.  facing = 0 --0 is front, 1 is right, 2 is back, 3 is left
  20.  cut = 0 --Trees cut
  21.  dropped = 0 --Wood/things dropped off
  22.  slotTypes = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  23.  numTypes = 2 --Used in assign types function
  24.  restock = {sapling = 64 * 2, bonemeal = 64*4}
  25.  keepOpen = 5
  26.  atHome = true --Whether or not its in its home spot
  27.  
  28.  typesTable = {}
  29. do local function assignValues(name, typeNum, side) typesTable[name] = {typeNum = typeNum, side = side} end
  30.   assignValues("sapling", 1, "left"); assignValues("bonemeal",2, "right"); assignValues("wood", 0, "back")
  31. end
  32.  highScores = {tree = {}, bonemeal = {}}
  33. local function registerScore(what, score)
  34.   if highScores[what][1] == nil then --Initialize table
  35.     highScores[what] = {0, 0, tally = {}}
  36.   end
  37.   local a = highScores[what]
  38.   a[1] = a[1] + 1
  39.   if score > a[2] then
  40.     a[2] = score
  41.   end
  42.   if not a.tally[score] then
  43.     a.tally[score] = 1
  44.   else
  45.     a.tally[score] = a.tally[score] + 1
  46.   end --Give every time something happens a tally too
  47. end
  48.  
  49. --Misc functions
  50. function getInvTable()
  51.   local toRet = {}
  52.   for i=1, 16 do
  53.     toRet[i] = turtle.getItemCount(i)
  54.   end
  55.   return toRet
  56. end
  57.  
  58. function getChangedSlots(input1, input2)
  59.   local toRet = {}
  60.   for i=1, math.min(#input1, #input2) do
  61.     if input1[i] ~= input2[i] then
  62.       table.insert(toRet,i)
  63.     end
  64.   end
  65.   return toRet
  66. end
  67. function countChange(func, num)
  68.   local snapshot, changed = getInvTable(), 0
  69.   func(num)
  70.   local ending = getInvTable()
  71.   for i=1,16 do
  72.     if snapshot[i] ~= ending[i] then
  73.       changed = changed + math.abs(snapshot[i]-ending[i])
  74.     end
  75.   end
  76.   return changed
  77. end
  78. function screenSet(x, y)
  79.   x, y = x or 1, y or 1
  80.   term.clear()
  81.   term.setCursorPos(x,y)
  82. end
  83. function display()
  84.   screenSet(1,1)
  85.   print("Fuel: ",turtle.getFuelLevel())
  86.   print("Blocks Cut: ",cut)
  87.   print("Blocks Dropped Off: ",dropped)
  88.   print("Current # Wood: ", countType(0))
  89.   print("Current # Saplings: ",countType(1))
  90.   print("Current # Bonemeal: ",countType(2))
  91.   print("Highest Tree: ",highScores.tree[2])
  92.   print("Number of Trees Cut: ",highScores.tree[1])
  93.   print("Bonemeal High Score: ",highScores.bonemeal[2])
  94.   print("Number of Bonemeal Uses: ",highScores.bonemeal[1])
  95.   print("Tree height tallys: ",textutils.serialize(highScores.tree.tally))
  96. end
  97. function fromBoolean(input) --Like a calculator
  98. if input then return 1 end
  99. return 0
  100. end
  101. function coterminal(num, limit) --I knew this would come in handy :D TI-83 FTW!
  102. limit = limit or 4 --This is for facing
  103. return math.abs((limit*fromBoolean(num < 0))-(math.abs(num)%limit))
  104. end
  105. --Custom movement related local functions
  106. function genericTurn(func, toAdd)
  107.   local toRet = func()
  108.   facing = coterminal(facing + toAdd)
  109.   return toRet
  110. end
  111. function right()
  112.   return genericTurn(turtle.turnRight, 1)
  113. end
  114. function left()
  115.   return genericTurn(turtle.turnLeft, -1)
  116. end
  117. function turnTo(toTurn)
  118.   toTurn = coterminal(toTurn) or facing
  119.   local func = right
  120.   if coterminal(facing-toTurn) == 1 then func = left end --0 - 1 = -3, 1 - 0 = 1, 2 - 1 = 1
  121.   while facing ~= toTurn do          --The above is used to smartly turn
  122.     func()
  123.   end
  124. end
  125. function turnAround()
  126.   return turnTo(facing + 2) --Works because input is coterminaled
  127. end
  128. function genericDig(func, doAdd)
  129.   if doAdd == nil then doAdd = true end
  130.   if func() then
  131.     if doAdd then
  132.       cut = cut + 1
  133.     end
  134.     return true
  135.   end
  136.   return false
  137. end
  138. function dig(doAdd) return genericDig(turtle.dig, doAdd) end
  139. function digUp(doAdd) return genericDig(turtle.digUp, doAdd) end
  140. function digDown(doAdd) return genericDig(turtle.digDown, doAdd) end
  141. function genericMove(move, dig, attack, force)
  142.   if force == nil then force = true end
  143.   while not move() do
  144.     if force then
  145.       if not dig() then
  146.         attack()
  147.        end
  148.     else print("Move Failed"); sleep(1)
  149.     end
  150.   end
  151.   display()
  152.   return true
  153. end
  154. function forward(force)
  155.   return genericMove(turtle.forward, dig, turtle.attack, force)
  156. end
  157. local function returnNil() return nil end --Used in back below
  158. function back()
  159.   return genericMove(turtle.back, returnNil, returnNil, false)
  160. end
  161. function up(force)
  162.   return genericMove(turtle.up, digUp, turtle.attackUp, force)
  163. end
  164. function down(force)
  165.   return genericMove(turtle.down, digDown, turtle.attackDown, force)
  166. end
  167. --Specific local functions
  168. function getRep(which, fromBack)
  169.   local first, start, finish, step = false
  170.   if fromBack then
  171.     start, finish, step = 16, 1, -1
  172.   else
  173.     start, finish, step = 1, 16, 1
  174.   end
  175.   for i=start, finish, step do --Goes backward because slots are often taken/dropped off
  176.     --[[if turtle.getItemCount(i) > 0 and not first then --If not a rep, will return first slot with items
  177.       first = i
  178.     end]]
  179.     if slotTypes[i] == which and turtle.getItemCount(i) > 0 then
  180.       return i
  181.     end
  182.   end
  183.   return first
  184. end
  185. local function purgeType(which)
  186.   for i=1, 16 do
  187.     if slotTypes[i] == which then slotTypes[i] = 0 end
  188.   end
  189. end
  190. function assignTypes(initial, ...) --This gives all items names, if not initial, will not give new types. ... is slot overrides
  191.   local overrides = {...}
  192.   for i=1,16 do --This handles the overrides
  193.     local a = overrides[i] or 0 --0 because cannot compare with number
  194.     if 1 <= a and a <= 16 then
  195.       if turtle.getItemCount(a) > 0 then
  196.         purgeType(i) --This makes it so this slot is the only one to compare to.
  197.         slotTypes[a] = i --i is the type value, a is the slot number
  198.       end
  199.     end
  200.   end
  201.   local currType --Types: 1 = saplings, 2 = bonemeal, >= 3 = other/wood
  202.   if initial then currType = 0 else currType = numTypes end
  203.   for i=1, 16 do --This handles comparing and new items
  204.     turtle.select(i)
  205.     local compares = false
  206.     for a=1, currType do
  207.       if turtle.compareTo(getRep(a, true) or 1) and turtle.getItemCount(i) > 0 then --There should always be a representative, unless first slot
  208.         slotTypes[i] = a
  209.         print("Slot ", i," Compares to Type ",a)
  210.         compares = true
  211.         break
  212.       end
  213.     end
  214.     if turtle.getItemCount(i) > 0 and initial and not compares and currType < 2 then --I don't care about the slot if its not a sapling/bonemeal
  215.       currType = currType + 1
  216.       slotTypes[i] = currType
  217.       print("Slot ",i," Has New Item Type ",currType)
  218.     end
  219.     if not initial and not compares then
  220.       slotTypes[i] = 0
  221.     end
  222.   end
  223.   turtle.select(1)
  224.   --types = currType
  225. end
  226. function countType(which)
  227.   local num = 0
  228.   for i=1, 16 do
  229.     if turtle.getItemCount(i) == 0 then
  230.       slotTypes[i] = 0
  231.     end
  232.     if slotTypes[i] == which then
  233.       num = num + turtle.getItemCount(i)
  234.     end
  235.   end
  236.   return num
  237. end
  238.  
  239.  
  240. function mineTree()
  241.   local moveDown = 0
  242.   forward()
  243.   atHome = false
  244.   while turtle.detectUp() do
  245.     up()
  246.     moveDown = moveDown + 1
  247.   end
  248.  
  249.   for i=1, moveDown do
  250.     down()
  251.   end
  252.   back()
  253.   if moveDown <= 1 then --These aren't saplings!
  254.     local tab = {}
  255.     tab[1] = getRep(0) --Assuming it thought trees were bonemeal
  256.     tab[2] = getRep(1) --I'm assuming that it thought bonemeal was saplings
  257.     if tab[1] then
  258.       assignTypes(false, unpack(tab)) --Saplings are probably in there somewhere
  259.     else
  260.       print("Assuming no saplings, going for more to compare")
  261.       getMaterials("sapling")
  262.     end
  263.   else
  264.     registerScore("tree",moveDown-1) -- -1 because goes up extra
  265.   end
  266.   atHome = true
  267. end
  268. function placeSapling()
  269.   local currSlot = getRep(typesTable.sapling.typeNum) or getMaterials("sapling")
  270.   turtle.select(currSlot) --If no saplings, get some saplings/wait
  271.   if not turtle.place() then
  272.     local k = not(dig(false)) or turtle.place() or error("Cannot place sapling, something broke") --Unexpected symbol crap --Digs without adding tries again, then prints that place failed
  273.   end
  274.   if turtle.getItemCount(currSlot) == 0 then
  275.     slotTypes[currSlot] = 0
  276.   end
  277. end
  278. function useBonemeal()
  279.   local count = 0
  280.   repeat
  281.     local currSlot = getRep(typesTable.bonemeal.typeNum) or getMaterials("bonemeal")
  282.     turtle.select(currSlot)
  283.     local test = turtle.place()
  284.     if test then
  285.       count = count + 1
  286.     end
  287.     if turtle.getItemCount(currSlot) == 0 then
  288.       slotTypes[currSlot] = 0
  289.     end
  290.   until not test
  291.   if count == 0 then --If this happens, then its actually hitting/using trees, not saplings
  292.     dig(false) --Kill tree, no counting
  293.     print("Bonemeal place failed something's wrong")
  294.     print("Refreshing inventory")
  295.     --[[print(textutils.serialize(slotTypes))
  296.         os.pullEvent("char")]]
  297.     getMaterials("sapling", true) --Get more saplings, this will also force a recount
  298. --[[print(textutils.serialize(slotTypes))
  299.         os.pullEvent("char")]]
  300.     getMaterials("bonemeal", true) --Actually, it might mean that bonemeal was misidentified too. Better get fresh
  301. --[[print(textutils.serialize(slotTypes))
  302.         os.pullEvent("char")]]
  303.   else
  304.     registerScore("bonemeal", count)
  305.   end
  306.     --[[turtle.select(getRep(typesTable.sapling.typeNum)) --This doesn't work because turtle.compare doesn't work with bonemealed saplings
  307.     if not turtle.compare() then return true end --This would have been in a while true do loop]]
  308. end
  309. local facingTable = {}
  310. do --This will be so I have all the info I need for dropping and sucking.
  311.   local function newEntry (side, number, dropFunc, suckFunc, detectFunc)
  312.     facingTable[side] = {number = number, drop = dropFunc, suck = suckFunc, detect = detectFunc}
  313.   end
  314.   newEntry("forward", 0, turtle.drop, turtle.suck, turtle.detect)
  315.   newEntry("top", 0, turtle.dropUp, turtle.suckUp, turtle.detectUp)
  316.   newEntry("bottom", 0, turtle.dropDown, turtle.suckDown, turtle.detectDown)
  317.   newEntry("left", 3, turtle.drop, turtle.suck, turtle.detect)
  318.   newEntry("right", 1, turtle.drop, turtle.suck, turtle.detect)
  319.   newEntry("back", 2, turtle.drop, turtle.suck, turtle.detect)
  320. end
  321. function getMaterials(what, forceWait) --This function will get materials from a certain place
  322.   print("Getting ",what)
  323.   turtle.select(1) --So materials go in in the first available spot
  324.   local toFace = facing
  325.   if forceWait == nil then forceWait = insistOnStock end
  326.   local facingInfo = facingTable[typesTable[what].side] --This table contains direction specific functions, since use is the same
  327.   turnTo(facingInfo.number) --Eg: facingTable[materialsTable["sapling"]].number --> facingTable["left"].number --> 3
  328.   local doWait = false
  329.   while not facingInfo.detect() do
  330.     doWait = true
  331.     screenSet()
  332.     print("Waiting for ",what," chest to be placed on ", typesTable[what].side)
  333.     sleep(2)
  334.   end
  335.   if doWait then
  336.     print("Waiting for key press when all materials in chest")
  337.     os.pullEvent("char")
  338.   end
  339.   local snapshot = getInvTable() --Done to compare inventory
  340.   local numObtained = countType(typesTable[what].typeNum)
  341.   local hasSucked = not forceWait --If forceWait is true, we want to make sure it sucks at least one stack, for flushing purposes.
  342.   while (numObtained < restock[what]) or (not hasSucked) do
  343.     local a = countChange(facingInfo.suck)
  344.     if a ~= 0 then
  345.       numObtained = numObtained + a
  346.       print("Obtained ",numObtained,"/",restock[what]," ",what)
  347.       hasSucked = true
  348.     else
  349.       if forceWait then
  350.         print("Suck failed, no more ",what,"?")
  351.         sleep(4)
  352.       else
  353.         break
  354.       end
  355.     end
  356.   end
  357.   local currType = typesTable[what].typeNum
  358.   local changedTable = getChangedSlots(getInvTable(), snapshot)
  359.   for a,b in ipairs(changedTable) do
  360.     slotTypes[b] = currType
  361.   end
  362.   local tempTable = {}
  363.   tempTable[typesTable[what].typeNum] = changedTable[1] --Doesn't even matter if nil. Nil means no override.
  364.   assignTypes(false, unpack(tempTable)) --This call overrides whatever it just got as the proper type
  365.   turnTo(toFace)
  366.   return (getRep(typesTable[what].typeNum) or getMaterials(what, true))
  367. end
  368. function dropMaterials(what, doAdd)
  369.   print("Dropping off ",what)
  370.   local toFace = facing
  371.   if doAdd == nil then doAdd = true end
  372.   local facingInfo = facingTable[typesTable[what].side] --This table contains direction specific functions, since use is the same
  373.   turnTo(facingInfo.number) --Eg: facingTable[materialsTable["sapling"]].number --> facingTable["left"].number --> 3
  374.   assignTypes(false) --This will catch any saplings and things that get picked up along the way
  375.   while not facingInfo.detect() do
  376.     screenSet()
  377.     print("Waiting for ",what," chest to be placed on ", typesTable[what].side)
  378.     sleep(2)
  379.   end
  380.   local currDropped = 0
  381.   for i=16, 1, -1 do
  382.     if slotTypes[i] == typesTable[what].typeNum and turtle.getItemCount(i) > 0 then
  383.       turtle.select(i)
  384.       local hasDropped = false
  385.       repeat
  386.         local currItems = turtle.getItemCount(i)
  387.         local amount = countChange(facingInfo.drop, currItems)
  388.         currDropped = currDropped + amount
  389.         if doAdd then
  390.           dropped = dropped + amount --This is the global
  391.         end
  392.         print("Dropped ",amount," ",what,". ",currDropped, " total")
  393.         if amount >= currItems then
  394.           hasDropped = true
  395.         else
  396.           screenSet(1,1)
  397.           print("Cannot drop ",what," on ",typesTable[what].side, " side")
  398.           sleep(2)
  399.         end
  400.       until hasDropped
  401.       slotTypes[i] = 0
  402.       if countType(typesTable[what].typeNum) <= (restock[what] or 0) then
  403.         break
  404.       end
  405.     end
  406.   end
  407.   turnTo(toFace)
  408.   turtle.select(1) --Its just nicer
  409.   return true
  410. end
  411.  
  412. function isFull()
  413.   local areFull = 0
  414.   local currInv = getInvTable()
  415.   for i=1, #currInv do
  416.     if currInv[i] > 0 then
  417.       areFull = areFull + 1
  418.     end
  419.   end
  420.   return areFull >= 16-keepOpen
  421. end
  422.  
  423. --Initial
  424. assignTypes(true) --Initial assign types
  425. if countType(typesTable.sapling.typeNum) == 0 then
  426.   getMaterials("sapling",true)
  427. end
  428. if countType(typesTable.bonemeal.typeNum) == 0 then
  429.   getMaterials("bonemeal", true)
  430. end
  431.  
  432. --Main Loop
  433. while true do
  434.   if turtle.detect() then mineTree() end --Dig out the tree
  435.   placeSapling() --Place a sapling
  436.   useBonemeal() --Use the bonemeal
  437.   if isFull() then --If inventory is full, drop it
  438.     dropMaterials("wood")
  439.   end
  440.   if countType(typesTable.sapling.typeNum) > restock.sapling then
  441.     dropMaterials("sapling", false)
  442.   end
  443.   if countType(typesTable.bonemeal.typeNum) > restock.bonemeal then
  444.     dropMaterials("bonemeal", false)
  445.   end
  446. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement